如何在QComboBox上设置不可选择的默认文本?

21

如果使用填充了项目的常规 QComboBox,并将 currentIndex 设置为 -1,则小部件为空。相反地,在组合框中显示一个初始描述性文本(例如“--选择国家--”,“--选择主题--”等),但不在下拉列表中显示,将非常有用。

我在文档和以往的问题与答案中都没有找到任何内容。

4个回答

29

似乎组合框API没有考虑到这种情况,但是由于底层模型的灵活性,你应该能够将--选择国家--作为第一个“合法”项目添加,并防止用户选择它:

QStandardItemModel* model =
        qobject_cast<QStandardItemModel*>(comboBox->model());
QModelIndex firstIndex = model->index(0, comboBox->modelColumn(),
        comboBox->rootModelIndex());
QStandardItem* firstItem = model->itemFromIndex(firstIndex);
firstItem->setSelectable(false);

根据您想要的具体行为,您可能需要使用setEnabled。或者我个人更喜欢它只是一个不同颜色的项目,我可以将其设置回去:

Qt,如何更改QComboBox的一个项目的文本颜色?(C ++)

(我不喜欢点击某些东西,然后被困在无法返回到之前状态的地方,即使它是未选择任何内容的状态!)


太好了!显然我还没有接触过Qt的某个部分,它似乎非常适合定制。从你提供的SO问题中可以看出,改变背景颜色使其看起来非常漂亮,可能比我最初设想的要好得多。firstItem->setData(Qt::lightGray , Qt::BackgroundRole);(如果您将此添加到您的答案中,我不介意)。 - swalog
@EXIT_FAILURE 我认为你的评论已经涵盖了你的替代方案,因为我没有尝试过,所以我不知道我是否会喜欢它。 :) 但是,是的,Qt提供了一些独创性,如果我们都联合起来,也许我们可以阻止GTK和wxWidgets! :-/ https://dev59.com/LlvUa4cB1Zd3GeqPvJ2g - HostileFork says dont trust SE
2
自Qt 5.15以来,正确的方法是使用setPlaceholderText,如此处所答复的:https://dev59.com/VWsz5IYBdhLWcg3w0rZC#63937462 - Luc Touraille

11

你可以采用设置占位符的方式来实现类似的效果:

comboBox->setPlaceholderText(QStringLiteral("--Select Country--"));
comboBox->setCurrentIndex(-1);

这样您就有一个不能被选中的默认值。

在此输入图片描述


2

我在这里提供一个基于PyQt5的解决方案。创建一个代理模型并将所有行向下移动一行,并在第0行返回默认值。

class NullRowProxyModel(QAbstractProxyModel):
    """Creates an empty row at the top for null selections on combo boxes
    """

    def __init__(self, src, text='---', parent=None):
        super(NullRowProxyModel, self).__init__(parent)
        self._text = text
        self.setSourceModel(src)

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

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

    def data(self, proxyIndex: QModelIndex, role=Qt.DisplayRole) -> typing.Any:
        if proxyIndex.row() == 0 and role == Qt.DisplayRole:
            return self._text
        elif proxyIndex.row() == 0 and role == Qt.EditRole:
            return None
        else:
            return super(NullRowProxyModel, self).data(proxyIndex, role)

    def index(self, row: int, column: int, parent: QModelIndex = ...) -> QModelIndex:
        return self.createIndex(row, column)

    def parent(self, child: 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 headerData(self, section: int, orientation: Qt.Orientation, role: int = ...) -> typing.Any:
        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)

谢谢你。在树莓派 (5.11.3) 上的一个旧版 Qt 上运行得很好。我在 这里 创建了一个更详细的答案,并提供了一个可用的示例。 - Chris

0
我发现了这个问题,因为我以一种不同的方式实现了它,但是我的新行不能被选择,而必须要能够选择。上面的一个答案指出了如何使其不可选择,这指引我找到了解决我的问题的方法。
我创建了一个派生自QSortFilterProxyModel的新类,用于操作“data”和“setData”方法以添加额外的行。在“data”方法中,对于第0行和源表的所有列,返回空值。在“setData”方法中,忽略对第0行的任何请求(虽然不应该有任何请求),并将其余请求传递给源模型的“setData”,并调整索引。我实现了mapToSource和mapFromSource来弥补源和代理之间行号差异的问题。
我还实现了“rowCount”方法来返回额外的一行。代理自动从源返回“columnCount”,这个值保持不变。
我忘记实现“flags”方法,所以我的代理没有为空白行返回ItemIsSelectable标志,导致它不可选择。

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