简体   繁体   English

QHBarModelMapper 和 QAbstractItemModel 行编号

[英]QHBarModelMapper and QAbstractItemModel row numbering

I am a beginner to Python and Qt and this is my first question in this forum that has been of great help in my learning process.我是 Python 和 Qt 的初学者,这是我在这个论坛上的第一个问题,对我的学习过程有很大帮助。

I store some hierarchical data in a QAbstractItemModel and it is working well with QTreeView.我将一些分层数据存储在 QAbstractItemModel 中,它与 QTreeView 配合得很好。 I am also succesfully using QDataWidgetMapper and selectionModel.currentChanged to map data of selected nodes to a lineEdit.我也成功地使用 QDataWidgetMapper 和 selectionModel.currentChanged 到 map 选定节点的数据到 lineEdit。

For some nodes I have 4 columns that I want to plot as bars in a bar graph.对于某些节点,我有 4 列我想将 plot 作为条形图中的条形。

I have made a ChartView that is working for a hardcoded set but when I add a QHBarModelMapper to map the selected row's column 1-4 to the bar series I get an empty chart.我制作了一个适用于硬编码集的 ChartView,但是当我将 QHBarModelMapper 添加到 map 时,将所选行的第 1-4 列添加到条形系列中,我得到一个空图表。

import sys
from PySide2.QtCore import (QModelIndex, Qt, QObject, QAbstractItemModel)
from PySide2.QtWidgets import (QWidget, QTreeView, QLineEdit, QVBoxLayout, QApplication, QDataWidgetMapper)
from PySide2.QtCharts import QtCharts


class CustomTreeModel(QAbstractItemModel):
    def __init__(self, root, parent=None):
        super(CustomTreeModel, self).__init__(parent)
        self._root_node = root

    def rowCount(self, parent):
        if not parent.isValid():
            parent_node = self._root_node
        else:
            parent_node = parent.internalPointer()

        return parent_node.childCount()

    def columnCount(self, parent):
        return 5

    def data(self, index, role):
        if not index.isValid():
            return None

        node = index.internalPointer()

        if role == Qt.DisplayRole or role == Qt.EditRole:
            if not isinstance(node, QModelIndex):
                if index.column() == 0:
                    return node.name
                if index.column() == 1:
                    return node.value1
                if index.column() == 2:
                    return node.value2
                if index.column() == 3:
                    return node.value3
                if index.column() == 4:
                    return node.value4

    def headerData(self, section, orientation, role):
        if role == Qt.DisplayRole:
            if section == 0:
                return self._root_node.name
            if section == 1:
                return "value1"
            if section == 2:
                return "value2"
            if section == 3:
                return "value3"
            if section == 4:
                return "value4"

    def parent(self, index):
        node = self.getNode(index)
        parent_node = node.parent

        if parent_node == self._root_node:
            return QModelIndex()

        return self.createIndex(parent_node.row(), 0, parent_node)

    def index(self, row, column, parent):

        parent_node = self.getNode(parent)
        child_item = parent_node.child(row)

        if child_item:
            return self.createIndex(row, column, child_item)
        else:
            return QModelIndex()

    def getNode(self, index):
        if index.isValid():
            node = index.internalPointer()
            if node:
                return node

        return self._root_node


class Nodes(QObject):
    def __init__(self, name, value1, value2, value3, value4, parent = QModelIndex):
        self.parent = parent
        self.name = name
        self.value1 = value1
        self.value2 = value2
        self.value3 = value3
        self.value4 = value4
        self.children = []

    def child(self, row):
        return self.children[row]

    def row(self):
        if self.parent is not None:
            return self.parent.children.index(self)

    def addChild(self, child):
        self.children.append(child)

    def removeChild(self, position):
        if position > 0 or position > len(self.children):
            return False
        node = self.children.pop(position)
        node.parent = None

    def childCount(self):
        return len(self.children)

