охватывающий несколько столбцов, используя QTreeView и QAbstractItemModel

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

Я пытался добиться этого с помощью QTreeView.setFirstColumnSpanned. Тем не менее, я не могу понять, где и когда это звонить (и, возможно, я с самого начала ошибаюсь).

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

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

Я также пробовал повторно реализовать insertRows в моей модели и / или rowsInserted в моем представлении, но они никогда не вызываются.

Вот чрезвычайно упрощенная версия того, что я делаю:

class MyModel(QtCore.QAbstractItemModel):
    def __init__(self, top_level_nodes):
        QtCore.QAbstractItemModel.__init__(self)
        self.top_level_nodes = top_level_nodes
        self.columns = 5

    def columnCount(self, parent):
        return self.columns

    def rowCount(self, parent):
        total = len(self.top_level_nodes)
        for node in self.top_level_nodes:
            total += len(node.subnodes)
        return total

    def data(self, index, role):

        if not index.isValid():
            return QtCore.QVariant()

        if role == QtCore.Qt.DisplayRole:
            obj = index.internalPointer()
            return obj.name

        return QtCore.QVariant()

    def index(self, row, column, parent):
        if not parent.isValid():
            if row > (len(self.top_level_nodes) - 1):
                return QtCore.QModelIndex()

            return self.createIndex(row, column, self.top_level_nodes[row])

        return QtCore.QModelIndex()

    def parent(self, index):
        if not index.isValid():
            return QtCore.QModelIndex()

        node = index.internalPointer()
        if node.parent is None:
            return QtCore.QModelIndex()

        else:
            return self.createIndex(node.parent.row, 0, node.parent)

class FakeEntry(object):
    def __init__(self, name, row, children=[]):
        self.parent = None
        self.row = row
        self.name = 'foo'
        self.subnodes = children

class MainWindow(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)

        self.resize(800, 600)

        self.layout = QtGui.QVBoxLayout(self)
        self.tree_view = QtGui.QTreeView(self)
        self.layout.addWidget(self.tree_view)

        entry = FakeEntry('foo', 0, children=[])
        self.model = MyModel([entry])
        self.tree_view.setModel(self.model)

def main():
    app = QtGui.QApplication(sys.argv)
    frame = MainWindow()
    frame.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

Этот код работает нормально. Что мне нужно знать:

Как сделать так, чтобы запись, созданная FakeEntry, охватывала все 5 столбцов вместо создания 5 идентичных ячеек?

Другие вопросы:

  • Могу ли я повторно реализовать QAbstractItemModel.insertRows или QTreeView.rowsInserted? Есть ли какой-то «трюк» для этого, который мне не хватает, из-за чего мой код выбирает реализацию по умолчанию?
  • Что на самом деле обрабатывает создание строк / столбцов в представлении после того, как модель заполнена данными и прикреплена к представлению?

person almaghest    schedule 24.07.2015    source источник


Ответы (1)


У меня это сработает, если я добавлю вызов setFirstColumnSpanned после вызова setModel() в MainWindow.__init__().

class MainWindow(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)

        self.resize(800, 600)

        self.layout = QtGui.QVBoxLayout(self)
        self.tree_view = QtGui.QTreeView(self)
        self.layout.addWidget(self.tree_view)

        entry = FakeEntry('foo', 0, children=[])
        self.model = MyModel([entry])
        self.tree_view.setModel(self.model)
        self.tree_view.setFirstColumnSpanned(0, QtCore.QModelIndex(), True)

Я считаю, что представление отслеживает составные столбцы внутри, отдельно от модели. Но он будет сбрасывать информацию о диапазоне всякий раз, когда вызывается setModel(). Итак, вы должны вызвать setFirstColumnSpanned() после вызова setModel() в представлении. Если ваша модель выполняет отложенную загрузку с fetchMore(), вам нужно будет разработать способ сообщить представлению, что оно должно обновлять промежутки после того, как модель загрузила новые данные.

Что касается того, что на самом деле обрабатывает создание строк / столбцов в представлении, я думаю об этом как о партнерстве между моделью и представлением. Как только в представлении будет установлена ​​модель, оно начинает задавать модели различные вопросы. Сколько столбцов у самого верхнего родительского элемента (недопустимый индекс)? Круто, там 5. Сколько там рядов? Хорошо, 1. На основе этой информации заголовок представления может начать настраиваться. В определенный момент представление выполняет итерацию по строкам, столбцам и дочерним элементам в модели и по очереди запрашивает данные у каждого индекса для каждой роли данных. Затем он может начать создание делегатов для отображения этих данных в соответствующем месте представления.

person Chris    schedule 24.07.2015