Zum Inhalt

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 main aus der Anwendung helloworld.
  • 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:

Hello World Tutorial 2 Fenster, unter macOS

Hello World Tutorial 2 Fenster, unter Linux

Hello World Tutorial 2 Fenster, unter
Windows

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.