简体   繁体   中英

PyQt5 get char format from QTextEdit

I have written a small text editor using PyQt5. Suppose I have typed Hello World in the editor, and upon clicking the print button, I need to know for each character in "Hello World" the followings:

  1. The actual character value (eg H when iterator is 1, e when iterator is 2...etc)

  2. If the character is bold or not

  3. If the character is italic or not

  4. The font size of the character

From the documentation https://doc.qt.io/qtforpython/PySide2/QtGui/QTextBlock.html , it seems that it is possible to iterate over a text block. I am unsure how to do it and also how to extract the above information.

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_())

Each QTextBlock can contain multiple QTextCharFormat, so you cannot use block.charFormat .

A possible solution is to use a QTextCursor for each block cycle through all letters.

Note that QTextBlock also behaves as an iterator, so you can start with the first block and then use block.next() to get the next one, as long as block.isValid() returns 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()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM