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
相关产品推荐
相关产品推荐

