問題描述
我想在 Qml 中顯示一個矩形,并且我想從我的 python 代碼中更改矩形的屬性(寬度、長度).其實python代碼中有一個socket連接,通過它從另一臺電腦接收width和length的值.簡單地說:另一個用戶應該能夠實時調整這個矩形.我知道如何在我的 python 文件中建立套接字連接并使用 PyQt5,我可以從 python 顯示 qml 文件.
I want to show a rectangle in Qml and I want to change the rectangle's properties(width, length) from my python code. In fact, there is a socket connection in the python code, through which the values of width and length are received from another computer. To put it simple: another user should be able to adjust this rectangle in real-time. I know how to make a socket connection in my python file and using PyQt5, I can show the qml file from python.
但是,我無法通過我的 python 代碼訪問矩形的參數.我該怎么做?
However, I am in trouble to access the rectangle's parameters through my python code. How can I do that?
這是我的 qml 文件的簡化示例:
This is a simplified sample of my qml file:
import QtQuick 2.11
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
ApplicationWindow {
visible: true
width: Screen.width/2
height: Screen.height/2
Rectangle {
id: rectangle
x: 187
y: 92
width: 200
height: 200
color: "blue"
}
}
這是我在 .py 文件中寫的內容:
And here is what I have written in my .py file:
from PyQt5.QtQml import QQmlApplicationEngine, QQmlProperty
from PyQt5.QtQuick import QQuickWindow, QQuickView
from PyQt5.QtCore import QObject, QUrl
from PyQt5.QtWidgets import QApplication
import sys
def run():
myApp = QApplication(sys.argv)
myEngine = QQmlApplicationEngine()
myEngine.load('mainViewofHoomanApp.qml')
if not myEngine.rootObjects():
return -1
return myApp.exec_()
if __name__ == "__main__":
sys.exit(run())
推薦答案
在python/C++中有幾種方法可以修改QML元素的屬性,各有優缺點.
There are several methods to modify a property of a QML element from python/C++, and each has its advantages and disadvantages.
- 通過另一個對象通過findChildren獲取QML對象.
- 分別使用
setProperty()
或property()
或使用 QQmlProperty 修改或訪問屬性.
- Obtain the QML object through findChildren through another object.
- Modify or access the property with
setProperty()
orproperty()
, respectively or with QQmlProperty.
ma??in.qml(qml 用于下一個 2 .py)
main.qml (the qml is for the next 2 .py)
import QtQuick 2.11
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
ApplicationWindow {
visible: true
width: Screen.width/2
height: Screen.height/2
Rectangle {
id: rectangle
x: 187
y: 92
width: 200
height: 200
color: "blue"
objectName: "foo_object"
}
}
1.1 setProperty(), property().
import os
import sys
from PyQt5 import QtCore, QtGui, QtQml
from functools import partial
def testing(r):
import random
w = r.property("width")
h = r.property("height")
print("width: {}, height: {}".format(w, h))
r.setProperty("width", random.randint(100, 400))
r.setProperty("height", random.randint(100, 400))
def run():
myApp = QtGui.QGuiApplication(sys.argv)
myEngine = QtQml.QQmlApplicationEngine()
directory = os.path.dirname(os.path.abspath(__file__))
myEngine.load(QtCore.QUrl.fromLocalFile(os.path.join(directory, 'main.qml')))
if not myEngine.rootObjects():
return -1
r = myEngine.rootObjects()[0].findChild(QtCore.QObject, "foo_object")
timer = QtCore.QTimer(interval=500)
timer.timeout.connect(partial(testing, r))
timer.start()
return myApp.exec_()
if __name__ == "__main__":
sys.exit(run())
1.2 QQml 屬性.
import os
import sys
from PyQt5 import QtCore, QtGui, QtQml
from functools import partial
def testing(r):
import random
w_prop = QtQml.QQmlProperty(r, "width")
h_prop = QtQml.QQmlProperty(r, "height")
print("width: {}, height: {}".format(w_prop.read(), w_prop.read()))
w_prop.write(random.randint(100, 400))
h_prop.write(random.randint(100, 400))
def run():
myApp = QtGui.QGuiApplication(sys.argv)
myEngine = QtQml.QQmlApplicationEngine()
directory = os.path.dirname(os.path.abspath(__file__))
myEngine.load(QtCore.QUrl.fromLocalFile(os.path.join(directory, 'main.qml')))
if not myEngine.rootObjects():
return -1
r = myEngine.rootObjects()[0].findChild(QtCore.QObject, "foo_object")
timer = QtCore.QTimer(interval=500)
timer.timeout.connect(partial(testing, r))
timer.start()
return myApp.exec_()
if __name__ == "__main__":
sys.exit(run())
這種方法的一個缺點是如果對象與根對象的關系很復雜(有時其他 QML 中的對象很難用 findChild 訪問)訪問對象的部分變得復雜,有時甚至不可能,所以這種方法將失敗.另一個問題是,當使用 objectName 作為主要搜索數據時,Python 層對 QML 層的依賴性很高,因為如果在 QML 中修改了 objectName,則必須修改 python 中的邏輯.另一個缺點是,如果不管理 QML 對象的生命周期,它可能會在 Python 不知情的情況下被消除,因此它會訪問不正確的引用,從而導致應用程序意外終止.
A disadvantage of this method is that if the relation of the object with the rootobject is complex(Sometimes objects that are in other QMLs are hard to access with findChild) the part of accessing the object becomes complicated and sometimes impossible so this method will fail. Another problem is that when using the objectName as the main search data there is a high dependency of the Python layer to the QML layer since if the objectName is modified in QML the logic in python would have to be modified. Another disadvantage is that by not managing the life cycle of the QML object it could be eliminated without Python knowing so it would access an incorrect reference causing the application to terminate unexpectedly.
- 創建一個具有相同類型屬性的 QObject.
- 使用 setContextProperty 導出到 QML.
- 在 QObject 的屬性和 item 的屬性之間進行綁定.
ma??in.qml
import QtQuick 2.11
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
ApplicationWindow {
visible: true
width: Screen.width/2
height: Screen.height/2
Rectangle {
id: rectangle
x: 187
y: 92
width: r_manager.width
height: r_manager.height
color: "blue"
}
}
ma??in.py
import os
import sys
from PyQt5 import QtCore, QtGui, QtQml
from functools import partial
class RectangleManager(QtCore.QObject):
widthChanged = QtCore.pyqtSignal(float)
heightChanged = QtCore.pyqtSignal(float)
def __init__(self, parent=None):
super(RectangleManager, self).__init__(parent)
self._width = 100
self._height = 100
@QtCore.pyqtProperty(float, notify=widthChanged)
def width(self):
return self._width
@width.setter
def width(self, w):
if self._width != w:
self._width = w
self.widthChanged.emit(w)
@QtCore.pyqtProperty(float, notify=heightChanged)
def height(self):
return self._height
@height.setter
def height(self, h):
if self._height != h:
self._height = h
self.heightChanged.emit(h)
def testing(r):
import random
print("width: {}, height: {}".format(r.width, r.height))
r.width = random.randint(100, 400)
r.height = random.randint(100, 400)
def run():
myApp = QtGui.QGuiApplication(sys.argv)
myEngine = QtQml.QQmlApplicationEngine()
manager = RectangleManager()
myEngine.rootContext().setContextProperty("r_manager", manager)
directory = os.path.dirname(os.path.abspath(__file__))
myEngine.load(QtCore.QUrl.fromLocalFile(os.path.join(directory, 'main.qml')))
if not myEngine.rootObjects():
return -1
timer = QtCore.QTimer(interval=500)
timer.timeout.connect(partial(testing, manager))
timer.start()
return myApp.exec_()
if __name__ == "__main__":
sys.exit(run())
缺點是您必須編寫更多代碼.優點是對象可以被所有 QML 訪問,因為它使用 setContextProperty,另一個優點是如果 QML 對象被刪除,它不會產生問題,因為只消除了綁定.最后,通過不使用 objectName,依賴項不存在.
The disadvantage is that you have to write some more code. The advantage is that the object is accessible by all the QML since it uses setContextProperty, another advantage is that if the QML object is deleted it does not generate problems since only the binding is eliminated. And finally, by not using the objectName, the dependency does not exist.
所以我更喜歡使用第二種方法,更多信息請閱讀 從 C++ 與 QML 交互.
So I prefer to use the second method, for more information read Interacting with QML from C++.
這篇關于如何從我的 Python 文件中更新 Qml 對象的屬性?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!