Lassen Sie uns nun tiefer in die Arbeit mit Qt unter Verwendung von PyQt5 eintauchen und die modernen Funktionen von Qt verwenden. Mit solchen Funktionen meine ich QtQuick und QML. Mit PyQt5 können Sie Qt-Klassen verwenden, die QML-Code verarbeiten können, und daher können Sie eine Schnittstelle in QML schreiben sowie die Ebene Signale an QML übergeben und Objektslots aufrufen, geerbt von QObject aus der QML-Schicht.
Um sich mit solchen Funktionen von PyQt5 vertraut zu machen, schreiben wir ein Programm, das die folgenden Aufgaben implementiert:
- Die Programmschnittstelle muss in QML geschrieben sein
- Eine von QObject geerbte und in Python geschriebene Klasse muss implementiert werden, mit der wir von QML interagieren werden
- Eine Anwendung, die diese Klasse verwendet, muss Ganzzahlen addieren und subtrahieren
Das Erscheinungsbild der Anwendung sollte wie folgt aussehen:
Projektstruktur
Das Projekt wird nur zwei Dateien haben:
- main .py - Anwendungsdatei in Python, es wird auch eine Klasse für Berechnungen geben
- main.qml - QML-Schnittstellendatei
Signale in PyQt5
Die Signalsignatur im allgemeinen Fall sieht folgendermaßen aus:
PyQt5.QtCore.pyqtSignal( Typen [, Name [, Revision=0 [, Argumente=[] ]]])
Erstellen Sie ein oder mehrere überladene unabhängige Signale als Attribut der Klasse.
| Optionen: | *
types
– Typen, die die C++-Signatur des Signals definieren. Jeder Typ kann ein Objekt vom Typ Python oder ein String sein, der der Name eines C++-Typs ist. Alternativ kann jedes eine Folge von Typargumenten sein. In diesem Fall definiert jede Sequenz die Überlastsignatur eines anderen Signals. Die erste Überladung wird standardmäßig verwendet.
name
– Signalname. Wenn weggelassen, wird der Name des Klassenattributs verwendet. Es kann nur als Schlüsselwortargument angegeben werden.
Revision
ist die Revision des Signals, das nach QML exportiert wird. Es kann nur als Schlüsselwortargument angegeben werden.
*
Argumente
- Eine Folge von Signalargumentnamen, die nach QML exportiert werden. Es kann nur als Schlüsselwortargument angegeben werden.
|
Slots in PyQt5
PyQt5 verwendet einen speziellen Decorator, um Slots zu deklarieren.
PyQt5.QtCore.pyqtSlot( Typen [, Name [, Ergebnis [, Revision=0 ]]])
| Optionen: | *
types
– Typen, die eine C++-Slot-Signatur definieren. Jeder Typ kann ein Objekt vom Typ Python oder ein String sein, der der Name eines C++-Typs ist.
name
– Der Name des Slots, der in C++ angezeigt werden soll. Wenn weggelassen, wird der Name der zu ergänzenden Python-Methode verwendet. Es kann nur als Schlüsselwortargument angegeben werden.
Revision
ist die Revision des Steckplatzes, der nach QML exportiert wird. Es kann nur als Schlüsselwortargument angegeben werden.
*
Ergebnis
– Der Typ des Ergebnisses und kann ein Objekt vom Typ Python oder eine Zeichenfolge sein, die einen C++-Typ angibt. Es kann nur als Schlüsselwortargument angegeben werden.
|
main .py
from PyQt5.QtGui import QGuiApplication from PyQt5.QtQml import QQmlApplicationEngine from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot class Calculator(QObject): def __init__(self): QObject.__init__(self) # cигнал передающий сумму # обязательно даём название аргументу через arguments=['sum'] # иначе нельзя будет его забрать в QML sumResult = pyqtSignal(int, arguments=['sum']) subResult = pyqtSignal(int, arguments=['sub']) # слот для суммирования двух чисел @pyqtSlot(int, int) def sum(self, arg1, arg2): # складываем два аргумента и испускаем сигнал self.sumResult.emit(arg1 + arg2) # слот для вычитания двух чисел @pyqtSlot(int, int) def sub(self, arg1, arg2): # вычитаем аргументы и испускаем сигнал self.subResult.emit(arg1 - arg2) if __name__ == "__main__": import sys # создаём экземпляр приложения app = QGuiApplication(sys.argv) # создаём QML движок engine = QQmlApplicationEngine() # создаём объект калькулятора calculator = Calculator() # и регистрируем его в контексте QML engine.rootContext().setContextProperty("calculator", calculator) # загружаем файл qml в движок engine.load("main.qml") engine.quit.connect(app.quit) sys.exit(app.exec_())
main.qml
import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.2 ApplicationWindow { visible: true width: 640 height: 240 title: qsTr("PyQt5 love QML") color: "whitesmoke" GridLayout { anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right anchors.margins: 9 columns: 4 rows: 4 rowSpacing: 10 columnSpacing: 10 Text { text: qsTr("First number") } // Поле ввода первого числа TextField { id: firstNumber } Text { text: qsTr("Second number") } // Поле ввода второго числа TextField { id: secondNumber } Button { height: 40 Layout.fillWidth: true text: qsTr("Sum numbers") Layout.columnSpan: 2 onClicked: { // Вызываем слот калькулятора, чтобы сложить числа calculator.sum(firstNumber.text, secondNumber.text) } } Text { text: qsTr("Result") } // Здесь увидим результат сложения Text { id: sumResult } Button { height: 40 Layout.fillWidth: true text: qsTr("Subtraction numbers") Layout.columnSpan: 2 onClicked: { // Вызываем слот калькулятора, чтобы вычесть числа calculator.sub(firstNumber.text, secondNumber.text) } } Text { text: qsTr("Result") } // Здесь увидим результат вычитания Text { id: subResult } } // Здесь забираем результат сложения или вычитания чисел Connections { target: calculator // Обработчик сигнала сложения onSumResult: { // sum было задано через arguments=['sum'] sumResult.text = sum } // Обработчик сигнала вычитания onSubResult: { // sub было задано через arguments=['sub'] subResult.text = sub } } }
Спасибо. Все очень доходчиво!
Подскажите как закидывать компоненты из python на форму qml? Я хочу график matplotlib закинуть на page qml
Вот сейчас Вы меня конкретно загрузили этим вопросом. Не работал с этой библиотекой, но я глянул, что есть сети по этому поводу и кое-какие мысли уже есть у меня. Но надо ещё самому разобраться, что можно придумать. Сегодня/завтра после работы гляну, и потом отвечу Вам, какие мысли у меня будут.
Но вообще, всё скорее всего должно сводиться к множественному наследованию от QQuickPaitedItem и класса библиотек matplotlib.
Спасибо, Вам, за отклик. У меня существует готовое решение с использованием pyqt5 + matplotlib. Где я просто на форму кидаю виджет, а виджет есть график matplotlib. Теперь хотелось бы интерфейс приятный сделать. Вчера потратил весь день на Qt Charts и осознал, что он очень не очень. Ощущение, что студенты на коленках делали.
почему не выполняется код после вызова слота?
Я вот сейчас банальность скажу, но у меня всё работало. Так что даже и не знаю, надо на код смотреть, что ещё у вас добавлено или отсутствует из библиотек.
P/S/ Извините, вы сейчас всё подряд пробуете или работаете именно с Python?
Изменив математические действия столкнулся с проблемой - не выводит десятичные дроби
Проблема должна быть в описании слота, там целочисленные аргументы
В вашем случае, я думаю, так должно быть
заменил, та же картина, причем в python я вывожу переменную 11.5, а в qml вижу 11
Вот это ещё замените
на вот это
Круто! Немного начинает проясняться что к чему. Спасибо.
А можно ли из QML сделать привязку свойства к свойству пайтоновского объекта? Ну, т.е. , например, у нашего объекта Calculator обхвялем свойства sumresult и subresult c с декоратором @pyqtProperty, а в QMLе делаем типа такого: