python - QMetaProperty::read: 无法处理未注册的数据类型 'QAbstractListModel*'
问题描述
我正在尝试创建一个自定义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*
我的代码的精简版本如下:
主文件
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_())
饼图模型.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()
饼图.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)
饼图视图.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>
解决方案
您有以下错误:
您有以下错误:
在 C++ 中,不必使用 Q_DECLARE_METATYPE 或 qRegisterMetaType 以便可以从 QML 访问模型,只需在 Q_Property 中将其注册为 QObject,在 PySide2 中也是如此。
在具有 2 列和 n 行的模型中,它不能是 QAbstractListModel,因此您必须将其更改为 QAbstractTableModel。
model 必须是一个常量属性,因为在您的逻辑中您不会更改它,而只会重置其信息。
虽然我不知道这是否是一个错误,但如果你想在 ChartView 中查看模型的数据,你必须将它与 PieSeries 关联。
考虑到上述情况,解决方案是:
饼图模型.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()
饼图.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)
饼图视图.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
}
}
}
推荐阅读
- mysql - 如何从两个不同的表中获取两个不同列的总和并将它们分组
- java - Spring data couchbase 4.0.0 - 使用列表保存对象始终为空
- json - Azure Cosmos DB - 如何从类似于从 SQL 表中检索列名的文档中检索 json 属性
- pandas - 将字典中的所有值弹出到单独的变量中
- powershell - 我怎样才能让我的 curl 命令在 gitlab-ci 中工作?
- flutter - 如何在 Flutter 中的图标之间绘制垂直连接线?
- r - 无法使用 R 执行迭代
- python - how to sort the bar chart values in python?
- javascript - 从 cellrenderer 调用父函数,例如在 vuejs ag-grid-vue 上发出
- python - 如何在windows上安装pip