事先与 OP 进行了一些对话,因为我非常怀疑 QTextEdit 的颜色属性是否也负责文本光标的颜色。
所有我在Qt Style Sheets Reference找到的:
用于渲染文本的颜色。
所有尊重 QWidget::palette 的小部件都支持此属性。
如果未设置此属性,则默认值为在小部件调色板中为 QWidget::foregroundRole 设置的任何内容(通常为黑色)。
出于好奇,我稍微摆弄了一下QTextEdit的颜色。
-
我可以重现 OP 描述的内容:
更改QTextEdit 的文本颜色(例如QTextEdit::setTextColor())会影响之后键入的插入文本,但不会更改文本光标颜色(至少在我测试的平台上)。
在摆弄时,我意识到另一个鼓励我写下这个答案的事实:
恕我直言,文本光标忽略任何颜色设置。相反,它会反转绘制的文本光标栏下的像素。
看看QPainter::RasterOp_NotSource 看看我的意思。
我的示例应用程序testQTextEditCursorColor.cc:
#include <QtWidgets>
class ColorButton: public QPushButton {
private:
QColor _qColor;
public:
explicit ColorButton(
const QString &text, const QColor &qColor = Qt::black,
QWidget *pQParent = nullptr):
QPushButton(text, pQParent)
{
setColor(qColor);
}
virtual ~ColorButton() = default;
ColorButton(const ColorButton&) = delete;
ColorButton& operator=(const ColorButton&) = delete;
const QColor& color() const { return _qColor; }
void setColor(const QColor &qColor)
{
_qColor = qColor;
QFontMetrics qFontMetrics(font());
const int h = qFontMetrics.height();
QPixmap qPixmap(h, h);
qPixmap.fill(_qColor);
setIcon(qPixmap);
}
QColor chooseColor()
{
setColor(QColorDialog::getColor(_qColor, this, text()));
return _qColor;
}
};
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
qDebug() << app.style();
// setup GUI
QMainWindow qWin;
qWin.resize(250, 100);
qWin.setWindowTitle("Test Set Cursor Color");
QTextEdit qTextEdit;
qWin.setCentralWidget(&qTextEdit);
QToolBar qToolBar;
ColorButton qBtnColor("Text Color", qTextEdit.palette().color(QPalette::Text));
qToolBar.addWidget(&qBtnColor);
ColorButton qBtnColorBg("Background", qTextEdit.palette().color(QPalette::Base));
qToolBar.addWidget(&qBtnColorBg);
qWin.addToolBar(&qToolBar);
qWin.show();
// install signal handlers
QObject::connect(&qBtnColor, &QPushButton::clicked,
[&]() { qTextEdit.setTextColor(qBtnColor.chooseColor()); });
QObject::connect(&qBtnColorBg, &QPushButton::clicked,
[&]() {
QPalette qPal = qTextEdit.palette();
qPal.setColor(QPalette::Base, qBtnColorBg.chooseColor());
qTextEdit.setPalette(qPal);
});
// runtime loop
return app.exec();
}
以及对应的Qt工程文件testQTextEditCursorColor.pro:
SOURCES = testQTextEditCursorColor.cc
QT += widgets
在 Windows 10 上的 cygwin64 中编译和测试:
$ qmake-qt5 testQTextEditCursorColor.pro
$ make && ./testQTextEditCursorColor
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o testQTextEditCursorColor.o testQTextEditCursorColor.cc
g++ -o testQTextEditCursorColor.exe testQTextEditCursorColor.o -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread
Qt Version: 5.9.4
QFusionStyle(0x6000e10c0, name = "fusion")
因此,黑色生成白色光标,白色生成黑色光标(与任何颜色设置无关)。假设我上面的陈述是正确的,青色背景(#00ffff)应该是红色光标(#ff0000):
为了比较,我写了一个CMake脚本CMakeLists.txt:
project(QTextEditCursorColor)
cmake_minimum_required(VERSION 3.10.0)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
find_package(Qt5Widgets CONFIG REQUIRED)
include_directories("${CMAKE_SOURCE_DIR}")
add_executable(testQTextEditCursorColor testQTextEditCursorColor.cc)
target_link_libraries(testQTextEditCursorColor Qt5::Widgets)
再次在VS2017中编译测试:
Qt Version: 5.11.2
QWindowsVistaStyle(0x1c1ed936690, name = "windowsvista")
(请注意,不同风格的引擎。)
Windows GDI 中的渲染很明显,字形像素也被反转了(但我在上面的 X11 测试中注意到了同样的情况):
考虑到以上,很明显使用中间灰色作为背景色是个坏主意。例如的按位非#808080 是 #7f7f7f 并且这两种颜色之间几乎没有对比。 (我没有提供快照,因为我无法识别为绘制文本光标的快照按下 Print 键的正确时间。)
OP 提到了另一个问答:SO: Qt 5.3 QPlainTextEdit Change the QTextCursor color。虽然,这个答案被接受并赞成,但如上所述以任何其他方式改变我这边的光标颜色并没有帮助。这些是修改,我在我的示例上尝试过:
- 将
QTextEdit 替换为QPlainTextEdit
- 用
qTextEdit.setCursorWidth()改变文本光标宽度
- 使用样式表而不是修改调色板中的颜色
包括在“字面上”的链接答案中使用公开的代码。
在与 thuga(SO: Qt 5.3 QPlainTextEdit Change the QTextCursor color 已接受答案的作者)进行了一番交谈后,似乎有一个关于 Qt 5.8 的错误报告:
Qt 5.8 no longer allows QPlainTextEdit's cursor color to be set
在撰写本文时标记为Unresolved。 (目前Qt5.12是最新版本。)
在解释了为什么它不能开箱即用之后,最后一个示例如何使用自定义绘制的光标来实现 OP 意图:
#include <QtWidgets>
class TextEdit: public QTextEdit {
protected:
virtual void paintEvent(QPaintEvent *pEvent) override;
};
void TextEdit::paintEvent(QPaintEvent *pQEvent)
{
// use paintEvent() of base class to do the main work
QTextEdit::paintEvent(pQEvent);
// draw cursor (if widget has focus)
if (hasFocus()) {
const QRect qRect = cursorRect(textCursor());
QPainter qPainter(viewport());
qPainter.fillRect(qRect, textColor());
}
}
class ColorButton: public QPushButton {
private:
QColor _qColor;
public:
explicit ColorButton(
const QString &text, const QColor &qColor = Qt::black,
QWidget *pQParent = nullptr):
QPushButton(text, pQParent)
{
setColor(qColor);
}
virtual ~ColorButton() = default;
ColorButton(const ColorButton&) = delete;
ColorButton& operator=(const ColorButton&) = delete;
const QColor& color() const { return _qColor; }
void setColor(const QColor &qColor)
{
_qColor = qColor;
QFontMetrics qFontMetrics(font());
const int h = qFontMetrics.height();
QPixmap qPixmap(h, h);
qPixmap.fill(_qColor);
setIcon(qPixmap);
}
QColor chooseColor()
{
setColor(QColorDialog::getColor(_qColor, this, text()));
return _qColor;
}
};
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
qDebug() << app.style();
// setup GUI
QMainWindow qWin;
qWin.resize(250, 100);
qWin.setWindowTitle("Test Set Cursor Color");
TextEdit qTextEdit;
qWin.setCentralWidget(&qTextEdit);
qTextEdit.setCursorWidth(QFontMetrics(qTextEdit.font()).averageCharWidth());
QToolBar qToolBar;
ColorButton qBtnColor("Text Color",
qTextEdit.palette().color(QPalette::Text));
qToolBar.addWidget(&qBtnColor);
ColorButton qBtnColorBg("Background",
qTextEdit.palette().color(QPalette::Base));
qToolBar.addWidget(&qBtnColorBg);
qWin.addToolBar(&qToolBar);
qWin.show();
// install signal handlers
QObject::connect(&qBtnColor, &QPushButton::clicked,
[&]() { qTextEdit.setTextColor(qBtnColor.chooseColor()); });
QObject::connect(&qBtnColorBg, &QPushButton::clicked,
[&]() {
QPalette qPal = qTextEdit.palette();
qPal.setColor(QPalette::Base, qBtnColorBg.chooseColor());
qTextEdit.setPalette(qPal);
});
// runtime loop
return app.exec();
}
QTextEdit 被派生的TextEdit 替换为被覆盖的paintEvent()。
在TextEdit::paintEvent() 中调用QTextEdit::paintEvent() 来完成主要工作。之后,光标在textColor 中用矩形(重新)绘制。 (这只是覆盖了已经渲染的内置文本光标。)
注意:
小陷阱是在TextEdit::paintEvent() 中使用QPainter。因为QTextEdit 派生自QAbstractScrollArea,所以QPainter qPainter(this); 是错误的。相反,必须使用QPainter qPainter(viewport());。这在 Qt 文档中有所提及。对于QAbstractScrollArea::paintEvent():
注意:如果你打开一个painter,一定要在viewport()上打开它。