QML PieSeries 自定义模型与自定义数据

huangapple go评论63阅读模式
英文:

QML PieSeries custom model with custom data

问题

我想加载一些自定义数据(不仅仅是标签和大小,还有其他我需要的内容)。比如说,我想要从模型中加载每个切片的颜色。如何访问“第三列”值 - “黑色”或“白色”,并让 QML 使用它?
这是我有的代码:

main.py:

import sys
from PyQt5 import QtCore, QtWidgets, QtQuick
import custom_model

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)

    view = QtQuick.QQuickView()

    outer_ring_model = custom_model.OuterRingModel()

    view.rootContext().setContextProperty('outerRingModel', outer_ring_model)

    view.setSource(QtCore.QUrl("main.qml"))
    view.show()

    sys.exit(app.exec_())

custom_model.py:

from PyQt5 import QtCore

class OuterRingModel(QtCore.QAbstractTableModel):

    def __init__(self, parent=None):
        super().__init__(parent)

        self.column_count = 2
        self.row_count = 100
        self.data = []

        i = 0
        while i < (self.row_count / 2):
            self.data.append(['Black', 50, 'black'])
            self.data.append(['White', 50, 'white'])
            i += 1

    def rowCount(self, parent):
        return len(self.data)

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

    def data(self, index, role):
        if role == QtCore.Qt.DisplayRole:
            return self.data[index.row()][index.column()]
        elif role == QtCore.Qt.EditRole:
            return self.data[index.row()][index.column()]
        elif role == QtCore.Qt.BackgroundRole:
            return QtGui.QColor(QtCore.Qt.white)
        return QtCore.QVariant()

main.qml:

import QtQuick 2.7
import QtQuick.Window 2.0
import QtQuick.Controls 1.4
import QtCharts 2.1

Grid {
    id: grid1
    width: 1024
    height: 600
    spacing: 10
    rows: 1
    columns: 2

    Component.onCompleted: { update() }

    ChartView {
        id: chart
        width: 600
        height: 600
        antialiasing: true
        animationDuration: 1000
        animationOptions: ChartView.AllAnimations
        title: "MyTitle"
        legend.visible: false

        PieSeries {
            id: serie0
            name: "Outer Ring"
            size: 0.75
            holeSize: 0.7
            onSliceAdded: {
                slice.color = Qt.lighter("red", 1.5)
                // slice.color = 如何在此处导入模型数据
            }

            VPieModelMapper {
                id: model0
                model: outerRingModel
                labelsColumn: 0
                valuesColumn: 1
                firstRow: 0
                rowCount: 100
            }
        }
    }
}
英文:

I want to load some custom data (not Just label and size, but something else I need too). Let say - I want to load every slice's color out of the model too. How can I access the "third column" value - "black" or "white" and make QML to use it?
This is the code I have:

main.py:

import sys
from PyQt5 import QtCore, QtWidgets, QtQuick
import custom_model

