You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt6文本粗体切换异常:全选加粗文本无法取消格式

问题:PyQt6文本编辑器无法正确切换选中文本的粗体格式

我正在用Python和PyQt6开发自定义文字处理器作为个人项目,编写了如下代码,意图实现选中文本按Ctrl-B切换粗体:若选中文本全为粗体则取消,否则添加粗体格式。

class OvidFont:
    def __init__(self, ovid) -> None:
        self.textEditor = ovid.textEditor

    def setBoldText(self) -> None:
        fmt = QTextCharFormat()
        if self.textEditor.currentCharFormat().fontWeight() != QFont.Weight.Bold:
            print("    setting bold")   # for debugging
            fmt.setFontWeight(QFont.Weight.Bold)
        else:
            print("    setting normal") # for debugging
            fmt.setFontWeight(QFont.Weight.Normal)
        self.textEditor.textCursor().mergeCharFormat(fmt)

实际运行时无法取消粗体:如选中“this is a test”里的“is a”设为粗体后,保持选中按Ctrl-B,粗体仍存在;但取消选中首尾任一字符时,切换功能正常。反转if/else逻辑也无效。

已添加可运行最小测试案例。

解决方案

问题出在currentCharFormat()的使用上:这个方法仅返回光标当前所在位置的字符格式,而非选中范围内所有字符的统一格式。当你选中一段混合格式的文本(比如部分粗体、部分正常)时,它只会取光标停留位置的格式来判断,导致逻辑判断错误。

比如你选中已加粗的“is a”后,光标可能停留在粗体字符上,此时currentCharFormat()会返回粗体格式,代码会执行取消粗体的逻辑,但mergeCharFormat()是合并格式——对于已经是粗体的字符,合并正常格式不会改变它的粗体属性,所以粗体依然存在。

要解决这个问题,需要遍历选中范围内的所有字符,检查它们的格式是否全部为粗体,再执行对应的切换逻辑:

from PyQt6.QtGui import QTextCharFormat, QFont, QTextCursor

class OvidFont:
    def __init__(self, ovid) -> None:
        self.textEditor = ovid.textEditor

    def setBoldText(self) -> None:
        cursor = self.textEditor.textCursor()
        # 处理无选中内容的情况:切换光标所在位置的格式
        if not cursor.hasSelection():
            current_weight = cursor.charFormat().fontWeight()
            fmt = QTextCharFormat()
            fmt.setFontWeight(QFont.Weight.Bold if current_weight != QFont.Weight.Bold else QFont.Weight.Normal)
            cursor.mergeCharFormat(fmt)
            self.textEditor.setTextCursor(cursor)
            return
        
        # 处理有选中内容的情况:检查所有选中字符是否全为粗体
        start_pos = cursor.selectionStart()
        end_pos = cursor.selectionEnd()
        all_bold = True

        # 遍历选中范围内的每个字符
        temp_cursor = QTextCursor(self.textEditor.document())
        temp_cursor.setPosition(start_pos)
        while temp_cursor.position() < end_pos:
            if temp_cursor.charFormat().fontWeight() != QFont.Weight.Bold:
                all_bold = False
                break
            temp_cursor.movePosition(QTextCursor.MoveOperation.NextCharacter)
        
        # 重置光标到原选中范围,应用格式
        cursor.setPosition(start_pos)
        cursor.setPosition(end_pos, QTextCursor.MoveMode.KeepAnchor)
        fmt = QTextCharFormat()
        fmt.setFontWeight(QFont.Weight.Normal if all_bold else QFont.Weight.Bold)
        cursor.mergeCharFormat(fmt)
        self.textEditor.setTextCursor(cursor)

代码说明

  1. 区分无选中和有选中两种场景:无选中时直接切换光标处的格式;
  2. 有选中时,创建临时光标遍历选中范围的所有字符,判断是否全部为粗体;
  3. 根据判断结果设置对应的格式,再应用到选中范围,确保所有字符统一切换粗体状态。

内容的提问来源于stack exchange,提问作者Ovid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 18:40:25