如何使用 QComboBox.setPlaceholderText?

Posted

技术标签:

【中文标题】如何使用 QComboBox.setPlaceholderText?【英文标题】:How do i use QComboBox.setPlaceholderText? 【发布时间】:2021-04-25 19:28:56 【问题描述】:

在 Qt 5.15 中引入了 placeholderText 属性 - link to documentation

但是使用setPlaceholderText 对我没有任何作用。运行下面的代码时,QComboBox 中没有任何文本(当然,除非我选择三个项目之一)

这是一个错误还是我错过了什么?我怎样才能做到这一点?

import sys
from PyQt5 import QtWidgets
from PyQt5 import QtCore


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        central_w = QtWidgets.QWidget()
        self.setCentralWidget(central_w)
        vbox = QtWidgets.QVBoxLayout()
        central_w.setLayout(vbox)

        self.combo_box = QtWidgets.QComboBox()
        self.combo_box.addItems(["one", "two", "three"])
        self.combo_box.setPlaceholderText("Some placeholder text here")
        self.combo_box.setCurrentIndex(-1)
        vbox.addWidget(self.combo_box)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    app.exec_()

我没有找到显示占位符文本的方法。我试过在组合框中根本没有项目,但即使这样也不显示占位符文本


这些是我正在运行的版本:

Qt:5.15.2 PyQt(Python 模块)版本:5.15.2(这恰好与 Qt 版本相同,但有时可能略有不同) Python:“3.8.5(默认,2020 年 7 月 28 日,12:59:40)\n[GCC 9.3.0]” 操作系统:Ubuntu 20.04.1 LTS(带 Xfce)

PS:如果你想达到类似的效果(即:在可点击区域上有一个文本,点击后显示带有不同选项的下拉菜单)你可以使用 QPushButtonsetMenu 函数.文档:https://doc.qt.io/qt-5/qpushbutton.html#setMenu

【问题讨论】:

print(app.style().objectName() 的输出是什么?如果不是“融合”,试试app.setStyle(QtWidgets.QStyleFactory.create('fusion')) @musicamante 我得到了app.style().objectName()='fusion'。顺便说一句,我不知道这是否重要,但我正在运行 Xfce(我会在问题中更新它) 嗯。您可以尝试其他可用的样式吗?您可以使用静态 QStyleFactory.keys() 查看完整列表。另外,您是否可以尝试通过显式设置placeholderText 角色来更改调色板(确保它具有足够的对比度并且没有alpha)? 尝试PySide2 而不是PyQt5。我刚刚在 Windows 上对其进行了测试,它确实有效。 【参考方案1】:

查看Qt源代码的修改,发现为了在Qt 5.15.0中添加placeHolderText的功能,修改了currentText():

// https://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/widgets/qcombobox.cpp?h=5.15.0#n2344
QString QComboBox::currentText() const

    Q_D(const QComboBox);
    if (d->lineEdit)
        return d->lineEdit->text();
    else if (d->currentIndex.isValid())
        return d->itemText(d->currentIndex);
    else
        return d->placeholderText;

但这会产生不良影响,QTBUG-86580 中报告了该影响,因此在 Qt 5.15.2 中删除了该功能:

QString QComboBox::currentText() const

    Q_D(const QComboBox);
    if (d->lineEdit)
        return d->lineEdit->text();
    if (d->currentIndex.isValid())
        return d->itemText(d->currentIndex);
    return ;

忘记纠正 placeHolder 不再可见的副作用。我已经报告了这个错误:QTBUG-90522。

考虑到上述情况,有以下备选方案:

使用 PyQt5/PySide2 5.15.0 或 5.15.1。

重写paintEvent方法将placeHolderText设置为currentText:

import sys
from PyQt5 import QtCore, QtGui, QtWidgets

# or
# from PySide2 import QtCore, QtGui, QtWidgets


class ComboBox(QtWidgets.QComboBox):
    # https://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/widgets/qcombobox.cpp?h=5.15.2#n3173
    def paintEvent(self, event):
        
        painter = QtWidgets.QStylePainter(self)
        painter.setPen(self.palette().color(QtGui.QPalette.Text))

        # draw the combobox frame, focusrect and selected etc.
        opt = QtWidgets.QStyleOptionComboBox()
        self.initStyleOption(opt)
        painter.drawComplexControl(QtWidgets.QStyle.CC_ComboBox, opt)

        if self.currentIndex() < 0:
            opt.palette.setBrush(
                QtGui.QPalette.ButtonText,
                opt.palette.brush(QtGui.QPalette.ButtonText).color().lighter(),
            )
            if self.placeholderText():
                opt.currentText = self.placeholderText()

        # draw the icon and text
        painter.drawControl(QtWidgets.QStyle.CE_ComboBoxLabel, opt)


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        self.combo_box = ComboBox()
        self.combo_box.addItems(["one", "two", "three"])
        self.combo_box.setPlaceholderText("Some placeholder text here")
        self.combo_box.setCurrentIndex(-1)

        central_w = QtWidgets.QWidget()
        self.setCentralWidget(central_w)
        vbox = QtWidgets.QVBoxLayout(central_w)
        vbox.addWidget(self.combo_box)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    app.exec_()

【讨论】:

在我看来,除了颜色之外,它都有效。颜色看起来与其他下拉项相同。【参考方案2】:

作为 eyllanesc 答案的附录,非常精确,这里只是 Qt 5.15.2 中占位符文本错误的一个更简单的解决方法,这是非常重要的版本,因为它是 Qt5 的最后一个非商业版本。它是 C++,但很容易翻译成 Python。

#include <QApplication>
#include <QComboBox>
#include <QLabel>
#include <QVBoxLayout>

int main(int argc, char *argv[])

    QApplication a(argc, argv);
    QComboBox combo;
    combo.show();
    combo.addItem("AAAA");
    combo.addItem("BBBB");

    // The following line does not work e.g. in Qt 5.15.2.
    //combo.setPlaceholderText("Select something...");

    // This is a simple workaround:
    auto space = QString(" ");
    auto placeholder = new QLabel(space + "Select something...");
    combo.setLayout(new QVBoxLayout());
    combo.layout()->setContentsMargins(0, 0, 0, 0);
    combo.layout()->addWidget(placeholder);
    QObject::connect(&combo, &QComboBox::currentIndexChanged, &combo, [placeholder](int index) placeholder->setVisible(index == -1); );
    combo.setCurrentIndex(-1);

    return a.exec();

【讨论】:

以上是关于如何使用 QComboBox.setPlaceholderText?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用本机反应创建登录以及如何验证会话

如何在自动布局中使用约束标识符以及如何使用标识符更改约束? [迅速]

如何使用 AngularJS 的 ng-model 创建一个数组以及如何使用 jquery 提交?

如何使用laravel保存所有行数据每个行名或相等

如何使用 Math.Net 连接矩阵。如何使用 Math.Net 调用特定的行或列?

WSARecv 如何使用 lpOverlapped?如何手动发出事件信号?