0
votes

I've virtually successfully created a TreeModel to handle multiple SQL databases feeding a QTreeView, with each parent being from a separate database. ItemTree & ItemModel contain no data, which is supplied by two QSqlTableModel's and custom 'MAKE DATA' code, creating ItemTree instances per event, then finding the children for each event and making instances of those (with the event as parent). The items are QModelIndexes.

When editing, the ItemModel's setData correctly finds the SQL data's QModelIndex (called RealIndex), but setData(realIndex, v, role=Qt.EditRole) fails for all items. Setting setEditStrategy(self.OnFieldChange) reverts the View to its original data; using OnManualSubmit updates the view, but not the model. Any ideas? Regards

#================ EXTERNAL SQL ==============
class Events(QSqlTableModel):
    def __init__(self):
        QSqlTableModel.__init__(self)

        self.setQuery(QSqlQuery("SELECT * FROM m_events"))
        self.setEditStrategy(self.OnManualSubmit)     
        self.select()            

events = Events()
eventsIdIndex = events.record().indexOf("id")
eventsUseIndex = events.record().indexOf("use")

class EventChildren(QSqlTableModel):
    def __init__(self):
        QSqlTableModel.__init__(self)

        self.setQuery(QSqlQuery("SELECT * FROM m_event_children"))
        self.select()

        self.childEventIndex = self.fieldIndex("event")
        self.childEventQi = self.createIndex(0, self.childEventIndex)
        self.childEventOccurrences = 1

children = EventChildren() 
childrenIdIndex = children.record().indexOf("id")
childrenEventIndex = children.record().indexOf("event")
childrenEventQi = children.createIndex(0, childrenEventIndex)
childrenDescIndex = children.record().indexOf("desc")

#========== INTERNAL DATA ==========
#----- TREE ITEMS -----
class ItemTree():            
    def __init__(self, data=[], parent=None): 

        self.itemData = data          # the data for each row, as a list of QModelIndexes from the SQL 
        self.itemParent = parent 
        self.itemChildren = []

        if parent:
            self.itemParent.itemChildren.append(self)  

    def child(self, row):                
        return self.itemChildren[row]

    def childCount(self):                            
        return len(self.itemChildren)

    def row(self):
        if self.itemParent:
            return self.itemParent.itemChildren.index(self)
        return False

    def columnCount(self):
        return len(self.itemData) 

    def data(self, index, role=Qt.DisplayRole):
        return self.itemData[index]   

    def parent(self):
        return self.itemParent

#----- VIEWS MODEL -----
class ItemModel(QAbstractItemModel):
    def __init__(self, rootItem=None, parent=None):
        QAbstractItemModel.__init__(self)

        self.rootItem = rootItem

    def rowCount(self, parent=QModelIndex()):
        if parent.column() > 0:
            return 0

        if not parent.isValid():
            parentItem = self.rootItem 

        else: parentItem = parent.internalPointer()

        return parentItem.childCount()

    def columnCount(self, parent):
        if parent.isValid():
            return parent.internalPointer().columnCount()
        else:
            return self.rootItem.columnCount() 

    def index(self, row, column, parent=QModelIndex()):   
        if not parent:
            return QModelIndex()

        if not parent.isValid():
            parentItem = self.rootItem
        else: 
            parentItem = parent.internalPointer()

        childItem = parentItem.child(row)
        if childItem:
            return self.createIndex(row, column, childItem) 
        else:
            return QModelIndex()   

    def parent(self, index=QModelIndex()):
        if not index.isValid():
            return QModelIndex()

        parentItem = index.internalPointer().parent()

        if parentItem == self.rootItem:
            return QModelIndex()

        return self.createIndex(parentItem.row(), 0, parentItem)

    def data(self, index, role=Qt.DisplayRole):
        if not index.isValid():
            return QVariant()
        if role == Qt.DisplayRole or role == Qt.EditRole:
            col = index.column()
            return index.internalPointer().itemData[col].data().toString()
        else:
            return QVariant()

    def setData(self, index, v, role=Qt.EditRole):
        if role == Qt.EditRole:
            realIndex = index.internalPointer().data(index.column())
            realModel = realIndex.model()

            print v.toString()
            print realIndex.row()
            print realIndex.column()
            print realIndex.model()            
            realModel.setData(realIndex, v, role=Qt.Qt.EditRole)

            realModel.submit()
            realModel.submitAll()
            return True

    def flags(self, index):
        if not index.isValid():
            return 0
        else:       
            return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable

    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return self.rootItem.data(section)
        return QVariant()

#===== MAKE DATA =====
eventsRootItem = ItemTree(data=["ID","Use"])

tempEvents = []; finalEvents = []
for e in range(events.rowCount()):
    id = str(events.record(e).value(eventsIdIndex).toString()); tempEvents.append("event"+id); finalEvents.append("event"+id)
    idQi = events.createIndex(e, eventsIdIndex, events)
    useQi = events.createIndex(e, eventsUseIndex, events)

    for i in range(len(tempEvents)):
        tempEvents[i] = ItemTree(data=[idQi, useQi], parent=eventsRootItem)
        finalEvents[i] = tempEvents[i]
        del tempEvents[0]

for e in eventsRootItem.itemChildren:
    eventId = e.itemData[0].data().toString()   # 0 here relates to the first item in the event data, which is the events id index
    eventsChildrenEventIds = children.match(childrenEventQi, Qt.DisplayRole, eventId, -1)
    for c in eventsChildrenEventIds:
        row = c.row()
        idQi = children.createIndex(row, childrenIdIndex, children)
        eventQi = children.createIndex(row, childrenEventIndex, children)
        descQi = children.createIndex(row, childrenDescIndex, children)
        t = ItemTree(data=[idQi, descQi], parent=e)

#----- RUN -----
eventsModel = ItemModel(rootItem=eventsRootItem)       
view = QTreeView()
view.setModel(eventsModel)
sys.exit(appl.exec_())
1

1 Answers

0
votes

Solved. Because the QSqlTableModel's were using a custom Query, there was no database set. When setData was called, QSqlTableModel would have nowhere to write to. Changing to:

self.setTable("talbe_name")
self.select()

writes to the database. This highlights also a limitation with QSqlTableModel, something that setFilter & sort won't be able to solve. Splitting the queries into separate QSqlTableModels & using Qts other functionality to display the appropriate data, or, using a custom QSqlTableModel seem a few possible options. Regards