我如何使用 QComboBox.setPlaceholderText?
How do i use QComboBox.setPlaceholderText?
在 Qt 5.15 中引入了 placeholderText
属性 - link to documentation
但是 使用 setPlaceholderText
对我没有任何作用。当 运行 下面的代码我没有在 QComboBox
中得到任何文本(当然除非我 select 三项之一)
这是一个错误还是我遗漏了什么?我怎样才能使这项工作?
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]”
- OS: Ubuntu 20.04.1 LTS(使用 Xfce)
PS:如果你想达到类似的效果(即:在可点击区域有一个文本,点击后显示一个带有不同选项的下拉菜单)你可以使用 QPushButton
与 setMenu
功能。文档:https://doc.qt.io/qt-5/qpushbutton.html#setMenu
查看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_()
作为 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();
}
在 Qt 5.15 中引入了 placeholderText
属性 - link to documentation
但是 使用 setPlaceholderText
对我没有任何作用。当 运行 下面的代码我没有在 QComboBox
中得到任何文本(当然除非我 select 三项之一)
这是一个错误还是我遗漏了什么?我怎样才能使这项工作?
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]”
- OS: Ubuntu 20.04.1 LTS(使用 Xfce)
PS:如果你想达到类似的效果(即:在可点击区域有一个文本,点击后显示一个带有不同选项的下拉菜单)你可以使用 QPushButton
与 setMenu
功能。文档:https://doc.qt.io/qt-5/qpushbutton.html#setMenu
查看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_()
作为 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();
}