lehrkraefte:blc:informatik:ffprg2-2021:l8

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
lehrkraefte:blc:informatik:ffprg2-2021:l8 [2021/12/07 07:02] – created Ivo Blöchligerlehrkraefte:blc:informatik:ffprg2-2021:l8 [2021/12/07 07:30] (current) Ivo Blöchliger
Line 1: Line 1:
 +====== Klassen und Instanzen ======
 +
 +<code c++>
 +// Definition typischer in .h Datei
 +class Beispiel {
 +  private:
 +  int instanz_variable = 42;
 +
 +  public:
 +
 +  static int klassen_variable;   // ACHTUNG: diese Variable **muss** in einer .cpp-Datei noch deklariert werden!  
 +  void hallo_instanz();
 +  static void hallo_klasse();
 +
 +};   // Strichpunkt nach Klassendefinition!
 +
 +// Implementation typischweise in .cpp-Datei
 +
 +void Beispiel::hallo_instanz() { // Zugriff auf Instanz-Variablen und -Methoden. Die Variable 'this' enthält einen Pointer auf die aktuelle Instanz.
 +  Serial.printf("hallo_instanz(): instanz=%d, klasse=%d\n", instanz_variable, klassen_variable);
 +  instanz_variable++;
 +  klassen_variable++;
 +}
 +
 +void Beispiel::hallo_klasse() {  // Kein Zugriff auf Instanz-Variablen (und -Methoden), wie eine ganz normale Funktion.
 +  Serial.printf("hallo_klasse(): klasse=%d\n", klassen_variable);
 +  klassen_variable++;
 +}
 +
 +// Diese Zeile **muss** in einer .cpp-Datei stehen.
 +int Beispiel::klassen_variable  = 23;
 +
 +// Start vom Programm (normalerweise main() in C++, ausser mit Arduino-Framework)
 +void setup() {
 +  Beispiel bsp1; // Neues Beispiel
 +  bsp1.hallo_instanz();      // hallo_instanz(): instanz=42, klasse=23
 +  bsp1.hallo_instanz();      // hallo_instanz(): instanz=43, klasse=24
 +  Beispiel::hallo_klasse();  // hallo_klasse(): klasse=25
 +  
 +  Beispiel* bsp_pointer = new Beispiel();
 +  bsp_pointer->hallo_instanz();  // hallo_instanz(): instanz=42, klasse=26
 +  bsp1.hallo_instanz();          // hallo_instanz(): instanz=43, klasse=27
 +  bsp_pointer->hallo_instanz();  // hallo_instanz(): instanz=43, klasse=28
 +  
 +  delete bsp_pointer;     // Für jedes new genau ein delete!
 +  bsp_pointer = nullptr;  // good practice
 +}
 +</code>
 +
 +
 +====== Callbacks ======
 +Callbacks sind Funktionen, die registriert werden und dann aufgerufen, wenn etwas passiert (z.B. ein Klick). Das ist oft besser als polling (permanent abfragen, ob was geklickt wurde).
 +
 +Das Problem ist, dass damit keine (bzw. nicht ohne weiteres) Instanz-Methoden registriert werden können, weil dazu eine Referenz (oder Pointer) auf die Instanz gebraucht wird. Dazu gibt es verschiedene Lösungsansätze:
 +  * Klassenvariable, die einen Pointer auf eine Instanz enthält (geht natürlich nur, wenn es nur **eine** Instanz geben kann). Ich finde diese Version «unschön»
 +  * Wenn der Callback die Möglichkeit bietet, zusätzliche Daten zu übermitteln, kann ein Pointer (this) auf die Instanz übergeben werden. Ich ziehe diese Version vor.
 +  * Je nachdem ist es möglich eine Closure zu machen und so einen Pointer auf die Instanz zu übergeben (nicht möglich mit unserer lvgl-Version, wäre aber das Eleganteste).
 +
 +===== User-Data in lvgl =====
 +In jedem lvgl-Objekt kann ein Pointer als user-data gespeichert werden. Dieser Pointer hat den Typ (void*), d.h. einfach eine Speicheradresse ohne Information, was dort zu finden ist.
 +
 +Dieser Pointer wird dann mittels Typenumwandlung (cast) zum gewünschten Pointer gemacht:
 +<code c++>
 +// In einer Instanz-Methode im GUI-Objekt ein Pointer auf die aktuelle Instanz speichern:
 +lv_obj_set_user_data(obj, this);
 +
 +// Im der Callback-Funktion die Instanz auslesen und darauf die Instanz-Methode aufrufen:
 +Beispiel* bsp = (Beispiel*) obj->user_data;
 +bsp->instanz_methode();
 +</code>
 +
 +===== Implementation eines Callbacks =====
 +Es gibt zwei Möglichkeiten:
 +  * Klassenmethode (static)
 +  * Anonyme Funktion (mit user_data im gui-Objekt)
 +
 +<code c++>
 +lv_obj_set_event_cb(button, [](lv_obj_t *button, lv_event_t event) {
 +        if (event != LV_EVENT_SHORT_CLICKED) return;
 +        ((Beispiel*)(button->user_data))->hallo_instanz();
 +    }
 +);
 +</code>
 +
 +Je nach Definition des Callbacks könnten in die eckigen Klammern noch Variablen eingetragen werden, auf die die Funktion Zugriff hat (closure). Das geht aber nicht mit lvgl-Callacks.
 +