【问题标题】:How to use QComboBox as delegate with QTableView如何使用 QComboBox 作为 QTableView 的委托
【发布时间】:2015-03-18 04:42:30
【问题描述】:

下面的代码创建了一个QTableView。双击其项目将使用委派的QComboBox 设置它。

问题
当点击ComboBox 时,它的下拉菜单会暂时显示,然后它会折叠回到展开状态。

如果将comboBox 设置为使用combox.setEditable(True) 可编辑, 下拉菜单将根据需要保持打开状态。但随后combobox 的项目变为可编辑。这不是所需要的。由于combobox 的项目只能是可选的。

如何解决 combobox 的自我折叠行为?

附:然后我注意到,当ComboBox 设置为可编辑并且其下拉菜单展开时,模型的data() 不断被调用......自折叠行为是否可能由模型触发?

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class ComboDelegate(QItemDelegate):
    comboItems=['Combo_Zero', 'Combo_One','Combo_Two']
    def createEditor(self, parent, option, proxyModelIndex):
        combo = QComboBox(parent)
        combo.addItems(self.comboItems)
        # combo.setEditable(True)
        self.connect(combo, SIGNAL("currentIndexChanged(int)"), self, SLOT("currentIndexChanged()"))
        return combo

    def setModelData(self, combo, model, index):
        comboIndex=combo.currentIndex()
        text=self.comboItems[comboIndex]        
        model.setData(index, text)
        print '\t\t\t ...setModelData() 1', text

    @pyqtSlot()
    def currentIndexChanged(self): 
        self.commitData.emit(self.sender())

class MyModel(QAbstractTableModel):
    def __init__(self, parent=None, *args):
        QAbstractTableModel.__init__(self, parent, *args)
        self.items=['Data_Item01','Data_Item02','Data_Item03']

    def rowCount(self, parent=QModelIndex()):
        return len(self.items)
    def columnCount(self, parent=QModelIndex()):
        return 1

    def data(self, index, role):        
        if not index.isValid(): return QVariant()

        row=index.row()
        item=self.items[row]

        if row>len(self.items): return QVariant()

        if role == Qt.DisplayRole:
            print ' << >> MyModel.data() returning ...', item
            return QVariant(item) 

    def flags(self, index):
        return Qt.ItemIsEditable | Qt.ItemIsEnabled

    def setData(self, index, text):
        self.items[index.row()]=text

if __name__ == '__main__':
    app = QApplication(sys.argv)

    model = MyModel()
    tableView = QTableView()
    tableView.setModel(model)

    delegate = ComboDelegate()

    tableView.setItemDelegate(delegate)
    tableView.resizeRowsToContents()

    tableView.show()
    sys.exit(app.exec_())

