【问题标题】:Why doesn't QComboBox.findData() accept an object as input?为什么 QComboBox.findData() 不接受对象作为输入?
【发布时间】:2016-03-05 14:51:25
【问题描述】:

我将一个对象作为 UserData 附加到一个 QStandardItem,该对象被添加到一个 QComboBox 模型中。如果我然后用 findData() 方法搜索它,我不会得到任何结果。如果我对一个简单的 int 做同样的事情,我会得到一个结果。我想这是 PySide 相关的,但我在源代码中找不到包装器。这是一个(有点)最小的例子:

import sys
from PySide import QtGui

class Foo(object):
    def __init__(self, value):
        self.value = value


class MyCombo(QtGui.QWidget):
    def __init__(self, *args):
        QtGui.QWidget.__init__(self, *args)

        combo = QtGui.QComboBox()
        combo.addItem(str(1), Foo(1))
        combo.addItem(str(2), 2)

        data = combo.itemData(0)
        print(data)  # prints the object repr
        print(combo.findData(data))  # returns -1 -> not found

        data = combo.itemData(1)
        print(data)  # prints 2
        print(combo.findData(data))  # returns 1 -> found

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    w = MyCombo()
    w.show()
    sys.exit(app.exec_())

为什么 findData() 为对象返回 -1?任何可以搜索的提示都表示赞赏!

【问题讨论】:

    标签: pyside python-3.4 qcombobox


    【解决方案1】:

    对我也不起作用。

    我将 QComboBox 子类化为自己编写 findData 方法:

    from PySide import QtGui
    
    
    class QComboBox(QtGui.QComboBox):
        def findData(self, data):
            for index in range(self.count()):
                if self.itemData(index) == data:
                    return index
            return -1
    

    【讨论】:

    • 似乎在 PySide2 中已修复
    【解决方案2】:

    QT C++ doc 提供了解释。这是findData的定义,强调我的:

    int QComboBox::findData(const QVariant & data, int role = Qt::UserRole, Qt::MatchFlags 标志 = static_cast ( Qt::MatchExactly | Qt::MatchCaseSensitive )) 常量

    组合框中的数据只能是QVariant,它是“最常见的Qt 数据类型的联合”。所以data只能是常见的Qt数据类型,不包括常规的python类。

    但是,数据可以是QtCore.QObject,所以您的问题很容易解决:

    class Foo(QtCore.QObject):
        def __init__(self, value,parent=None):
            super(Foo,self).__init__(parent)
            self.value = value
    
    class MyCombo(QtGui.QWidget):
        def __init__(self, *args):
            QtGui.QWidget.__init__(self, *args)
    
            combo = QtGui.QComboBox()
            combo.addItem(str(1),Foo(1,self) )
    
            data = combo.itemData(0)
            print("data",data)  # prints the object repr
            print(combo.findData(data))  # returns 0 -> found
    

    注意:QVariant 在 C++ 中使用,因为您需要用类型定义每个值(如 int i=0;)。在 python 中,你不需要这个,因为值可以随时更改类型。所以在 PySide 中,QVariant 没有实现,而是使用常规的 python 类型或 Qt 类型。

    【讨论】:

    • 这实际上是 pyside 和 pyqt4 中的一个错误(或至少是一个缺失的功能)。在比较自定义类型(例如 python 对象)时,QVariant 应该使用包含值的地址。这已在 pyqt5 中得到修复,其中 OPs 示例将按预期工作。我不知道实现的细节,但我怀疑注册了一个特殊的元类型来包装 python 类型,因此它们可以包含在QVariant 中。这里的问题可能是 pyside/pyqt4 正在比较临时 wrappers 的地址而不是包含的值。
    • 在这种情况下,您的方法工作得很好,但不幸的是,我的真实代码要复杂得多,我不想为解决方案子类化 QObject。我现在做最明显的事情并遍历元素并比较它们以找到正确的元素。我对这种奇怪行为的原因更感兴趣,但您的回答和 @ekhumoro 非常有用的评论帮助解开了这个谜团!
    猜你喜欢
    • 2020-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-14
    • 2016-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多