<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; color: rgb(0, 0, 0); "><div style="font-size: 14px; font-family: Calibri, sans-serif; ">Hi Dan,</div><div style="font-size: 14px; font-family: Calibri, sans-serif; "><br></div><div style="font-size: 14px; font-family: Calibri, sans-serif; ">The best way to do this IMHO is to use a tree model to hold your data and then use the view classes you suggest to view different parts of it. The QListView would hold the top level tree items and the QTableView would be set to view its child items. The following example does just that including implementing a simple tree model (based on the <a href="http://qt-project.org/doc/qt-4.8/itemviews-simpletreemodel.html">Simple Tree Model Example</a>):</div><div style="font-size: 14px; font-family: Calibri, sans-serif; "><br></div><div><div><font face="Courier" style="font-size: 12px;">import sip</font></div><div><font face="Courier" style="font-size: 12px;">sip.setapi('QVariant',2)</font></div><div><font face="Courier" style="font-size: 12px;">sip.setapi('QString',2)</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;">from PyQt4.QtCore import *</font></div><div><font face="Courier" style="font-size: 12px;">from PyQt4.QtGui import *</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;">class TreeItem(object):</font></div><div><font face="Courier" style="font-size: 12px;"> def __init__(self, data, parent=None):</font></div><div><font face="Courier" style="font-size: 12px;"> self._childItems=[]</font></div><div><font face="Courier" style="font-size: 12px;"> self._itemData=data</font></div><div><font face="Courier" style="font-size: 12px;"> self._parentItem=parent</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> def appendChild(self, child): self._childItems.append(child)</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> def child(self, row): return self._childItems[row]</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> def childCount(self): return len(self._childItems)</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> def columnCount(self): return len(self._itemData)</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> def data(self, column): return self._itemData[column]</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> def row(self):</font></div><div><font face="Courier" style="font-size: 12px;"> if self._parentItem: return self._parentItem._childItems.index(self)</font></div><div><font face="Courier" style="font-size: 12px;"> return 0</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> def parent(self): return self._parentItem</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;">class TreeModel(QAbstractItemModel):</font></div><div><font face="Courier" style="font-size: 12px;"> def __init__(self, data, parent=None):</font></div><div><font face="Courier" style="font-size: 12px;"> QAbstractItemModel.__init__(self, parent)</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> self._rootItem=TreeItem(['',''])</font></div><div><font face="Courier" style="font-size: 12px;"> self.setupModelData(data, self._rootItem)</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> def data(self, index, role):</font></div><div><font face="Courier" style="font-size: 12px;"> if not index.isValid() or role!=Qt.DisplayRole: return None</font></div><div><font face="Courier" style="font-size: 12px;"> return index.internalPointer().data(index.column())</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> def flags(self, index):</font></div><div><font face="Courier" style="font-size: 12px;"> if not index.isValid(): return 0</font></div><div><font face="Courier" style="font-size: 12px;"> return Qt.ItemIsEnabled | Qt.ItemIsSelectable</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> def headerData(self, section, orientation, role):</font></div><div><font face="Courier" style="font-size: 12px;"> if orientation==Qt.Horizontal and role==Qt.DisplayRole: return self._rootItem.data(section)</font></div><div><font face="Courier" style="font-size: 12px;"> return None</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> def index(self, row, column, parent=QModelIndex()):</font></div><div><font face="Courier" style="font-size: 12px;"> if not self.hasIndex(row, column, parent): return QModelIndex()</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> if not parent.isValid(): parentItem=self._rootItem</font></div><div><font face="Courier" style="font-size: 12px;"> else: parentItem=parent.internalPointer()</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> childItem=parentItem.child(row)</font></div><div><font face="Courier" style="font-size: 12px;"> if childItem: return self.createIndex(row, column, childItem)</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> return QModelIndex()</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> def parent(self, index):</font></div><div><font face="Courier" style="font-size: 12px;"> if not index.isValid(): return QModelIndex()</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> parentItem=index.internalPointer().parent()</font></div><div><font face="Courier" style="font-size: 12px;"> if parentItem==self._rootItem: return QModelIndex()</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> return self.createIndex(parentItem.row(), 0, parentItem)</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> def rowCount(self, parent=QModelIndex()):</font></div><div><font face="Courier" style="font-size: 12px;"> if parent.column()>0: return 0</font></div><div><font face="Courier" style="font-size: 12px;"> if not parent.isValid(): parentItem=self._rootItem</font></div><div><font face="Courier" style="font-size: 12px;"> else: parentItem=parent.internalPointer()</font></div><div><font face="Courier" style="font-size: 12px;"> return parentItem.childCount()</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> def columnCount(self, parent=QModelIndex()):</font></div><div><font face="Courier" style="font-size: 12px;"> if parent.isValid(): return parent.internalPointer().columnCount()</font></div><div><font face="Courier" style="font-size: 12px;"> return self._rootItem.columnCount()</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> def setupModelData(self, data, parent):</font></div><div><font face="Courier" style="font-size: 12px;"> for category, details in data.iteritems():</font></div><div><font face="Courier" style="font-size: 12px;"> parent.appendChild(TreeItem([category, ''], parent))</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> categoryItem=parent.child(parent.childCount()-1)</font></div><div><font face="Courier" style="font-size: 12px;"> for k,v in details.iteritems():</font></div><div><font face="Courier" style="font-size: 12px;"> categoryItem.appendChild(TreeItem([k,v], categoryItem))</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;">if __name__=="__main__":</font></div><div><font face="Courier" style="font-size: 12px;"> from sys import argv, exit</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> class Widget(QWidget):</font></div><div><font face="Courier" style="font-size: 12px;"> def __init__(self, parent=None, **kwargs):</font></div><div><font face="Courier" style="font-size: 12px;"> QWidget.__init__(self, parent, **kwargs)</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> self.setWindowTitle("Simple Tree Model")</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> l=QHBoxLayout(self)</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> data={</font></div><div><font face="Courier" style="font-size: 12px;"> "Category 1": {</font></div><div><font face="Courier" style="font-size: 12px;"> "Key 1.1": "Value 1.1",</font></div><div><font face="Courier" style="font-size: 12px;"> "Key 1.2": "Value 1.2",</font></div><div><font face="Courier" style="font-size: 12px;"> "Key 1.3": "Value 1.3",</font></div><div><font face="Courier" style="font-size: 12px;"> },</font></div><div><font face="Courier" style="font-size: 12px;"> "Category 2": {</font></div><div><font face="Courier" style="font-size: 12px;"> "Key 2.1": "Value 2.1",</font></div><div><font face="Courier" style="font-size: 12px;"> "Key 2.2": "Value 2.2",</font></div><div><font face="Courier" style="font-size: 12px;"> "Key 2.3": "Value 2.3",</font></div><div><font face="Courier" style="font-size: 12px;"> },</font></div><div><font face="Courier" style="font-size: 12px;"> "Category 3": {</font></div><div><font face="Courier" style="font-size: 12px;"> "Key 3.1": "Value 3.1",</font></div><div><font face="Courier" style="font-size: 12px;"> "Key 3.2": "Value 3.2",</font></div><div><font face="Courier" style="font-size: 12px;"> "Key 3.3": "Value 3.3",</font></div><div><font face="Courier" style="font-size: 12px;"> }</font></div><div><font face="Courier" style="font-size: 12px;"> }</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> self._model=TreeModel(data)</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> self._lview=QListView(self)</font></div><div><font face="Courier" style="font-size: 12px;"> self._lview.setModel(self._model)</font></div><div><font face="Courier" style="font-size: 12px;"> l.addWidget(self._lview)</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> self._tview=QTableView(self)</font></div><div><font face="Courier" style="font-size: 12px;"> l.addWidget(self._tview)</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> self._lview.clicked.connect(self.indexClicked)</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> @pyqtSlot(QModelIndex)</font></div><div><font face="Courier" style="font-size: 12px;"> def indexClicked(self, index):</font></div><div><font face="Courier" style="font-size: 12px;"> if not self._tview.model(): self._tview.setModel(self._model)</font></div><div><font face="Courier" style="font-size: 12px;"> self._tview.setRootIndex(index)</font></div><div><font face="Courier" style="font-size: 12px;"><br></font></div><div><font face="Courier" style="font-size: 12px;"> a=QApplication(argv)</font></div><div><font face="Courier" style="font-size: 12px;"> w=Widget()</font></div><div><font face="Courier" style="font-size: 12px;"> w.show()</font></div><div><font face="Courier" style="font-size: 12px;"> w.raise_()</font></div><div><font face="Courier" style="font-size: 12px;"> exit(a.exec_())</font></div></div><div style="font-size: 14px; font-family: Calibri, sans-serif; "><br></div><div style="font-size: 14px; font-family: Calibri, sans-serif; ">I hope this helps,</div><div style="font-size: 14px; font-family: Calibri, sans-serif; "><br></div><div style="font-size: 14px; font-family: Calibri, sans-serif; ">Rob</div><div style="font-size: 14px; font-family: Calibri, sans-serif; "><br></div><span id="OLK_SRC_BODY_SECTION" style="font-size: 14px; font-family: Calibri, sans-serif; "><div style="font-family:Calibri; font-size:11pt; text-align:left; color:black; BORDER-BOTTOM: medium none; BORDER-LEFT: medium none; PADDING-BOTTOM: 0in; PADDING-LEFT: 0in; PADDING-RIGHT: 0in; BORDER-TOP: #b5c4df 1pt solid; BORDER-RIGHT: medium none; PADDING-TOP: 3pt"><span style="font-weight:bold">From: </span> "Dan F." <<a href="mailto:danfobble@gmail.com">danfobble@gmail.com</a>><br><span style="font-weight:bold">Date: </span> Monday, 11 November 2013 02:07<br><span style="font-weight:bold">To: </span> <<a href="mailto:pyqt@riverbankcomputing.com">pyqt@riverbankcomputing.com</a>><br><span style="font-weight:bold">Subject: </span> [PyQt] Master-Detail model advice: link a QListView to a QTableView<br></div><div><br></div><div dir="ltr">I'm brand new to PyQT and would like some general advice (and class/method suggestions) on the appropriate way to implement a Master-and-Detail/List-and-Table data browser.<div><br></div><div>The QListView presents a list of entities, and the QTableView presents a table of key-value pairs for the particular entity currently selected in the QListView.<br></div><div><br></div><div>Surely there's some example code out there for this...?</div><div><br></div><div>Thanks.</div><div><br></div></div>
_______________________________________________
PyQt mailing list <a href="mailto:PyQt@riverbankcomputing.com">PyQt@riverbankcomputing.com</a>
<a href="http://www.riverbankcomputing.com/mailman/listinfo/pyqt">http://www.riverbankcomputing.com/mailman/listinfo/pyqt</a></span></body></html>