【问题讨论】:

    标签: python qt pyqt qtableview qcombobox


    【解决方案1】:

    您的原始代码在 PyQt5 中运行,combobox 保持打开状态。但是用户必须点击打开编辑器,然后点击打开combobox。为了避免这种情况,我在您的代码中将QComboBox 替换为QlistWidget。另外我设置editorGeometry:

    import sys
    # from PyQt4.QtCore import *
    # from PyQt4.QtGui import *
    
    from PyQt5.QtCore import *
    from PyQt5.QtWidgets import *
    
    class ComboDelegate(QItemDelegate):
        editorItems=['Combo_Zero', 'Combo_One','Combo_Two']
        height = 25
        width = 200
        def createEditor(self, parent, option, index):
            editor = QListWidget(parent)
            # editor.addItems(self.editorItems)
            # editor.setEditable(True)
            editor.currentItemChanged.connect(self.currentItemChanged)
            return editor
    
        def setEditorData(self,editor,index):
            z = 0
            for item in self.editorItems:
                ai = QListWidgetItem(item)
                editor.addItem(ai)
                if item == index.data():
                    editor.setCurrentItem(editor.item(z))
                z += 1
            editor.setGeometry(0,index.row()*self.height,self.width,self.height*len(self.editorItems))
    
        def setModelData(self, editor, model, index):
            editorIndex=editor.currentIndex()
            text=editor.currentItem().text() 
            model.setData(index, text)
            # print '\t\t\t ...setModelData() 1', text
    
        @pyqtSlot()
        def currentItemChanged(self): 
            self.commitData.emit(self.sender())
    
    class MyModel(QAbstractTableModel):
        def __init__(self, parent=None, *args):
            QAbstractTableModel.__init__(self, parent, *args)
            self.items=['Data_Item01','Data_Item02','Data_Item03']
    
        def rowCount(self, parent=QModelIndex()):
            return len(self.items)
        def columnCount(self, parent=QModelIndex()):
            return 1
    
        def data(self, index, role):        
            if not index.isValid(): return QVariant()
    
            row=index.row()
            item=self.items[row]
    
            if row>len(self.items): return QVariant()
    
            if role == Qt.DisplayRole:
                # print ' << >> MyModel.data() returning ...', item
                return QVariant(item) 
    
        def flags(self, index):
            return Qt.ItemIsEditable | Qt.ItemIsEnabled
    
        def setData(self, index, text):
            self.items[index.row()]=text
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
    
        model = MyModel()
        tableView = QTableView()
        tableView.setModel(model)
    
        delegate = ComboDelegate()
    
        tableView.setItemDelegate(delegate)
        for i in range(0,tableView.model().rowCount()):
            tableView.setRowHeight(i,tableView.itemDelegate().height)
        for i in range(0,tableView.model().columnCount()):
            tableView.setColumnWidth(i,tableView.itemDelegate().width)
    
        tableView.show()
        sys.exit(app.exec_())
    

    【讨论】:

    • 谢谢!很高兴知道!
    【解决方案2】:

    这里尝试用链接到QMenuQActions 的QToolButton 替换QComboBox

    外观与QComboBox 大致相同,但附加功能是可以设置多个QActions 选中(目前无法选中多个组合框的项目)。

    import sys
    from PyQt4.QtCore import *
    from PyQt4.QtGui import *
    
    class ComboDelegate(QItemDelegate):
        comboItems=['Combo_Zero', 'Combo_One','Combo_Two']
        def __init__(self, parent):
            QItemDelegate.__init__(self, parent=None)
            self.actionEmitted=None
    
        def createEditor(self, parent, option, index):
            if not index.isValid(): return
    
            model=index.model()
            itemName=model.data(index, Qt.DisplayRole)
    
            toolButton=QToolButton(parent)
            toolButton.setText( itemName.toString() )
    
            toolButton.setPopupMode(QToolButton.InstantPopup)        
    
            menu=QMenu(parent)
    
            action1=QAction('Action 01', menu, checkable=True)
            action2=QAction('Action 02', menu, checkable=True)
            action3=QAction('Action 03', menu, checkable=True)
    
            action1.setObjectName('Action 01')
            action2.setObjectName('Action 02')
            action3.setObjectName('Action 03')       
    
            action1.setChecked(True)
            action3.setChecked(True)
    
            self.connect(action1, SIGNAL("triggered(bool)"), self, SLOT("actionTriggered()"))
            self.connect(action2, SIGNAL("triggered(bool)"), self, SLOT("actionTriggered()"))
            self.connect(action3, SIGNAL("triggered(bool)"), self, SLOT("actionTriggered()"))
    
            menu.addAction(action1)
            menu.addAction(action2)
            menu.addAction(action3)
    
            toolButton.setMenu(menu) 
    
            return toolButton
    
        def setModelData(self, toolButton, model, index):
            print '\t\t\t ...setModelData() 1', toolButton, model, index
    
            if not self.actionEmitted: return
    
            menu=toolButton.menu()
            for action in menu.actions():
                actionName=action.objectName()
                actionStatus=action.isChecked()            
                if actionStatus:
                    model.setData(index, actionName)
                    print '####', actionName, actionStatus
    
        @pyqtSlot()
        def actionTriggered(self): 
            self.actionEmitted=self.sender()        
            self.commitData.emit( self.actionEmitted )
            print 'actionTriggered.....', self.actionEmitted
    
    
    class MyModel(QAbstractTableModel):
        def __init__(self, parent=None, *args):
            QAbstractTableModel.__init__(self, parent, *args)
            self.items=['Data_Item01','Data_Item02','Data_Item03']
    
        def rowCount(self, parent=QModelIndex()):
            return len(self.items)
        def columnCount(self, parent=QModelIndex()):
            return 1
    
        def data(self, index, role):        
            if not index.isValid(): return QVariant()
    
            row=index.row()
            item=self.items[row]
    
            if row>len(self.items): return QVariant()
    
            if role == Qt.DisplayRole:
                print ' << >> MyModel.data() returning ...', item
                return QVariant(item) 
    
        def flags(self, index):
            return Qt.ItemIsEditable | Qt.ItemIsEnabled
    
        def setData(self, index, itemName):
            self.items[index.row()]=itemName
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
    
        combo=QComboBox()
        combo.addItems(['Combo_Zero', 'Combo_One','Combo_Two'])
    
        model = MyModel()
        tableView = QTableView()
        tableView.setModel(model)
    
        delegate = ComboDelegate(tableView)
    
        tableView.setItemDelegate(delegate)
        tableView.resizeRowsToContents()
    
        tableView.show()
        sys.exit(app.exec_())
    

    【讨论】:

      猜你喜欢
      • 2015-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多