python 3.x - QTreeView only edits in first column? -


i trying make simple property editor, property list nested dict , data displayed , edited in qtreeview. (before question -- if has working implementation of in python 3 i'd love pointed @ it).

anyway, after work have qabstractitemmodel , can open qtreeview model , shows data. if click on label in first column (the key) opens editor, either text editor or spinbox etc depending on datatype. when finish editing calls "model.setdata" reject because don't want allow editable keys. can disable editing of using flags , works fine. wanted check works way i'd expect to.

here doesn't happen: if click on cell in second column (the value want edit) bypasses loading of editor , calls model.setdata current value. baffled. i've tried changing tree selectionbehavior , selectionmode no dice. i'm returning qt.itemisenabled | qt.itemisselectable | qt.itemiseditable in flags. seems display fine. won't open editor.

any thoughts stupid mistake must making? i'll include code below, print statements i'm using try debug thing.

thanks

ps 1 thing hung me long time qmodelindex members disappear, indices got garbage. found keeping reference them (throwing them in list) worked. seems problem springs lot in qt work (i had same problem menus disappearing -- guess means should think sooner). there "best practices" way of dealing this?

# -*- coding: utf-8 -*-  collections import ordereddict pyqt4.qtcore import qabstractitemmodel, qmodelindex, qt pyqt4.qtgui import qabstractitemview  class propertylist(ordereddict):     def __init__(self, *args, **kwargs):         ordereddict.__init__(self, *args, **kwargs)         self.mymodel = propertylistmodel(self)      def __getitem__(self,index):         if issubclass(type(index), list):             item = self             key in index:                 item = item[key]             return item         else:             return ordereddict.__getitem__(self, index)   class propertylistmodel(qabstractitemmodel):      def __init__(self, proplist, *args, **kwargs):         qabstractitemmodel.__init__(self, *args, **kwargs)         self.propertylist = proplist         self.myindexes = []   # needed stop garbage collection      def index(self, row, column, parent):         """returns qmodelindex row, column in parent (qmodelindex)"""         if not self.hasindex(row, column, parent):             return qmodelindex()                 if parent.isvalid():             indexptr = parent.internalpointer()             parentdict = self.propertylist[indexptr]         else:             parentdict = self.propertylist             indexptr = []         rowkey = list(parentdict.keys())[row]         childptr = indexptr+[rowkey]         newindex = self.createindex(row, column, childptr)         self.myindexes.append(childptr)         return newindex      def get_row(self, key):         """returns row of given key (list of keys) in parent"""         if key:             parent = key[:-1]             return list(self.propertylist[parent].keys()).index(key[-1])         else:             return 0      def parent(self, index):         """         returns parent (qmodelindex) of given item (qmodelindex)         top level returns qmodelindex()         """         if not index.isvalid():             return qmodelindex()         childkeylist = index.internalpointer()         if childkeylist:             parentkeylist = childkeylist[:-1]             self.myindexes.append(parentkeylist)             return self.createindex(self.get_row(parentkeylist), 0,                                     parentkeylist)         else:             return qmodelindex()      def rowcount(self, parent):         """returns number of rows in parent (qmodelindex)"""         if parent.column() > 0:             return 0    # keys have children, not values         if parent.isvalid():             indexptr = parent.internalpointer()             try:                 parentvalue = self.propertylist[indexptr]             except:                 return 0             if issubclass(type(parentvalue), dict):                 return len(self.propertylist[indexptr])             else:                 return 0         else:             return len(self.propertylist)      def columncount(self, parent):         return 2  # key & value      def data(self, index, role):         """returns data given role given index (qmodelindex)"""        # print('looking data in role {}'.format(role))         if not index.isvalid():             return none         if role in (qt.displayrole, qt.editrole):             indexptr = index.internalpointer()             if index.column() == 1:    # column 1, send value                 return self.propertylist[indexptr]             else:                   # column 0, send key                 if indexptr:                     return indexptr[-1]                 else:                     return ""         else:  # not display or edit             return none      def setdata(self, index, value, role):         """sets value of index in given role"""         print('in setdata')         if not index.isvalid():             return false         print('trying set {} {}'.format(index,value))         print('that column {}'.format(index.column()))         if not index.column():  # change column 1             return false         try:             ptr = index.internalpointer()             self.propertylist[ptr[:-1]][ptr[-1]] = value             self.emit(self.datachanged(index, index))             return true         except:             return false      def flags(self, index):         """indicates can done data"""         if not index.isvalid():             return qt.noitemflags         if index.column():  # enable editing of values, not keys             return qt.itemisenabled | qt.itemisselectable | qt.itemiseditable         else:             return qt.itemisenabled | qt.itemisselectable | qt.itemiseditable #qt.noitemflags  if __name__ == '__main__':     p = propertylist({'k1':'v1','k2':{'k3':'v3','k4':4}})      import sys     pyqt4 import qtgui     qapp = qtgui.qapplication(sys.argv)      treeview = qtgui.qtreeview()  # i've played settings on these no avail     treeview.setheaderhidden(false)     treeview.setallcolumnsshowfocus(true)     treeview.setuniformrowheights(true)     treeview.setselectionbehavior(qabstractitemview.selectrows)     treeview.setselectionmode(qabstractitemview.singleselection)     treeview.setalternatingrowcolors(true)     treeview.setedittriggers(qabstractitemview.doubleclicked |                               qabstractitemview.selectedclicked |                              qabstractitemview.editkeypressed |                              qabstractitemview.anykeypressed)     treeview.settabkeynavigation(true)                                  treeview.setmodel(p.mymodel)     treeview.show()      sys.exit(qapp.exec_()) 

@strubbly real close forgot unpack tuple in index method.

here's working code qt5. there couple of imports , stuff need fixed. cost me couple weeks of life :)

import sys collections import ordereddict pyqt5 import qtcore, qtwidgets pyqt5.qtcore import qt  class tuplekeyedordereddict(ordereddict):     def __init__(self, *args, **kwargs):         super().__init__(sorted(kwargs.items()))      def __getitem__(self, key):         if isinstance(key, tuple):             item = self             k in key:                 if item != ():                     item = item[k]             return item         else:             return super().__getitem__(key)      def __setitem__(self, key, value):         if isinstance(key, tuple):             item = self             previous_item = none             k in key:                 if item != ():                     previous_item = item                     item = item[k]             previous_item[key[-1]] = value         else:             return super().__setitem__(key, value)  class settingsmodel(qtcore.qabstractitemmodel):     def __init__(self, data, parent=none):         super().__init__(parent)         self.root = data         self.my_index = {}   # needed stop garbage collection      def index(self, row, column, parent):         if not self.hasindex(row, column, parent):             return qtcore.qmodelindex()         if parent.isvalid():             index_pointer = parent.internalpointer()             parent_dict = self.root[index_pointer]         else:             parent_dict = self.root             index_pointer = ()         row_key = list(parent_dict.keys())[row]         child_pointer = (*index_pointer, row_key)         try:             child_pointer = self.my_index[child_pointer]         except keyerror:             self.my_index[child_pointer] = child_pointer         index = self.createindex(row, column, child_pointer)         return index      def get_row(self, key):         if key:             parent = key[:-1]             if not parent:                 return 0             return list(self.root[parent].keys()).index(key[-1])         else:             return 0      def parent(self, index):         if not index.isvalid():             return qtcore.qmodelindex()         child_key_list = index.internalpointer()         if child_key_list:             parent_key_list = child_key_list[:-1]             try:                 parent_key_list = self.my_index[parent_key_list]             except keyerror:                 self.my_index[parent_key_list] = parent_key_list             return self.createindex(self.get_row(parent_key_list), 0,                                     parent_key_list)         else:             return qtcore.qmodelindex()      def rowcount(self, parent):         if parent.column() > 0:             return 0    # keys have children, not values         if parent.isvalid():             indexptr = parent.internalpointer()             parentvalue = self.root[indexptr]             if isinstance(parentvalue, ordereddict):                 return len(self.root[indexptr])             else:                 return 0         else:             return len(self.root)      def columncount(self, parent):         return 2  # key & value      def data(self, index, role):         if not index.isvalid():             return none         if role in (qtcore.qt.displayrole, qtcore.qt.editrole):             indexptr = index.internalpointer()             if index.column() == 1:    # column 1, send value                 return self.root[indexptr]             else:                   # column 0, send key                 if indexptr:                     return indexptr[-1]                 else:                     return none         else:  # not display or edit             return none      def setdata(self, index, value, role):         pointer = self.my_index[index.internalpointer()]         self.root[pointer] = value         self.datachanged.emit(index, index)         return true      def flags(self, index):         if not index.isvalid():             return 0         return qt.itemisenabled | qt.itemisselectable | qt.itemiseditable  if __name__ == '__main__':     app = qtwidgets.qapplication(sys.argv)     data = tuplekeyedordereddict(**{'1': ordereddict({'sub': 'b'}), '2': ordereddict({'subsub': '3'})})      model = settingsmodel(data)     tree_view = qtwidgets.qtreeview()     tree_view.setmodel(model)     tree_view.show()     sys.exit(app.exec_()) 

Comments