为什么我的 charFormat 样式只适用于选择,而且只适用于特定方向的选择?

Why are my charFormat styles only working on selections, and only those made in a specific direction?

我一直在尝试更明确地分配文本编辑器的字符格式,以便我可以了解我可以根据当前的技能范围自定义哪些内容。虽然我的格式化方法的基本复制粘贴版本工作得很好,但下面的版本一直在工作,然后以令人沮丧的方式无法工作,需要帮​​助找出可能导致它的原因。

该编辑器最初旨在成为一个所见即所得的编辑器,通过文档标签设置样式。 Qt 对 Html 的混淆使用并没有让事情变得简单。


我的基本流程是提取当前格式的副本,检查其当前状态,反转它,然后将格式重新应用到提取它的位置或选择。

# textEdit is a QTextEdit with a loaded document.

# This function is one of several related pairs called by a switchboard.
# It's intent is to invert the italic state of the current position/selection.

def toggle_italic_text(textEdit):
    # Get the cursor, and the format's state at its current selection/position.
    cursor = textEdit.textCursor()
    charFormat = cursor.charFormat()
    currentState = charFormat.fontItalic()

    # Invert the state within the format.
    print(currentState)
    charFormat.setFontItalic(not currentState)
    print(charFormat.fontItalic())

    # Reapply the format to the cursor's current selection/position.
    cursor.mergeCharFormat(charFormat)

当我第一次实现它时,发现它很有效。现在,它只适用于选择,即便如此,它似乎也会根据我选择的方向来识别错误的状态。在试验之后,似乎如果我向右进行选择,它就会正确反转。如果我在左侧进行选择,则不会。

当尝试将它分配到一个位置 而没有 选择时,打印状态从 False 变为 True,这是需要的,但效果在我键入时不适用.如果我 运行 它重复到位,它会继续从 False 变为 True,这意味着更改正在丢失。

该函数被一致地调用并且 运行 完全通过。 charFormat 副本的存储状态确实发生了变化。

为什么这个模式停止工作了?我使用的 charFormats 错了吗?为什么选择的方向会改变结果?

就我这边发生的变化而言,在需要通过 QFonts、QCharFormats、QPalette 和 CSS 样式表(和 doc.defaultStylesheet)应用样式后,我在样式设置上迷失了方向针对小部件和 html 标签。我非常希望通过一种方法来控制我的样式,但无法弄清楚层次结构或找到一种应用足够广泛的方法。最后,我删除了除分配给 window.

的样式表之外的所有内容

如果代码本身没有问题,我真的很希望能得到一些提示,指出可能会破坏事情的原因。我花了一段时间才习惯这样的想法,即光标和格式是要更改和重新应用的副本,而文档及其块才是真正的结构。

关于 QTextCursor.charFormat() 必须考虑的重要事项是:

Returns the format of the character immediately before the cursor position().

因此,不仅这对于包含多种字符格式的选择效果不佳,而且您还必须考虑光标位置,它可能会在选择中发生变化:它可能在开头(所以它return 字符的格式 选择之前),或者在最后(return 字符的格式 last 选择中的字符)。

如果要根据当前光标位置反转状态(如果在开头,则使用第一个字符,如果在结尾,则使用最后一个),则可以使用以下方法:

    def toggle_italic_text(self):
        cursor = self.textEdit.textCursor()
        if not cursor.hasSelection():
            charFormat = cursor.charFormat()
            charFormat.setFontItalic(not charFormat.fontItalic())
            cursor.setCharFormat(charFormat)
            # in this case, the cursor has to be applied to the textEdit to ensure
            # that the following typed characters use the new format
            self.textEdit.setTextCursor(cursor)
            return

        start = cursor.selectionStart()
        end = cursor.selectionEnd()
        newCursor = QtGui.QTextCursor(self.textEdit.document())
        newCursor.setPosition(start)

        if cursor.position() == start:
            cursor.setPosition(start + 1)
        charFormat = cursor.charFormat()
        charFormat.setFontItalic(not charFormat.fontItalic())
        newCursor.setPosition(end, cursor.KeepAnchor)
        newCursor.mergeCharFormat(charFormat)

如果要反转选择中的所有状态,则需要循环遍历所有字符。
虽然您可以更改每个字符的 char 格式,但这对于非常大的选择来说并不是一件好事,因此解决方案是仅当 char 格式实际从以前的状态发生变化时才应用斜体, 在选择结束时。

    def toggle_italic_text(self):
        # ...
        start = cursor.selectionStart()
        end = cursor.selectionEnd()
        newCursor = QtGui.QTextCursor(self.textEdit.document())
        newCursor.setPosition(start)

        cursor.setPosition(start)
        prevState = cursor.charFormat().fontItalic()
        while cursor.position() < end:
            cursor.movePosition(cursor.Right)
            charFormat = cursor.charFormat()
            if charFormat.fontItalic() != prevState or cursor.position() >= end:
                newPos = cursor.position()
                if cursor.position() < end:
                    newPos -= 1
                newCursor.setPosition(newPos, cursor.KeepAnchor)
                charFormat.setFontItalic(not prevState)
                newCursor.mergeCharFormat(charFormat)
                prevState = not prevState
                newCursor.setPosition(cursor.position() - 1)