Изменить цвет текста-заполнителя в QLineEdit

Когда я устанавливаю текст-заполнитель с помощью QLineEdit::setPlaceholderText(), он становится серым.

введите здесь описание изображения

Есть ли способ изменить цвет на что-то другое, например красный?


person Programming    schedule 01.12.2014    source источник
comment
Вам нужно реализовать собственную функцию рисования заполнителей. Вы можете просмотреть исходный код Qt, как это работает. Это очень просто.   -  person Dmitry Sazonov    schedule 01.12.2014
comment
Здесь вы можете увидеть как это обрабатывается в исходном коде QLineEdit. По сути, он просто берет цвет текста и уменьшает альфа-канал.   -  person thuga    schedule 01.12.2014
comment
Я отредактировал вопрос, чтобы сделать его более общим и понятным.   -  person alediaferia    schedule 01.12.2014


Ответы (6)


Вы не можете, по крайней мере, с текущим кодом QLineEdit.

Как видно из исходного кода, текст-заполнитель просто берет кисть переднего плана палитры и делает ее частично прозрачной, см. QLineEdit::paintEvent:

if (d->shouldShowPlaceholderText()) {
    if (!d->placeholderText.isEmpty()) {
        QColor col = pal.text().color();
        col.setAlpha(128);
        QPen oldpen = p.pen();
        p.setPen(col);
        QRect ph = lineRect.adjusted(minLB, 0, 0, 0);
        QString elidedText = fm.elidedText(d->placeholderText, Qt::ElideRight, ph.width());
        p.drawText(ph, va, elidedText);
        p.setPen(oldpen);
    }
}

Однако вы можете работать с восходящим потоком в более общем решении. В частности, я ожидал, что этот цвет будет добавлен в палитру или вообще предоставлен текущим QStyle (например, как подсказка по стилю).

person peppe    schedule 22.01.2015

Вам нужно создать подкласс QLineEdit и нарисовать собственный заполнитель в paintEvent().

class CustomColorPlaceholderLineEdit : public QLineEdit
{
public:
    CustomColorPlaceholderLineEdit(QWidget * parent = 0) : QLineEdit(parent) { color = QColor(0,0,0,128); }
    void setCustomPlaceholderText(const QString &text) { this->mText = text; }
    const QString &customPlaceholderText() const { return mText; }
    void setCustomPlaceholderColor(const QColor &color) { this->color = color; }
    const QColor &customPlaceholderColor() const { return color; }
    void paintEvent(QPaintEvent *event) {
        QLineEdit::paintEvent(event);
        if (!hasFocus() && text().isEmpty() && !mText.isEmpty()) {
            // QLineEdit's own placeholder clashes with ours.
            Q_ASSERT(placeholderText().isEmpty());
            QPainter p(this);
            p.setPen(color);
            QFontMetrics fm = fontMetrics();
            int minLB = qMax(0, -fm.minLeftBearing());
            QRect lineRect = this->rect();
            QRect ph = lineRect.adjusted(minLB + 3, 0, 0, 0);
            QString elidedText = fm.elidedText(mText, Qt::ElideRight, ph.width());
            p.drawText(ph, Qt::AlignVCenter, elidedText);
        }
    }
private:
    QString mText;
    QColor color;
};
person Meefte    schedule 22.01.2015
comment
Я бы не рекомендовал идти по этому пути. Это чрезвычайно хрупкий хак, так как вы в основном закрашиваете существующий текст-заполнитель. Что, если Qt решит тонко настроить стиль и переместить элементы на пиксель или около того? Что, если условие, проверяющее, следует ли закрасить заполнитель, изменится? (В частности, тот, что в этом коде, неверен.) - person peppe; 23.01.2015
comment
Стандартный текст-заполнитель @peppe Qt не существует. Я рисую пользовательский текст поверх QLineEdit при определенных условиях. И вы можете изменить условие на то, что вы хотите. - person Meefte; 24.01.2015
comment
@peppe У меня есть идея - вы можете просто изменить цвет текста в событии onFocus () - изменить его на собственный цвет при выходе из фокуса и снова изменить его при входе в фокус. - person sashoalm; 24.01.2015
comment
И все, что вы хотите, это то, о чем я сомневаюсь. Условие уже нарушено, поскольку оно не соответствуют тому же условию, при котором Qt рисует свой собственный. Конечно, это можно решить, используя приватные заголовки. Но опять же, если Qt решит каким-то образом изменить поведение (например, так же, как вы, изменив поля), вы в конечном итоге получите неработающий рендеринг. Это взлом. Не обходной путь. Не решение. - person peppe; 24.01.2015

