英文:
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__ == '__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 = 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 ""
sl.setColor(QtGui.QColor(color))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
view = QtQuick.QQuickView()
manager = Manager()
outer_ring_model = custom_model.OuterRingModel()
view.rootContext().setContextProperty("manager", manager)
view.rootContext().setContextProperty("outerRingModel", outer_ring_model)
filename = os.path.join(os.path.dirname(os.path.realpath(__file__)), "main.qml")
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(["Black", 50, "black"])
self._data.append(["White", 50, "white"])
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: "MyTitle"
legend.visible: false
PieSeries {
id: serie0
name: "Outer Ring"
size: 0.75
holeSize: 0.7
onSliceAdded: {
manager.updateSlice(mapper0.series, slice, mapper0.model, mapper0.firstRow)
}
}
}
}
<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 ""
sl.setColor(QtGui.QColor(color))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
view = QtQuick.QQuickView()
manager = Manager()
outer_ring_model = custom_model.OuterRingModel()
view.rootContext().setContextProperty("manager", manager)
view.rootContext().setContextProperty("outerRingModel", outer_ring_model)
filename = os.path.join(os.path.dirname(os.path.realpath(__file__)), "main.qml")
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(["Black", 50, "black"])
self._data.append(["White", 50, "white"])
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: "MyTitle"
legend.visible: false
PieSeries {
id: serie0
name: "Outer Ring"
size: 0.75
holeSize: 0.7
onSliceAdded: {
manager.updateSlice(mapper0.series, slice, mapper0.model, mapper0.firstRow)
}
}
}
}
答案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: [
{
"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}]
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< 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"]
}
}
And then call it with Component.onCompleted or any other event you want to use:
Component.onCompleted: {
addPies(pieArray);}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论