Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6753331
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 26, 20262026-05-26T13:08:55+00:00 2026-05-26T13:08:55+00:00

I want to produce a simple enough application which uses a QTreeView widget to

  • 0

I want to produce a simple enough application which uses a QTreeView widget to show hierarchical data from a SQLite3 (flat) table, use QDataWidgetMapper to populate some lineedit fields, allow user to edit, which in turn updates the table. Simple & basic (for most!).

I have been working on the basis that the following process would be the best way of doing this:

  1. Connect to Dbase
  2. Query data
  3. Create and populate custom QAbstractItemModel from the data (manipulating it through a dict to create nodes, parents and children dynamically – for each dict entry a ‘node’ is generated with an associated parent)
  4. Use QDatawidgetmapper to populate other widgets
  5. User edits data
  6. QAbstractItemModel (QAIM) is updated
  7. Then have to run an UPDATE, INSERT or whatever query using new values in the QAIM model.
  8. Refresh the QAIM and associated widgets.

I realise if I were just using a QTableView or QListView I would not need the custom model and could just write straight back into the database. The process I have outlined above seems to mean having to keep two sets of data going – i.e. the SQLite table and the custom QAIM and ensure that they are both kept up to date. This seems a bit cumbersome to me and I’m sure there must be a better way of doing it where the QTreeView is taking its data straight from the SQLite table – with the obvious need for some manipulation to convert the flat data into hierarchical data.

I am wondering, of course, whether I have completely misunderstood the relationship between QAbstractItemModel and the QSQL*Models and I am overcomplicating it through ignorance?

