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

Qt QPlainTextEdit当前行高亮覆盖选中匹配单词高亮问题问询

问题描述

我在使用QPlainTextEdit控件时,需要同时实现两个功能:一是高亮显示用户当前光标所在行,二是高亮显示所有与用户选中单词相同的匹配词。目前单词高亮在除当前选中行外的所有行都可以正常生效,但当前行上的匹配词高亮会被「选中行」的背景样式覆盖,无法正常显示。如何调整高亮的执行顺序,让单词高亮在当前行高亮之后执行,从而实现两种高亮效果同时生效?

效果说明

效果截图
截图中黄色为当前高亮行,第一个'test'被选中后其余所有匹配的'test'都应显示浅蓝背景,仅高亮行上的'test'未生效。


解决方案

根本原因

你的实现存在绘制层级优先级问题:QPlainTextEdit的ExtraSelection(你用来实现当前行高亮的方案)的绘制层级高于文档本身的字符格式(你用来实现单词高亮的方案),无论执行顺序如何调整,行高亮的黄色背景都会覆盖当前行内单词的浅蓝背景。

优化方案

统一两种高亮的实现方式,全部使用ExtraSelection实现,利用ExtraSelection列表后加项绘制优先级更高的特性,先加行高亮项,再加单词高亮项即可实现叠层效果,同时还可以省去修改文档原生格式、保存恢复原格式的冗余逻辑。

修改后核心代码

MainWindow.h 无需改动

TextEditor.h 修改后代码

#pragma once
#include <QPlainTextEdit>
#include <QRegExp>
#include <algorithm>

class TextEditor : public QPlainTextEdit
{
    Q_OBJECT

public:
    TextEditor(QWidget* parent) : QPlainTextEdit(parent)
    {
        connect(this, &QPlainTextEdit::selectionChanged, this, &TextEditor::updateExtraSelections);
        connect(this, &QPlainTextEdit::cursorPositionChanged, this, &TextEditor::updateExtraSelections);
    }

private:
    // 统一更新所有高亮
    void updateExtraSelections()
    {
        QList<QTextEdit::ExtraSelection> extraSelections;

        // 第一步:先添加当前行高亮(底层)
        if (!isReadOnly())
        {
            QTextEdit::ExtraSelection lineSel;
            lineSel.format.setBackground(Qt::yellow);
            lineSel.format.setProperty(QTextFormat::FullWidthSelection, true);
            lineSel.cursor = textCursor();
            lineSel.cursor.clearSelection();
            extraSelections.append(lineSel);
        }

        // 第二步:再添加匹配单词高亮(上层)
        auto cur = textCursor();
        if (cur.selectionStart() < cur.selectionEnd())
        {
            auto plaintext = toPlainText();
            bool isFullWord = true;
            
            // 校验选中内容为完整单词(两侧为非字母数字字符)
            if (cur.selectionStart() > 0)
            {
                auto prevChar = plaintext.mid(cur.selectionStart() - 1, 1).toStdString()[0];
                if (isalnum(prevChar)) isFullWord = false;
            }
            if (cur.selectionEnd() < plaintext.size())
            {
                auto nextChar = plaintext.mid(cur.selectionEnd(), 1).toStdString()[0];
                if (isalnum(nextChar)) isFullWord = false;
            }
            // 校验选中内容本身不含非字母数字字符
            auto selectedText = cur.selectedText();
            if (std::any_of(selectedText.begin(), selectedText.end(), [](QChar c) { return !c.isLetterOrNumber(); }))
            {
                isFullWord = false;
            }

            if (isFullWord)
            {
                QTextCharFormat wordFormat;
                wordFormat.setBackground(QColor::fromRgb(0x70, 0xED, 0xE0));
                QRegExp reg("\\b" + selectedText + "\\b");
                int index = reg.indexIn(plaintext, 0);
                while (index >= 0)
                {
                    QTextEdit::ExtraSelection wordSel;
                    wordSel.format = wordFormat;
                    wordSel.cursor = textCursor();
                    wordSel.cursor.setPosition(index);
                    wordSel.cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor, 1);
                    extraSelections.append(wordSel);
                    index = reg.indexIn(plaintext, index + reg.matchedLength());
                }
            }
        }

        // 一次性设置所有高亮
        setExtraSelections(extraSelections);
    }
};

修改后当前行的黄色背景会作为底层,匹配单词的浅蓝背景会叠在上方,两种高亮效果可以同时正常显示。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 09:24:04