Python 无法使用pyqt5从表视图中已选择的项中选择单个项
我正在使用pyqt进行模型/视图编程,试图理解它。 我的问题是,当我尝试从已选择的项目组中选择si select in item时,onSelection changed事件不会触发,并且选择行为变得怪异。(不仅无法从以前选择的项目中选择项目,而且还会进行连续选择…) 如果我对def数据(self,_index,role=Qt.DisplayRole):方法进行注释,我会得到我想要的行为,因此我想我在表中填充数据的方式中遗漏了一些东西。但是如果表中有注释(Hello:),则无法填充该表中的数据 我试图用onMouseClick事件和选择行为来处理它,但没有成功。 我想要的选择行为也可以在本例中找到: 下面是我的代码,这可能有点混乱,因为我只是做了一些尝试(为此感到抱歉)。 任何评论都将不胜感激,非常感谢Python 无法使用pyqt5从表视图中已选择的项中选择单个项,python,pyqt,pyqt5,tableview,Python,Pyqt,Pyqt5,Tableview,我正在使用pyqt进行模型/视图编程,试图理解它。 我的问题是,当我尝试从已选择的项目组中选择si select in item时,onSelection changed事件不会触发,并且选择行为变得怪异。(不仅无法从以前选择的项目中选择项目,而且还会进行连续选择…) 如果我对def数据(self,_index,role=Qt.DisplayRole):方法进行注释,我会得到我想要的行为,因此我想我在表中填充数据的方式中遗漏了一些东西。但是如果表中有注释(Hello:),则无法填充该表中的数据
from PyQt5.QtWidgets import QApplication, QTableView, QAbstractItemView
import sys
from PyQt5.QtCore import QAbstractTableModel, Qt, QModelIndex, QItemSelection, QItemSelectionModel, QAbstractItemModel
class myTableModel(QAbstractTableModel):
def __init__(self, rows, columns, parent=None, *args):
QAbstractTableModel.__init__(self, parent, *args)
self.rowCount = rows
self.columnCount = columns
self.table_data = [[None] * columns for _ in range(rows)]
self.unselectedItems = []
def rowCount(self, parent):
return self.rowCount
def columnCount(self, parent):
return self.columnCount
def flags(self, index):
return Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsSelectable
def data(self, _index, role=Qt.DisplayRole):
if role == Qt.DisplayRole and _index.isValid():
row = _index.row()
column = _index.column()
item = _index.internalPointer()
if item is not None:
print(item)
value = self.table_data[row][column]
# print('value returned: ' + str(value) + ' row: ' + str(row) + ' col: ' + str(column))
return value
else:
return None
def setData(self, _index, value, role=Qt.EditRole):
if role == Qt.EditRole and _index.isValid():
# print(_index.row())
# self.arraydata[index.row()] = [value]
# print('Return from rowCount: {0}'.format(self.rowCount(index)))
row = _index.row()
column = _index.column()
self.table_data[row][column] = value
self.dataChanged.emit(_index, _index)
return True
return QAbstractTableModel.setData(self, index, value, role)
def updateSelection(self, selected, deselected):
selectedItems = selected.indexes()
for _index in selectedItems:
_text = f"({_index.row()}, {_index.column()})"
self.setData(_index, _text)
del selectedItems[:]
self.unselectedItems = deselected.indexes()
for _index in self.unselectedItems:
_text = "previous selection"
self.setData(_index, _text)
print('unselected item: ' + str(_index))
class myTableView(QTableView):
def __init__(self, rowCount, columnCount, model):
super().__init__()
self.rowCount = rowCount
self.columnCount = columnCount
self.model = model
self.setModel(model)
self.selectionModel().selectionChanged.connect(tblModel.updateSelection)
self.setSelectionMode(QAbstractItemView.ContiguousSelection)
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
selectedItems = self.selectedIndexes()
allIndexes = []
for i in range(self.rowCount):
for j in range(self.columnCount):
allIndexes.append(self.model.index(i, j))
# print('all indexes appended')
indexesToClear = [_index for _index in allIndexes if
_index not in selectedItems and _index not in self.model.unselectedItems]
for _index in indexesToClear:
valueFromIndex = str(self.model.data(_index, Qt.DisplayRole))
if valueFromIndex == "previous selection":
self.model.setData(_index, "")
# def mousePressEvent(self, event):
# if event.button() == Qt.LeftButton:
# self.selectionModel().reset()
app = QApplication(sys.argv)
tblModel = myTableModel(8, 4, app) # create table model
tblView = myTableView(8, 4, tblModel)
topLeft = tblModel.index(0, 0, QModelIndex())
bottomRight = tblModel.index(5, 2, QModelIndex())
selectionMode = tblView.selectionModel()
selection = QItemSelection(topLeft, bottomRight)
selectionMode.select(selection, QItemSelectionModel.Select)
# set selected indexes text to selection
indexes = selectionMode.selectedIndexes()
for index in indexes:
text = str(index.row()) + str(index.column())
tblModel.setData(index, text, role=Qt.EditRole)
tblView.show()
app.exec()
该行为是不稳定的,还因为您没有调用
mouseReleaseEvent
的基类实现,它执行正确更新选择所需的一些操作,包括取消选择除当前/新项目之外的先前选择的项目(但行为可以根据视图的selectionMode
而改变)。此外,考虑选择模型的选择更改的信号仅发出更改:如果选择更改时已经选择了项,则将在<代码>选择的信号参数列表中列出<强>>不>强。< / P> 为了访问所选项目的完整列表,您需要调用视图的SelectedIndex()或其选择模型 我还删除了表init的rowCount和columnCount参数,因为它是冗余的(如果更改模型大小,则容易出错):它们的值仅取决于模型本身的大小,您应该仅通过它访问它们
最后,您永远不应该覆盖现有的类属性;除了我在上面注释掉的
self.model
之外,这也适用于您在模型中使用的self.rowCount
和self.columnCount
(这也没什么意义,因为公共方法会返回方法本身,导致递归).谢谢您的回答。将updateSelection移动到myTableView类并使用模型作为参数似乎是非常正确的。但是这样做,我无法在updateSelection方法中访问模型。我得到:对于范围内的行(self.model.rowCount()):AttributeError:“builtin_function_或_method”对象没有属性“rowCount”@RustyBucketBay与PyQt对象的所有属性和几乎所有变量一样(特殊情况除外,例如QStyleOption变量),不是“python属性”,但必须作为函数访问;只需调用self.model()
。我试图添加这个model=self.model(),在model()和rowCount()中使用括号的所有选项,同时删除和包含自我。我无法访问模型参数。很抱歉我的无能,你能在答案中提供完整的工作脚本吗?提前谢谢解决。我的错误。感谢答案和所有周围的解释。这非常有用。我借此机会问,我如何知道默认类属性不应该被覆盖的es???(我在文档中查找到,对于多重继承,我不清楚).我的意思是,关于你所说的关于tableView模型的内容,不应该被覆盖,因为这是一个类属性没有问题!关于命名问题,不幸的是,你只能从经验中得到它。从学习基类函数和属性开始(这总是有用的),最重要的是QObject和QWidget,请记住,您始终可以阅读出现在每个Qt类描述顶部的“所有成员列表,包括继承的成员”链接。幸运的是,Qt有一个非常描述性和一致的命名约定,因此,在大多数情况下,如果您最终命名的内容似乎是“很明显,它应该已经存在了”,可能是:-)
class myTableView(QTableView):
def __init__(self, model):
super().__init__()
# no need for these
# self.rowCount = rowCount
# self.columnCount = columnCount
# NEVER overwrite existing class property names!
# self.model = model
self.setModel(model)
self.selectionModel().selectionChanged.connect(self.updateSelection)
self.setSelectionMode(QAbstractItemView.ContiguousSelection)
def updateSelection(self, selected, deselected):
selectedIndexes = self.selectedIndexes()
for row in range(model.rowCount()):
for column in range(model.columnCount()):
_index = model.index(row, column)
if _index in selectedIndexes:
_text = f"({_index.row()}, {_index.column()})"
elif _index in deselected:
_text = "previous selection"
else:
_text = ""
model.setData(_index, _text)