Есть еще один немного хакерский, но простой и надежный способ.

connect(lineEdit, &QLineEdit::textChanged, this, &YourClass::updateLineEditStyleSheet);

void YourLineEdit::updateLineEditStyleSheet()
{
    if (lineEdit->text().isEmpty()) {
        lineEdit->setStyleSheet("#lineEdit { color: lightGray;"); // Set your color but remember that Qt will reduce alpha
    } else {
        lineEdit->setStyleSheet("#lineEdit { color: black;"); // usual color
    }
}

также вы можете использовать этот способ для получения класса QLineEdit

person Vernat Khisamov    schedule 29.12.2016

Если вы хотите использовать QSS вместо QPalette, попробуйте следующее:

setStyleSheet("QLineEdit{"
              "    color: red;" //TEXT COLOR
              "}"
              "QLineEdit[text=\"\"]{"
              "    color: gray;" //TEXTHOLDER COLOR
              "}");
connect(ui->lineEdit, &QLineEdit::textChanged, [=]{ style()->polish(ui->lineEdit); });

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

person laurapons    schedule 26.02.2019

Если вы хотите изменить цвет текста-заполнителя для QLineEdit, вам необходимо настроить объект QPalette компонента.

QPalette p = lineEdit->palette();
p.setColor(QPalette::Mid, Qt::red); // assuming Mid is the color you want to change.
lineEdit->setPalette(p);

Я не помню точно, какой QPalette::ColorRole подходит для изменения цвета текста заполнителя QLineEdit.

person alediaferia    schedule 01.12.2014
comment
Этот код не работает - я проверил его, цвет текста остается серым. Я начал вознаграждение за этот вопрос. - person sashoalm; 22.01.2015
comment
В Qt 5.12 есть QPalette::PlaceholderText, который работает для этой цели и позволяет избежать проблемы непрозрачности 0,5. - person Alex Kritchevsky; 24.07.2019
comment
@AlexKritchevsky tnx QPalette::PlaceholderText у меня работает. - person DRPK; 22.01.2021

Решение @Meefte неплохое, учитывая ситуацию, когда Qt придает заполнителю тот же цвет, что и для текста, за исключением того, что он добавляет 50% непрозрачности. Таким образом, выбор цвета заполнителя, отличающегося от цвета текста, невелик. Однако даже это решение можно улучшить, убедившись, что вам не нужно будет устанавливать какую-либо другую переменную, кроме той, которую Qt предоставляет вам по умолчанию.

Необходимость использовать placeholderText() по умолчанию может возникнуть в ситуации, когда у вас есть много элементов управления QLineEdit, которые уже повышены до какого-либо элемента управления, переопределяющего поведение QLineEdit, а placeholderText() уже задано через код или через Qt Creator, т.е. было бы немного болезненно вводить другое динамическое свойство. Однако, если вы не повысили до какого-либо дочернего элемента управления, это было бы необходимо сделать, чтобы использовать такое решение.

class CustomColorPlaceholderLineEdit : public QLineEdit
{
public:
    CustomColorPlaceholderLineEdit(QWidget * parent = 0) : QLineEdit(parent) { color = QColor(0,0,0,128); }

    const QString &customPlaceholderText() const { return mText; }

    void setCustomPlaceholderColor(const QColor &color) { this->color = color; }

    const QColor &customPlaceholderColor() const { return color; }

    void paintEvent(QPaintEvent *event)
    {
        if(color.isValid() && text().isEmpty() && (!placeholderText().isEmpty() || !mText.isEmpty()))
        {
            if(!placeholderText().isEmpty())
            {
                // In this way, placeholderText() is taken into local variable 'mText' care. Whenever placeholderText() will change, there it will be taken care of.
                mText = placeholderText();

                // This will ensure Qt will not draw placeholder for us.
                setPlaceholderText("");
            }

            // By this, we make sure Qt will paint QLineEdit default parts properly.
            QLineEdit::paintEvent(e);

            // And now @Meefte code is reused here.
            QPainter p(this);
            p.setPen(color);
            QFontMetrics fm = fontMetrics();
            int minLB = qMax(0, -fm.minLeftBearing());
            QRect lineRect = this->rect();
            QRect ph = lineRect.adjusted(minLB + 3, 0, 0, 0);
            QString elidedText = fm.elidedText(mText, Qt::ElideRight, ph.width());
            p.drawText(ph, Qt::AlignVCenter, elidedText);
            return; // No need to paint again.
        }

        // Default Qt's painting behavior for QLineEdit.
        QLineEdit::paintEvent(e);
    }
private:
    QString mText;
    QColor color;
};
person Vaidotas Strazdas    schedule 10.10.2017