从 QML 到 Python Signal/Slots 的数据
Posted
技术标签:
【中文标题】从 QML 到 Python Signal/Slots 的数据【英文标题】:Data from QML to Python Signal/Slots 【发布时间】:2021-06-28 19:33:33 【问题描述】:我试图弄清楚如何将数据从 TextField 输入传递到我的 Python 类。我认为解决这个问题的方法是使用信号和插槽;但是,我在传递数据的 widget.qml(主 qml 类)中使用了自定义 QML 组件。我需要这样做,以便对通过 TextField 传入的数据执行更复杂的操作。
我对如何将数据从 BasicContainer.qml 传递到我的 python 类感到困惑,并且不确定我的 widget.qml 类中的逻辑是否支持它,因为它使用嵌套模型。我附上了一个例子,希望能用控制流来说明问题。我可以在我添加的 widget.qml 中使用基本信号,但如果我在 BasicContainer.qml 中做同样的事情,我会得到一个 PySide6.QtQuick.QQuickItem object has no attribute 'displayValueChanged'
main.py
import os
import sys
from pathlib import Path
sys.path.append(os.path.join(os.path.dirname(sys.path[0]), ".."))
from PySide6.QtCore import Property, QUrl, QObject, Qt, QCoreApplication, Slot
from PySide6.QtGui import QGuiApplication, QStandardItem, QStandardItemModel
from PySide6.QtQuick import QQuickView
CURRENT_DIRECTORY = Path(__file__).resolve().parent
# QstandardItem roles
SetText = Qt.UserRole + 1
class ControlledSignalWidget(QObject):
def __init__(self):
super().__init__()
self._model = QStandardItemModel()
# self._model.setItemRoleNames(Qt.DisplayRole: b"display")
self._setpoints_models = []
@Property(QObject, constant=True)
def model(self):
return self._model
@Slot(int, result=QObject)
def setpoints(self, idx):
return self._setpoints_models[idx]
# create custom number of widgets
def create_widgets(self, widgets, allComponents):
counter = 1
# Iterates for the amount of widgets created
for general, widget in widgets.items():
# for key in widget:
print("Adding new widget")
item = QStandardItem(widget["Header"])
self._model.appendRow(item)
self.create_setpoints(allComponents["item" + str(counter) + "Components"])
print("Added widget")
counter += 1
def create_setpoints(self, component):
setpoints_model = QStandardItemModel()
setpoints_model.setItemRoleNames(SetText: b"textField")
for subWidget in component:
print(subWidget)
item = QStandardItem()
item.setData(subWidget["title"], SetText)
setpoints_model.appendRow(item)
self._setpoints_models.append(setpoints_model)
def display(s):
print(s)
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
view = QQuickView()
view.setResizeMode(QQuickView.SizeViewToRootObject)
url = QUrl.fromLocalFile(os.fspath(CURRENT_DIRECTORY / "widget.qml"))
def handle_status_changed(status):
if status == QQuickView.Error:
QCoreApplication.exit(-1)
widgets =
"widget1": "Header": "Header Text",
"widget2": "Header": "Header 2 Text",
item1Components = ["title": "widget1random", "title": "widget1random2"]
item2Components = ["title": "widget2random", "title": "widget2random2"]
allComponents =
"item1Components": item1Components,
"item2Components": item2Components,
mainWidget = ControlledSignalWidget()
mainWidget.create_widgets(widgets, allComponents)
view.rootContext().setContextProperty("mainWidget", mainWidget)
view.statusChanged.connect(
handle_status_changed, Qt.ConnectionType.QueuedConnection
)
view.setSource(url)
# SIGNAL CONNECTION MADE
root = view.rootObject()
root.displayValueChanged.connect(display)
view.show()
sys.exit(app.exec())
widget.qml
import QtQuick 2.0
import QtQuick.Controls.Material 2.15
import QtQuick.Layouts 1.12
Item
id: root
width: 1000
height: 800
signal displayValueChanged(string setpoint)
GridLayout
columns: 3
Repeater
id: repeater1
model: mainWidget.model
ColumnLayout
property int outerIndex: index
Repeater
id: repeater2
model: mainWidget.setpoints(outerIndex)
ColumnLayout
BasicContainer
Component.onCompleted:
//Signal called
displayValueChanged(inputText)
BasicContainer.qml
import QtQuick 2.12
import QtQuick.Controls.Material 2.15
import QtQuick.Layouts 1.12
Item
id: basicContainerItem
width: 300
height: 60
visible: true
signal valueChanged()
property alias inputText: containerInput.text
Rectangle
id: rectangle
width: parent.width
ColumnLayout
TextField
id: containerInput
visible: true
placeholderText: qsTr("Text Field")
text: "Default value"
// Contended line
//textColor: "#FF3333"
onAccepted:
console.log(text)
basicContainerItem.valueChanged()
重要编辑:
我修改了代码以使用信号将值从 BasicContainer 类一直传递到 Python,因此当您进行文本输入并按 Enter 时,将记录您输入的新文本。这应该解决了一切;但是,当我尝试进行任何样式更改时,例如 BasicContainer.qml 中的文本颜色更改行:textColor: "#FF3333"
将导致我的应用程序中断,从而导致此错误:
root.displayValueChanged.connect(display) AttributeError 'Nonetype' object has no attribute 'displayValueChanged'
【问题讨论】:
【参考方案1】:没关系,似乎正确的解决方案就是我上面所说的;期待我使用 textColor 的部分,因为显然这应该是 color
而不是 textColor
。但是,信号按预期工作,这是我对这个问题的目标。
【讨论】:
以上是关于从 QML 到 Python Signal/Slots 的数据的主要内容,如果未能解决你的问题,请参考以下文章