检查 QTextEdit 中所选文本的格式 - PySide6

Posted

技术标签:

【中文标题】检查 QTextEdit 中所选文本的格式 - PySide6【英文标题】:Checking formatting of selected text in QTextEdit - PySide6 【发布时间】:2022-01-10 01:40:09 【问题描述】:

我正在开发一个富文本编辑器,遇到了一个小问题,我用看起来像是“hack”的方法解决了这个问题。

所以我想检查所选文本或光标位置的文本是否有任何格式、粗体、斜体等,并检查执行相应工作的相应按钮,但它变得很奇怪。

如果我做类似的事情

                       if self.ed.fontItalic() is True:
                            self.italic.setChecked(True)
                        else:
                            self.italic.setChecked(False)
            
                        if self.ed.fontUnderline() is True:
                            self.uline.setChecked(True)
                        else:
                            self.uline.setChecked(False)

其中“self.italic”和“self.uline”是可检查的QPushButtons;

只检查光标下的格式,但不检查斜体和下划线按钮,即,如果所选文本具有机器人格式。

基本上,它会忽略选定的文本并查找光标下文本的格式。

所以我目前正在解析 html 以查看它是否具有格式;

   def check_formatting(self):

        if self.ed.textCursor().hasSelection():
            print(self.ed.textCursor().selection().toHtml())
            if "font-style:italic;" in self.ed.textCursor().selection().toHtml():
                self.italic.setChecked(True)
            else:
                self.italic.setChecked(False)

            if "text-decoration: underline;" in self.ed.textCursor().selection().toHtml():
                self.uline.setChecked(True)
            else:
                self.uline.setChecked(False)

        else:
            if self.ed.fontItalic() is True:
                self.italic.setChecked(True)
            else:
                self.italic.setChecked(False)

            if self.ed.fontUnderline() is True:
                self.uline.setChecked(True)
            else:
                self.uline.setChecked(False)

在按钮单击时格式化所选文本或光标下的文本的代码如下

    def set_italic(self):
                if self.italic.isChecked():
                    self.ed.setFontItalic(True)
                    if self.ed.textCursor().hasSelection():
                        if self.ed.fontItalic() != QTextFormat.FontItalic:
                            self.ed.setFontItalic(True)
                        else:
                            self.ed.setFontItalic(False)
                else:
                    self.ed.setFontItalic(False)

所有这些几乎都按预期工作,但感觉都超级 hacky。并且通过 html 解析,显然,如果用户输入“font-style:italic;”在文本编辑中并选择输入的文本,斜体按钮被选中。

我在互联网上浏览了很多东西,但没有一个能像上面的代码那样帮助我实现。

【问题讨论】:

这是预期的行为:默认情况下,只有光标位置用于检查格式,这是有道理的;如果选择包含多种格式(甚至是多种字体粗细,因为除了“正常”和“粗体”之外还有其他粗细),函数应该返回什么?您可能对所选内容包含粗体/斜体/下划线文本这一事实感兴趣,但其他人可能想知道所选内容 only 是否包含粗体(或斜体或下划线)文本。你的方法也有问题,好像你选择了inside格式的文本,你根本不会得到任何格式信息。 假设您有一个 big 选择,其中有一个不同格式的 single 字符,按照您的方法,所有选择都将具有该格式,这将是违反直觉的。无论如何,如果那是您想要的,它仍然可以完成,但是您无论如何都不能使用 html,但是您必须使用 QTextCursor 并循环浏览选择中的所有格式(如果有)。除此之外,您的按钮逻辑过于复杂,因为格式功能和按钮切换功能都是布尔值,只需执行self.italic.setChecked(self.ed.fontItalic()) 【参考方案1】:

默认行为是预期的,从编程的角度来看,无法知道开发人员是否有兴趣知道选择是否在任何点设置了格式,或者他们想知道如果它确实包含该格式。

此外,检查文档的 html 在概念上是错误的,因为格式可以在选择之外设置(包括使用默认样式表),同样重要的是要记住 toHtml() 函数返回“翻译" 的基础 QTextDocument,它不是文档对象本身。 验证指定位置的格式的唯一正确方法是获取给定字符位置的文本光标的QTextCharFormat。

如果您真的想检查所选内容是否在任何位置包含任何格式更改,无论光标位置如何,您都需要循环浏览所选内容中的所有字符并验证它们的格式。

请注意,在这种情况下,您需要同时连接cursorPositionChangedselectionChanged 信号,因为用户可以在光标位置单击编辑器,这将清除选择但赢得'不改变光标位置。

使用下面的代码,check_formatting 函数会自动切换按钮,这样你就不需要在按钮函数中检查当前格式,但是你可以直接连接到文本编辑函数,因为它们会切换格式完全基于check_formatting 设置的状态,从而覆盖默认行为。

class Editor(QtWidgets.QWidget):
    def __init__(self):
        # ...
        self.ed.cursorPositionChanged.connect(self.check_formatting)
        self.ed.selectionChanged.connect(self.check_formatting)

        self.bold.toggled.connect(self.toggle_bold)
        self.italic.toggled.connect(self.ed.setFontItalic)
        self.underline.toggled.connect(self.ed.setFontUnderline)

    def toggle_bold(self, bold):
        self.ed.setFontWeight(QtGui.QFont.Bold if bold else QtGui.QFont.Normal)

    def check_formatting(self):
        # assume no format by default
        bold = italic = underline = False
        cursor = self.ed.textCursor()
        if cursor.hasSelection():
            rangeEnd = cursor.selectionEnd() + 1
        else:
            rangeEnd = cursor.selectionStart() + 1
        for pos in range(cursor.selectionStart(), rangeEnd):
            cursor.setPosition(pos)
            fmt = cursor.charFormat()
            if fmt.fontWeight() >= QtGui.QFont.Bold:
                bold = True
            if fmt.fontItalic():
                italic = True
            if fmt.fontUnderline():
                underline = True
            if all((bold, italic, underline)):
                # all formats are set, no need for further checking
                break

        # set check states of buttons but block their signals to avoid
        # unnecessary calls and unwanted behavior when using keyboard
        # navigation for selection (eg: shift+arrows)
        with QtCore.QSignalBlocker(self.bold):
            self.bold.setChecked(bold)
        with QtCore.QSignalBlocker(self.italic):
            self.italic.setChecked(italic)
        with QtCore.QSignalBlocker(self.underline):
            self.underline.setChecked(underline)

【讨论】:

我已经用类似的方法解决了这个问题,但使用了 while 循环。但是您的解决方案更加强大。谢谢。

以上是关于检查 QTextEdit 中所选文本的格式 - PySide6的主要内容,如果未能解决你的问题,请参考以下文章

RichTextBox 中所选文本的颜色

如何更改材质ui表中所选行的文本颜色

使用啥代替 FirstOrDefault 来获取与 C# 中使用 linq 中所选章节关联的 json 文本?

在 QTextEdit 中使用富文本

QT软件开发之基础控件--2.4.4 QTextEdit文本编辑器

是否可以更改 Flutter 中所选标签栏图标的大小?