我想将委托(delegate) QComboBox 委托(delegate)添加到某些 QTableView 行中的特定单元格。我找到了几篇关于如何添加委托(delegate)的帖子,但没有一篇包含使用 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>
测试.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 选择内容?
最佳答案
How do I need to change the code to display the QComboBox in rows 0, 2, 4 and 6 or any arbitrary row for that matter. (Whether or not the QComboBox needs to be displayed depends on the value of the first cell in reach row.)
导致你只能看到一个QComboBox的问题是因为你只创建了一个QComboBox,要解决这个问题,你必须为每个你想要建立它们的单元格创建一个QComboBox。
What kind of method do I need to use to replace the cell contents with the QComboBox selection?
你必须将适当的信号连接到模型的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)
执行类似操作的另一种方法是使用委托(delegate),为此我们创建一个继承自 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/