Tutorial 2 - Es wird interessant¶
In Tutorial 1 haben wir ein lauffähiges Rumpfprojekt erstellt, aber eigenen Code haben wir nicht geschrieben. Schauen wir uns an, was für uns generiert wurde.
Was generiert wurde¶
In dem Verzeichnis src/helloworld sollten 3 Dateien zu sehen sein:
__init__.py, __main__.py und app.py.
__init__.py markiert das helloworld-Verzeichnis als importierbares
Python-Modul. Es ist eine leere Datei; allein die Tatsache, dass sie existiert,
sagt dem Python-Interpreter, dass das helloworld-Verzeichnis ein Modul
definiert.
__main__.py markiert das helloworld Modul als eine besondere Art von Modul -
ein ausführbares Modul. Wenn Sie versuchen, das Modul helloworld mit python
-m helloworld auszuführen, ist die Datei __main__.py der Ort, an dem Python
mit der Ausführung beginnen wird. Der Inhalt von __main__.py ist relativ
einfach:
from helloworld.app import main
if __name__ == "__main__":
main().main_loop()
Diese Datei hat zwei Funktionen:
- Sie importiert die Methode
mainaus der Anwendunghelloworld. - Anschließend startet es die Hauptschleife der Anwendung. Die Hauptschleife ist die Methode, mit der eine GUI-Anwendung auf Benutzereingaben (wie Mausklicks und Tastatureingaben) reagiert.
Die interessantere Datei ist app.py - diese enthält die Logik, die unser
Anwendungsfenster erstellt:
import toga
from toga.style.pack import COLUMN, ROW
class HelloWorld(toga.App):
def startup(self):
main_box = toga.Box()
self.main_window = toga.MainWindow(title=self.formal_name)
self.main_window.content = main_box
self.main_window.show()
def main():
return HelloWorld()
Gehen wir diese Zeile für Zeile durch:
import toga
from toga.style.pack import COLUMN, ROW
Als erstes importieren wir das toga-Widget-Toolkit, sowie einige stilbezogene
Utility-Klassen und Konstanten. Unser Code verwendet diese noch nicht - aber wir
werden sie in Kürze nutzen.
Definieren wir eine Klasse:
class HelloWorld(toga.App):
Jede Toga-Anwendung hat eine einzige toga.App-Instanz, die laufende Entität,
die Anwendung, darstellt. Die Anwendung kann mehrere Fenster verwalten, aber für
einfache Anwendungen gibt es ein einziges Hauptfenster.
Als nächstes definieren wir eine Startup() Methode:
def startup(self):
main_box = toga.Box()
Das erste, was die Startup-Methode macht, ist die Definition eines Hauptfeldes. Das Layout-Schema von Toga verhält sich ähnlich wie HTML. Sie bauen eine Anwendung auf, indem Sie eine Sammlung von Boxen konstruieren, von denen jede andere Boxen oder Widgets enthält. Sie wenden dann Stile auf diese Boxen an, um zu definieren, wie sie den verfügbaren Platz im Fenster nutzen werden.
In dieser Anwendung definieren wir ein einzelnes Feld, in das wir jedoch nichts einfügen.
Als Nächstes definieren wir ein Fenster, in das wir dieses leere Feld einfügen können:
self.main_window = toga.MainWindow(title=self.formal_name)
Dies erzeugt eine Instanz eines toga.MainWindow, das einen Titel hat, der dem
Namen der Anwendung entspricht. Ein Hauptfenster ist eine besondere Art von
Fenster in Toga - es ist ein Fenster, das eng an den Lebenszyklus der Anwendung
gebunden ist. Wenn das Hauptfenster geschlossen wird, wird die Anwendung
beendet. Das Hauptfenster ist auch das Fenster, in dem sich das Menü der
Anwendung befindet (wenn Sie auf einer Plattform wie Windows arbeiten, wo die
Menüleisten Teil des Fensters sind)
Wo ist mein Fenster?
Wenn Sie einen Fehler in Ihrem Code gemacht haben, wird das Hauptfenster der App möglicherweise nicht angezeigt. In diesem Fall können Sie Strg+C in dem Terminal eingeben, in dem Sie die App gestartet haben. Dadurch wird die App beendet. Anschließend können Sie den Fehler beheben und die App neu starten.
Dann fügen wir unsere leere Box als Inhalt des Hauptfensters hinzu und weisen die Anwendung an, unser Fenster anzuzeigen:
self.main_window.content = main_box
self.main_window.show()
Als letztes definieren wir eine main() Methode. Diese erzeugt die Instanz
unserer Anwendung:
def main():
return HelloWorld()
Diese main() Methode ist diejenige, die von __main__.py importiert und
aufgerufen wird. Sie erzeugt eine Instanz unserer HelloWorld-Anwendung und
gibt diese zurück.
Das ist die einfachste mögliche Toga-Anwendung. Lassen Sie uns einige unserer eigenen Inhalte in die Anwendung einfügen und die Anwendung etwas Interessantes tun lassen.
Hinzufügen von eigenen Inhalten¶
Lassen Sie uns etwas Interessanteres mit unserer HelloWorld App machen.
Hinweis
Entfernen Sie nicht die Importe am Anfang der Datei oder main() am Ende. Sie
müssen nur die Klasse HelloWorld aktualisieren.
Ändern Sie Ihre HelloWorld Klasse in src/helloworld/app.py so, dass sie wie
folgt aussieht:
class HelloWorld(toga.App):
def startup(self):
main_box = toga.Box(direction=COLUMN)
name_label = toga.Label(
"Your name: ",
margin=(0, 5),
)
self.name_input = toga.TextInput(flex=1)
name_box = toga.Box(direction=ROW, margin=5)
name_box.add(name_label)
name_box.add(self.name_input)
button = toga.Button(
"Say Hello!",
on_press=self.say_hello,
margin=5,
)
main_box.add(name_box)
main_box.add(button)
self.main_window = toga.MainWindow(title=self.formal_name)
self.main_window.content = main_box
self.main_window.show()
def say_hello(self, widget):
print(f"Hello, {self.name_input.value}")
Schauen wir uns im Detail an, was sich geändert hat.
Wir erstellen immer noch ein Hauptfeld, aber wir wenden jetzt einen Stil an:
main_box = toga.Box(direction=COLUMN)
Das in Toga eingebaute Layoutsystem heißt "Pack". Es verhält sich sehr ähnlich
wie CSS. Sie definieren Objekte in einer Hierarchie - in HTML sind die Objekte
<div>, <span> und andere DOM-Elemente; in Toga sind es Widgets und Boxen.
Sie können dann den einzelnen Elementen Stile zuweisen. In diesem Fall geben wir
an, dass es sich um einen COLUMN-Kasten handelt - das heißt, es handelt sich
um einen Kasten, der die gesamte verfügbare Breite beansprucht und sich in der
Höhe vergrößert, wenn Inhalt hinzugefügt wird, aber er versucht, so kurz wie
möglich zu sein.
Hinweis
Für fortgeschrittenere Anwendungen unterstützt Toga auch ein separates Style-Objekt, das wie folgt verwendet wird:
from toga.style import Pack
main_box = toga.Box(style=Pack(direction=COLUMN))
Als nächstes definieren wir ein paar Widgets:
name_label = toga.Label(
"Your name: ",
margin=(0, 5),
)
self.name_input = toga.TextInput(flex=1)
Hier definieren wir ein Label und einen TextInput. Beiden Widgets sind Stile zugeordnet; das Label hat links und rechts ein Padding von 5px und oben und unten kein Padding. Der TextInput ist als flexibel gekennzeichnet, d. h. er nimmt den gesamten verfügbaren Platz in seiner Layoutachse ein.
Der TextInput wird als Instanzvariable der Klasse zugewiesen. Dies ermöglicht uns einen einfachen Zugriff auf die Instanz des Widgets - etwas, das wir gleich verwenden werden.
Als nächstes definieren wir eine Box, die diese beiden Widgets enthält:
name_box = toga.Box(direction=ROW, margin=5)
name_box.add(name_label)
name_box.add(self.name_input)
Die name_box ist eine Box genau wie die Hauptbox, aber dieses Mal ist es eine
ROW-Box. Das bedeutet, daß der Inhalt horizontal eingefügt wird, und daß
versucht wird, die Breite so schmal wie möglich zu machen. Die Box hat auch
etwas Padding - 5px auf allen Seiten.
Jetzt definieren wir eine Schaltfläche:
button = toga.Button(
"Say Hello!",
on_press=self.say_hello,
margin=5,
)
Die Schaltfläche hat außerdem einen Rand von 5 px an allen Seiten. Wir definieren auch einen Handler - eine Methode, die aufgerufen wird, wenn die Schaltfläche gedrückt wird.
Dann fügen wir das Namensfeld und die Schaltfläche zum Hauptfeld hinzu:
main_box.add(name_box)
main_box.add(button)
Damit ist unser Layout fertiggestellt; der Rest der Startup-Methode ist wie zuvor - Definition eines MainWindow und Zuweisung des Hauptfeldes als Inhalt des Fensters:
self.main_window = toga.MainWindow(title=self.formal_name)
self.main_window.content = main_box
self.main_window.show()
Als Letztes müssen wir den Handler für die Schaltfläche definieren. Ein Handler kann eine beliebige Methode, ein Generator oder eine asynchrone Co-Routine sein; er akzeptiert das Widget, das Ereignis erzeugt hat, als Argument und wird immer dann aufgerufen, wenn die Schaltfläche gedrückt wird:
def say_hello(self, widget):
print(f"Hello, {self.name_input.value}")
Der Hauptteil der Methode ist eine einfache Druckanweisung - sie fragt jedoch den aktuellen Wert der Namenseingabe ab und verwendet diesen Inhalt als den Text, der gedruckt wird.
Nachdem wir nun diese Änderungen vorgenommen haben, können wir sehen, wie sie aussehen, indem wir die Anwendung erneut starten. Wie zuvor werden wir den Entwicklermodus verwenden:
(beeware-venv) $ briefcase dev
[helloworld] Starting in dev mode...
===========================================================================
(beeware-venv) $ briefcase dev
[helloworld] Starting in dev mode...
===========================================================================
(beeware-venv) C:\...>briefcase dev
[helloworld] Starting in dev mode...
===========================================================================
Sie werden feststellen, dass dieses Mal keine Abhängigkeiten installiert
werden. Briefcase kann erkennen, dass die Anwendung schon einmal ausgeführt
wurde, und um Zeit zu sparen, wird nur die Anwendung ausgeführt. Wenn Sie neue
Abhängigkeiten zu Ihrer Anwendung hinzufügen, können Sie sicherstellen, dass
diese installiert werden, indem Sie die Option -r beim Aufruf von briefcase
dev mitgeben.
Dies sollte ein GUI-Fenster öffnen:



Wenn Sie einen Namen in das Textfeld eingeben und die Schaltfläche GUI drücken, sollte die Ausgabe in der Konsole erscheinen, in der Sie die Anwendung gestartet haben.
Bevor Sie fortfahren, schließen Sie die App. Wie in Tutorial 1 können Sie dies
tun, indem Sie auf die Schaltfläche „Schließen” im Anwendungsfenster klicken, im
Menü der Anwendung „Beenden/Exit” auswählen oder Strg+C in dem Terminal
eingeben, in dem Sie briefcase dev ausgeführt haben.
Nächste Schritte¶
Wir haben jetzt eine Anwendung, die etwas Interessanteres macht. Aber sie läuft nur auf unserem eigenen Computer. Lassen Sie uns diese Anwendung für die Verteilung verpacken. In Tutorial 3 werden wir unsere Anwendung als eigenständiges Installationsprogramm verpacken, das wir an einen Freund oder Kunden schicken oder in einen App Store hochladen können.