2015-12-14 10 views
2

Я пытаюсь создать QTreeView с пользовательской моделью и на всю жизнь, я не могу понять, как заставить редактор по умолчанию отображаться во втором столбце , Показывает штраф в первой колонкеРедактирование второго столбца в QTreeView с пользовательской моделью Не отображает редактор

Основными данными в моей пользовательской модели являются вложенные OrderedDicts. Базовый OrderedDict является специальным подклассом TupleKeyedOrderedDict с переопределенным методом __getitem__, чтобы проверить, является ли ключ кортежем. Если ключ является кортежем, структура данных повторяется рекурсивно, пока не осталось больше ключей.

Приведенный ниже пример - это рабочий пример, когда второй столбец не имеет редактора, хотя данные могут быть изменены.

import sys 
from collections import OrderedDict 
from PyQt5 import QtCore, QtWidgets 
from 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 
      for 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 
      for 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 to 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 # only 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 the value 
       return self.root[indexPtr] 
      else:     # Column 0, send the 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_()) 

ответ

2

Проблема была с распаковкой кортежа в index методе SettingsModel

import sys 
from collections import OrderedDict 
from PyQt5 import QtCore, QtWidgets 
from 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 
      for 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 
      for 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 to 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 # only 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 the value 
       return self.root[indexPtr] 
      else:     # Column 0, send the 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_())