if __name__ == &#39;__main__&#39;:
    app = QtWidgets.QApplication( sys.argv )

    view = QtQuick.QQuickView()

    outer_ring_model = custom_model.OuterRingModel()

    view.rootContext().setContextProperty( &#39;outerRingModel&#39;, outer_ring_model )

    view.setSource( QtCore.QUrl( &quot;main.qml&quot; ) )
    view.show()

    sys.exit( app.exec_() )

custom_model.py:

from PyQt5 import QtCore

class OuterRingModel( QtCore.QAbstractTableModel ):

    def __init__( self, parent=None ):
        super().__init__( parent )

        self.column_count = 2
        self.row_count = 100
        self.data = []

        i = 0
        while i &lt; (self.row_count / 2):
            self.data.append([&#39;Black&#39;, 50, &#39;black&#39;])
            self.data.append([&#39;White&#39;, 50, &#39;white&#39;])
            i += 1

    def rowCount( self, parent ):
        return len( self.data )

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

    def data( self, index, role ):
        if role == QtCore.Qt.DisplayRole:
            return self.data[ index.row() ][ index.column() ]
        elif role == QtCore.Qt.EditRole:
            return self.data[ index.row() ][ index.column() ]
        elif role == QtCore.Qt.BackgroundRole:
            return QtGui.QColor( QtCore.Qt.white )
        return QtCore.QVariant()

main.qml:

import QtQuick 2.7
import QtQuick.Window 2.0
import QtQuick.Controls 1.4
import QtCharts 2.1

Grid {
    id: grid1
    width: 1024
    height: 600
    spacing: 10
    rows: 1
    columns: 2

    Component.onCompleted: { update() }

    ChartView {
        id: chart
        width: 600
        height: 600
        antialiasing: true
        animationDuration: 1000
        animationOptions: ChartView.AllAnimations
        title: &quot;MyTitle&quot;
        legend.visible: false

        PieSeries {
            id: serie0
            name: &quot;Outer Ring&quot;
            size: 0.75
            holeSize: 0.7
            onSliceAdded: {
                slice.color = Qt.lighter(&quot;red&quot;, 1.5)
                // slice.color = HOW_TO_IMPORT_MODEL_DATA_HERE
            }

            VPieModelMapper {
                id: model0
                model: outerRingModel
                labelsColumn: 0
                valuesColumn: 1
                firstRow: 0
                rowCount: 100
            }
        }
    }
}

答案1

得分: 2

以下是您要翻译的代码部分:

What you require cannot be implemented in QML since you cannot know the index associated with the slice so you will have to implement that logic in Python/C++. In addition, your model has errors that I have already corrected.

**main.py**
```python
import os
import sys

from PyQt5 import QtCore, QtGui, QtWidgets, QtQuick, QtChart

import custom_model


class Manager(QtCore.QObject):
    @QtCore.pyqtSlot(
        QtChart.QPieSeries, QtChart.QPieSlice, QtCore.QAbstractItemModel, int
    )
    def updateSlice(self, serie, sl, model, firstRow):
        row = firstRow + serie.slices().index(sl)
        index = model.index(row, 2)
        color = model.data(index) or &quot;&quot;
        sl.setColor(QtGui.QColor(color))


if __name__ == &quot;__main__&quot;:
    app = QtWidgets.QApplication(sys.argv)

    view = QtQuick.QQuickView()

    manager = Manager()
    outer_ring_model = custom_model.OuterRingModel()

    view.rootContext().setContextProperty(&quot;manager&quot;, manager)
    view.rootContext().setContextProperty(&quot;outerRingModel&quot;, outer_ring_model)

    filename = os.path.join(os.path.dirname(os.path.realpath(__file__)), &quot;main.qml&quot;)

    view.setSource(QtCore.QUrl.fromLocalFile(filename))
    view.show()

    sys.exit(app.exec_())

custom_model.py

from PyQt5 import QtCore


class OuterRingModel(QtCore.QAbstractTableModel):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.column_count = 3
        self._data = []

        for i in range(50):
            self._data.append([&quot;Black&quot;, 50, &quot;black&quot;])
            self._data.append([&quot;White&quot;, 50, &quot;white&quot;])

    def rowCount(self, parent):
        return len(self._data)

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

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

main.qml

import QtQuick 2.7
import QtQuick.Window 2.0
import QtQuick.Controls 1.4
import QtCharts 2.1

Grid {
    id: grid1
    width: 1024
    height: 600
    spacing: 10
    rows: 1
    columns: 2

    VPieModelMapper {
        id: mapper0
        model: outerRingModel
        series: serie0
        labelsColumn: 0
        valuesColumn: 1
        firstRow: 0
        rowCount: 100
    }

    ChartView {
        id: chart
        width: 600
        height: 600
        antialiasing: true
        animationDuration: 1000
        animationOptions: ChartView.AllAnimations
        title: &quot;MyTitle&quot;
        legend.visible: false

        PieSeries {
            id: serie0
            name: &quot;Outer Ring&quot;
            size: 0.75
            holeSize: 0.7
            onSliceAdded: {
                manager.updateSlice(mapper0.series, slice, mapper0.model, mapper0.firstRow)
            }   
        }
    }
}

QML PieSeries 自定义模型与自定义数据


<details>
<summary>英文:</summary>

What you require cannot be implemented in QML since you cannot know the index associated with the slice so you will have to implement that logic in Python/C++. In addition, your model has errors that I have already corrected.

**main.py**
```python
import os
import sys

from PyQt5 import QtCore, QtGui, QtWidgets, QtQuick, QtChart

import custom_model


class Manager(QtCore.QObject):
    @QtCore.pyqtSlot(
        QtChart.QPieSeries, QtChart.QPieSlice, QtCore.QAbstractItemModel, int
    )
    def updateSlice(self, serie, sl, model, firstRow):
        row = firstRow + serie.slices().index(sl)
        index = model.index(row, 2)
        color = model.data(index) or &quot;&quot;
        sl.setColor(QtGui.QColor(color))


if __name__ == &quot;__main__&quot;:
    app = QtWidgets.QApplication(sys.argv)

    view = QtQuick.QQuickView()

    manager = Manager()
    outer_ring_model = custom_model.OuterRingModel()

    view.rootContext().setContextProperty(&quot;manager&quot;, manager)
    view.rootContext().setContextProperty(&quot;outerRingModel&quot;, outer_ring_model)

    filename = os.path.join(os.path.dirname(os.path.realpath(__file__)), &quot;main.qml&quot;)

    view.setSource(QtCore.QUrl.fromLocalFile(filename))
    view.show()

    sys.exit(app.exec_())

custom_model.py

from PyQt5 import QtCore


class OuterRingModel(QtCore.QAbstractTableModel):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.column_count = 3
        self._data = []

        for i in range(50):
            self._data.append([&quot;Black&quot;, 50, &quot;black&quot;])
            self._data.append([&quot;White&quot;, 50, &quot;white&quot;])

    def rowCount(self, parent):
        return len(self._data)

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

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

main.qml

import QtQuick 2.7
import QtQuick.Window 2.0
import QtQuick.Controls 1.4
import QtCharts 2.1

Grid {
    id: grid1
    width: 1024
    height: 600
    spacing: 10
    rows: 1
    columns: 2

    VPieModelMapper {
        id: mapper0
        model: outerRingModel
        series: serie0
        labelsColumn: 0
        valuesColumn: 1
        firstRow: 0
        rowCount: 100
    }

    ChartView {
        id: chart
        width: 600
        height: 600
        antialiasing: true
        animationDuration: 1000
        animationOptions: ChartView.AllAnimations
        title: &quot;MyTitle&quot;
        legend.visible: false

        PieSeries {
            id: serie0
            name: &quot;Outer Ring&quot;
            size: 0.75
            holeSize: 0.7
            onSliceAdded: {
                manager.updateSlice(mapper0.series, slice, mapper0.model, mapper0.firstRow)
            }   
        }
    }
}

QML PieSeries 自定义模型与自定义数据

答案2

得分: 0

以下是翻译好的部分:

我已经成功完成了,没有任何新的实现。

我的切片列表如下所示:

property variant pieArray: [
    {
        "label":"10",
        "value":0.1,
        "active":true,
        "originalColor":"#ff9900",
        "labelColor":"#000000",
        "labelFont":"Arial",
        "labelPointSize":20,
        "borderWidth":6,
        "borderColor":"#000000",
        "explodeDistanceFactor":0.0,
        "exploded":false,
        "from":0,
        "to":10
    }
]

以下是用于添加饼图和其自定义属性的函数。自定义属性将自动添加,您无需考虑它。

function addPies(pieArr) {
    for (var i = 0; i < pieArr.length; i++) {
        console.log(pieArr[i]["label"], pieArr[i]["value"]);
        pieOuter.append(pieArr[i]["label"], pieArr[i]["value"]);
        pieOuter.find(pieArr[i]["label"]).labelPosition = PieSlice.LabelInsideHorizontal;
        pieOuter.find(pieArr[i]["label"]).labelVisible = true;
        pieOuter.find(pieArr[i]["label"]).labelColor = pieArr[i]["labelColor"];
        pieOuter.find(pieArr[i]["label"]).labelFont.family = pieArr[i]["labelFont"];
        pieOuter.find(pieArr[i]["label"]).labelFont.pointSize = pieArr[i]["labelPointSize"];
        pieOuter.find(pieArr[i]["label"]).borderWidth = pieArr[i]["borderWidth"];
        pieOuter.find(pieArr[i]["label"]).borderColor = pieArr[i]["borderColor"];
        pieOuter.find(pieArr[i]["label"]).explodeDistanceFactor = pieArr[i]["explodeDistanceFactor"];
        pieOuter.find(pieArr[i]["label"]).exploded = pieArr[i]["exploded"];
        pieOuter.find(pieArr[i]["label"]).color = pieArr[i]["originalColor"];
        pieOuter.find(pieArr[i]["label"]).originalColor = pieArr[i]["originalColor"];
        pieOuter.find(pieArr[i]["label"]).active = pieArr[i]["active"];
        pieOuter.find(pieArr[i]["label"]).from = pieArr[i]["from"];
        pieOuter.find(pieArr[i]["label"]).to = pieArr[i]["to"];
        pieOuter.find(pieArr[i]["label"]).to = pieArr[i]["to"];
    }
}

然后在Component.onCompleted或任何其他您想要使用的事件中调用它:

Component.onCompleted: {
    addPies(pieArray);
}
英文:

I've managed to do it without any new implementations.

My Slice list is something like this:

property variant pieArray: [
{
&quot;label&quot;:&quot;10&quot;,
&quot;value&quot;:0.1,
&quot;active&quot;:true,
&quot;originalColor&quot;:&quot;#ff9900&quot;,
&quot;labelColor&quot;:&quot;#000000&quot;,
&quot;labelFont&quot;:&quot;Arial&quot;,
&quot;labelPointSize&quot;:20,
&quot;borderWidth&quot;:6,
&quot;borderColor&quot;:&quot;#000000&quot;,
&quot;explodeDistanceFactor&quot;:0.0,
&quot;exploded&quot;:false,
&quot;from&quot;:0,
&quot;to&quot;:10}]

And this is the function to add the pies and it's custom properties. Custom properties are added automatically, you don't have to think about it.

function addPies(pieArr) {
for (var i = 0; i&lt; pieArr.length; i++) {
console.log(pieArr[i][&quot;label&quot;],pieArr[i][&quot;value&quot;]);
pieOuter.append(pieArr[i][&quot;label&quot;],pieArr[i][&quot;value&quot;]);
pieOuter.find(pieArr[i][&quot;label&quot;]).labelPosition = PieSlice.LabelInsideHorizontal;
pieOuter.find(pieArr[i][&quot;label&quot;]).labelVisible= true;
pieOuter.find(pieArr[i][&quot;label&quot;]).labelColor=pieArr[i][&quot;labelColor&quot;]
pieOuter.find(pieArr[i][&quot;label&quot;]).labelFont.family=pieArr[i][&quot;labelFont&quot;]
pieOuter.find(pieArr[i][&quot;label&quot;]).labelFont.pointSize=pieArr[i][&quot;labelPointSize&quot;]
pieOuter.find(pieArr[i][&quot;label&quot;]).borderWidth=pieArr[i][&quot;borderWidth&quot;]
pieOuter.find(pieArr[i][&quot;label&quot;]).borderColor=pieArr[i][&quot;borderColor&quot;]
pieOuter.find(pieArr[i][&quot;label&quot;]).explodeDistanceFactor=pieArr[i][&quot;explodeDistanceFactor&quot;]
pieOuter.find(pieArr[i][&quot;label&quot;]).exploded=pieArr[i][&quot;exploded&quot;]
pieOuter.find(pieArr[i][&quot;label&quot;]).color=pieArr[i][&quot;originalColor&quot;]
pieOuter.find(pieArr[i][&quot;label&quot;]).originalColor=pieArr[i][&quot;originalColor&quot;]
pieOuter.find(pieArr[i][&quot;label&quot;]).active=pieArr[i][&quot;active&quot;]
pieOuter.find(pieArr[i][&quot;label&quot;]).from=pieArr[i][&quot;from&quot;]
pieOuter.find(pieArr[i][&quot;label&quot;]).to=pieArr[i][&quot;to&quot;]
pieOuter.find(pieArr[i][&quot;label&quot;]).to=pieArr[i][&quot;to&quot;]
}
}

And then call it with Component.onCompleted or any other event you want to use:

 Component.onCompleted: {
addPies(pieArray);}

huangapple
  • 本文由 发表于 2020年1月6日 22:24:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/59613774.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定