Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add an example using QML
  • Loading branch information
hosaka committed Nov 17, 2023
commit a4bef242a42b957660b4a5ca58e0fbfb06d94e7d
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)