2015-12-01 3 views
2

Я присоединяю объект как UserData к QStandardItem, который добавляется в модель QComboBox. Если я буду искать его с помощью метода findData(), я не получаю никакого результата. Если я делаю то же самое с простым int, я получаю результат. Я полагаю, что это связано с PySide, но я не смог найти обертку в источнике. Вот (несколько) минимальный пример:Почему QComboBox.findData() не принимает объект как вход?

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 для объекта? Любые подсказки для того, что можно найти, оценены!

ответ

2

QT C++ doc содержит пояснения. Вот определение findData, курсив мой:

INT QComboBox :: findData (Const QVariant & данные, внутр роль = Qt :: UserRole, Qt :: MatchFlags флаги = static_cast ( Qt :: MatchExactly | Qt :: MatchCaseSensitive)) Const

данные в выпадающем списке может быть только QVariant, что «союз для наиболее распространенных типов данных Qt». Таким образом, данные могут быть только общим типом данных 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 

NB: QVariant используются в C++, потому что вы должны определить все значения с типом (например, int i=0;). В python вам это не нужно, так как значение может изменять тип в любое время. Таким образом, в PySide QVariant не реализован, вместо этого они используют обычные типы python или типы Qt.

+3

Это фактически ошибка (или, по крайней мере, отсутствует функция) в PySide и PyQt4. При сравнении пользовательских типов (таких как объекты python), 'QVariant' должен использовать адрес содержащегося значения. Это было исправлено в pyqt5, где пример OPs будет работать, как ожидалось. Я не знаю подробностей реализации, но я подозреваю, что специальный мета-тип зарегистрирован для обертывания типов python, поэтому они могут содержаться в 'QVariant'. Возможно, проблема заключается в том, что pyside/pyqt4 сравнивает адреса временных * wrappers *, а не содержащиеся значения. – ekhumoro

+0

В этом случае ваш подход работает отлично, но, к сожалению, мой реальный код намного сложнее, и я не хочу подкласса QObject для решения. Теперь я делаю самые очевидные и повторяю элементы и сравниваю их, чтобы найти правильный элемент. Меня больше интересовала причина этого странного поведения, но ваш ответ и очень полезный комментарий @ ekhumoro помогли решить эту тайну! – Fookatchu

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 
Смежные вопросы