QMetaProperty::read: 无法处理未注册的数据类型 'QAbstractListModel*'
QMetaProperty::read: Unable to handle unregistered datatype '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*
我的代码的精简版本如下:
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>
您有以下错误:
您有以下错误:
在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
}
}
}
我正在尝试创建自定义 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>
您有以下错误:
您有以下错误:
在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
}
}
}