Thanks

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-26T13:08:56+00:00Added an answer on May 26, 2026 at 1:08 pm

    What you want is a proxy model that acts as a bridge between QSql*Model and the view. For that, you need to subclass QAbstractProxyModel. You have to have a consistent way of finding parent-child relationships in proxy model and mapping them to the source model, so that might require keeping some tally in the proxy model.

    When you are sub-classing QAbstractProxyModel, you need to re-define, at minimum, these methods:

    • rowCount
    • columnCount
    • parent
    • index
    • data
    • mapToSource
    • mapFromSource

    Also, keep in mind that QAbstractProxyModel does not auto-propagate signals through. So, in order to have the view be aware of changes in source model (like insert, delete, update), you need to pass them in the proxy model (while of course, updating your mappings in the proxy model).

    It will require some work, but in the end you’ll have a more flexible structure. And it will eliminate all the stuff that you need to do for synchronizing database and custom QAbstractItemModel.

    Edit

    A custom proxy model that groups items from a flat model according to a given column:

    import sys
    from collections import namedtuple
    import random
    
    from PyQt4 import QtCore, QtGui
    
    groupItem = namedtuple("groupItem",["name","children","index"])
    rowItem = namedtuple("rowItem",["groupIndex","random"])
    
    
    class GrouperProxyModel(QtGui.QAbstractProxyModel):
        def __init__(self, parent=None):
            super(GrouperProxyModel, self).__init__(parent)
    
            self._rootItem = QtCore.QModelIndex()
            self._groups = []       # list of groupItems
            self._groupMap = {}     # map of group names to group indexes
            self._groupIndexes = [] # list of groupIndexes for locating group row
            self._sourceRows = []   # map of source rows to group index
            self._groupColumn = 0   # grouping column.
    
        def setSourceModel(self, source, groupColumn=0):
            super(GrouperProxyModel, self).setSourceModel(source)
    
            # connect signals
            self.sourceModel().columnsAboutToBeInserted.connect(self.columnsAboutToBeInserted.emit)
            self.sourceModel().columnsInserted.connect(self.columnsInserted.emit)
            self.sourceModel().columnsAboutToBeRemoved.connect(self.columnsAboutToBeRemoved.emit)
            self.sourceModel().columnsRemoved.connect(self.columnsRemoved.emit)
    
            self.sourceModel().rowsInserted.connect(self._rowsInserted)
            self.sourceModel().rowsRemoved.connect(self._rowsRemoved)
            self.sourceModel().dataChanged.connect(self._dataChanged)
    
            # set grouping
            self.groupBy(groupColumn)
    
        def rowCount(self, parent):
            if parent == self._rootItem:
                # root level
                return len(self._groups)
            elif parent.internalPointer() == self._rootItem:
                # children level
                return len(self._groups[parent.row()].children)
            else:
                return 0
    
        def columnCount(self, parent):
            if self.sourceModel():
                return self.sourceModel().columnCount(QtCore.QModelIndex())
            else:
                return 0
    
        def index(self, row, column, parent):
            if parent == self._rootItem:
                # this is a group
                return self.createIndex(row,column,self._rootItem)
            elif parent.internalPointer() == self._rootItem:
                return self.createIndex(row,column,self._groups[parent.row()].index)
            else:
                return QtCore.QModelIndex()
    
        def parent(self, index):
            parent =  index.internalPointer()
            if parent == self._rootItem:
                return self._rootItem
            else:
                parentRow = self._getGroupRow(parent)
                return self.createIndex(parentRow,0,self._rootItem)
    
        def data(self, index, role):
            if role == QtCore.Qt.DisplayRole:
                parent = index.internalPointer()
                if parent == self._rootItem:
                    return self._groups[index.row()].name
                else:
                    parentRow = self._getGroupRow(parent)
                    sourceRow = self._sourceRows.index(self._groups[parentRow].children[index.row()])
                    sourceIndex = self.createIndex(sourceRow, index.column(), 0)
                    return self.sourceModel().data(sourceIndex, role)
            return None
    
        def flags(self, index):
            return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
    
        def headerData(self, section, orientation, role):
            return self.sourceModel().headerData(section, orientation, role)
    
        def mapToSource(self, index):
            if not index.isValid():
                return QtCore.QModelIndex()
    
            parent = index.internalPointer()
            if not parent.isValid():
                return QtCore.QModelIndex()
            elif parent == self._rootItem:
                return QtCore.QModelIndex()
            else:
                rowItem_ = self._groups[parent.row()].children[index.row()]
                sourceRow = self._sourceRows.index(rowItem_)
                return self.createIndex(sourceRow, index.column(), QtCore.QModelIndex())
    
        def mapFromSource(self, index):
            rowItem_ = self._sourceRows[index.row()]
            groupRow = self._getGroupRow(rowItem_.groupIndex)
            itemRow = self._groups[groupRow].children.index(rowItem_)
            return self.createIndex(itemRow,index.column(),self._groupIndexes[groupRow])
    
        def _clearGroups(self):
            self._groupMap = {}
            self._groups = []
            self._sourceRows = []
    
        def groupBy(self,column=0):
            self.beginResetModel()
            self._clearGroups()
            self._groupColumn = column
            sourceModel = self.sourceModel()
            for row in range(sourceModel.rowCount(QtCore.QModelIndex())):
                groupName = sourceModel.data(self.createIndex(row,column,0),
                                             QtCore.Qt.DisplayRole)
    
                groupIndex = self._getGroupIndex(groupName)
                rowItem_ = rowItem(groupIndex,random.random())
                self._groups[groupIndex.row()].children.append(rowItem_)
                self._sourceRows.append(rowItem_)
    
            self.endResetModel()
    
        def _getGroupIndex(self, groupName):
            """ return the index for a group denoted with name.
            if there is no group with given name, create and then return"""
            if groupName in self._groupMap:
                return self._groupMap[groupName]
            else:
                groupRow = len(self._groupMap)
                groupIndex = self.createIndex(groupRow,0,self._rootItem)
                self._groupMap[groupName] = groupIndex
                self._groups.append(groupItem(groupName,[],groupIndex))
                self._groupIndexes.append(groupIndex)
                self.layoutChanged.emit()
                return groupIndex
    
        def _getGroupRow(self, groupIndex):
            for i,x in enumerate(self._groupIndexes):
                if id(groupIndex)==id(x):
                    return i
            return 0
    
        def _rowsInserted(self, parent, start, end):
            for row in range(start, end+1):
                groupName = self.sourceModel().data(self.createIndex(row,self._groupColumn,0),
                                                    QtCore.Qt.DisplayRole)
                groupIndex = self._getGroupIndex(groupName)
                self._getGroupRow(groupIndex)
                groupItem_ = self._groups[self._getGroupRow(groupIndex)]
                rowItem_ = rowItem(groupIndex,random.random())
                groupItem_.children.append(rowItem_)
                self._sourceRows.insert(row, rowItem_)
            self.layoutChanged.emit()
    
        def _rowsRemoved(self, parent, start, end):
            for row in range(start, end+1):
                rowItem_ = self._sourceRows[start]
                groupIndex = rowItem_.groupIndex
                groupItem_ = self._groups[self._getGroupRow(groupIndex)]
                childrenRow = groupItem_.children.index(rowItem_)
                groupItem_.children.pop(childrenRow)
                self._sourceRows.pop(start)
                if not len(groupItem_.children):
                    # remove the group
                    groupRow = self._getGroupRow(groupIndex)
                    groupName = self._groups[groupRow].name
                    self._groups.pop(groupRow)
                    self._groupIndexes.pop(groupRow)
                    del self._groupMap[groupName]
            self.layoutChanged.emit()
    
        def _dataChanged(self, topLeft, bottomRight):
            topRow = topLeft.row()
            bottomRow = bottomRight.row()
            sourceModel = self.sourceModel()
            # loop through all the changed data
            for row in range(topRow,bottomRow+1):
                oldGroupIndex = self._sourceRows[row].groupIndex
                oldGroupItem = self._groups[self._getGroupRow(oldGroupIndex)]
                newGroupName = sourceModel.data(self.createIndex(row,self._groupColumn,0),QtCore.Qt.DisplayRole)
                if newGroupName != oldGroupItem.name:
                    # move to new group...
                    newGroupIndex = self._getGroupIndex(newGroupName)
                    newGroupItem = self._groups[self._getGroupRow(newGroupIndex)]
    
                    rowItem_ = self._sourceRows[row]
                    newGroupItem.children.append(rowItem_)
    
                    # delete from old group
                    oldGroupItem.children.remove(rowItem_)
                    if not len(oldGroupItem.children):
                        # remove the group
                        groupRow = self._getGroupRow(oldGroupItem.index)
                        groupName = oldGroupItem.name
                        self._groups.pop(groupRow)
                        self._groupIndexes.pop(groupRow)
                        del self._groupMap[groupName]
    
            self.layoutChanged.emit()
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I want to produce a desktop application with a very simple GUI (a background
I want to compile GCC and binutils which would produce 64bit executables. From GNU
I'm trying to produce a line chart using Flot, but I want the data
I want to produce a simple, static HTML file, that has one or more
I must develop a simple web application to produce reports. I have a single
I want to do something that I thought was fairly simple. Produce a comma
I have a list of products coming from a repository. Simple enough. Now I
If I have two stl vectors vect1, vect2 and I want to produce from
I want to translate this simple SQL statement to linq-to-sql: SELECT SUM(field1), SUM(field2) FROM
I am making a simple application for iPhone, and I want to enter a

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.