GTKMM / HelloWorld



  • Hallo,

    ich habe nur wenig Programmiererfahrung in C++, deshalb wäre es hilfreich für mich wenn ich von jemanden mit mehr Erfahrung etwas Rückendeckung bekomme.
    Mir geht es in erster Linie darum ob ich das Prinzip verstanden habe.

    Fangen wir doch mal mit dem Hello World von der gtkmm Seite an:

    HelloWorld.h

    #ifndef GTKMM_EXAMPLE_HELLOWORLD_H
    #define GTKMM_EXAMPLE_HELLOWORLD_H
    
    #include <gtkmm/button.h>
    #include <gtkmm/window.h>
    
    class HelloWorld : public Gtk::Window
    {
    
    public:
      HelloWorld();
      virtual ~HelloWorld();
    
    protected:
      //Signal handlers:
      void on_button_clicked();
    
      //Member widgets:
      Gtk::Button m_button;
    };
    
    #endif // GTKMM_EXAMPLE_HELLOWORLD_H
    

    Am besten ich schreib einfach mal auf wie ich die Sache verstanden habe, und wenn ich mich irgendwo irre, dann korrigiert mich bitte.

    So... Zeile 01,02 und 22 stellen sicher das die Header-Datei auch nach mehrmaligem #include nur einmal eingebunden wird.

    Die beiden includes sind klar.

    Bei Zeile 07 wird die Klasse für das Fenster deklariert, und zwar mittels Vererbung von Gtk::Window.

    Zeile 11 und 12 sind Konstruktor und Destruktor. (warum ist der Destruktor virtual und der Konstruktor nicht?)

    In Zeile 19 wird die Variable m_button mit dem Typ Button deklariert. Button ist member von Gtk. Spricht man hier auch von Vererbung?
    _______________________________________________

    HelloWorld.cpp

    #include "helloworld.h"
    #include <iostream>
    
    HelloWorld::HelloWorld()
    : m_button("Hello World")   // creates a new button with label "Hello World".
    {
      // Sets the border width of the window.
      set_border_width(10);
    
      // When the button receives the "clicked" signal, it will call the
      // on_button_clicked() method defined below.
      m_button.signal_clicked().connect(sigc::mem_fun(*this,
                  &HelloWorld::on_button_clicked));
    
      // This packs the button into the Window (a container).
      add(m_button);
    
      // The final step is to display this newly created widget...
      m_button.show();
    }
    
    HelloWorld::~HelloWorld()
    {
    }
    
    void HelloWorld::on_button_clicked()
    {
      std::cout << "Hello World" << std::endl;
    }
    

    Zeile 4 der Konstruktor wird definiert, und in Zeile 5 wird gleich die Membervariable m_button gesetzt.
    Zeile 7 bis 19 gehören zum Konstruktor, hier wird der Button initialisiert und parameter für das Fenster gesetzt. Den Signal-Handler hat man auch hier untergebracht. Wo kommt sigc::mem_fun her?
    &HelloWorld::on_button_clicked das & bedeutet doch das es um eine Referenz geht, richtig? Heißt das das die gesamte Klasse als Parameter übergeben wird?
    In Zeile 22 Steckt der Dekonstruktor.
    Und ab 26 die Definition von on_button_clicked()
    ________________________________________________

    Main.cpp

    #include "helloworld.h"
    #include <gtkmm/main.h>
    
    int main (int argc, char *argv[])
    {
     Gtk::Main kit(argc, argv);
    
      HelloWorld helloworld;
      //Shows the window and returns when it is closed.
      Gtk::Main::run(helloworld);
    
      return 0;
    }
    

    Was mir noch unklar ist, wird argc und argv in Zeile 4 deklariert? Muss da denn nichts zugewiesen werden?
    Wofür braucht man kit?
    In Zeile 8 wird das eigentliche Fensterobject erstellt und in Zeile 10 angezeigt (wird da die eigentliche GUI gestartet?)

    Danke schon mal im Voraus für eure Hilfe.



  • Vorab: Zu den gtk-spezifischen Sachen kann ich nichts sagen, aber zu den Fragen, die C++ allgemein betreffen.

    0BackBONE0 schrieb:

    So... Zeile 01,02 und 22 stellen sicher das die Header-Datei auch nach mehrmaligem #include nur einmal eingebunden wird.

    Korrekt - das nennt sich "Include Guard"

    Bei Zeile 07 wird die Klasse für das Fenster deklariert, und zwar mittels Vererbung von Gtk::Window.

    auch richtig.

    Zeile 11 und 12 sind Konstruktor und Destruktor. (warum ist der Destruktor virtual und der Konstruktor nicht?)

    Konstruktoren können nicht virtuell sein, bei Destruktoren macht es Sinn (vor allem wenn das System dein Fenster später über einen Gtk::Window-Zeiger wieder freigeben will)

    In Zeile 19 wird die Variable m_button mit dem Typ Button deklariert. Button ist member von Gtk. Spricht man hier auch von Vererbung?

    Nein, das ist keine Vererbung, das nennt sich Membervariable.
    (btw, das "Gtk::" nennt sich Namensraum)

    Zeile 4 der Konstruktor wird definiert, und in Zeile 5 wird gleich die Membervariable m_button gesetzt.
    Zeile 7 bis 19 gehören zum Konstruktor, hier wird der Button initialisiert und parameter für das Fenster gesetzt. Den Signal-Handler hat man auch hier untergebracht. Wo kommt sigc::mem_fun her?

    sigc::mem_fun dürfte in einem der eingebundenen Header definiert sein und liefert dir vermutlich einen Wrapper um die Memberfunktion (ich kenne nur std::mem_fun).

    &HelloWorld::on_button_clicked das & bedeutet doch das es um eine Referenz geht, richtig? Heißt das das die gesamte Klasse als Parameter übergeben wird?

    Nein, in erster Linie ist & der Adress-Operator - du holst dir also die Adresse der Memberfunktion.

    In Zeile 22 Steckt der Dekonstruktor.
    Und ab 26 die Definition von on_button_clicked()

    Stimmt.

    Was mir noch unklar ist, wird argc und argv in Zeile 4 deklariert? Muss da denn nichts zugewiesen werden?

    Das sind Parameter der Funktion, die werden von außen gefüllt. Bei main() kommen dort die Parameter rein, mit denen dein Programm aufgerufen wurde.

    Wofür braucht man kit?

    Da muß ich raten, vermutlich stellt es die Laufumgebung dar, in der dein Fenster leben kann.



  • CStoll schrieb:

    Vorab: Zu den gtk-spezifischen Sachen kann ich nichts sagen, aber zu den Fragen, die C++ allgemein betreffen.

    Gut, dann versuch ich dich zu ergänzen.

    Den Signal-Handler hat man auch hier untergebracht. Wo kommt sigc::mem_fun her?

    sigc::mem_fun dürfte in einem der eingebundenen Header definiert sein und liefert dir vermutlich einen Wrapper um die Memberfunktion (ich kenne nur std::mem_fun).

    Es macht das gleiche wie std::mem_fun. Nur etwas besser und allgemeiner. Es hat übrigens eine Überladung, dass du die Dereferenzierung von this sein lassen kannst.

    Wofür braucht man kit?

    Da muß ich raten, vermutlich stellt es die Laufumgebung dar, in der dein Fenster leben kann.

    Genau.
    GTK+ hat einige Kommandozeilenoptionen, die für alle Programme gelten. Darum musst du ihm irgendwo argc und argv geben.

    Du hast ja im offiziellen Hello World gelesen, dass jedes Programm ein Objekt von Gtk::Main haben muss. Es ist sogar ein Singleton.

    Das heisst: Beim run wird auf dein kit zurückgegriffen. Es braucht das kit. Wenn du etwas weiter im Programmieren bist (ich weiss nicht, ob du schon reif für GUIs bist), wirst du das verstehen.


Anmelden zum Antworten