【问题标题】:QComboBox - How to set hint text on combo boxQComboBox - 如何在组合框上设置提示文本
【发布时间】:2011-09-13 18:03:44
【问题描述】:

我工作的应用程序 GUI 需要一个组合框供用户选择项目。当应用程序启动时,组合框将显示类似“请选择”的提示文本,而不是显示组合框的第一项。我在http://doc.qt.io/qt-5/qcombobox.html#currentText-prop 中找不到任何设置提示文本的方法。

提前致谢!

【问题讨论】:

  • 我不确定 Qt 在其组合框中是否支持提示横幅。但是,本机 Windows 控件可以。发送CB_SETCUEBANNER message。使用非原生小部件是有成本的。
  • 感谢您的回答。不幸的是,我的应用程序在 Linux 操作系统上运行。

标签: qt qcombobox


【解决方案1】:

如果QComboBoxeditable,则有an elegant solution

myQComboBox->lineEdit()->setPlaceHolderText("Please select");

QComboBoxes 不是editable 没有QLineEdits,所以这对那些不起作用。

【讨论】:

  • 这个问题是很久以前提出的,当时甚至行编辑都没有占位符。
  • @nwp 使用您的建议阻止组合框执行下拉功能。如何解决这个问题?
  • @XavierGeoffrey 它不应该那样做,也不适合我。您是否可能每次都在点击事件上运行代码,而不是在初始化时只运行一次?
【解决方案2】:

对于较新版本的 Qt,请尝试 QComboBox::setPlaceholderText()

我碰巧在 Raspberry Pi 上使用旧版本的 Qt (5.11.3),需要不同的解决方案。

这是一个使用proxy model 来调整作为占位符添加的额外项目的工作pyqt5 示例。 (感谢this answer):

import sys
from PyQt5.QtCore import Qt, QT_VERSION_STR, QAbstractProxyModel, QModelIndex, QItemSelection
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import (QApplication, QGridLayout, QWidget, QComboBox)
from typing import Any

class Main(QWidget):
    def __init__(self):
        super().__init__()
        self.setGeometry(50,50,320,200)
        self.setWindowTitle(f"Qt Version {QT_VERSION_STR}")

        layout = QGridLayout()

        cmbox = QComboBox()

        model = QStandardItemModel()
        
        for i in range(1, 11):
            model.appendRow(QStandardItem(f"Item {i}"))

        cmbox.setModel(ProxyModel(model, '---PlaceholderText---'))
        cmbox.setCurrentIndex(0)
        layout.addWidget(cmbox, 0, 0)
        

        self.setLayout(layout)
        self.show()


class ProxyModel(QAbstractProxyModel):
    def __init__(self, model, placeholderText='---', parent=None):
        super().__init__(parent)
        self._placeholderText = placeholderText
        self.setSourceModel(model)
        
    def index(self, row: int, column: int, parent: QModelIndex = ...) -> QModelIndex:
        return self.createIndex(row, column)

    def parent(self, index: QModelIndex = ...) -> QModelIndex:
        return QModelIndex()

    def rowCount(self, parent: QModelIndex = ...) -> int:
        return self.sourceModel().rowCount()+1 if self.sourceModel() else 0

    def columnCount(self, parent: QModelIndex = ...) -> int:
        return self.sourceModel().columnCount() if self.sourceModel() else 0

    def data(self, index: QModelIndex, role: int = Qt.DisplayRole) -> Any:
        if index.row() == 0 and role == Qt.DisplayRole:
            return self._placeholderText
        elif index.row() == 0 and role == Qt.EditRole:
            return None
        else:
            return super().data(index, role)

    def mapFromSource(self, sourceIndex: QModelIndex):
        return self.index(sourceIndex.row()+1, sourceIndex.column())

    def mapToSource(self, proxyIndex: QModelIndex):
        return self.sourceModel().index(proxyIndex.row()-1, proxyIndex.column())

    def mapSelectionFromSource(self, sourceSelection: QItemSelection):
        return super().mapSelection(sourceSelection)

    def mapSelectionToSource(self, proxySelection: QItemSelection):
        return super().mapSelectionToSource(proxySelection)
    
    def headerData(self, section: int, orientation: Qt.Orientation, role: int = Qt.DisplayRole):
        if not self.sourceModel():
            return None
        if orientation == Qt.Vertical:
            return self.sourceModel().headerData(section-1, orientation, role)
        else:
            return self.sourceModel().headerData(section, orientation, role)

    def removeRows(self, row: int, count: int, parent: QModelIndex = ...) -> bool:
        return self.sourceModel().removeRows(row, count -1)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Main()
    sys.exit(app.exec_())

【讨论】:

    【解决方案3】:

    无法为QComboBox 设置占位符文本。但是你可以解决这个问题。使用setEditText( const QString& ) 插槽来设置您的文本。如果用户在comboBox 中选择一个项目,将设置项目的文本。但是如果用户选择文本,删除它,然后选择其他控制元素(组合框失去焦点),您的文本将不再存在。可以通过从QComboBox 继承并重新实现focusOutEvent(...) 来解决,您可以在其中检查:if ( currentIndex() == -1 ) setEditText( tr( "Please select" ) );。并且不要忘记先致电QComboBox::focusOutEvent(...)

    【讨论】:

    • 感谢 Pie_Jesu。我对 Pie_Jesu 的想法进行了一些更新。我在用于设置提示横幅文本的函数中将包含提示横幅文本的项目添加到组合框的第一个索引。在焦点事件中,我删除了组合框的第一项。成功了!
    【解决方案4】:

    在 Qt Designer 中,您可以设置占位符文本。

    如果您也在设计器中添加项目并且您将运行代码,它可能会从选择的第一个项目开始。

    在代码中你应该只调用(在 ctor 或任何初始化部分)

    comboBox->setCurrentIndex(-1);
    

    【讨论】:

    • 不幸的是,这在 Qt 5.15.2 中不起作用,这是最新的非商业 Qt 5 版本。 API 可用,但不显示占位符文本。我也用 Qt 6.2.1 对其进行了测试,在这个版本中它可以工作,所以这个错误可能已经修复。
    【解决方案5】:

    这是 Qt 5.15.2 中占位符文本错误的更简单解决方法,这是非常重要的版本,因为它是 Qt5 的最后一个非商业版本。它修复了combo.isEditable() == false时不可见的占位符文本。

    #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();
    }
    

    【讨论】:

      猜你喜欢
      • 2015-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-29
      • 1970-01-01
      相关资源
      最近更新 更多