Qt 5.8 Цвет текстового курсора QTextEdit не изменится - PullRequest
1 голос
/ 27 апреля 2019

Я пытаюсь сделать текстовый курсор на QTextEdit красным (rgb (255,0,0)). Несмотря на все мои усилия, он продолжает мигать белым.

Из того, что я обнаружил, свойство "Color" таблицы стилей должно изменять цвет курсора. Не уверен, что не так.

Мой код:

    textEntry = new QTextEdit();
    textEntry->setFont(QFont("Electrolize", 9, 1));
    textEntry->setMinimumHeight(25);
    textEntry->setMaximumHeight(25);
    textEntry->setLineWrapMode(QTextEdit::NoWrap);
    textEntry->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    textEntry->setStyleSheet("color: rgb(255, 0, 0);"
                             "border: 1px solid rgb(255, 0, 0);");

Edit: Я рекомендую полностью прочитать ответ Шеффа. Это круто Я заметил, что курсор, созданный с помощью его решения, не мигает, поэтому я хотел поделиться мигающей версией, полученной из кода Шеффа, с моим (неопытным) дополнением.

textedit.h

#ifndef TEXTEDIT_H
#define TEXTEDIT_H

#include <QTextEdit>
#include <QTimer>

class TextEdit : public TextEdit
{
    Q_OBJECT
public:
    explicit TextEdit(QWidget *parent = nullptr);

private:
    QTimer *timer;
    QPainter *pPainter;
    bool bCursorVisible;

protected:
    virtual void paintEvent(QPaintEvent *pEvent) override;

signals:
    sendUpdate();

public slots:
    void timerSlot();
};

#endif // TEXTEDIT_H

textedit.cpp

#include "textedit.h"

#include <QPainter>
#include <QColor>
#include <QTimer>

TextEdit::TextEdit(QWidget *parent) : QTextEdit(parent) {
    bCursorVisible = true;

    timer = new QTimer(this);
    timer->start(500);
    connect(this, SIGNAL(sendUpdate()), this, SLOT(update()));
    connect(timer, SIGNAL(timeout()), this, SLOT(timerSlot()));
}

void TextEdit::paintEvent(QPaintEvent *event)
{
  // use paintEvent() of base class to do the main work
  QTextEdit::paintEvent(event);
  // draw cursor (if widget has focus)
  if (hasFocus()) {
    if(bCursorVisible) {
        const QRect qRect = cursorRect(textCursor());
        QPainter qPainter(viewport());
        qPainter.fillRect(qRect, QColor(255, 0, 0, 255));
    } else {
        const QRect qRect = cursorRect(textCursor());
        QPainter qPainter(viewport());
        qPainter.fillRect(qRect, QColor(0, 0, 0, 255));
    }
  }
}

void TextEdit::timerSlot() {
    if(bCursorVisible) {
        bCursorVisible = false;
    } else {
        bCursorVisible = true;
    }

    emit sendUpdate();
}

1 Ответ

2 голосов
/ 28 апреля 2019

Заранее поговорили с OP, так как я серьезно сомневался, отвечает ли свойство color QTextEdit и за цвет текстового курсора.

Все, что я нашел в справочнике таблиц стилей Qt :

Цвет, используемый для визуализации текста.

Это свойство поддерживается всеми виджетами, которые относятся к QWidget :: palette.

Если это свойство не задано, по умолчанию используется значение, указанное в палитре виджета для QWidget :: foregroundRole (обычно черного цвета).

Из любопытства я немного поиграл с цветами QTextEdit.

  1. Я мог бы воспроизвести то, что описал ОП:
    Изменение цвета текста на QTextEdit (например, с помощью QTextEdit::setTextColor()) влияет на введенный текст, введенный впоследствии, но не меняет цвет курсора текста (по крайней мере, на платформах, где я тестировал) .

  2. Пока я возился, я понял еще один факт, побудивший меня написать этот ответ:
    ИМХО, текстовый курсор игнорирует любые настройки цвета. Вместо этого он инвертирует пиксели под нарисованной текстовой панелью курсора.
    Взгляните на 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

Скомпилировано и протестировано в cygwin64 в Windows 10:

$ 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")

Snapshot in X11 (white background) Snapshot in X11 (black background)

Итак, черный делает белый курсор, белый делает черный курсор (независимо от настроек цвета). Предполагая, что мое приведенное выше утверждение верно, голубой фон (#00ffff) должен сделать красный курсор (#ff0000):

Snapshot in X11 (cyan background)

Для сравнения я написал скрипт 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")

(Обратите внимание, движок другого стиля.)

Snapshot in Windows 10 (white background) Snapshot in Windows 10 (black background)

Визуализация в Windows GDI делает очевидным, что глиф-пиксели также инвертированы (но я заметил то же самое в тесте X11 выше):

Cursor in Windows 10 (5× magnified)


Принимая во внимание вышесказанное, становится очевидным, что плохой идеей является использование среднего серого в качестве цвета фона. Побитовое НЕ, например, #808080 - это #7f7f7f, и между этими двумя цветами существует небольшой контраст. (Я не предоставляю снимок, потому что я не смог распознать правильное время нажатия клавиши Print для снимка с нарисованным текстовым курсором.)


OP ссылается на другой Q & A: SO: Qt 5.3 QPlainTextEdit Изменить цвет QTextCursor . Хотя этот ответ был принят и отклонен, это не помогло изменить цвет курсора на моей стороне любым другим способом, как описано выше. Вот те модификации, которые я пробовал на своем образце:

  • замена QTextEdit на QPlainTextEdit
  • изменение ширины текстового курсора с помощью qTextEdit.setCursorWidth()
  • использовал таблицы стилей вместо изменения цветов в палитре

включая использование открытого кода в связанном ответе «буквально».


После некоторого разговора с thuga (автором принятого ответа на SO: Qt 5.3 QPlainTextEdit Измените цвет QTextCursor , оказалось, что есть сообщение об ошибке для Qt 5.8 относительно этого:

Qt 5.8 больше не позволяет устанавливать цвет курсора QPlainTextEdit

который отмечен как 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().

QTextEdit::paintEvent() вызывается в TextEdit::paintEvent() для выполнения основной работы. После этого курсор (пере) окрашивается прямоугольником в textColor. (Это просто закрашивает уже отрисованный встроенный текстовый курсор.)

Snapshot in cygwin with X11 Snapshot in Windows 10 with GDI

Примечание:

Небольшой ловушкой является использование QPainter в TextEdit::paintEvent().Поскольку QTextEdit является производным от QAbstractScrollArea, QPainter qPainter(this); будет неправильным.Вместо этого следует использовать QPainter qPainter(viewport());.Это упоминается в документе Qt.для QAbstractScrollArea::paintEvent():

Примечание: Если вы открываете художник, обязательно откройте его в окне просмотра () .

...