ICON: Tutorial Teil 23: Vidgets und GUI-Entwicklungen mit VIB

  • Hallo Himbeerfreunde, Linux-Freaks und Forumsbewohner,


    im heutigen Tutorial geht es um Vidgets - virtual input gadgets - auf Deutsch: graphische Bedienelemente. Diese werden am einfachsten mit dem Virtual Interface Builder VIB erzeugt, auf dem Bildschirm platziert, an die entsprechenden Bedürfnisse angepasst (konfiguriert). VIB erzeugt den Quellcode einer lauffähigen GUI-Anwendung (GUI = Graphical User Interface, graphische Benutzerschnittstelle). Wer es genauer wissen möchte: Quellcode in der Programmiersprache Icon - aber das war wohl klar, oder?


    In diesem Tutorial
    - werden die graphischen Bedienelemente der Programmiersprache Icon vorgestellt,
    - wird das Konzept der Callback-Routinen vorgestellt,
    - wird gezeigt, wie das Programm VIB bedient wird,
    - wird die Entwicklung einer Beispielanwendung gezeigt, die wohl jeder Raspbianer nützlich finden wird: ein Programm zum Ansteuern der GPIO-Pins per Mausklick,
    - werden Records und Prozeduren aus [font="Courier"]/home/pi/icon9_51/ipl/gprocs[/font] vorgestellt, mit denen Vidgets auch ohne VIB erstellt und angezeigt werden können sowie Ereignisse auf eigene Vidgets ausgedehnt werden können
    - wird gezeigt, wie man aus dem Icon-Code, der von VIB erzeugt wird, eine vollfunktionsfähige GUI-Anwendung erstellt,


    In der Übungsaufgabe bekommt Ihr die Aufgabe gestellt, ein GPIO-Kontrollzentrum zu kreieren - zunächst als VIB-Anwendung:
    - alle GPIOs auf einen Blick
    - 2 GPIOs werden mit einer DUO-LED belegt; über eine Checkbox wird ausgewählt, ob die LED automatisch blinken soll, über einen Rollbalken wird die Blinkfrequenz eingestellt
    - mehrere LEDs können angesteuert werden
    - eine 7Segment-Anzeige wird angesteuert


    Im nächsten Tutorial zeige ich dann, wie aus der VIB-Ausgabe ein richtiges GPIO-Kontrollzentrum wird - und auf der 7Segment-Anzeige nicht nur alle Ziffern sondern auch noch darstellbare Buchstaben angezeigt werden.


    Sollte ich jemanden jetzt neugierig gemacht haben, dieses Tutorial als Gelegenheit zu nutzen, doch noch mit elektronischen Basteleien zu beginnen, habe ich auf den letzten 5 Seiten eine Übersicht über eine Grundausstattung (Elektronik-Bauteile, Werkzeuge) zusammengestellt, die im nächsten Tutorial-Teil zum Einsatz kommen.


    In der nächsten Ausgabe zeige ich dann, wie man daraus
    - Jumperkabel und
    - mit Hilfe der Schneid-Klemmtechnik GPIO-Kabel
    herstellt


    Beides ist für das GPIO-Kontrollzenrum erforderlich.


    Ach ja, dieses Tutorial hat aufgrund
    - der Länge der Lösung der Übungsaufgabe (Alles mit Primzahlen machen),
    - begleitender Screenschots,
    - der ausführlichen Bedienungsanleitung der Anwendung VIB,
    - weiterer zahlreicher Screenshots zur Erläuterung der Dialogfenster von VIB,
    - der Vorstellung der mit den Vidgets zusammenhängenden Records,
    - der Vorstellung der mit den Vidgets zusammenhängenden Prozeduren
    Ü B E R L Ä N G E.


    Die Zusammenstellung der Bauteile und Werkzeuge inkl. Photos habe ich auf Extraseiten ausgelagert (da letztere jeglichen Rahmen sprengen).


    Egal, es war viel Arbeit - endlich mal sinnvolle Abende im Hotel, da ich einen Großteil dieses Tutorials auf meinem neuesten Raspberry Pi mit 7"-Touchscreen in den Abendstunden geschrieben habe.


    Ich wünsche Euch viel Spaß und viele neue Erkenntnisse.


    Gutes Gelingen!


    Andreas


    P.S.: Während der etwas längeren Berabeitung dieses Tutorial-Teil kam mir eine Idee, Buttons relativ zur Bildschrimgröße zu positionieren und auch deren Größe anzupassen. Herausgekommen ist folgendes kleines Programm.


    Das Programm würde ich heute allerdings anders schreiben, denn man kann der Prozedur ProcessEvent() eine Routine mit auf den Weg geben, die sich mit Resizing-Ereignissen (also Größen-Änderung von Fenstern) beschäftigt. Diese Resizing-Funktion ruft automatisch die Resizing-Funktionen jedes Vidget-Typs auf. Aus meiner Resizing-Funktion wird dann ein Einzeiler... bzw. wird ganz überflüssig. Daran kann man erkennen, dass die Icon-Entwickler nicht nur den Ansatz verfolgten, eine Programmiersprache zu erdichten - sondern ursprünglich die Absicht im Vordergrund stand, ein komplettes Betriebssystem zu erschaffen. Denn dafür gab es mal Fördermittel für den Fachbereich Computer Science der Uni in Arizona in Höhe von 640.000 $. Lang, lang ist's her...


    Hier das Programm in der ursprünglichen Version:




    [hr]
    Inhaltsangabe:
    1. Icon Tutorial Teil 1: Die Programmiersprache Icon - Installation
    2. Icon Tutorial Teil 2: Geany: Installation und Konfiguration der IDE Geany
    3. Icon Tutorial Teil 3: Eingabe und Ausgabe
    4. Icon Tutorial Teil 4: Programmierer-definierte Kontrollstrukturen: Schleifen und Fallentscheidungen


    5. Icon tutorial Teil 5: Numerische Datentypen, ihre Funktionen und Operatoren
    6. Icon Tutorial Teil 6: Zeichen-basierte Datentypen, ihre Funktionen ud Operatoren
    7. Icon Tutorial Teil 7: Struktureirte Datentypen, ihre Funktionen und Operatoren
    8. Icon Tutorial Teil 8: Die Datentypen procedure und co-expression
    9. Icon Tutorial Teil 9: Konzept des Zeichenketten-Scannens


    10. Icon Tutorial Teil 10: Ausdrucks-Auswertung, Typ-Umwandlung, Strukturen sortieren
    11. Icon Tutorial Teil 11: Sammelsurium: Zeichenkettennamen, Zeichenketten-Anrufungen, Speichermanagement, Sonstige Fähigkeiten
    12. Icon Tutorial Teil 12: Bibliotheken
    13. Icon Tutorial Teil 13: Präprozessor
    14. Icon Tutorial Teil 14: Fehler & Fehlerbeseitigung


    15. Icon Tutorial Teil 15: Graphik I: Window-Datentyp
    16. Icon Tutorial Teil 16: Graphik II: Zeichnen und Füllen
    17. Icon Tutorial Teil 17: Graphik III: Turtle-Graphik
    18. Icon Tutorial Teil 18: Graphik IV: Text
    19. Icon Tutorial Teil 19: Graphik V: Farben und Images
    20. Icon Tutorial Teil 20: Graphik VI: Fenster


    21. Icon Tutorial Teil 21: Interaktion
    22. Icon Tutorial Teil 22: Standard-Dialoge
    23. Icon Tutorial Teil 23: Vidgets und GUI-Entwicklungen mit VIB (Visual Interface Builder)


    24. Icon Tutorial Teil 24: Hardware-Basteleien & Vervollständigung der GPIO-Kommandozentrale


    25. Icon-Tutorial Teil 25: Ereignisbehandlung bei Anwendungen mit mehr als einem Fenster - Individuelle Dialoge mit VIB erstellen und programmieren
    26. Icon Tutorial Teil 26: Individuelle Dialoge mit VIB


    27. Icon Tutorial Teil 27: Ein Spiel entwickeln: Mastermind - Entwurf und GUI-Layout
    28. Icon Tutorial Teil 28: Ein Spiel entwickeln: Mastermind - Ereignisbehandlung & Auswertelogik
    29. Icon Tutorial Teil 29: Ein Spiel entwickeln: Mastermind - Der Code


    Ideen, Block I (in Entwicklung)
    30. Icon Tutorial Teil 30: Von Icon auf C-Bibliotheken zugreifen
    31. Icon Tutorial Teil 31: Von Icon auf C++-Bibliotheken zugreifen
    32. Von Icon auf Prolog-Bibliotheken zugreifen


    Ideen, Block II (Software läuft!)
    33: Text-to-Speech - Speech-to-Text: Sprachsynthese und Sprachanalyse auf dem Raspberry Pi in Icon


    Ideen, Block III (Software für #35 läuft!)
    34: GUI mit dem Event-Multiplexor (EVMUX) gestalten inkl. Programmierung der Ereignisbehandlung
    35: Symbolizer für Bi-Level-Graphiken
    36: Symbolizer für Grafiken mit Icon-Farbpaletten


    Ideen, Block IV (Software läuft!)
    37: Pseudo-Code-Compiler


    Ideen, Block V (Software läuft)
    38: Dia-Shower


    Ideen, Block VI (Ideensammlung)
    39: Hardware-Basteleien: A/D-Wandler und dessen Programmierung in Icon

    Files

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    • Icon-Tutorials (IDE: Geany) - GPIO-Library - µController-Programmierung in Icon! - ser. Devices - kein Support per PM / Konversation

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

    Edited 3 times, last by Andreas ().

  • Hallo zusammen,


    kann man eigentlich auch Graphiken auf den Bildschirm bringen und diese anklicken, um damit Ereignisse auszulösen, die von der Hauptereignisbehandlungsroutine (EventHandler) erkannt werden?


    Klar, das geht, wenn man sich an folgender Vorgehensweise orientiert.


    1. Mit VIB die Schaltfläche in das Bearbeitungsfenster der zu erstellenden GUI ziehen und durch Ziehen der 4 Ecken ungefähr auf die gewünschte Größe bringen.
    2. Feineinstellungen können vorgenommen werden, indem man die Region mit der rechten Maustaste anklickt und in dem sich öffnenden Dialogfenster die passenden Werte für x und y (als linke obere Ecke der Region) und Breite und Höhe pixelgenau festlegt. Als ID legt man den Namen fest, unter dem das Vidget innerhalb der Vidget-Liste (voreingestellt als local vidgets ==> besser also global VIDGETS umdefinieren!) angesprochen werden soll (in meinem Beispiel will ich ein Mikrophon-Piktogramm darstellen, also ist etwas wie r_micro naheliegend). Im Texteingabefeld callback wird der Name der Callback-Funktion festgelegt - also die Funktion, in der man definiert, was nach dem Anklicken eines Bedienelemeentes passieren soll. In meinem Fall (und faul wie ich bin, habe ich mir zur Gewohnheit gemacht, für ID und callback die Eingabe zu wiederholen) also auch r_micro.
    3. Tipp am Rande: Es hat sich als vorteilhaft erwiesen, Breite und Höhe um jeweils 4 größer zu wählen als die später aufzunehmende Graphikschaltfläche.
    4. Dann bearbeitet man mit z.B. ImageMagick eine Graphik durch Zurechtschneiden, Verkleinern etc. und speichert diese letztlich im Format "GIF".
    5. Diese Graphik kann mit dem Icon-Befehl ReadImage(s, x, y) in die Anwendung gebracht werden. ReadImage("/Pfad/zum/Bild.gif", x, u) mit Angabe des Pfades zum Bild sowie der linken oberen Ecke der Graphik.
    6. Wenn man die Graphik in die Region einpassen will, nutzt man die Angaben der Vidget-Struktur, z.B. ReadImage("/home/andreas/Bilder/Mikrophon32.gif", vidgets["r_micro.ux"].ux, vidgets["r_micro"].uy) oder innerhalb eines Callbacks als ReadImage("/home/andreas/Bilder/Mikrophon32.gif", vidget.ux, vidget.uy)
    7. Noch ein Tip: Der Unterschied der ebenfalls möglichen Vidget-Felder .ax und .ay besteht darin, dass die Paarung .ax und .ay sich auf die linke obere Ecke der Region bezieht und die Paarung .ux und .uy die tatsächlich nutzbare Zeichenfläche beschreiben. Deswegen auch der Tipp unter 3.
    8. Das Ergebnis sieht dann z.B. so aus:
    9. Der von VIB automatisch erzeugte Eintrag im UserInterface ist dann z.B. ["r_micro:Rect:raised::12,274,36,36:",r_micro],
    10. Als Callback kann man dann z.B. folgendes programmieren:

    Code
    procedure r_micro(vidget, e, x, y)
        if Event() === &lrelease then
        {
            Status_Micro := ixor(Status_Micro, 1)
            ReadImage("/home/andreas/Bilder/Mikrophon32.gif", vidget.ux, vidget.uy)
            if Status_Micro = 0 then cross(vidget)
        }
    end

    Code-Deutung:

    Nach Anklicken des Piktogramms Mikrophon soll beim Ereignis Linke Maustaste losgelassen etwas passieren, nämlich Toggeln des Status (Exklusiv-ODER-Verknüpfung von Status_Micro mit 1). Die GIF-Datei wird auf Position gebracht. Sollte der Status 0 sein, wird eine Funktion cross() mit dem Parameter dieses Vidgets aufgerufen. In der Funktion cross() wird ein rotes Kreuz über das Piktogramm gezeichnet.


    Beste Grüße


    Andreas




    Images

    • pasted-from-clipboard.png
    • pasted-from-clipboard.png

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    • Icon-Tutorials (IDE: Geany) - GPIO-Library - µController-Programmierung in Icon! - ser. Devices - kein Support per PM / Konversation

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

    Edited 4 times, last by Andreas ().

  • Hallo zusammen,


    viele meiner Funktionen haben folgenden generellen Aufbau:



    Bei der Benennung der Argumente orientiere ich mich an den üblichen Icon-Vorgaben des Datentyps bzw. der Bedeutung als Argument der entsprechenden Funktion.


    Die obige Struktur hat den Vorteil, dass man sich auf das Wesentliche - das Programmieren der eigentlichen Aktion konzentrieren kann. Der Rest macht man irgendwie wie im Tran.

    Der Nachteil ist, dass man sich einen Wolf sucht, wenn man mal vergessen hat, z.B. den Zeichensatz für einen Alarm oder eine Systemmeldung zurückzusetzen, und alle weiteren Ausgaben auf der GUI in einem unpassenden Stil erfolgen.


    Viel einfacher geht das bei Verwendung eines Stapelspeichers STACK, der mit STACK := [] oder STACK := list() angelegt wurde.


    Eine Funktion sieht dann z.B. so aus:



    Code-Deutung:


    Die Zeile put(STACK, Font(), Fg(), Bg()) speichert den vorher verwendeten Zeichensatz, Vordergrundfarbe, Hintergrundfarbe auf diesen Stapelspeicher STACK.

    STACK[1] enthält den Zeichensatz, STACK[2] die Vordergrundfarbe etc.



    Die Zeile every i := 1 to *STACK do i(Bg, Fg, Font)(pull(STACK)) macht das dann wieder rückgängig. Hier habe ich die Funktion pull() verwendet, die - beginnend mit dem zuletzt mit put()auf den Stapel gebrachten Eintrag - den Stapel abräumt. Prinzipiell wären auch die anderen beiden Funktionen get() und pop() möglich gewesen. Dann müsste aber entweder in put() oder in der unteren Funktion die Reihenfolge der Parameter geändert werden, um FIFO, FILO / LIFO abzubilden.


    Was hier mit i(...)(...) sehr strange aussieht, nennt sich in Icon "mutual evaluation". Damit ist eine extreme Einsparung an Code verbunden.

    Ganz allgemein besteht dies aus einem Ausdruck, der ein ganzzahliges Ergebnis liefert, einer in Klammern stehenden Auflistung an "Angeboten", was getan werden könnte (also weitere Ausdrücke, Funktionen oder Variablen) und - sollten leere Funktionsnamen aufgeführt sein - dann folgen deren Parameter in einem weiteren Klammerpaar.

    Bei dem i ist das leicht durchschaubar, da dies die Schleifenvariable ist, die von 1 bis 3 laufen soll.

    Dieses ganzzahlige Ergebnis bildet nicht den Funktionsnamen sondern den Index, unter dem aus der nachfolgenden Aufzählung etwas ausgewählt werden soll. Bei i = 1 wird also der erste Eintrag herangezogen, also Bg. Hier könnte ein weiterer auswertbarer Ausdruck stehen, eine Variable, eine Funktion oder was auch immer. Hier steht also Bg, was eigentlich die Funktion für das Setzen der Hintergrundfarbe für kommende Zeichenfunktionen darstellt. Wenn es sich um eine Funktion handeln sollte, müssen danach auch Parameter in Klammern () angeboten werden. OK - Klammern folgen da auch noch. Die Argumente werden vom zuvor beschriebenen Stack geholt. Es handelt sich also tatsächlich um die Abwicklung der Icon-Funktion Bg().


    Bei i = 2 wird Analoges für den zweiten Index, also Fg und bei i = 3 für den drittem Index Font() durchgeführt.


    Am Ende ist der Stapel leer, egal, ob man ausreichend Funktionen bereitgestellt hat oder nicht und die betrachteten Einstellungen sind wieder so wie vorher.


    Ich mag "mutual evaluation", weil hier in einer Zeile stehen kann, was sonst in einer Fallunterscheidung geklärt werden muss.



    Beste Grüße


    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    • Icon-Tutorials (IDE: Geany) - GPIO-Library - µController-Programmierung in Icon! - ser. Devices - kein Support per PM / Konversation

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

    Edited 3 times, last by Andreas ().