【问题标题】:PyQt5 get char format from QTextEditPyQt5 从 QTextEdit 获取字符格式
【发布时间】:2020-08-10 22:44:57
【问题描述】:

我使用 PyQt5 编写了一个小型文本编辑器。假设我在编辑器中输入了 Hello World,点击打印按钮后,我需要知道“Hello World”中每个字符的以下内容:

  1. 实际字符值(例如,当迭代器为 1 时为 H,当迭代器为 2 时为 e...等)

  2. 字符是否为粗体

  3. 字符是否为斜体

  4. 字符的字体大小

从文档 https://doc.qt.io/qtforpython/PySide2/QtGui/QTextBlock.html 来看,似乎可以迭代文本块。我不确定如何做以及如何提取上述信息。

from PyQt5 import QtCore, QtGui, QtWidgets

class freeTextPrint(QtWidgets.QMainWindow):
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)
        self.setupUI()
    
    def setupUI(self):

        #Render the font size label
        self.toolbar = self.addToolBar('format')
        labelFontSize = QtWidgets.QLabel('Font Size')
        font = QtGui.QFont()
        font.setPointSize(11)
        font.setBold(True)
        labelFontSize.setFont(font)
        self.toolbar.addWidget(labelFontSize)
        self.toolbar.addSeparator()

        #Font Size combo box
        self.fontSizeComboBox = QtWidgets.QComboBox(self)
        #Insert font sizes to the combo box
        sizeList = list(range(10, 31))
        for i in sizeList:
            self.fontSizeComboBox.addItem(str(i))
        self.fontSizeComboBox.currentIndexChanged.connect(self.fontSizeChanged)
        
        font.setBold(False)
        self.fontSizeComboBox.setFont(font)
        self.toolbar.addWidget(self.fontSizeComboBox)

        #A toogle button to set bold font to True or False
        self.toolbar.addSeparator()
        self.boldAction = QtWidgets.QAction(QtGui.QIcon('icons/format-text-bold.svg'), 'bold', self)
        self.boldAction.triggered.connect(self.bold)
        self.toolbar.addAction(self.boldAction)

        #A toogle button to set italic to true or false
        self.italicAction = QtWidgets.QAction(QtGui.QIcon('icons/format-text-italic.svg'),'italic', self)
        self.italicAction.triggered.connect(self.italic)
        self.toolbar.addAction(self.italicAction)

        #Setup textedit
        self.textEdit = QtWidgets.QTextEdit(self)
        self.textEdit.setGeometry(QtCore.QRect(20, 40, 521, 121))
        #Limit characters
        self.textEdit.LineWrapMode(QtWidgets.QTextEdit.FixedColumnWidth)

        #Add print push button
        self.printPushButton = QtWidgets.QPushButton(self)
        self.printPushButton.setGeometry(QtCore.QRect(418, 180, 120, 30))
        self.printPushButton.setText('Print')
        self.printPushButton.clicked.connect(self.print)
        font.setBold(True)
        self.printPushButton.setFont(font)

        #Label for Printer connection
        labelPrinterConnection = QtWidgets.QLabel('Printer Connection', self)
        labelPrinterConnection.setGeometry(QtCore.QRect(20, 180, 160, 30))
        labelPrinterConnection.setFont(font)
        
        #Geometry of the main window
        self.setGeometry(100, 100, 600, 300)
    
    def fontSizeChanged(self):
        #Get the value of the updated font size
        selectedFontSize = int(self.fontSizeComboBox.currentText())
        hasSelection, cursor = self.textSelected()
        fmt = QtGui.QTextCharFormat()
        if hasSelection:
            fmt.setFontPointSize(selectedFontSize)
            cursor.mergeCharFormat(fmt)
        else:
            self.textEdit.setFontPointSize(selectedFontSize)
        
    def bold(self):
        #check anything has selected. If found only the selected part is formatted
        hasSelection, cursor = self.textSelected()

        if hasSelection:
            #Get the current weight of the selected text
            selection = cursor.selection()
            htmlString = selection.toHtml()
            #Check if the the htmlString already has code for bold character. If found, the bold setting is turned off, otherwise it is turned on
            fmt = QtGui.QTextCharFormat()
            if 'font-weight:600' in htmlString:
                fmt.setFontWeight(QtGui.QFont.Normal)
                cursor.mergeCharFormat(fmt)
            else:
                fmt.setFontWeight(QtGui.QFont.Bold)
                cursor.mergeCharFormat(fmt)
    
    def textSelected(self):
        '''
        get the cursor object from text editor and checks if text is selected. If text is selected return True together with the cursor object, otherwise 
        return False with the cursor object
        '''
        cursor = self.textEdit.textCursor()
        if cursor.hasSelection():
            return True, cursor
        else:
            return False, cursor

    def italic(self):
        hasSelection, cursor = self.textSelected()
        if hasSelection:
            selection = cursor.selection()
            htmlString = selection.toHtml()
            #Check if the selection is already italic if so, italic will be turned off. Otherwise, italic will be turned on
            fmt = QtGui.QTextCharFormat()
            
            if 'font-style:italic' in htmlString:
                fmt.setFontItalic(False)
            else:
                fmt.setFontItalic(True)
            cursor.mergeCharFormat(fmt)
            
    def print(self):
        document = self.textEdit.document()
        currentBlock = document.firstBlock()
        blockCharFormat = currentBlock.charFormat()
        print(blockCharFormat)
        
        pass

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    ui = freeTextPrint()
    ui.show()
    sys.exit(app.exec_())

【问题讨论】:

  • 只是出于好奇,您为什么需要循环浏览所有个字母?
  • 因为我需要将它发送到标签打印机。通过了解字符格式,我可以生成标签打印机使用的相应 zpl 命令。

标签: python python-3.x pyqt pyqt5


【解决方案1】:

每个QTextBlock可以包含多个QTextCharFormat,所以不能使用block.charFormat

一种可能的解决方案是使用 QTextCursor 为每个块循环遍历所有字母。

请注意,QTextBlock 也充当迭代器,因此您可以从第一个块开始,然后使用 block.next() 获取下一个块,只要 block.isValid() 返回 True。

    def print(self):
        document = self.textEdit.document()
        block = document.firstBlock()
        while block.isValid():
            cursor = QtGui.QTextCursor(block)
            text = block.text()
            for l in range(block.length() - 1):
                charFormat = cursor.charFormat()
                size = charFormat.font().pointSize()
                if size < 0:
                    size = document.defaultFont().pointSize()
                print('{letter} Bold: {bold}, Italic: {italic}, Size: {size}'.format(
                    letter = text[l], 
                    bold = charFormat.fontWeight() > 50, 
                    italic = charFormat.fontItalic(), 
                    size = size
                ))
                cursor.movePosition(cursor.Right)
            block = block.next()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-11
    • 1970-01-01
    相关资源
    最近更新 更多