代码之家  ›  专栏  ›  技术社区  ›  Nemo XXX

如何使用QCombobox选择更新QTableView单元格?

  •  2
  • Nemo XXX  · 技术社区  · 7 年前

    我想向某些QTableView行中的特定单元格添加委托QComboBox委托。我找到了几篇关于如何添加代理的帖子,但没有一篇文章提供了使用QComboBox选项更新单元格的示例。

    这就是我目前的情况:

    主要的用户界面

    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
     <class>Dialog</class>
     <widget class="QDialog" name="Dialog">
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>0</y>
        <width>350</width>
        <height>239</height>
       </rect>
      </property>
      <property name="windowTitle">
       <string>Dialog</string>
      </property>
      <widget class="QWidget" name="formLayoutWidget">
       <property name="geometry">
        <rect>
         <x>0</x>
         <y>0</y>
         <width>341</width>
         <height>231</height>
        </rect>
       </property>
       <layout class="QFormLayout" name="formLayout">
        <item row="0" column="1">
         <widget class="QPushButton" name="btnPopulate">
          <property name="text">
           <string>Populate Table</string>
          </property>
         </widget>
        </item>
        <item row="1" column="1">
         <widget class="QTableView" name="tableView"/>
        </item>
       </layout>
      </widget>
     </widget>
     <resources/>
     <connections/>
    </ui>
    

    测验py公司

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import sys, os
    from PyQt5 import uic, QtWidgets
    from PyQt5.QtGui import QStandardItemModel
    from PyQt5.QtWidgets import QDialog, QComboBox, QApplication
    
    class GUI(QDialog):
    
        def __init__(self):
            super(GUI, self).__init__()
            dirname = os.path.dirname(os.path.abspath(__file__))
            uic.loadUi(os.path.join(dirname,'main.ui'), self)
            # button
            self.btnPopulate.clicked.connect(self.populate)
            # table model
            self.header = ['col1', 'col2', 'col3']
            self.QSModel = QStandardItemModel()
            self.QSModel.setColumnCount(3)
            self.QSModel.setHorizontalHeaderLabels(self.header)
            self.tableView.setModel(self.QSModel)
            # combobox delegate
            self.cbDelegate = QComboBox()
            self.cbDelegate.addItems(['choice1', 'choice2'])
    
        def populate(self):
            row = self.QSModel.rowCount()
            for x in range(0, 7):
                self.QSModel.insertRow(row)
                self.QSModel.setData(self.QSModel.index(row, 0), 'data')
                self.QSModel.item(row, 0).setEditable(True)
                self.QSModel.setData(self.QSModel.index(row, 1), 'data')
                self.QSModel.item(row, 1).setEditable(True)
                # add combobox delegate to even rows
                if x % 2 == 0:
                    print('Delegate added.')
                    index = self.tableView.model().index(row, 1)
                    self.tableView.setIndexWidget(index, self.cbDelegate)
                self.QSModel.setData(self.QSModel.index(row, 2), 'data')
                self.QSModel.item(row, 1).setEditable(True)
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        window = GUI()
        window.show()
        sys.exit(app.exec_())
    

    但是,当我单击 填充表格 按钮仅第一行中的第二个单元格显示QComboBox。

    1. 我需要如何更改代码以在第0、2、4和6行或任何任意行中显示QComboBox。(是否需要显示QComboBox取决于reach行中第一个单元格的值。)

    2. 我需要使用什么样的方法来用QComboBox选择替换单元格内容?

    1 回复  |  直到 5 年前
        1
  •  3
  •   eyllanesc Yonghwan Shin    7 年前

    如何更改代码以在第0行中显示QComboBox, 2、4和6或任何任意行。(无论 QComboBox是否需要显示取决于第一个单元格的值 在reach行中。)

    之所以出现只能看到QCOMBOX的问题,是因为您只创建了一个QCOMBOX,要解决这个问题,您必须为要在其中建立QCOMBOX的每个单元格创建一个QCOMBOX。

    我需要使用什么样的方法来替换单元格内容 QComboBox选择?

    您必须将适当的信号连接到模型的setData()方法,我们可以使用QModelIndex,但这很危险,因为当您删除、移动或插入项目时,它可能会发生更改,因此使用QPersistentModelIndex是适当的,在这种情况下,您必须使用信号currentIndexChanged

    在本例中,我将使用 QModelIndex :

    def populate(self):
        row = self.QSModel.rowCount()
        for x in range(7):
            self.QSModel.insertRow(row)
            self.QSModel.setData(self.QSModel.index(row, 0), 'data')
            self.QSModel.item(row, 0).setEditable(True)
            self.QSModel.setData(self.QSModel.index(row, 1), 'data')
            self.QSModel.item(row, 1).setEditable(True)
            # add combobox delegate to even rows
            if x % 2 == 0:
                index = self.tableView.model().index(row, 1)
                cbDelegate = QComboBox()
                pix = QPersistentModelIndex(index)
                cbDelegate.currentIndexChanged[str].connect(lambda txt, pix=pix:self.tableView.model().setData(QModelIndex(pix), txt))
                cbDelegate.addItems(['choice1', 'choice2'])
                self.tableView.setIndexWidget(index, cbDelegate)
            self.QSModel.setData(self.QSModel.index(row, 2), 'data')
            self.QSModel.item(row, 1).setEditable(True)
    

    在本例中,我将使用 QStandartItem :

    def populate(self):
        row = self.QSModel.rowCount()
        for x in range(7):
            self.QSModel.insertRow(row)
            self.QSModel.setData(self.QSModel.index(row, 0), 'data')
            self.QSModel.item(row, 0).setEditable(True)
            self.QSModel.setData(self.QSModel.index(row, 1), 'data')
            self.QSModel.item(row, 1).setEditable(True)
            if x % 2 == 0:
                item = self.tableView.model().item(row, 1)
                cbDelegate = QComboBox()
                cbDelegate.currentIndexChanged[str].connect(item.setText)
                cbDelegate.addItems(['choice1', 'choice2'])
                self.tableView.setIndexWidget(item.index(), cbDelegate)
            self.QSModel.setData(self.QSModel.index(row, 2), 'data')
            self.QSModel.item(row, 1).setEditable(True)
    

    执行类似操作的另一种方法是使用委托,为此我们创建一个继承自 QStyledItemDelegate :

    class ComboBoxDelegate(QStyledItemDelegate):
        def paint(self, painter, option, index):
            if index.row()%2 == 0:
                opt = QStyleOptionComboBox()
                opt.rect = option.rect 
                opt.currentText = index.data()
                QApplication.style().drawComplexControl(QStyle.CC_ComboBox, opt, painter)
                QApplication.style().drawControl(QStyle.CE_ComboBoxLabel, opt, painter)
            else:
                QStyledItemDelegate.paint(self, painter, option, index)
    
        def createEditor(self, parent, option, index):
            if index.row()%2 == 0:
                combobox = QComboBox(parent)
                options = ['choice1', 'choice2']
                if index.data() not in options:
                    combobox.addItem(index.data())
                combobox.addItems(options)
                return combobox
            return QStyledItemDelegate.createEditor(self, parent, option, index)
    
        def setEditorData(self, editor, index):
            if isinstance(editor, QComboBox):
                text = index.data()
                ix = editor.findText(text)
                if ix > 0:
                    editor.setCurrentIndex(ix)
                else:
                    index.model().setData(index, editor.currentText())
            else:
                QStyledItemDelegate.setEditorData(self, editor, index)
    
        def setModelData(self, editor, model, index):
            if isinstance(editor, QComboBox):
                model.setData(index, editor.currentText())
            else:
                QStyledItemDelegate.setModelData(self, editor, model, index)
    
    class GUI(QDialog):
        def __init__(self):
            super(GUI, self).__init__()
            dirname = os.path.dirname(os.path.abspath(__file__))
            uic.loadUi(os.path.join(dirname,'main.ui'), self)
            self.btnPopulate.clicked.connect(self.populate)
            self.header = ['col1', 'col2', 'col3']
            self.QSModel = QStandardItemModel()
            self.QSModel.setColumnCount(3)
            self.QSModel.setHorizontalHeaderLabels(self.header)
            self.tableView.setModel(self.QSModel)
            self.tableView.setItemDelegateForColumn(1, ComboBoxDelegate(self.tableView))
            self.populate()
    
        def populate(self):
            row = self.QSModel.rowCount()
            for x in range(7):
                for i, value in enumerate(['data1', 'data2', 'data3']):
                    self.QSModel.setItem(row+x, i, QStandardItem(value))
                    self.QSModel.item(row+x, i).setEditable(True)