Как я могу обновить свойство объекта Qml из моего файла Python? - PullRequest
0 голосов
/ 14 февраля 2019

Я хочу показать прямоугольник в Qml, и я хочу изменить свойства прямоугольника (ширина, длина) из моего кода Python.На самом деле, в коде Python есть соединение с сокетом, через которое значения ширины и длины принимаются с другого компьютера.Проще говоря: другой пользователь должен иметь возможность регулировать этот прямоугольник в режиме реального времени.Я знаю, как установить сокет-соединение в моем файле python и, используя PyQt5, я могу показать файл qml из python.

Однако у меня проблемы с доступом к параметрам прямоугольника через мой код python.Как я могу это сделать?

Это упрощенный пример моего файла 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: 200
        height: 200
        color: "blue"
    }
}

И вот что я написал в своем файле .py:

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())

Ответы [ 2 ]

0 голосов
/ 14 февраля 2019

Существует несколько методов для изменения свойства элемента QML из python / C ++, и у каждого есть свои преимущества и недостатки.

1.Получение ссылок из QML

  • Получение объекта QML через findChildren через другой объект.
  • Измените или получите доступ к свойству с помощью setProperty() или property() соответственно или с помощью QQmlProperty.

main.qml (qml для следующих 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 QQmlProperty.

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, поскольку, если objectName изменяется в QML, необходимо изменить логику в python.Другим недостатком является то, что, не управляя жизненным циклом объекта QML, его можно устранить без знания Python, чтобы получить доступ к неверной ссылке, что приведет к неожиданному завершению работы приложения.

2.Отправка ссылок на QML

  • Создание объекта QObject с такими же типами свойств.
  • Экспорт в QML с использованием setContextProperty.
  • Создание привязки между свойствами объектаQObject и свойства элемента.

main.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"
    }
}

main.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 зависимость не существует.


Поэтому я предпочитаю использовать второй метод, для получения дополнительной информации читайте Взаимодействие с QML из C ++ .

0 голосов
/ 14 февраля 2019

Попробуйте что-то вроде ниже (не проверено, но даст вам представление).

создайте objectname для прямоугольника, как показано ниже:

Rectangle {
        id: rectangle
        x: 187
        y: 92
        width: 200
        height: 200
        color: "blue"
        objectName: "myRect"
    }

Взаимодействуйте с QML инайдите своего ребенка, затем установите свойство.

    #INTERACT WITH QML
    engine = QQmlEngine()
    component = QQmlComponent(engine)
    component.loadUrl(QUrl('mainViewofHoomanApp.qml'))
    object = component.create()

    #FIND YOUR RECTANGLE AND SET WIDTH
    child = object.findChild(QObject,"myRect")
    child.setProperty("width", 500)  
...