Skip to content

Commit

Permalink
Add an example using QML
Browse files Browse the repository at this point in the history
  • Loading branch information
hosaka committed Nov 17, 2023
1 parent 429df50 commit a4bef24
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ if __name__ == "__main__":

event_loop = QEventLoop(app)
asyncio.set_event_loop(event_loop)

app_close_event = asyncio.Event()
app.aboutToQuit.connect(app_close_event.set)


main_window = MainWindow()
main_window.show()

Expand Down
41 changes: 41 additions & 0 deletions examples/qml_httpx/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import sys
import asyncio
from pathlib import Path

from qasync import QEventLoop, QApplication
from PySide6.QtCore import QUrl
from PySide6.QtQml import QQmlApplicationEngine, qmlRegisterType

from service import ExampleService

QML_PATH = Path(__file__).parent.absolute().joinpath("qml")


if __name__ == "__main__":
app = QApplication(sys.argv)

engine = QQmlApplicationEngine()
engine.addImportPath(QML_PATH)

app.aboutToQuit.connect(engine.deleteLater)
engine.quit.connect(app.quit)

# register our service, making it usable directly in QML
qmlRegisterType(ExampleService, "qasync", 1, 0, ExampleService.__name__)

# alternatively, instantiate the service and inject it into the QML engine
# service = ExampleService()
# engine.rootContext().setContextProperty("service", service)

event_loop = QEventLoop(app)
asyncio.set_event_loop(event_loop)

app_close_event = asyncio.Event()
app.aboutToQuit.connect(app_close_event.set)
engine.quit.connect(app_close_event.set)

qml_entry = QUrl.fromLocalFile(str(QML_PATH.joinpath("Main.qml")))
engine.load(qml_entry)

with event_loop:
event_loop.run_until_complete(app_close_event.wait())
18 changes: 18 additions & 0 deletions examples/qml_httpx/qml/Main.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQuick.Window 2.15

ApplicationWindow {
id: root
title: "qasync"
visible: true
width: 420
height: 240

Loader {
id: mainLoader
anchors.fill: parent
source: "Page.qml"
}
}
65 changes: 65 additions & 0 deletions examples/qml_httpx/qml/Page.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Controls.Material 2.15
import QtQuick.Layouts 1.15

Item {
ExampleService {
id: service

// handle value changes inside the service object
onValueChanged: {
// use value
}
}

Connections {
target: service

// handle value changes with an external Connection
function onValueChanged(value) {
// use value
}
}

ColumnLayout {
anchors {
fill: parent
margins: 10
}

RowLayout {
Layout.fillWidth: true

Button {
id: button
Layout.preferredWidth: 100
enabled: !service.isLoading

text: {
return service.isLoading ? qsTr("Loading...") : qsTr("Fetch")
}
onClicked: function() {
service.fetch(url.text)
}
}

TextField {
id: url
Layout.fillWidth: true
enabled: !service.isLoading
text: qsTr("https://jsonplaceholder.typicode.com/todos/1")
}
}

TextEdit {
id: text
Layout.fillHeight: true
Layout.fillWidth: true

// react to value changes from other widgets
text: service.value
}
}

}
44 changes: 44 additions & 0 deletions examples/qml_httpx/service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import httpx

from qasync import asyncSlot
from PySide6.QtCore import QObject, Signal, Property, Slot


class ExampleService(QObject):
valueChanged = Signal(str, arguments=["value"])
loadingChanged = Signal(bool, arguments=["loading"])

def __init__(self, parent=None):
QObject.__init__(self, parent)

self._value = None
self._loading = False

def _set_value(self, value):
if self._value != value:
self._value = value
self.valueChanged.emit(value)

def _set_loading(self, value):
if self._loading != value:
self._loading = value
self.loadingChanged.emit(value)

@Property(str, notify=valueChanged)
def value(self) -> str:
return self._value

@Property(bool, notify=loadingChanged)
def isLoading(self) -> bool:
return self._loading

@asyncSlot(str)
async def fetch(self, endpoint: str):
if not endpoint:
return

self._set_loading(True)
async with httpx.AsyncClient() as client:
resp = await client.get(endpoint)
self._set_value(resp.text)
self._set_loading(False)

0 comments on commit a4bef24

Please sign in to comment.