I have a QtreeView as the view in a QComboBox. In my app the root items are category labels and are not to be selected. When i create the view i would like to pre select one of the child items (the first root item is selected by default), but i can't figure out how. Examples of this are (especially for python) thin on the ground.
Here's my simplified example:
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
data = [ (("Cat A",False), [(("Thing 1",True), []),(("Thing 2",True), [])]),
(("Cat B",False), [(("Thing 3",True), []), (("Thing 4",True), [])])]
class MyComboBox(QComboBox):
def __init__(self):
super(QComboBox,self).__init__()
self.setView(QTreeView())
self.view().setHeaderHidden(True)
self.view().setItemsExpandable(False)
self.view().setRootIsDecorated(False)
def showPopup(self):
self.view().expandAll()
QComboBox.showPopup(self)
class Window(QWidget):
def __init__(self):
QWidget.__init__(self)
self.model = QStandardItemModel()
self.addItems(self.model, data)
self.combo = MyComboBox()
self.combo.setModel(self.model)
layout = QVBoxLayout()
layout.addWidget(self.combo)
self.setLayout(layout)
# I can choose which combobox item to select here, but I am unable to
#choose child items
#self.combo.setCurrentIndex(1)
def addItems(self, parent, elements):
for text, children in elements:
item = QStandardItem(text[0])
# root items are not selectable, users pick from child items
item.setSelectable(text[1])
parent.appendRow(item)
if children:
self.addItems(item, children)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
I have worked from the examples here and here
the question has pretty much been asked before, but not for python, and the solution posted doesn't work for me.
This is an alternative and more generic way for your current code. It will work for additional level of nested items and any configuration of selectable items.
class MyComboBox(QComboBox):
def __init__(self):
super(MyComboBox,self).__init__() # your super was wrong.
# you need to pass the _current_ class name
self.setView(QTreeView())
self.view().setHeaderHidden(True)
self.view().setItemsExpandable(False)
self.view().setRootIsDecorated(False)
def showPopup(self):
self.setRootModelIndex(QModelIndex()) # you need to add this
self.view().expandAll()
QComboBox.showPopup(self)
def setModel(self, model):
super(MyComboBox, self).setModel(model)
parent, row = self._firstSelectableItem()
if row is not None:
self.setRootModelIndex(parent)
self.setCurrentIndex(row)
def _firstSelectableItem(self, parent=QModelIndex()):
"""
Internal recursive function for finding the first selectable item.
"""
for i in range(self.model().rowCount(parent)):
itemIndex = self.model().index(i,0,parent)
if self.model().itemFromIndex(itemIndex).isSelectable():
return parent, i
else:
itemIndex, row = self._firstSelectableItem(itemIndex)
if row is not None:
return itemIndex, row
return parent, None