Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Update: Forum Guidelines & Code of Conduct

    QSortFilterProxyModel: Update after insert columns

    General and Desktop
    3
    5
    3066
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • K
      Knacktus last edited by

      Hi guys,

      I've got a problem with a QSortFilterProxyModel. After inserting a new column, the view doesn't update properly. I've called beginInsertColumns(QModelIndex(), old_row_count, old_row_count) before and self.model.endInsertColumns() after inserting the new column, but the view doesn't display the data and alternating row coloring properly.

      All seems to be fine and dandy if I don't use the proxy model.

      My understanding is that under "normal" circumstances I don't need to reimplement the usual methods (like, "index", "data", ...) when subclassing a QSortFilterProxyModel. The QSortFilterProxyModel's standard implementations call these methods after converting the indeces. Is that correct?

      Any advice?

      Cheers and many thanks in advance,

      Jan

      I've prepared a full working example, posted in two parts. Here Part 1 (custom tree_items, header, proxymodel and view), Part 2 (model and code to run the example) follows in the first answer to this question.

      @
      import collections

      from PyQt4.QtGui import *
      from PyQt4.QtCore import *

      class ViewItem(object):

      def __init__(self, data, parent):
          self.data = data
          self.parent = parent
          self.children = []
      

      class ColumnHeader(QHeaderView):

      colums_about_to_be_updated = pyqtSignal(int)
      colums_updated = pyqtSignal()
      
      def __init__(self, applicable_columns, initial_columns, parent=None):
          super(ColumnHeader, self).__init__(Qt.Horizontal, parent)
          self.applicable_columns = applicable_columns
          self.initial_columns = initial_columns
          self.all_columns = self.applicable_columns
          self.columns = initial_columns
          self.setMovable(True)
          self.setContextMenuPolicy(Qt.ActionsContextMenu)
          self.att_name_to_action = collections.OrderedDict()
          self._prepopulate_att_name_to_action()
          self._create_att_name_to_action()
          self._set_initial_colums()
      
      def _prepopulate_att_name_to_action(self):
          for col in self.columns:
              self.att_name_to_action[col] = None
      
      def _create_att_name_to_action(self):
          for col in self.all_columns:
              action = QAction(col, self)
              action.setCheckable(True)
              action.toggled.connect(self.set_columns)
              self.addAction(action)
              self.att_name_to_action[col] = action
      
      def _set_initial_colums(self):
          for active_name in self.columns:
              self.att_name_to_action[active_name].toggle()
      
      def set_columns(self):
          self.colums_about_to_be_updated.emit(len(self.columns))
          self.columns = []
          for att, action in self.att_name_to_action.items():
              if action.isChecked():
                  self.columns.append(att)
          self.colums_updated.emit()
      

      class SearchFilterProxyModel(QSortFilterProxyModel):

      def __init__(self, source_model, parent=None):
          super(SearchFilterProxyModel, self).__init__(parent)
          self.source_model = source_model
          self.setSourceModel(self.source_model)
      

      class TreeView(QTreeView):

      def __init__(self, aux_root_view_item, all_applicable_attributes, initial_columns, parent=None):
      
          super(TreeView, self).__init__(parent)
          self.aux_root_view_item = aux_root_view_item
          self.setAlternatingRowColors(True)
      
          self.column_header = ColumnHeader(all_applicable_attributes, initial_columns)
          self.column_header.setStretchLastSection(True)
          self.setHeader(self.column_header)
      
          self.column_header.colums_about_to_be_updated.connect(self.header_about_to_be_changed)
          self.column_header.colums_updated.connect(self.header_changed)
      
          self.model = TreeModel(aux_root_view_item, self.column_header, self)
          self.proxy_model = SearchFilterProxyModel(self.model, self)
      
          #self.setModel(self.proxy_model)
          self.setModel(self.model)
      
          self.selection_model = self.selectionModel()
      
      def header_about_to_be_changed(self, old_row_count):
          self.model.beginInsertColumns(QModelIndex(), old_row_count, old_row_count)
      
      def header_changed(self):
          self.model.endInsertColumns()
      

      @

      1 Reply Last reply Reply Quote 0
      • K
        Knacktus last edited by

        Here Part 2:

        @
        class TreeModel(QAbstractItemModel):
        def init(self, aux_root_view_item, header, parent):
        super(TreeModel, self).init(parent)
        self.tree_view = parent
        self.aux_root_view_item = aux_root_view_item
        self.header = header

        def rowCount(self, parent_index=QModelIndex()):
            if parent_index.column() > 0:
                return 0
            parent_view_item = self.view_item_from_index(parent_index)
            if parent_view_item is None:
                return 0
            return len(parent_view_item.children)
        
        def columnCount(self, parent_index=QModelIndex()):
            return len(self.header.columns)
        
        def headerData(self, section, orientation, role):
            if (orientation == Qt.Horizontal and
                role == Qt.DisplayRole):
                assert 0 <= section <= len(self.header.columns)
                return self.header.columns[section]
            elif role == Qt.DisplayRole:
                return QVariant(int(section + 1))
            return QVariant()
        
        def data(self, index, role):
            view_item = self.view_item_from_index(index)
            data = view_item.data
            if data is None:
                return None
            if role != Qt.DisplayRole and role != Qt.EditRole:
                return None
            column = index.column()
            value = data[column]
            return unicode(value)
        
        def index(self, row, column, parent_index):
            if row < 0 or column < 0:
                return QModelIndex()
            view_item_parent = self.view_item_from_index(parent_index)
            if row > len(view_item_parent.children) - 1:
                return QModelIndex()
            child = view_item_parent.children[row]
            return self.createIndex(row, column, child)
        
        def parent(self, child_index):
            child_view_item = self.view_item_from_index(child_index)
            if child_view_item is None:
                return QModelIndex()
            parent_view_item = child_view_item.parent
            if parent_view_item is None:
                return QModelIndex()
            grandparent_view_item = parent_view_item.parent
            if grandparent_view_item is None:
                return QModelIndex()
            row = grandparent_view_item.children.index(parent_view_item)
            assert row != -1
            return self.createIndex(row, 0, parent_view_item)
        
        def view_item_from_index(self, index):
            if index.isValid():
                view_item = index.internalPointer()
                return view_item
            else:
                return self.aux_root_view_item
        

        def create_test_data():

        aux_root_view_item = ViewItem(None, None)
        root_view_item = ViewItem(["1a", "1b", "1c"], aux_root_view_item)
        child_11 = ViewItem(["11a", "11b", "11c"], root_view_item)
        child_12 = ViewItem(["12a", "12b", "12c"], root_view_item)
        child_111 = ViewItem(["111a", "111b", "111c"], child_11)
        child_112 = ViewItem(["112a", "112b", "112c"], child_11)
        
        aux_root_view_item.children = [root_view_item]
        root_view_item.children = [child_11, child_12]
        child_11.children = [child_111, child_112]
        
        return aux_root_view_item
        

        if name == "main":

        import sys
        
        app = QApplication(sys.argv)
        
        aux_root_view_item = create_test_data()
        tree_view = TreeView(aux_root_view_item,["a", "b", "c"], ["a", "b"])
        tree_view.show()
        
        app.exec_()
        

        @

        1 Reply Last reply Reply Quote 0
        • A
          andre last edited by

          Did you call setDynamicSortFilter(true) on your proxy model?

          1 Reply Last reply Reply Quote 0
          • K
            Knacktus last edited by

            No, I didn't. And doing (toggle true / false) so does not have any effect on my issue.

            1 Reply Last reply Reply Quote 0
            • L
              LivTarg last edited by

              Hi,
              I know this thread is half a year old but i'm facing
              the same problem right now.
              Did you manage to solve it somehow?

              Ben

              1 Reply Last reply Reply Quote 0
              • First post
                Last post