class MyWidget(QWidget):
    def __init__(self):
        QWidget.__init__(self)

        self.line_edit = QLineEdit()
        self.tree_view = QTreeView()

        self.bar_chart = QtCharts.QChart()
        self.bar_series = QtCharts.QBarSeries()

        self.bar_chart.addSeries(self.bar_series)

        categories = ["value 1", "value 2", "value 3", "value 4"]

        axis_x = QtCharts.QBarCategoryAxis()
        axis_x.append(categories)
        self.bar_chart.addAxis(axis_x, Qt.AlignBottom)
        self.bar_series.attachAxis(axis_x)

        axis_y = QtCharts.QValueAxis()
        self.bar_chart.addAxis(axis_y, Qt.AlignLeft)
        self.bar_series.attachAxis(axis_y)

        self.chart_view = QtCharts.QChartView(self.bar_chart)
        self.chart_view.setMinimumSize(640, 480)

        self.v_layout = QVBoxLayout(self)
        self.v_layout.addWidget(self.line_edit)
        self.v_layout.addWidget(self.tree_view)
        self.v_layout.addWidget(self.chart_view)

        self.mapper = None
        self.bar_mapper = None

    def set_selection(self, current, old):
        parent = current.parent()
        self.mapper.setRootIndex(parent)
        self.mapper.setCurrentModelIndex(current)
        self.bar_mapper.setFirstBarSetRow(current.row())

    def set_model(self, model):
        self.tree_view.setModel(model)
        self.tree_view.selectionModel().currentChanged.connect(self.set_selection)

        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(model)
        self.mapper.addMapping(self.line_edit, 0)

        self.bar_mapper = QtCharts.QHBarModelMapper()
        self.bar_mapper.setModel(model)
        self.bar_mapper.setFirstColumn(1)
        self.bar_mapper.setColumnCount(4)
        self.bar_mapper.setSeries(self.bar_series)


if __name__ == "__main__":
    # Qt Application

    app = QApplication(sys.argv)

    root_node = Nodes('Data Tree', 0,0,0,0)
    node1 = Nodes('node 1', 23, 54, 35 ,35, root_node)
    node1_1 = Nodes('node 1.1', 23 , 24 , 25 , 26, node1)
    node1_2 = Nodes('node 1.2', 24, 25, 26, 23, node1)
    node2 = Nodes('node 2', 26, 27, 22, 24, root_node)
    node2_1 = Nodes('node 2.1', 25, 26, 23, 24, node2)
    node2_2 = Nodes('node 2.2', 26, 23, 24, 25, node2)
    node1.addChild(node1_1)
    node1.addChild(node1_2)
    node2.addChild(node2_1)
    node2.addChild(node2_2)
    root_node.addChild(node1)
    root_node.addChild(node2)

    data_model = CustomTreeModel(root_node)

    widget = MyWidget()
    widget.set_model(data_model)

    widget.show()
    sys.exit(app.exec_())

I realize that row numbers of the QAbstractItemModel tree model restarts after every parent in the tree.我意识到 QAbstractItemModel 树 model 的行号在树中的每个父级之后重新启动。 Does that mean I cannot use QHBarModelMapper directly on this model like this:这是否意味着我不能像这样直接在这个 model 上使用 QHBarModelMapper:

self.bar_mapper.setFirstBarSetRow(current.row()). 

What should I use instead?我应该改用什么?

Unfortunately, although the docs of the Q{X}ModelMapper classes indicate that they support a QAbstractItemModel as a model, they can only handle a list or table type model or the first layer of a tree type model.不幸的是,尽管Q{X}ModelMapper类的文档表明它们支持 QAbstractItemModel 作为 model,但它们只能处理列表或表类型 model 或树类型 Z20F35E630DAF399D88F 的第一层Unlike QListView, QDataWidgetMapper, etc. you can set the iteration point through the rootIndex property but that is not the case with the Q{X}ModelMapper .与 QListView、QDataWidgetMapper 等不同,您可以通过 rootIndex 属性设置迭代点,但Q{X}ModelMapper

A possible solution is to implement a proxy to extract a sub tree but in your special case I see it unnecessary since it is enough to iterate over the row:一个可能的解决方案是实现一个代理来提取一个子树,但在你的特殊情况下,我认为它是不必要的,因为它足以遍历该行:

def set_selection(self, current, old):
    parent = current.parent()
    self.mapper.setRootIndex(parent)
    self.mapper.setCurrentModelIndex(current)

    model = self.tree_view.model()
    if isinstance(model, CustomTreeModel):
        node = model.getNode(current)
        self.bar_series.clear()
        bar_set = QtCharts.QBarSet(node.name)
        bar_set << node.value1 << node.value2 << node.value3 << node.value4
        self.bar_series.append(bar_set)
        axs = self.bar_chart.axes(Qt.Vertical, self.bar_series)
        if axs:
            axis_y = axs[0]
            axis_y.setMax(max([bar_set.at(i) for i in range(bar_set.count())]) + 10)

def set_model(self, model):
    self.tree_view.setModel(model)
    self.tree_view.selectionModel().currentChanged.connect(self.set_selection)

    self.mapper = QDataWidgetMapper()
    self.mapper.setModel(model)
    self.mapper.addMapping(self.line_edit, 0)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM