Hi there,

I'm using PySide2 to write a simple app to display list of items in a grid like layout with some filtering but I have a problem with selection.

It starts with a ListModel of items (called Assets for example) that is plugged into SortFilterModel where I do my filtering based on a name and that is plugged into IdenityProxyModel where I reorganize the list to a table and that is displayed in TableView.

It all "seems" to work until I use CTRL+SHIFT selection and query the self.selectionModel().selectedIndexes() later where I found out it selects the wrong stuff. I'm not really sure if my .index() and .parent() methods are correct at all too.

If you select cells horizontally it seems to work but it behaves odd when selecting vertically. Please see the image for the issue.

Thanks a lot for any help!

selection.jpg


Qt Code:
  1. from PySide2 import QtWidgets, QtGui, QtCore
  2. from PySide2.QtCore import Qt
  3. import math
  4. import sys
  5.  
  6.  
  7. class CustomTableView(QtWidgets.QTableView):
  8. def __init__(self):
  9. super(CustomTableView, self).__init__()
  10. self.setMouseTracking(True)
  11.  
  12. def mousePressEvent(self, event: QtGui.QMouseEvent) -> None:
  13. if event.button() == Qt.LeftButton:
  14. super(CustomTableView, self).mousePressEvent(event)
  15. elif event.button() == Qt.RightButton:
  16. self.doSomethingWithSelected()
  17.  
  18. def doSomethingWithSelected(self):
  19. for ix in self.selectionModel().selectedIndexes():
  20. print("Selected Indexes:", ix.row(), ix.column(), ix.data(Qt.DisplayRole))
  21.  
  22.  
  23. class CustomListModel(QtCore.QAbstractListModel):
  24. def __init__(self, parent=None):
  25. super(CustomListModel, self).__init__(parent)
  26. self._data = [
  27. "Asset_A1",
  28. "Asset_A2",
  29. "Asset_A3",
  30. "Asset_B1",
  31. "Asset_B2",
  32. "Asset_B3",
  33. "Asset_C1",
  34. "Asset_C2",
  35. "Asset_C3",
  36. "Asset_C4",
  37. "Asset_D1",
  38. "Asset_D2",
  39. "Asset_D3",
  40. "Asset_D4",
  41. ]
  42.  
  43. def rowCount(self, parent=QtCore.QModelIndex()):
  44. return len(self._data)
  45.  
  46. def data(self, index, role=Qt.DisplayRole):
  47. if role == Qt.DisplayRole:
  48. return self._data[index.row()]
  49.  
  50. def parent(self, index: QtCore.QModelIndex) -> QtCore.QObject:
  51. return QtCore.QModelIndex()
  52.  
  53.  
  54. class CustomList2TableProxyModel(QtCore.QIdentityProxyModel):
  55. def __init__(self, columns=1, parent=None):
  56. super(CustomList2TableProxyModel, self).__init__(parent)
  57. self._columns = columns
  58.  
  59. def columnCount(self, parent=QtCore.QModelIndex()):
  60. return self._columns
  61.  
  62. def rowCount(self, parent=QtCore.QModelIndex()):
  63. if parent.isValid():
  64. return 0
  65. return math.ceil(self.sourceModel().rowCount()/self.columnCount())
  66.  
  67. def mapToSource(self, proxyIndex):
  68. if proxyIndex.isValid():
  69. r = proxyIndex.row()
  70. c = proxyIndex.column()
  71. row = r * self.columnCount() + c
  72. return self.sourceModel().index(row, 0)
  73. return QtCore.QModelIndex()
  74.  
  75. def mapFromSource(self, sourceIndex):
  76. r = math.ceil(sourceIndex.row()/self.columnCount())
  77. c = sourceIndex.row() % self.columnCount()
  78. return self.index(r, c)
  79.  
  80. def data(self, index, role=Qt.DisplayRole):
  81. r = index.row()
  82. c = index.column()
  83. row = r*self.columnCount() + c
  84. if row < self.sourceModel().rowCount():
  85. return super(CustomList2TableProxyModel, self).data(index, role)
  86.  
  87. def parent(self, index: QtCore.QModelIndex) -> QtCore.QObject:
  88. return QtCore.QModelIndex()
  89.  
  90. def index(self, row, column, parent=QtCore.QModelIndex()):
  91. if parent.isValid():
  92. return QtCore.QModelIndex()
  93. return self.createIndex(row, column)
  94.  
  95. # def sibling(self, row: int, column: int, idx: QtCore.QModelIndex) -> QtCore.QModelIndex:
  96. # print("Sibling", row, column, idx.data(Qt.DisplayRole))
  97.  
  98.  
  99. class CustomMainWindow(QtWidgets.QMainWindow):
  100. def __init__(self):
  101. super(CustomMainWindow, self).__init__()
  102. self.initUI()
  103.  
  104. def initUI(self):
  105. self.mainLayout = QtWidgets.QHBoxLayout()
  106. self.mainWidget = QtWidgets.QWidget()
  107.  
  108. # List Model
  109. self.listViewWidget = QtWidgets.QWidget()
  110. self.listViewLayout = QtWidgets.QVBoxLayout()
  111. sourceModel = CustomListModel()
  112. self.listView = QtWidgets.QListView()
  113. self.listView.setModel(sourceModel)
  114. self.listViewLayout.addWidget(QtWidgets.QLabel("QAbstractListModel: Source model"))
  115. self.listViewLayout.addWidget(self.listView)
  116. self.listViewWidget.setLayout(self.listViewLayout)
  117.  
  118. # Filter model
  119. self.filterListViewWidget = QtWidgets.QWidget()
  120. self.filterListViewLayout = QtWidgets.QVBoxLayout()
  121. self.filterListView = QtWidgets.QListView()
  122. self.filterProxy = QtCore.QSortFilterProxyModel()
  123. self.filterProxy.setSourceModel(sourceModel)
  124. self.filterProxy.setFilterRegExp(QtCore.QRegExp("1", Qt.CaseInsensitive, QtCore.QRegExp.FixedString))
  125. self.filterProxy.setFilterKeyColumn(0)
  126. self.filterListView.setModel(self.filterProxy)
  127. self.filterListViewLayout.addWidget(QtWidgets.QLabel("QSortFilterProxyModel: Filter '1'"))
  128. self.filterListViewLayout.addWidget(self.filterListView)
  129. self.filterListViewWidget.setLayout(self.filterListViewLayout)
  130.  
  131. # List to Grid model
  132. self.gridViewWidget = QtWidgets.QWidget()
  133. self.gridViewLayout = QtWidgets.QVBoxLayout()
  134. self.gridView = CustomTableView()
  135. self.gridProxy = CustomList2TableProxyModel(2)
  136. self.gridProxy.setSourceModel(self.filterProxy)
  137. self.gridView.setModel(self.gridProxy)
  138. self.gridViewLayout.addWidget(QtWidgets.QLabel("QIdentityProxyModel: List to table model"))
  139. self.gridViewLayout.addWidget(self.gridView)
  140. self.gridViewWidget.setLayout(self.gridViewLayout)
  141.  
  142. # Assemble main Layout
  143. self.mainLayout.addWidget(self.listViewWidget)
  144. self.mainLayout.addWidget(self.filterListViewWidget)
  145. self.mainLayout.addWidget(self.gridViewWidget)
  146. self.mainWidget.setLayout(self.mainLayout)
  147. self.setCentralWidget(self.mainWidget)
  148.  
  149.  
  150. if __name__ == '__main__':
  151. app = QtWidgets.QApplication(sys.argv)
  152. w = CustomMainWindow()
  153. w.show()
  154. sys.exit(app.exec_())
To copy to clipboard, switch view to plain text mode