【发布时间】:2022-02-04 13:30:54
【问题描述】:
设置说明
- PySide 中的表使用
创建 QMainWindow -> QWidget -> QTableView -> TableModel (QAbstractTableModel) -> array[] - 为第二和第三列创建ButtonDelegate(QStyledItemDelegate)
- 第一列中的按钮切换值 - 但在我的应用程序中,出于特定原因,按钮必须分开(用一个按钮切换不是解决方案)
- 第一列值为“隐藏”的按钮
- 只选择了整行(在我的应用程序中很重要,我在所选行上单独显示详细数据)
功能的详细描述
- 我的应用程序中的按钮不需要切换值。最容易解释我的应用程序的功能是配置列表。
- 列表中最初是可以选择的通用项目,两个按钮是“+”(添加/选择)和“-”(删除/取消选择)。
- 有些项目只能添加一次,在这种情况下,按钮实际上只是切换项目选择。如果未选择,则仅显示按钮“+”,如果选择仅显示按钮“-”。
- 有些项目可以多次添加。在这种情况下,最初该项目未被选中。按“+”选择项目,显示“-”按钮,但仍然显示“+”按钮,因为该项目可以多次添加。再次按下“+”时,将添加具有相同项目的下一行,再次显示“+”和“-”。然后按“-”以相反的方式工作,删除按“-”的行,直到最后一个相同类型的项目,其中“-”导致未选择的项目。因此 +/- 的功能取决于内容。
- 我决定在单独的列中设置按钮的原因很少 - 保留根据选择状态进行排序的可能性,标题为“+”显示“添加”,为“-”显示“删除”
问题描述
- 当最后一列中的按钮被禁用时(按下 False 按钮,然后按下 True 按钮),选择移至下一行 - 应保持不变
- 另外,活动按钮的显示和隐藏可能应该在绘画中完成(而不是 openPersistentEditor)。我正在查看来自谷歌的文档和示例以找到方法,但我仍然没有弄清楚。如果你能告诉我怎么做,我将不胜感激。此外,如果您有一些关于这个主题(绘画)的好教程的链接,我会很高兴,因为我仍然不知道如何使用它。
最小功能示例:
from PySide6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QAbstractItemView
from PySide6.QtWidgets import QTableView, QWidget, QStyledItemDelegate, QPushButton
from PySide6.QtCore import Qt, QModelIndex, QAbstractTableModel, QItemSelectionModel
class TrueButtonDelegate(QStyledItemDelegate):
def __init__(self, parent):
QStyledItemDelegate.__init__(self, parent)
def paint(self, painter, option, index):
self.parent().openPersistentEditor(index) # this should be somewhere else, not in paint
def createEditor(self, parent, option, index):
editor = QPushButton('True', parent)
editor.setEnabled(False)
editor.clicked.connect(self.buttonClicked)
return editor
def setEditorData(self, editor, index):
if not index.data():
editor.setText('True')
editor.setEnabled(True)
editor.setFlat(False)
else:
editor.setText('')
editor.setEnabled(False)
editor.setFlat(True)
def setModelData(self, editor, model, index):
model.setData(index, True, role=Qt.EditRole)
def buttonClicked(self):
self.commitData.emit(self.sender())
def eventFilter(self, obj, event):
if event.type() == event.Type.Wheel:
event.setAccepted(False)
return True
return super().eventFilter(obj, event)
class FalseButtonDelegate(QStyledItemDelegate):
def __init__(self, parent):
QStyledItemDelegate.__init__(self, parent)
def paint(self, painter, option, index):
self.parent().openPersistentEditor(index) # this should be somewhere else, not in paint
def createEditor(self, parent, option, index):
editor = QPushButton('False', parent)
editor.setEnabled(True)
editor.clicked.connect(self.buttonClicked)
return editor
def setEditorData(self, editor, index):
if index.data():
editor.setText('False')
editor.setEnabled(True)
editor.setFlat(False)
else:
editor.setText('')
editor.setEnabled(False)
editor.setFlat(True)
def setModelData(self, editor, model, index):
model.setData(index, False, role=Qt.EditRole)
def buttonClicked(self):
self.commitData.emit(self.sender())
def eventFilter(self, obj, event):
if event.type() == event.Type.Wheel:
event.setAccepted(False)
return True
return super().eventFilter(obj, event)
class TableModel(QAbstractTableModel):
def __init__(self, localData=[[]], parent=None):
super().__init__(parent)
self.modelData = localData
def headerData(self, section: int, orientation: Qt.Orientation, role: int):
if role == Qt.DisplayRole:
if orientation == Qt.Vertical:
return "Row " + str(section)
def columnCount(self, parent=None):
return 3
def rowCount(self, parent=None):
return len(self.modelData)
def data(self, index: QModelIndex, role: int):
if role == Qt.DisplayRole:
row = index.row()
return self.modelData[row]
def setData(self, index, value = None, role=Qt.DisplayRole):
row = index.row()
self.modelData[row] = value
index = self.index(row, 0)
self.dataChanged.emit(index, index)
index = self.index(row, 1)
self.dataChanged.emit(index, index)
index = self.index(row, 2)
self.dataChanged.emit(index, index)
return True
app = QApplication()
data = [True, True, True, True, True, True, True, True, True, True, True, True, True, True]
model = TableModel(data)
tableView = QTableView()
tableView.setModel(model)
selectionModel = QItemSelectionModel(model)
tableView.setSelectionModel(selectionModel)
tableView.setItemDelegateForColumn(1, FalseButtonDelegate(tableView))
tableView.setItemDelegateForColumn(2, TrueButtonDelegate(tableView))
tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
tableView.setSelectionMode(QAbstractItemView.SingleSelection)
widget = QWidget()
widget.horizontalHeader = tableView.horizontalHeader()
widget.horizontalHeader.setStretchLastSection(True)
widget.mainLayout = QVBoxLayout()
widget.mainLayout.setContentsMargins(1,1,1,1)
widget.mainLayout.addWidget(tableView)
widget.setLayout(widget.mainLayout)
mainWindow = QMainWindow()
mainWindow.setCentralWidget(widget)
mainWindow.setGeometry(0, 0, 380, 300)
mainWindow.show()
exit(app.exec())
【问题讨论】:
-
您的实现存在一些问题(
openPersistentEditor()除外),但最重要的是,由于每当更改索引时都会调用setModelData(),因此您的代码每次都会更改模型当其中一个单元格失去焦点时(尝试使用 tab 和 shift-tab ,你会看到)。你说你的按钮必须分开:你能澄清为什么你需要那个吗?此外,不要使用两个单独的列和小部件,为什么不使用带有两个按钮的单个小部件? -
是的,用箭头移动也按下按钮。那很不好。如何修复?我在功能的详细描述部分回答了您的其余问题
标签: qt selection pyside qtableview qstyleditemdelegate