Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QSortFilterProxyModel: Update after insert columns
QtWS25 Last Chance

QSortFilterProxyModel: Update after insert columns

Scheduled Pinned Locked Moved General and Desktop
5 Posts 3 Posters 3.3k Views
  • 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 Offline
    K Offline
    Knacktus
    wrote on last edited by
    #1

    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
    0
    • K Offline
      K Offline
      Knacktus
      wrote on last edited by
      #2

      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
      0
      • A Offline
        A Offline
        andre
        wrote on last edited by
        #3

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

        1 Reply Last reply
        0
        • K Offline
          K Offline
          Knacktus
          wrote on last edited by
          #4

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

          1 Reply Last reply
          0
          • L Offline
            L Offline
            LivTarg
            wrote on last edited by
            #5

            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
            0

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved