GTKmm Tutorial Teil 2



  • Grafische Benutzerschnittstellen in C++ mit GTKmm betriebssystemunabhängig gestalten Teil 2

    Nach einer langen Auszeit habe ich mich dazu aufgerafft, endlich am Tutorial weiterzuschreiben. Ich hoffe, ihr könnt mir diese Pause verzeihen. 🙂

    Wie versprochen behandle ich in diesem Teil das GTK+ Boxensystem, Labels, Buttons und Signale (Events). Ich werde ein paar Anwendungsbeispiele zu dem jeweiligen Thema anführen. Zum Schluss werde ich ein Beispiel mit allen Widgets zeigen und die eventuell noch unbekannten Schritte zusätzlich kommentieren.

    1.GTK+ Boxensystem

    1.1 Einführung

    In GTK+ und somit auch in GTKmm werden die Widgets mit so genannten „boxes“ angeordnet. Das sind Container, die die Widgets aufnehmen können. Mit diesem Konzept ordnet man Widgets nur relativ und nicht absolut an - im Gegensatz zu dem, wie man es von den bekannteren GUI-Designern kennt (z.b. Borland C++ Builder, Visual C++, Visual C# usw.)

    Dieses Konzept ermöglicht ein dynamisches Anpassen der Größe der Widgets zur jeweiligen Fenstergröße, ohne das sich der Programmierer darum kümmern müsste.

    Von diesen Containern gibt es verschiedene Arten.
    Es gibt Container, die nur jeweils ein Widget aufnehmen können ( diese wurden von Gtk::Bin abgeleitet ), Container die mehrere Widgets aufnehmen können, aber nur in eine Richtung, sprich Horizontal oder Vertikal. Dies wären z.B. Gtk::Hbox für die horizontale und Gtk::VBox für die vertikale Richtung.
    Und zu guter Letzt gibt es noch eine Tabelle ( Gtk::Table ), in der man n x m Widgets, je nach dem, wie man es braucht, unterbringen kann, eben in einer tabellarischen Anordnung.

    Eine Besonderheit ist aber das Widget Gtk::Fixed. Dies kann Elemente an festen Koordinaten aufnehmen, welche dann aber nicht resizable sind.
    Ich werde auf diese Widgets nicht näher eingehen, da ich der Meinung bin, dass man auf diese auch verzichten kann, und mir das Programmieren mit dem Boxensystem wesentlich einfacher und eleganter erscheint.

    1.2 Widgets und Boxes

    Die Container Gtk::HBox und Gtk::VBox haben neben dem Standard-Konstruktor einen Konstruktor mit folgenden Parametern:

    Gtk::HBox( bool homogenous , int padding );
    Gtk::VBox( bool homogenous , int padding );
    

    homogenous gibt hier an, dass der Platz der Widgets gleichmäßig aufgeteilt wird, wenn man true übergibt. Der Parameter padding gibt an, wie viel Platz in Pixeln zwischen den Bereichen der Widgets sein soll.

    Um Widgets in die Boxes einzufügen, haben diese folgende Methoden:

    void pack_start(Gtk::Widget& child, PackOptions options = PACK_EXPAND_WIDGET, guint padding = 0);
    void pack_end(Gtk::Widget& child, PackOptions options = PACK_EXPAND_WIDGET, guint padding = 0);
    

    Der erste Parameter ist eine Referenz auf das Widget, das wir hinzufügen wollen, z.B. ein Gtk::Button Objekt.

    Der zweite Parameter gibt die PackOption an. Davon hängt es ab, wie sich die Anordnung der Widgets abspielt.

    Es gibt 3 verschiedene Optionen:

    • PACK_SHRINK
    • PACK_EXPAND_WIDGET
    • PACK_EXPAND_PADDING

    Gibt man PACK_SHRINK an, wird nur so viel Platz verwendet, wie das Widget wirklich braucht, und es wird niemals expandiert.

    Bei PACK_EXPAND_WIDGET wird der freie Platz ausgefüllt, indem das Widget einfach vergrößert wird.

    Bei PACK_EXPAND_PADDING wird der freie Platz einfach durch Abstände ausgefüllt; das Widget ist dann so gesehen zentriert in seinem Bereich. Der Bereich ist abhängig von dem Drumherum und das wird alles immer dynamisch angepasst.

    Der dritte Parameter padding gibt an, wie viel Platz das Widget drum herum haben soll. Im Gegensatz zu dem Parameter des Konstruktors ist hier der Platz um das Widget herum gemeint.

    1.3 Widgets und Tables

    Gtk::Table hat folgenden Konstruktor:

    Gtk::Table::Table(guint n_rows = 1, guint n_columns = 1, bool homogeneous = false)
    

    Im Grunde ist dieser eigentlich selbsterklärend. n_rows gibt an, wie viele Zeilen das Table haben soll, und n_columns, wie viele Spalten.
    homogenous gibt an, ob die Zellen homogen, sprich immer gleich groß, sein sollen.
    Generell wäre ich vorsichtig mit der Verwendung von homogenous = true, da es viele Widgets gibt, die sehr viel Platz brauchen und es damit eine negative Auswirkung auf alle Widgets haben kann. Aber natürlich kann dieser Effekt auch erwünscht sein.
    Das Beste ist, dass man sich generell erst mal mit den ganzen Containern auseinander setzt und damit etwas rumspielt, bis man das alles verstanden hat.
    Das ist einfacher, als ellenlange Texte darüber zu lesen. Die eigene Erfahrung ist immer noch die lehrreichste. (Das ist meine Meinung 😉 )

    So und nun möchte ich euch erst mal schocken:

    void Gtk::Table::attach(Gtk::Widget& child,
                            guint left_attach, guint right_attach,
                            guint top_attach, guint bottom_attach,
                            guint xoptions = Gtk::FILL | Gtk::EXPAND,
                            guint yoptions = Gtk::FILL | Gtk::EXPAND,
                            guint xpadding = 0, guint ypadding = 0);
    

    Diese Methode ist natürlich auf den ersten Blick ziemlich abschreckend, aber die Verwendung ist einfacher, als es auf den ersten Blick aussehen mag.

    child ist das Widget, das wir einfügen möchten und das als Referenz auf das Widget-Objekt übergeben wird.
    left_attach gibt an, welche Zelle die Startposition auf der X-Achse ist.
    right_attach gibt an, welche Zelle die Endposition auf der X-Achse ist, wobei die Endposition mindestens 1 größer als die Startposition sein muss.
    top_attach gibt an, welche Zelle die Startposition auf der Y-Achse ist.
    bottom_attach gibt an, welche Zelle die Endposition auf der Y-Achse ist, wobei die Endposition mindestens 1 größer als die Startposition sein muss.

    xoptions gibt an, wie sich das Widget innerhalb seiner Zelle auf der X-Achse verhalten soll. Dies ist den PackOptions bei den Boxes ähnlich.
    yoptions gibt an, wie sich das Widget innerhalb seiner Zelle auf der Y-Achse verhalten soll. Dies ist den PackOptions bei den Boxes ähnlich.

    xpadding gibt an, wie viel Platz das Widget links und rechts von sich haben soll (freier Platz).
    ypadding gibt an, wie viel Platz das Widget oben und unten von sich haben soll (freier Platz).

    Um das Ganze zu verstehen, schauen wir uns einfach mal den Aufbau einer Tabelle an:

    0   1   2
      +---+---+---+
    0 | a | b | c |
      +---+---+---+
    1 | d | e | f |
      +---+---+---+
    2 | g | h | i |
      +---+---+---+
    

    Ich habe die Buchstaben in die Tabelle eingefügt, um besser erklären zu können, wie das Ganze dann beim Aufruf auszusehen hat. Die Zahlen entsprechen dem Zeilen- und Reihenindex.

    Angenommen, wir wollen hier Widget 'a' in Zelle 0/0 einfügen, dann würde der Aufruf folgendermaßen aussehen:

    m_table.attach( a , 0 , 1 , 0 , 1 );
    

    für b sieht das Ganze so aus:

    m_table.attach( b , 1 , 2 , 0 , 1 );
    

    für e sieht das Ganze dann so aus:

    m_table.attach( e , 1 , 2 , 1 , 2 );
    

    für i sieht das Ganze dann so aus:

    m_table.attach( i , 2 , 3 , 2 , 3 );
    

    Nun möchte man aber, dass sich ein Widget über mehrere Zellen erstreckt. Wie das Widget 'd' in diesem Beispiel:

    0   1   2
      +---+---+---+
    0 | a | b | c |
      +---+---+---+
    1 |     d     |
      +---+---+---+
    2 | e | f | g |
      +---+---+---+
    

    Dann würde das Einfügen für das Widget 'd' folgendermaßen aussehen:

    m_table.attach( d , 0 , 3 , 1 , 2 );
    

    Und für folgendes Layout

    0   1   2
      +---+---+---+
    0 | a | b | c |
      +---+---+---+
    1 |           |
      +     d     +
    2 |           |
      +---+---+---+
    

    so:

    m_table.attach( d , 0 , 3 , 1 , 3 );
    

    Bei den xoptions und yoptions gibt es folgende Optionen:

    • FILL
    • SHRINK
    • EXPAND

    Bei Gtk::FILL wird das Widget, sollte es kleiner als die Zelle selbst sein, auf Zellengröße vergrößert.
    Gtk::EXPAND zwingt das Table zum Größerwerden, sollte der Platz für das Widget nicht ausreichen.
    Wenn die Tabelle weniger Platz bekommt, als sie braucht, weil der Benutzer z.B. die Fenstergröße ändert, verschwindet das Wigdet einfach. Wenn man Gtk::SHRINK angibt, werden die Widgets in der Tabelle verkleinert, damit sie in den Bereich passen.

    1.4 Single Widget Container

    Es gibt auch Container-Widgets, die nur ein einziges Widget aufnehmen können. Bestes Beispiel ist Gtk::Window.

    Diese Widgets haben nur die Methode add zum Hinzufügen der Widgets und nehmen als Parameter eine Referenz auf das Widget, das hinzugefügt werden soll.

    Es gibt auch noch Ausnahmen bei den "Single Widget Containern": Das ist Gtk::Paned, aber auf das werde ich ein anderes Mal zu sprechen kommen 😉

    1.5 Anwendung

    In dem Beispiel werde ich bereits das erste Mal Gtk::Label benutzen, um zu verdeutlichen, wie man die Boxes verwendet.

    struct MyWindow : Gtk::Window
    {
        MyWindow();
    
        Gtk::VBox   m_vbox;
        Gtk::HBox   m_hbox;
        Gtk::Label  m_label1;
        Gtk::Label  m_label2;
        Gtk::Label  m_label3;
    };    
    
    MyWindow::MyWindow()
    : Gtk::Window(),
      m_vbox(true,5),// homogene Ausrichtung und 5 px Abstand
      m_hbox(true,5),// homogene Ausrichtung und 5 px Abstand
      m_label1("Label 1"),
      m_label2("Label 2"),
      m_label3("Label 3")
    {
        // Text der Titelleiste setzen
        set_title("GTKmm Tutorial Teil 2");
    
        // m_label1 der horizontalen box als erstes Element übergeben
        m_hbox.pack_start(m_label1);
        // m_label2 der horizontalen box als zweites Element übergeben
        m_hbox.pack_start(m_label2);
    
        // m_hbox der vertikalen box als erstes Element übergeben
        m_vbox.pack_start(m_hbox);
        // m_label3 der vertikalen box als zweites Element übergeben
        m_vbox.pack_start(m_label3);
    
        // die vertikale Box an das Fenster übergeben
        add(m_vbox);
    
        // sorgt dafür, dass alle Widgets angezeigt werden
        show_all_children();
    }
    

    Und so sieht's aus:

    Ein Beispiel für die Verwendung eines Gtk::Table Containers findet ihr im Anwendungsbeispiel für die Buttons 🙂

    2.Signale

    2.1 Einführung

    In GTKmm wird, um auf Signale/Events zu reagieren, die Bibliothek SigC++ verwendet. SigC++ ist sehr flexibel und mächtig und ist sehr vielseitig verwendbar. Es ist möglich, Funktionen und Methoden aller Art zu verwenden, und es besteht sogar die Möglichkeit, zusätzliche Parameter an ein Signal zu binden, um zusätzliche Daten an den eigenen Signalhandler zu übergeben.

    Um nicht zu ausschweifend zu werden, zeige ich euch einfach ein paar Verwendungsbeispiele:

    2.2 Anwendung

    2.2.1 Eine Funktion als Signalhandler

    void on_button_clicked(); // Unser Signalhandler
    
    Gtk::Button button("Ich bin ein button"); // Wir verwenden einen Button zur Veranschaulichung
    
    button.signal_clicked().connect(sigc::ptr_fun(&on_button_clicked));
    

    Wie man sieht, ist die Verwendung recht unkompliziert. Die meisten Widgets haben spezielle Zugriffsmethoden, die es einem erlauben, Signalhandler zu setzen.

    Gtk::Button hat in diesem Fall z.B. die Methode Gtk::Button::signal_clicked(), um den Handler zu setzen, der auf ein Klick-Ereignis reagiert.

    Die Signale aller Widgets zu beschreiben, würde den Rahmen dieses Tutorials sprengen. Sie sollten daher der GTKmm-Dokumentation entnommen werden.

    2.2.2 Methoden als Signalhandler

    struct test
    {
       void on_button_clicked(); // Unser Signalhandler
    };
    
    Gtk::Button button("Ich bin ein button"); // Wir verwenden einen Button zur Veranschaulichung
    
    test test_obj;
    
    button.signal_clicked().connect(sigc::mem_fun(test_obj,&test::on_button_clicked));
    

    Um Methoden zu binden, bietet SigC++ die Funktion sigc::mem_fun.

    Als ersten Parameter nimmt sigc::mem_fun eine Referenz auf das Objekt der Methode und als zweiten Parameter den Methodenzeiger auf die Methode an.

    2.2.3 Binden von Parametern

    Da man manchmal zusätzliche Parameter bei einem Ereignis braucht, um auf ein Signal zu reagieren, bietet SigC++ die Funktion sigc::bind an, um zusätzliche Parameter an den Signalhandler zu übergeben.

    struct data
    {};
    struct test
    {
       void on_button_clicked(data d);
    };
    
    Gtk::Button button("Ich bin ein button"); // Wir verwenden einen Button zur Veranschaulichung
    
    test test_obj;
    data d;
    
    button.signal_clicked().connect( sigc::bind<data>( sigc::mem_fun( test_obj , &test::on_button_clicked ), d ) );
    

    3.Buttons

    3.1 Einführung

    In GTKmm gibt es neben den "normalen" Buttons auch RadioButtons, CheckButtons (aka CheckBox) und so genannte ToggleButtons. Viel zu erzählen gibt es hier nicht.

    Schaut euch einfach mal das Beispiel an und ihr seht, dass die Verwendung sehr simpel ist. In diesem Beispiel kann man auch schön die Verwendung der oben besprochenen Parameterbindung sehen. Des Weiteren verwende ich ein Gtk::Table als Container, um dessen Verwendung auch darzustellen. 🙂

    3.2 Anwendung

    struct MyWindow : Gtk::Window
    {
        MyWindow();
    private:
        Gtk::ToggleButton     m_toggle_button;
    
        Gtk::CheckButton      m_check_button1;
        Gtk::CheckButton      m_check_button2;
    
        Gtk::RadioButtonGroup m_radiogroup;
        Gtk::RadioButton      m_radio_button1;
        Gtk::RadioButton      m_radio_button2;
    
        Gtk::Button           m_button;
    
        Gtk::Table            m_table;
    
    private:
        void attach_widgets_to_table();
        void connect_signals();
        void on_toggle_button_clicked();
        void on_radio_button_clicked(int);
        void on_check_button_clicked(int,Gtk::CheckButton const *);
        void on_button_clicked();
    };
    
    MyWindow::MyWindow()
    : Gtk::Window(),
      m_toggle_button("Gtk::ToggleButton"),
      m_check_button1("Gtk::CheckButton 1"),
      m_check_button2("Gtk::CheckButton 2"),
      m_radiogroup(),
      m_radio_button1(m_radiogroup,"Gtk::RadioButton 1"),// RadioButton einer Gruppe zuordnen und Beschriftung geben
      m_radio_button2(m_radiogroup,"Gtk::RadioButton 2"),// RadioButton einer Gruppe zuordnen und Beschriftung geben
      m_button("Gtk::Button"),
      m_table(3,2,true) // 3 Zeilen, 2 Spalten, homogene Aufteilung der Zellen
    {
        // Standardfenstergröße setzen; Breite: 400px Höhe: 170px
        set_default_size(400,170); 
    
        // Titel setzen
        set_title("GTKmm Tutorial Teil 2");
    
        // Widgets in das Table einfügen
        attach_widgets_to_table();
    
        // Signale verbinden
        connect_signals();
    
        // Tabelle dem Fenster übergeben
        add(m_table);
    
        // Alle Widgets anzeigen
        show_all_children();
    }
    
    void MyWindow::attach_widgets_to_table()
    {
        // Button in Zelle(0,0) einfügen
        m_table.attach(m_button,0,1,0,1);
    
        // ToggleButton in Zelle(1,0) einfügen
        m_table.attach(m_toggle_button,1,2,0,1);
    
        // CheckButton in Zelle(0,1) einfügen
        m_table.attach(m_check_button1,0,1,1,2);
    
        // CheckButton in Zelle(1,1) einfügen
        m_table.attach(m_check_button2,1,2,1,2);
    
        // RadioButton in Zelle(0,2) einfügen
        m_table.attach(m_radio_button1,0,1,2,3);
    
        // RadioButton in Zelle(1,2) einfügen
        m_table.attach(m_radio_button2,1,2,2,3);
    }
    
    void MyWindow::connect_signals()
    {
        // Signale verbinden:
    
        m_button.signal_clicked().connect(sigc::mem_fun(*this,&MyWindow::on_button_clicked));
    
        m_toggle_button.signal_clicked().connect(sigc::mem_fun(*this,&MyWindow::on_toggle_button_clicked));
    
        m_radio_button1.signal_clicked().connect(sigc::bind<int>(sigc::mem_fun(*this,&MyWindow::on_radio_button_clicked),1));
    
        m_radio_button2.signal_clicked().connect(sigc::bind<int>(sigc::mem_fun(*this,&MyWindow::on_radio_button_clicked),2));
    
        m_check_button1.signal_clicked().connect(sigc::bind<int,Gtk::CheckButton const *>(sigc::mem_fun(*this,&MyWindow::on_check_button_clicked),1,&m_check_button1));
    
        m_check_button2.signal_clicked().connect(sigc::bind<int,Gtk::CheckButton const *>(sigc::mem_fun(*this,&MyWindow::on_check_button_clicked),2,&m_check_button2));
    }
    
    void MyWindow::on_toggle_button_clicked()
    {
        Glib::ustring msg = "ToggleButton wurde angeklickt. Neuer Status ist: ";
        if(m_toggle_button.get_active())
            msg += "gedrueckt";
        else
            msg += "nicht gedrueckt";
    
        Gtk::MessageDialog dia(*this,msg);
    
        dia.run();
    }
    
    void MyWindow::on_radio_button_clicked(int which)
    {
        Glib::ustring msg = "Der Status von RadioButton ";
        if(which == 1)
            msg += "1 hat sich geaendert";
        else
            msg += "2 hat sich geaendert";
    
        Gtk::MessageDialog dia(*this,msg);
    
        dia.run();
    }
    
    void MyWindow::on_check_button_clicked(int which, Gtk::CheckButton const * cb)
    {
        if(!cb)
        {
            Gtk::MessageDialog dia(*this,"Es ist ein Fehler aufgetreten",false,Gtk::MESSAGE_ERROR);
            dia.run();
            return;
        }
    
        Glib::ustring msg = "CheckButton ";
        if(which == 1)
            msg += "1";
        else
            msg += "2";
    
        if(cb->get_active())
            msg += " markiert";
        else
            msg += " Markierung aufgehoben";
    
        Gtk::MessageDialog dia(*this,msg);
    
        dia.run();
    }
    
    void MyWindow::on_button_clicked()
    {
        Gtk::MessageDialog dia(*this,"Button wurde angeklickt :)");
    
        dia.run();
    }
    
    int main(int argc, char **argv)
    {
        Gtk::Main main(argc,argv);
        MyWindow window;
        main.run(window);
        return 0;
    }
    

    Und so sieht's aus:

    4.Implementation eines weiteren Beispiels

    #include <gtkmm.h>
    
    struct MyWindow : Gtk::Window
    {
        MyWindow();
        ~MyWindow();
    
        void on_button1_clicked();
        void on_button2_clicked();
    
        Gtk::Button m_button1;
        Gtk::Button m_button2;
        Gtk::Label  m_label;
        Gtk::VBox   m_vbox;
        Gtk::HBox   m_hbox;
    };
    
    MyWindow::MyWindow()
    : Gtk::Window(), 
      m_button1("Klick mich1"),
      m_button2("Klick mich2"),
      m_label("<u><i><b>Ich bin ein Label</b></i></u>"),
      m_vbox(true,5),
      m_hbox(true,5)
    {
        set_title("GTKmm Tutorial Teil 2");
    
        m_label.set_use_markup(true);
    
        m_hbox.pack_start(m_button1);
        m_hbox.pack_end(m_button2);
    
        m_button1.signal_clicked().connect(sigc::mem_fun(*this,&MyWindow::on_button1_clicked));
        m_button2.signal_clicked().connect(sigc::mem_fun(*this,&MyWindow::on_button2_clicked));
    
        m_vbox.pack_start(m_hbox);
        m_vbox.pack_start(m_label);
    
        add(m_vbox);
    
        set_default_size(200,100);
        show_all_children(true);
    }
    MyWindow::~MyWindow()
    {
    
    }
    
    void MyWindow::on_button1_clicked()
    {
        m_label.set_markup("<b><i>Button 1</i> wurde angeklickt</b>");
        m_label.set_use_markup(true);
    }
    void MyWindow::on_button2_clicked()
    {
        m_label.set_markup("<b><u>Button 2</u> wurde angeklickt</b>");
        m_label.set_use_markup(true);
    }
    
    int main(int argc, char **argv)
    {
        Gtk::Main main(argc,argv);
        MyWindow window;
        main.run(window);
        return 0;
    }
    

    Und last but not least: So sieht's aus:

    So, diesmal gab's viel Code und wenig Erklärungen, so wird es auch im nächsten Teil aussehen, da ich nicht glaube, dass es zu den Widgets viel zu erzählen gibt. Ich hoffe, dass dieses Tutorial hilfreich war.

    Ich schmeiße mich gleich auch ans nächste Tutorial, damit da nicht wieder so ne Ewigkeit dazwischen liegt 🙂

    BR

    evilissimo



  • evilissimo, lass dich knuddeln!

    Ich freu mich! Endlich ein neuer Teil! 🙂

    Das Magazin ist ja allgemein superklasse, aber deine GTK-Reihe ist mein persönliches Highlight. Aber auch ein Lob an die anderen Autoren, fast alles hier ist uneingeschränkt empfehlenswert. 🙂



  • So, habs mir jetzt durchgelsen, ein Fehler ist mir aufgefallen:

    xpadding gibt an, wie viel Platz das Widget links und rechts von sich haben soll (freier Platz).
    xpadding gibt an, wie viel Platz das Widget oben und unten von sich haben soll (freier Platz).

    Einmal müsste es ypadding heißen.

    Erklärungen sind wirklich knapp ausgefallen, aber haut noch so hin, ansonsten schön! 🙂



  • Shit, jetzt hab ich noch was vergessen:

    Bei der Tabelle ist deine Erklärung etwas verwirrend, weil du die Zellen nummerierst, geeigneter wäre aber eine Nummerierung derer Eckpunkte.
    Also wenn ich die erste Zelle haben will, mach ich das zweimal von Eckpunkt 0 ganz außen bis Eckpunkt Nummer 1.
    Und nicht von Zelle 0 nach Zelle 1....

    🙂



  • Fan des guten Essens schrieb:

    Shit, jetzt hab ich noch was vergessen:

    Bei der Tabelle ist deine Erklärung etwas verwirrend, weil du die Zellen nummerierst, geeigneter wäre aber eine Nummerierung derer Eckpunkte.
    Also wenn ich die erste Zelle haben will, mach ich das zweimal von Eckpunkt 0 ganz außen bis Eckpunkt Nummer 1.
    Und nicht von Zelle 0 nach Zelle 1....

    🙂

    Hmm wohl wahr.



  • hil evilissimo

    zu allererst: Sehr gute Arbeit.
    Mein Verbesserungsvorschlag: Du könntest noch deine Teile untereinander verlinken, also am Ende von Teil 1 noch einen Link auf Teil 2 setzen usw.



  • Benutzername: schrieb:

    hil evilissimo

    zu allererst: Sehr gute Arbeit.
    Mein Verbesserungsvorschlag: Du könntest noch deine Teile untereinander verlinken, also am Ende von Teil 1 noch einen Link auf Teil 2 setzen usw.

    Danke für den Vorschlag. Habe ich gemacht 😉

    BR
    Vinzenz



  • Hi evilissimo,
    ich habe eine Tabelle mit 3 Zeilen und 2 Spalten. in der linken spalte sind 3 buttons und in der rechten ein Textview. Wenn ich aber bei der Tabelle homogenous auf false setze zeigt er nur die linke spalte an, setze ich auf true zeigt er alles an, allerdings ist die aufteilung jeweils halbe halbe, was ein wenig doof aussieht. wie kann ich angeben wieviel pix oder % die linke spalte einnehmen soll?



  • Benutzername: schrieb:

    Hi evilissimo,
    ich habe eine Tabelle mit 3 Zeilen und 2 Spalten. in der linken spalte sind 3 buttons und in der rechten ein Textview. Wenn ich aber bei der Tabelle homogenous auf false setze zeigt er nur die linke spalte an, setze ich auf true zeigt er alles an, allerdings ist die aufteilung jeweils halbe halbe, was ein wenig doof aussieht. wie kann ich angeben wieviel pix oder % die linke spalte einnehmen soll?

    Du kannst die Prozentzahl oder Anzahl der Pixel nicht direkt setzen. Eine Möglichkeit wäre, dass du die Tabelle nicht homogen anlegst, die Buttons mit Gtk::SHRINK einsetzt und ein Padding setzt bis es so aussieht wie du das haben willst und dann eben das ScrolledWindow vom Treeview mit Gtk::EXPAND widget in die Tabelle einfügst.

    Alternativ wäre HBox und eine VBox bzw eine VButtonBox für die Buttons vielleicht besser.

    BR
    Vinzenz



  • ich hab gerade mit glade-2 einen editor erstellt, aber ch kapier folgendes nicht:

    ich hab 2fenster: ein mainwindow und einen aboutdialog. ich will, dass der aboutdialog aufgerufen wird, sobald man auf help klickt (ein icon in der mueleiste(deteils: label: help, name: imagemenuitem33, handler: on_aboutdialog_show)

    und im aboutdialog hab ich bei signals folgendes eingetragen:

    Signals: open, close
    Handler: on_aboutdialog_show, on_aboutdialog_close
    objekt: aboutdialog, aboutdialog

    und in der menüleiste folgendes: (menubar3)

    signal: activate current
    handler: on_aboutdialog_show
    objekt: menuitem33

    nachdem er den sourcecode erstellt hatte, hab ich da paar kleinigkeiten geändert

    main.c:

    X3_Editor = create_X3_Editor ();
      gtk_widget_show (X3_Editor);
      g_signal_connect ((gpointer) X3_Editor, "destroy",
    		    G_CALLBACK (gtk_main_quit), NULL);
      aboutdialog = create_aboutdialog ();
      gtk_widget_show (aboutdialog);
        gtk_widget_hide (aboutdialog); //damit der dia unsichtbar ist
      g_signal_connect ((gpointer) aboutdialog, "destroy",
    		    G_CALLBACK (gtk_main_quit), NULL);
    

    callback

    GtkWidget *X3_Editor; //definition vom mainwindow
      GtkWidget *aboutdialog; //definition vom aboutdialog
    
    void
    on_aboutdialog_show (GtkMenuShell * menushell,
    		     gboolean force_hide, gpointer user_data)
    {
      gtk_widget_show (aboutdialog); //damit der dia wieder sichtbar wird
    }
    

    wenn ich komiliere und starte, dann kommt mein editor, das aboutfenster ist unsichtbar, aber dafür kann man es auch nicht mehr sichtbar machen (d.h. bei einem klick auf help passiert nix)

    was läuft da falsch?

    vielen dank schonmal im voraus!

    btw: wie bekommt man glade dazu einen c++ sourcecode zu erstellen? wenn ich bei optionen c++ einstelle, bekomme ich keinen sc sondern einen fehler, in dem steht, dass ich sicherstellen soll, dass glade-- installiert ist. ich habs gedownloaded und hab es sogut wie in jeden ordner gestckt, aber es kommt immer wieder derselbe fehler...



  • Hat alles wunderbar geklappt.


Anmelden zum Antworten