I am learning PyQt4 and I am having trouble understanding all the ways to use the Model / View design.
I have data in the form of a dictionary, which I use to create a model.
The dictionary values are namedtuples, which contain 2 lists.
Each of these lists contains row data for the table. An example would look like this:
data = { key : ( [ [col1, col2, col3], row2 ],
[ [col1, col2, col3], row2 ]
) }
My goal is to have a list view, which is a list of all the keys from a dictionary. Clicking on a key in the list view will update 2 table views with the data associated with this key.
I have working code , but I feel that this is not the best way to do something. For example, I used a simplified data structure , where dictionary values are single tables.
I created a model for presenting a list and a model for presenting tables that use the same data. I feel that it is possible to use one model for both, but I could not understand how to relate them and change the displayed values.
My search made me read about proxyModels, dataMappers, itemDelegates, QSortFilterProxyModel and now TreeViews. But I do not know what to use or how to implement them when my data is a dictionary.
What is the correct way to achieve the above?
Do I need to change the data from the dictionary to something else?
Here is an example of the code I came up with:
from PyQt4 import QtCore, QtGui
import random
import sys
def build_mock_data(num_keys, num_rows=4, num_columns=3):
result = {}
key = "key"
build_row = lambda: [random.randint(0,10) for _ in xrange(num_columns)]
for i in xrange(num_keys):
result[key+str(i)] = [build_row() for _ in xrange(num_rows)]
return result
mock_data = build_mock_data(10)
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, data, parent=None):
super(TableModel, self).__init__(parent)
self._data = data
self.dict_key = 'key0'
def set_key(self, key):
self.beginResetModel()
self.dict_key = key
self.endResetModel()
def rowCount(self, QModelIndex_parent=None, *args, **kwargs):
return len(self._data[self.dict_key])
def columnCount(self, QModelIndex_parent=None, *args, **kwargs):
return len(self._data[self.dict_key][0])
def data(self, QModelIndex, int_role=None):
row = QModelIndex.row()
column = QModelIndex.column()
if int_role == QtCore.Qt.DisplayRole:
return str(self._data[self.dict_key][row][column])
class ListModel(QtCore.QAbstractListModel):
def __init__(self, data, parent=None):
super(ListModel, self).__init__(parent)
self._data = sorted(data.keys())
def list_clicked(self, index):
row = index.row()
key = self._data[row]
table_model.set_key(key)
def rowCount(self, QModelIndex_parent=None, *args, **kwargs):
return len(self._data)
def data(self, QModelIndex, int_role=None):
row = QModelIndex.row()
if int_role == QtCore.Qt.DisplayRole:
return str(self._data[row])
def flags(self, QModelIndex):
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
#########################################
# temporary just to get above code to run
app = QtGui.QApplication(sys.argv)
list_view = QtGui.QListView()
list_model = ListModel(mock_data)
list_view.setModel(list_model)
list_view.clicked.connect(list_model.list_clicked)
list_view.show()
table_view = QtGui.QTableView()
table_model = TableModel(mock_data)
table_view.setModel(table_model)
table_view.show()
sys.exit(app.exec_())