PyQt5 从 QTextEdit 获取字符格式
PyQt5 get char format from QTextEdit
我使用 PyQt5 编写了一个小型文本编辑器。假设我在编辑器中输入了 Hello World,点击打印按钮后,我需要知道“Hello World”中的每个字符如下:
实际字符值(例如迭代器为 1 时为 H,迭代器为 2 时为 e...等)
是否加粗
是否为斜体
字符的字体大小
根据文档 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_())
每个QTextBlock可以包含多个QTextCharFormat,所以不能使用block.charFormat
。
一个可能的解决方案是对所有字母的每个块循环使用 QTextCursor。
注意QTextBlock也是一个迭代器,所以你可以从第一个块开始,然后使用block.next()
得到下一个,只要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()
我使用 PyQt5 编写了一个小型文本编辑器。假设我在编辑器中输入了 Hello World,点击打印按钮后,我需要知道“Hello World”中的每个字符如下:
实际字符值(例如迭代器为 1 时为 H,迭代器为 2 时为 e...等)
是否加粗
是否为斜体
字符的字体大小
根据文档 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_())
每个QTextBlock可以包含多个QTextCharFormat,所以不能使用block.charFormat
。
一个可能的解决方案是对所有字母的每个块循环使用 QTextCursor。
注意QTextBlock也是一个迭代器,所以你可以从第一个块开始,然后使用block.next()
得到下一个,只要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()