(我是PyQt的初学者。)
我想在一些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.朋友
#!/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是因为你只创建了一个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)