我想向某些QTableView行中的特定单元格添加一个委托QComboBox委托。我发现了几篇有关如何添加委托的文章,但没有关于使用QComboBox选择项更新单元的示例。

这是我到目前为止所拥有的:

main.ui

<?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>


test.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。


我该如何更改代码以在第0、2、4和6行或任何此行中显示QComboBox。 (是否需要显示QComboBox取决于到达范围行中第一个单元格的值。)
我需要使用哪种方法用QComboBox选项替换单元格内容?

最佳答案

我如何更改代码以在第0行中显示QComboBox,
  2、4、6或与此相关的任意行。 (无论
  需要显示QComboBox取决于第一个单元格的值
  在到达行中。)


这个问题使您只能看到QComboBox,这是因为您仅创建了一个QComboBox,要解决该问题,必须为要在其中建立它们的每个单元格创建一个QComboBox。


  我需要使用哪种方法替换单元格内容
  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)

关于python - 如何使用QCombobox选择来更新QTableView单元格?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48105026/

10-12 22:17