我正在尝试创建一个自定义QQuickItem
来在我的应用程序中显示图表。我的C ++版本正在运行,但是我的Python版本无法运行。我相信这是因为Q_DECLARE_METATYPE
和qRegisterMetaType
没有移植到PySide2。尽管下面的示例并未对此进行演示,但我的要求是饼图不是静态的(可以随时更改),并且可以在运行时添加或删除任意数量的饼图。
我的程序将运行,但不显示任何内容,并且在控制台上出现以下错误:
QMetaProperty::read: Unable to handle unregistered datatype 'QAbstractListModel*' for property 'CustomPieChart::model'
QMetaProperty::read: Unable to handle unregistered datatype 'QAbstractListModel*' for property 'CustomPieChart::model'
qrc:/PieChartView.qml:24:17: Unable to assign [undefined] to QAbstractItemModel*
我的代码的精简版如下:
main.py
import sys
from PySide2.QtCore import QUrl
from PySide2.QtGui import QIcon
from PySide2.QtQml import QQmlApplicationEngine, qmlRegisterType
from PySide2.QtWidgets import QApplication
from pie_chart import CustomPieChart
import qml_rc # noqa: F401
# Need to register PieChartModel in here somehow...
def register_quick_items() -> None:
qmlRegisterType(CustomPieChart, "Custom.CustomPieChart", 1, 0, "CustomPieChart")
if __name__ == "__main__":
app = QApplication(sys.argv)
register_quick_items()
engine = QQmlApplicationEngine()
engine.load(QUrl("qrc:/main.qml"))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
pie_chart_model.py
from typing import Dict
from PySide2.QtCore import QAbstractListModel, QModelIndex, Qt
class PieChartModel(QAbstractListModel):
_model_data: Dict[str, int]
def __init__(self, parent=None):
super().__init__(parent)
self._model_data = []
def rowCount(self, parent=QModelIndex()) -> int:
return 2
def columnCount(self, parent=QModelIndex()):
return len(self._model_data)
def data(self, index, role=Qt.DisplayRole):
# Not relevant
def headerData(self, section, orientation, role):
# Not relevant
def reset_with_data(self, model_data):
self.beginResetModel()
self._model_data = model_data
self.endResetModel()
pie_chart.py
from PySide2.QtCore import Property, Signal, Slot
from PySide2.QtQuick import QQuickItem
from pie_chart_model import PieChartModel
class CustomPieChart(QQuickItem):
model_changed = Signal(PieChartModel)
_model: PieChartModel
def __init__(self, parent=None):
super().__init__(parent)
self._model = PieChartModel(parent)
@Property(PieChartModel, notify=model_changed)
def model(self):
return self._model
@Slot(result=None)
def reset_model(self):
pie_slices = {
"A": 1,
"B": 2,
"C": 3
}
self._model.reset_with_data(pie_slices)
self.model_changed.emit(self._model)
PieChartView.qml
import QtCharts 2.13
import QtQuick 2.13
import Custom.CustomPieChart 1.0
CustomPieChart {
id: customPieChart
Component.onCompleted: {
customPieChart.reset_model()
}
ChartView {
id: chartView
anchors.fill: parent
antialiasing: true
animationOptions: ChartView.AllAnimations
legend.visible: false
PieSeries {
id: pieSeries
HPieModelMapper {
model: customPieChart.model
labelsRow: 0
valuesRow: 1
}
}
}
}
main.qml
import QtQuick 2.13
import QtQuick.Controls 2.13
ApplicationWindow {
visible: true
width: 500
height: 500
PieChartView {
anchors.fill: parent
}
}
qml.qrc
<RCC>
<qresource prefix="/">
<file>main.qml</file>
<file>PieChartView.qml</file>
</qresource>
</RCC>
答案 0 :(得分:1)
您遇到以下错误:
您遇到以下错误:
在C ++中,不必使用Q_DECLARE_METATYPE或qRegisterMetaType以便可以从QML访问模型,只需在Q_Property中将其注册为QObject,在PySide2中也是如此。
在具有2列和n行的模型中,它不能是QAbstractListModel,因此必须将其更改为QAbstractTableModel。
模型必须是常量属性,因为在您的逻辑中您不能更改它,而只能重置其信息。
虽然我不知道这是否是错误,但是如果您想在ChartView中查看模型的数据,则必须将其与PieSeries关联。
考虑到上述情况,解决方案是:
pie_chart_model.py
from typing import Dict
from PySide2.QtCore import QAbstractTableModel, QModelIndex, Qt
class PieChartModel(QAbstractTableModel):
_model_data: Dict[str, int]
def __init__(self, parent=None):
super().__init__(parent)
self._model_data = []
def rowCount(self, parent=QModelIndex()) -> int:
return 2
def columnCount(self, parent=QModelIndex()) -> int:
return len(self._model_data)
def data(self, index, role=Qt.DisplayRole):
if not index.isValid():
return
r = index.row()
c = index.column()
if 0 <= r < self.rowCount() and 0 <= c < self.columnCount():
if role == Qt.DisplayRole:
if r == 0:
return list(self._model_data.keys())[c]
elif r == 1:
return list(self._model_data.values())[c]
def reset_with_data(self, model_data):
self.beginResetModel()
self._model_data = model_data
self.endResetModel()
pie_chart.py
from PySide2.QtCore import Property, Slot, QObject
from PySide2.QtQuick import QQuickItem
from pie_chart_model import PieChartModel
class CustomPieChart(QQuickItem):
_model: PieChartModel
def __init__(self, parent=None):
super().__init__(parent)
self._model = PieChartModel(self)
@Property(QObject, constant=True)
def model(self):
return self._model
@Slot(result=None)
def reset_model(self):
pie_slices = {
"A": 1,
"B": 2,
"C": 3
}
self._model.reset_with_data(pie_slices)
PieChartView.qml
import QtCharts 2.13
import QtQuick 2.13
import Custom.CustomPieChart 1.0
CustomPieChart {
id: customPieChart
Component.onCompleted: {
customPieChart.reset_model()
}
ChartView {
id: chartView
anchors.fill: parent
antialiasing: true
animationOptions: ChartView.AllAnimations
legend.visible: false
PieSeries{
id: pie_series
}
HPieModelMapper {
series: pie_series
model: customPieChart.model
labelsRow: 0
valuesRow: 1
}
}
}