更改QLineEdit中占位文本的颜色

7

当我使用QLineEdit::setPlaceholderText()设置占位符文本时,它会显示为灰色。

enter image description here

是否有办法将其颜色更改为其他颜色,例如红色?


您需要实现自己的占位符绘制函数。您可以查看Qt源代码以了解其工作原理。这很简单。 - Dmitry Sazonov
在这里,您可以看到如何在QLineEdit的源代码中处理它。基本上,它只是获取文本颜色并减少alpha值。 - thuga
我编辑了问题,使其更加通用和易懂。 - alediaferia
7个回答

7
你需要继承 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;
};

我不建议这样做。这是一种极其脆弱的hack,因为你基本上是在现有的占位符文本上进行覆盖绘制。如果Qt决定微调样式并将东西移动一个像素左右怎么办?如果检查是否应该绘制占位符的条件发生变化怎么办?(特别是此代码中的条件是错误的。) - peppe
@peppe Qt标准的占位符文本并不存在。在某些条件下,我会在QLineEdit上绘制自定义文本。而你可以根据需要更改这个条件。 - Meefte
@peppe 我有一个想法 - 你可以在onFocus()事件中改变文本颜色 - 在焦点离开时将其更改为自定义颜色,并在焦点进入时将其改回原来的颜色。 - sashoalm
“whatever you want” 是我质疑的内容。条件已经被打破了,因为它与Qt绘制自己的相同条件不匹配。当然,私有头文件可以解决这个问题。但是,如果Qt决定以某种方式改变行为(例如,就像您正在做的那样,通过修改边距),则会导致渲染出现问题。这是一个hack,而不是一个解决方法或解决方案。 - peppe

7
有一种有点“hacky”的但简单可靠的方法。
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类。

5
如果您想使用QSS而非QPalette,可以尝试以下方法:
setStyleSheet("QLineEdit{"
              "    color: red;" //TEXT COLOR
              "}"
              "QLineEdit[text=\"\"]{"
              "    color: gray;" //TEXTHOLDER COLOR
              "}");
connect(ui->lineEdit, &QLineEdit::textChanged, [=]{ style()->polish(ui->lineEdit); });

您可以更改颜色,但请注意源代码中占位符设置了透明度因子(如另一条评论中所述),该因子无法被移除。因此,您将始终看到占位符较暗(此选项不可能出现白色)。


如果这个能够工作的话就太好了。但是当QLineEdit中有文本时,它也会将颜色更改为灰色。至少在Qt 5.15中是这样的。 - i know nothing

3

目前的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提供(例如作为样式提示)。

2
如果你想改变 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的占位符文本颜色。


这段代码不起作用 - 我测试了一下,文本颜色仍然是灰色的。我已经在这个问题上开始了一个赏金任务。 - sashoalm
1
在Qt 5.12中,有一个名为QPalette::PlaceholderText的功能可以用于此目的,并避免了0.5不透明度的问题。 - Alex Kritchevsky
@AlexKritchevsky 谢谢,QPalette::PlaceholderText 对我有用。 - DRPK

0

QT还存在这个问题) 我是这样解决的:

bool CustomLineEdit::event(QEvent *event)
{
    bool eventResult = QLineEdit::event(event);

    if (event->type() == QEvent::StyleChange) {
         QPalette pal = palette();
         pal.setColor(QPalette::PlaceholderText, Qt::red);
        setPalette(pal);
    }
    return eventResult;
}

0

@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;
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接