Отображение данных из QAbstractTableModel в QTreeView

Обновить

November 2018

Просмотры

3.5k раз

1

Укороченная версия

Я пытаюсь для отображения данных из файла QAbstracctTableModelв QTreeView. Когда я делаю, я в конечном итоге с всей таблицы отображаются в виде ребенка каждого узла (и внучки, и так далее). Как я могу отобразить TreeView абстрактной модели таблицы?

подробности

Я пытаюсь показать некоторые данные в QAbstractTableModelв QTreeView. В Model-View Tutorial , представив пример QAbstractTableModel, он делает это , кажется , что это так же просто , как замена QTableViewс QTreeView:

Вы можете конвертировать в приведенном выше примере в приложение с деревом. Просто замените QTableView с QTreeView , что приводит к дереву чтения / записи. Никакие изменения не должны быть внесены в модель.

Когда я делаю эту замену, я в конечном итоге с деревом показа, но если я нажимаю на любую из иконок , чтобы развернуть его (который не должен ничего делать, так как нет никакой иерархии встроенный), Python падает с Python.exe has stopped working. Это было доведено до того ], но без эффективного решения.

Для того, чтобы попытаться решить эту проблему, я переписана функция индекса в моем QAbstractTableModelподклассу (см полный рабочий пример ниже). Это приводит к совершенно другому типу ошибки. А именно, каждый узел в дереве теперь содержит всю таблицу в качестве данных. Независимо от того , сколько раз я нажимаю, вся таблица показывает вверх. Как это:

плохое дерево

Я , кажется, в каком - то рекурсивный кошмаре, и не знаю , как избежать. Соответствующий вопрос ниже предлагает мне , возможно , придется пойти QAbstractItemModel, но учебник выше цитата показывает , в противном случае ( в котором говорится, никакие изменения не должны быть внесены в модель ).

Связанные вопросы

QTreeView всегда отображает те же данные,

Полный рабочий пример

from PySide import QtGui, QtCore

class Food(object):
    def __init__(self, name, shortDescription, note, parent = None):
        self.data = (name, shortDescription, note);
        self.parentIndex = parent

class FavoritesTableModel(QtCore.QAbstractTableModel):
    def __init__(self):
        QtCore.QAbstractTableModel.__init__(self)
        self.foods = []  
        self.loadData() 

    def data(self, index, role = QtCore.Qt.DisplayRole):
        if role == QtCore.Qt.DisplayRole:
            return self.foods[index.row()].data[index.column()]
        return None

    def rowCount(self, index=QtCore.QModelIndex()):
        return len(self.foods)

    def columnCount(self, index=QtCore.QModelIndex()):
        return 3

    def index(self, row, column, parent = QtCore.QModelIndex()):  
        return self.createIndex(row, column, parent)

    def loadData(self):   
        allFoods=("Apples", "Pears", "Grapes", "Cookies", "Stinkberries")
        allDescs = ("Red", "Green", "Purple", "Yummy", "Huh?")
        allNotes = ("Bought recently", "Kind of delicious", "Weird wine grapes",
                    "So good...eat with milk", "Don't put in your nose")
        for name, shortDescription, note in zip(allFoods, allDescs, allNotes):
            food = Food(name, shortDescription, note)                                      
            self.foods.append(food) 

def main():
    import sys
    app = QtGui.QApplication(sys.argv)

    model = FavoritesTableModel() 

    #Table view
    view1 = QtGui.QTableView()
    view1.setModel(model)
    view1.show()

    #Tree view
    view2 = QtGui.QTreeView()
    view2.setModel(model)
    view2.show()

    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

2 ответы

2

Решение

В теории, Приятная особенность Model-View рамок является то , что вы можете иметь несколько представлений одного и ту же модель. На практике, однако, QAbstractTableModelна самом деле имел в виду , чтобы помочь вам просматривать таблицы, а не деревья. Документация по QAbstractTableModelговорит:

Так как модель обеспечивает более специализированный интерфейс, чем QAbstractItemModel, он не подходит для использования с видом дерева

Однако, даже учитывая , что предостережение, есть способ , чтобы получить эту работу. Во- первых, как было отмечено JKSH, вы должны исправить rowCount(и заметим , что его второй параметр является родительский индекс):

def rowCount(self, parent=QtCore.QModelIndex()):
    if parent.isValid():
        return 0
    return len(self.foods)

Во- вторых, удалить донкихотскую переопределённой из index, который делая выбор поведения акт действительно странное по причинам , я искренне не понимаю.

В целом, однако, если вы хотите , общая модель , то рискуйте и подкласс от QAbstractItemModelвместо одного из готовых моделей.

обсуждение

Не обращая внимания на родителей в rowCountприемлемо в модели таблицы. В официальной Qt книге, они следуют стандартной процедуре , имеющие rowCountвозвращения исключительно количеству строк , которые будут отображаться в таблице. Бланшетт и Саммерфильд примечание:

Родительский параметр не имеет никакого значения для модели таблицы; именно там, потому что ROWCOUNT () и ColumnCount () унаследованы от более общего QAbstractItemModel базового класса, который поддерживает heirarchies. (Стр 255)

В своей книге PyQt, Саммерфильд отмечает:

[T] он родитель QModelIndex р имеет значение только для моделей дерева (стр 434)

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

Следовательно, утверждение о том , что родительский параметр «не имеет никакого значения для модели таблицы» должны быть изменены с оговоркой , что это верно только в том случае , если данные только будут отображаться на дисплееQTableView (который, как правило, довольно хорошо предположение).

3

Из официальной документации :

При реализации модели на основе таблицы, rowCount()должна возвращать 0 , когда родитель является действительным.

То же самое columnCount(). И для полноты картины , data()следует вернуться , Noneесли родитель является действительным.


То, что произошло это:

  1. Вы нажмите на знак «+» рядом с «Stinkberries».
  2. QTreeView думает, «Мне нужно , чтобы расширить представление. Интересно , сколько строк существуют под„Stinkberries“?» Чтобы выяснить это , QTreeView звонки rowCount(), и передает индекс «Stinkberries» ячейки в качестве родителя.
  3. FavoritesTableModel::rowCount()возвращает 5, так что QTreeView думает, «Ах, есть 5 рядов под„Stinkberries“.»
  4. Тот же самый процесс происходит по столбцам.
  5. QTreeView решает получить первый пункт в разделе «Stinkberries». Она требует data(), проходя строки 0, столбец 0, а индекс «Stinkberries» ячейки в качестве родителя.
  6. FavoritesTableModel::data()возвращает «Яблоки», так QTreeView думает, «Ах, первый пункт под„Stinkberries“является„Яблоки“.»
  7. и т.п.

Для того, чтобы получить правильное поведение, ваш код должен возвращать 0 для Steps # 3 и # 4.


Наконец, чтобы убедиться , что «+» знаки не появляются вообще, делают hasChildren()вернуться ложным для каждой ячейки.