Γραφικά συστατικά πολλαπλών στοιχείων
Τα γραφικά συστατικά πολλαπλών στοιχείων κληρονομούν από την Gtk::Container; ακριβώς όπως με την Gtk::Bin, χρησιμοποιείτε τις μεθόδους add() και remove() για την πρόσθεση και αφαίρεση περιεχόμενων γραφικών συστατικών. Αντίθετα με την Gtk::Bin::remove(), όμως, η μέθοδος remove() για την Gtk::Container παίρνει ένα όρισμα, ορίζοντας ποιο γραφικό συστατικό θα αφαιρεθεί.
- 8.2.1. Πακετάρισμα
- 8.2.2. Ένα βελτιωμένο Hello World
- 8.2.3. Πλαίσια (Boxes)
- 8.2.4. Πλαίσια με κουμπιά (ButtonBoxes)
- 8.2.5. Πλέγμα
- 8.2.6. Πίνακας
- 8.2.7. Σημειωματάριο
- 8.2.8. Βοηθός
8.2.1. Πακετάρισμα
Έχετε προφανώς σημειώσει ότι τα παράθυρα gtkmm φαίνονται "ελαστικά" - μπορούν συνήθως να τεντωθούν με πολλούς διαφορετικούς τρόπους. Αυτό οφείλεται στο σύστημα συσκευασίας γραφικού συστατικού.
Πολλά πακέτα εργαλείων GUI απαιτούν την ακριβή τοποθέτηση γραφικών συστατικών σε ένα παράθυρο, χρησιμοποιώντας απόλυτη τοποθέτηση, χρησιμοποιώντας συχνά έναν οπτικό επεξεργαστή. Αυτό οδηγεί σε πολλά προβλήματα:
- Τα γραφικά συστατικά δεν αναδιατάσσουν τους εαυτούς τους όταν το παράθυρο αυξομειώνεται. Κάποια γραφικά συστατικά κρύβονται όταν το παράθυρο γίνεται μικρότερο και πολύς άχρηστος χώρος εμφανίζεται όταν το παράθυρο γίνεται μεγαλύτερο.
- Είναι αδύνατο να προβλέψετε τον απαραίτητο χώρο για κείμενο αφού έχει μεταφραστεί σε άλλες γλώσσες ή όταν εμφανίζεται με μια διαφορετική γραμματοσειρά. Στο Γιούνιξ είναι επίσης αδύνατο να προβλέψτε τις επιδράσεις κάθε θέματος και διαχειριστή παραθύρου.
- Η αλλαγή της διάταξης ενός παραθύρου "άμεσα", για να εμφανιστούν κάποια πρόσθετα γραφικά συστατικά, για παράδειγμα, είναι σύνθετη. Απαιτεί κουραστικούς επανυπολογισμούς κάθε θέσης του γραφικού συστατικού.
Το gtkmm χρησιμοποιεί το σύστημα συσκευασίας για την επίλυση αυτών των προβλημάτων. Αντί να ορίζει τη θέση και το μέγεθος κάθε γραφικού συστατικού στο παράθυρο, μπορείτε να τακτοποιήσετε τα γραφικά συστατικά σας σε γραμμές, στήλες και/ή πλέγματα. Το gtkmm μπορεί να προσαρμόσει το παράθυρό σας αυτόματα, με βάση τα μεγέθη των γραφικών συστατικών που περιέχει. Και τα μεγέθη των γραφικών συστατικών καθορίζονται, με τη σειρά τους, από το πόσο κείμενο περιέχουν, ή το ελάχιστο και μέγιστο μέγεθος που ορίζετε, και/ή πώς έχετε ζητήσει να μοιράζεται ο διαθέσιμος χώρος μεταξύ ομάδων γραφικών συστατικών. Μπορείτε να τελειοποιήσετε τη διάταξή σας ορίζοντας απόσταση συμπλήρωσης και κεντράρισμα τιμών για κάθε γραφικό συστατικό σας. Τότε το gtkmm χρησιμοποιεί όλες αυτές τις πληροφορίες για αυξομείωση και ανατοποθέτηση καθενός λογικά και ομαλά, όταν ο χρήστης χειρίζεται το παράθυρο.
Το gtkmm τακτοποιεί τα γραφικά συστατικά ιεραρχικά, χρησιμοποιώντας περιέκτες. Ένα γραφικό συστατικό περιέκτη περιέχει άλλα γραφικά συστατικά. Τα περισσότερα γραφικά συστατικά του gtkmm είναι περιέκτες. Παράθυρα, καρτέλες σημειωματάριου και κουμπιά είναι όλα γραφικά συστατικά περιεκτών. Υπάρχουν δύο γεύσεις περιεκτών: περιέκτες μοναδικού θυγατρικού, που είναι όλοι απόγονοι της Gtk::Bin, και περιέκτες πολλαπλών θυγατρικών, που είναι απόγονοι της Gtk::Container. Τα περισσότερα γραφικά συστατικά στο gtkmm είναι απόγονοι της Gtk::Bin, συμπεριλαμβανόμενης της Gtk::Window.
Ναι, αυτό είναι σωστό: ένα παράθυρο μπορεί να περιέχει το πολύ ένα γραφικό συστατικό. Πώς, τότε, μπορούμε να χρησιμοποιούμε ένα παράθυρο για ο,τιδήποτε χρήσιμο; Τοποθετώντας έναν περιέκτη πολλαπλού θυγατρικού στο παράθυρο. Τα πιο χρήσιμα γραφικά συστατικά περιεκτών είναι οι Gtk::Grid και Gtk::Box.
- Η Gtk::Grid τακτοποιεί τα θυγατρικά της γραφικά συστατικά σε γραμμές και στήλες. Χρησιμοποιήστε attach(), attach_next_to() και add() για την εισαγωγή θυγατρικών γραφικών συστατικών.
- Η Gtk::Box τακτοποιεί τα θυγατρικά της γραφικά συστατικά κάθετα ή οριζόντια. Χρησιμοποιήστε pack_start() και pack_end() για εισαγωγή θυγατρικών γραφικών συστατικών.
Υπάρχουν αρκετοί άλλοι περιέκτες, που θα συζητήσουμε επίσης.
Αν δεν έχετε χρησιμοποιήσει ποτέ πριν ένα πακέτο εργαλείων συσκευασίας, μπορεί να πάρει κάμποσο για να το χρησιμοποιήσετε. Θα βρείτε προφανώς, όμως, ότι δεν χρειάζεστε να βασίζεστε σε οπτικές μορφές επεξεργαστών τόσο πολύ όσο θα πρέπει με άλλα πακέτα εργαλείων.
8.2.2. Ένα βελτιωμένο Hello World
Ας ρίξουμε μια ματιά σε ένα ελαφρά βελτιωμένο helloworld, που δείχνει τι έχουμε μάθει.
File: helloworld.h (For use with gtkmm 3, not gtkmm 2)
#ifndef GTKMM_EXAMPLE_HELLOWORLD_H #define GTKMM_EXAMPLE_HELLOWORLD_H #include <gtkmm/box.h> #include <gtkmm/button.h> #include <gtkmm/window.h> class HelloWorld : public Gtk::Window { public: HelloWorld(); virtual ~HelloWorld(); protected: // Signal handlers: // Our new improved on_button_clicked(). (see below) void on_button_clicked(Glib::ustring data); // Child widgets: Gtk::Box m_box1; Gtk::Button m_button1, m_button2; }; #endif // GTKMM_EXAMPLE_HELLOWORLD_H
File: main.cc (For use with gtkmm 3, not gtkmm 2)
#include "helloworld.h" #include <gtkmm/application.h> int main (int argc, char *argv[]) { Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.example"); HelloWorld helloworld; //Shows the window and returns when it is closed. return app->run(helloworld); }
File: helloworld.cc (For use with gtkmm 3, not gtkmm 2)
#include "helloworld.h" #include <iostream> HelloWorld::HelloWorld() : m_button1("Button 1"), m_button2("Button 2") { // This just sets the title of our new window. set_title("Hello Buttons!"); // sets the border width of the window. set_border_width(10); // put the box into the main window. add(m_box1); // Now when the button is clicked, we call the "on_button_clicked" function // with a pointer to "button 1" as it's argument m_button1.signal_clicked().connect(sigc::bind<Glib::ustring>( sigc::mem_fun(*this, &HelloWorld::on_button_clicked), "button 1")); // instead of gtk_container_add, we pack this button into the invisible // box, which has been packed into the window. // note that the pack_start default arguments are Gtk::EXPAND | Gtk::FILL, 0 m_box1.pack_start(m_button1); // always remember this step, this tells GTK that our preparation // for this button is complete, and it can be displayed now. m_button1.show(); // call the same signal handler with a different argument, // passing a pointer to "button 2" instead. m_button2.signal_clicked().connect(sigc::bind<-1, Glib::ustring>( sigc::mem_fun(*this, &HelloWorld::on_button_clicked), "button 2")); m_box1.pack_start(m_button2); // Show the widgets. // They will not really be shown until this Window is shown. m_button2.show(); m_box1.show(); } HelloWorld::~HelloWorld() { } // Our new improved signal handler. The data passed to this method is // printed to stdout. void HelloWorld::on_button_clicked(Glib::ustring data) { std::cout << "Hello World - " << data << " was pressed" << std::endl; }
Μετά τη δόμηση και εκτέλεση αυτού του προγράμματος, προσπαθήστε να αυξομειώσετε το παράθυρο για να δείτε τη συμπεριφορά. Επίσης, δοκιμάστε να παίξετε με τις επιλογές στη pack_start(), ενώ διαβάζετε την ενότητα Πλαίσια (Boxes).
8.2.3. Πλαίσια (Boxes)
Οι περισσότερες συσκευασίες χρησιμοποιούν πλαίσια (boxes) όπως στο παραπάνω παράδειγμα. Αυτά είναι αόρατοι περιέκτες στους οποίους μπορούμε να συσκευάσουμε τα γραφικά συστατικά μας. Όταν συσκευάζονται γραφικά συστατικά σε ένα οριζόντιο πλαίσιο, τα αντικείμενα εισάγονται οριζόντια από αριστερά προς τα δεξιά ή δεξιά προς τα αριστερά ανάλογα με το αν χρησιμοποιείται pack_start() ή pack_end(). Σε ένα κάθετο πλαίσιο, τα γραφικά συστατικά συσκευάζονται από πάνω προς τα κάτω ή αντίστροφα. Μπορεί να χρησιμοποιήσετε οποιοδήποτε συνδυασμό πλαισίων μέσα ή δίπλα σε άλλα πλαίσια για τη δημιουργία της επιθυμητής επίδρασης.
- 8.2.3.1. Προσθήκη γραφικών συστατικών
- 8.2.3.2. Gtk::επιλογές εφαρμογής και γραμμής εντολών
- 8.2.3.3. Παράδειγμα
8.2.3.1. Προσθήκη γραφικών συστατικών
- 8.2.3.1.1. Επιλογές συσκευασίας ανά θυγατρικό
- 8.2.3.1.2. Επιλογές συσκευασίας ανά περιέκτη
8.2.3.1.1. Επιλογές συσκευασίας ανά θυγατρικό
Οι μέθοδοι pack_start() και pack_end() τοποθέτησης γραφικών συστατικών μέσα σε αυτούς τους περιέκτες. Η μέθοδος pack_start() θα ξεκινήσει στην κορυφή και θα δουλέψει τον τρόπο της κάτω σε ένα Box με κάθετο προσανατολισμό, ή θα συσκευάσει από αριστερά προς τα δεξιά σε ένα Box με οριζόντιο προσανατολισμό. Η pack_end() θα κάνει το αντίθετο, συσκευάζοντας από κάτω προς τα πάνω ή από δεξιά προς τα αριστερά. Η χρήση αυτών των μεθόδων επιτρέπει τη δεξιά ή αριστερή στοίχιση των γραφικών συστατικών μας. Θα χρησιμοποιήσουμε τη pack_start() στα περισσότερα παραδείγματά μας.
Υπάρχουν αρκετές επιλογές που διέπουν τον τρόπο συσκευασίας των γραφικών συστατικών και αυτό μπορεί να μπερδεύει στην αρχή. Αν δυσκολεύεστε, τότε είναι μερικές φορές καλή ιδέα να παίξετε με τον σχεδιαστή γραφικής διεπαφής glade για να δείτε τι είναι δυνατό. Μπορείτε ακόμα να αποφασίσετε τη χρήση της API Gtk::Builder για τη φόρτωση της γραφικής διεπαφής κατά τον χρόνο εκτέλεσης.
Υπάρχουν βασικά πέντε διαφορετικές τεχνοτροπίες, όπως φαίνεται σε αυτήν την εικόνα:
Κάθε γραμμή περιέχει ένα οριζόντιο Box με αρκετά κουμπιά. Κάθε κουμπί σε μια γραμμή συσκευάζεται σε ένα Box με τα ίδια ορίσματα στη μέθοδο pack_start().
Αυτή είναι η δήλωση της μεθόδου pack_start():
void pack_start(Gtk::Widget& child, Gtk::PackOptions options = Gtk::PACK_EXPAND_WIDGET, guint padding = 0);
Το πρώτο όρισμα είναι το γραφικό συστατικό που συσκευάζετε. Στο παράδειγμά μας όλα αυτά είναι Buttons.
The options argument can take one of these three options:
- Gtk::PACK_SHRINK: Space is contracted to the child widget size. The widget will take up just-enough space and never expand.
- Gtk::PACK_EXPAND_PADDING: Extra space is filled with padding. The widgets will be spaced out evenly, but their sizes won't change - there will be empty space between the widgets instead.
- Gtk::PACK_EXPAND_WIDGET: Extra space is taken up by increasing the child widget size, without changing the amount of space between widgets.
Το όρισμα padding καθορίζει το πλάτος μιας πρόσθετης περιοχής περιγράμματος για να αφήσει ολόγυρα το συσκευασμένο γραφικό συστατικό.
8.2.3.1.2. Επιλογές συσκευασίας ανά περιέκτη
Here's the constructor for the Box widget, and methods that set per-container packing options:
Gtk::Box(Gtk::Orientation orientation = Gtk::ORIENTATION_HORIZONTAL, int spacing = 0); void set_spacing(int spacing); void set_homogeneous(bool homogeneous = true);
Ποια είναι η διαφορά μεταξύ διακένου (που ορίστηκε όταν δημιουργείται το πλαίσιο (box)) και συμπλήρωσης (που ορίζεται όταν συσκευάζονται στοιχεία); Το διάκενο προστίθεται μεταξύ αντικειμένων και η συμπλήρωση προστίθεται σε όποια πλευρά του γραφικού συστατικού. Η παρακάτω εικόνα πρέπει να το ξεκαθαρίζει:
8.2.3.2. Gtk::επιλογές εφαρμογής και γραμμής εντολών
Το παρακάτω παράδειγμα προγράμματος απαιτεί μια επιλογή γραμμής εντολών. Ο πηγαίος κώδικας εμφανίζει δύο τρόπους χειρισμού των επιλογών της γραμμής εντολών σε συνδυασμό με την Gtk::Application.
Χειριστείτε τις επιλογές στη main() και κρύψτε τες από την Gtk::Application ορίζοντας argc = 1 στην κλήση στην Gtk::Application::create().
-
Δώστε όλες τις επιλογές της γραμμής εντολών στη Gtk::Application::create() και προσθέστε τη σημαία Gio::APPLICATION_HANDLES_COMMAND_LINE. Συνδέστε έναν χειριστή σήματος στο σήμα command_line και χειριστείτε τις επιλογές της γραμμής εντολών στον χειριστή σήματος.
Πρέπει να ορίσετε μια προαιρετική παράμετρο after = false στην κλήση στο signal_command_line().connect(), επειδή ο χειριστής σήματός σας πρέπει να κληθεί πριν τον προεπιλεγμένο χειριστή σήματος. Πρέπει επίσης να καλέσετε την Gio::Application::activate() στον χειριστή σήματος, εκτός και θέλετε η εφαρμογή σας να εξέλθει χωρίς την εμφάνιση του κυρίως παραθύρου. (η Gio::Application είναι μια βασική κλάση της Gtk::Application.)
8.2.3.3. Παράδειγμα
Να ο πηγαίος κώδικας για το παράδειγμα που παρήγαγε τα παραπάνω στιγμιότυπα. Όταν εκτελείτε αυτό το παράδειγμα, δώστε έναν αριθμό μεταξύ 1 και 3 ως επιλογή της γραμμής εντολών, για να δείτε σε χρήση τις διαφορετικές επιλογές συσκευασίας.
File: examplewindow.h (For use with gtkmm 3, not gtkmm 2)
#ifndef GTKMM_EXAMPLEWINDOW_H #define GTKMM_EXAMPLEWINDOW_H #include <gtkmm.h> class ExampleWindow : public Gtk::Window { public: ExampleWindow(int which); virtual ~ExampleWindow(); protected: //Signal handlers: void on_button_quit_clicked(); //Child widgets: Gtk::Button m_button; Gtk::Box m_box1; Gtk::Box m_boxQuit; Gtk::Button m_buttonQuit; Gtk::Label m_Label1, m_Label2; Gtk::Separator m_separator1, m_separator2; }; #endif //GTKMM_EXAMPLEWINDOW_H
File: packbox.h (For use with gtkmm 3, not gtkmm 2)
#ifndef GTKMM_EXAMPLE_PACKBOX_H #define GTKMM_EXAMPLE_PACKBOX_H #include <gtkmm.h> class PackBox : public Gtk::Box { public: PackBox(bool homogeneous, int spacing, Gtk::PackOptions options, int padding = 0); virtual ~PackBox(); protected: Gtk::Button m_button1, m_button2, m_button3; Gtk::Button* m_pbutton4; }; #endif //GTKMM_EXAMPLE_PACKBOX_H
File: examplewindow.cc (For use with gtkmm 3, not gtkmm 2)
#include <iostream> #include "examplewindow.h" #include "packbox.h" ExampleWindow::ExampleWindow(int which) : m_box1(Gtk::ORIENTATION_VERTICAL), m_buttonQuit("Quit") { set_title("Gtk::Box example"); PackBox *pPackBox1, *pPackBox2, *pPackBox3, *pPackBox4, *pPackBox5; switch(which) { case 1: { m_Label1.set_text("Gtk::Box(Gtk::ORIENTATION_HORIZONTAL); set_homogeneous(false);"); // Align the label to the left side. We'll discuss this function and // others in the section on Widget Attributes. m_Label1.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_START); // Pack the label into the vertical box (vbox box1). Remember that // widgets added to a vbox will be packed one on top of the other in // order. m_box1.pack_start(m_Label1, Gtk::PACK_SHRINK); // Create a PackBox - homogeneous = false, spacing = 0, // options = Gtk::PACK_SHRINK, padding = 0 pPackBox1 = Gtk::manage(new PackBox(false, 0, Gtk::PACK_SHRINK)); m_box1.pack_start(*pPackBox1, Gtk::PACK_SHRINK); // Create a PackBox - homogeneous = false, spacing = 0, // options = Gtk::PACK_EXPAND_PADDING, padding = 0 pPackBox2 = Gtk::manage(new PackBox(false, 0, Gtk::PACK_EXPAND_PADDING)); m_box1.pack_start(*pPackBox2, Gtk::PACK_SHRINK); // Create a PackBox - homogeneous = false, spacing = 0, // options = Gtk::PACK_EXPAND_WIDGET, padding = 0 pPackBox3 = Gtk::manage(new PackBox(false, 0, Gtk::PACK_EXPAND_WIDGET)); m_box1.pack_start(*pPackBox3, Gtk::PACK_SHRINK); // pack the separator into the vbox. Remember each of these // widgets are being packed into a vbox, so they'll be stacked // vertically. m_box1.pack_start(m_separator1, Gtk::PACK_SHRINK, 5); // create another new label, and show it. m_Label2.set_text("Gtk::Box(Gtk::ORIENTATION_HORIZONTAL); set_homogeneous(true);"); m_Label2.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_START); m_box1.pack_start(m_Label2, Gtk::PACK_SHRINK); // Args are: homogeneous, spacing, options, padding pPackBox4 = Gtk::manage(new PackBox(true, 0, Gtk::PACK_EXPAND_PADDING)); m_box1.pack_start(*pPackBox4, Gtk::PACK_SHRINK); // Args are: homogeneous, spacing, options, padding pPackBox5 = Gtk::manage(new PackBox(true, 0, Gtk::PACK_EXPAND_WIDGET)); m_box1.pack_start(*pPackBox5, Gtk::PACK_SHRINK); m_box1.pack_start(m_separator2, Gtk::PACK_SHRINK, 5); break; } case 2: { m_Label1.set_text("Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 10); set_homogeneous(false);"); m_Label1.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_START); m_box1.pack_start(m_Label1, Gtk::PACK_SHRINK); pPackBox1 = Gtk::manage(new PackBox(false, 10, Gtk::PACK_EXPAND_PADDING)); m_box1.pack_start(*pPackBox1, Gtk::PACK_SHRINK); pPackBox2 = Gtk::manage(new PackBox(false, 10, Gtk::PACK_EXPAND_WIDGET)); m_box1.pack_start(*pPackBox2, Gtk::PACK_SHRINK); m_box1.pack_start(m_separator1, Gtk::PACK_SHRINK, 5); m_Label2.set_text("Gtk::Box(Gtk::ORIENTATION_HORIZONTAL); set_homogeneous(false);"); m_Label2.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_START); m_box1.pack_start(m_Label2, Gtk::PACK_SHRINK); pPackBox3 = Gtk::manage(new PackBox(false, 0, Gtk::PACK_SHRINK, 10)); m_box1.pack_start(*pPackBox3, Gtk::PACK_SHRINK); pPackBox4 = Gtk::manage(new PackBox(false, 0, Gtk::PACK_EXPAND_WIDGET, 10)); m_box1.pack_start(*pPackBox4, Gtk::PACK_SHRINK); m_box1.pack_start(m_separator2, Gtk::PACK_SHRINK, 5); break; } case 3: { // This demonstrates the ability to use Gtk::Box::pack_end() to // right justify widgets. First, we create a new box as before. pPackBox1 = Gtk::manage(new PackBox(false, 0, Gtk::PACK_SHRINK)); // create the label that will be put at the end. m_Label1.set_text("end"); // pack it using pack_end(), so it is put on the right side // of the PackBox. pPackBox1->pack_end(m_Label1, Gtk::PACK_SHRINK); m_box1.pack_start(*pPackBox1, Gtk::PACK_SHRINK); // this explicitly sets the separator to 500 pixels wide by 5 pixels // high. This is so the hbox we created will also be 500 pixels wide, // and the "end" label will be separated from the other labels in the // hbox. Otherwise, all the widgets in the hbox would be packed as // close together as possible. m_separator1.set_size_request(500, 5); // pack the separator into the vbox. m_box1.pack_start(m_separator1, Gtk::PACK_SHRINK, 5); break; } default: { std::cerr << "Unexpected command-line option." << std::endl; break; } } // Connect the signal to hide the window: m_buttonQuit.signal_clicked().connect( sigc::mem_fun(*this, &ExampleWindow::on_button_quit_clicked) ); // pack the button into the quitbox. // The last 2 arguments to Box::pack_start are: options, padding. m_boxQuit.pack_start(m_buttonQuit, Gtk::PACK_EXPAND_PADDING); m_box1.pack_start(m_boxQuit, Gtk::PACK_SHRINK); // pack the vbox (box1) which now contains all our widgets, into the // main window. add(m_box1); show_all_children(); } ExampleWindow::~ExampleWindow() { } void ExampleWindow::on_button_quit_clicked() { hide(); }
File: packbox.cc (For use with gtkmm 3, not gtkmm 2)
#include "packbox.h" PackBox::PackBox(bool homogeneous, int spacing, Gtk::PackOptions options, int padding) : Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, spacing), m_button1("box.pack_start("), m_button2("button,"), m_button3((options == Gtk::PACK_SHRINK) ? "Gtk::PACK_SHRINK" : ((options == Gtk::PACK_EXPAND_PADDING) ? "Gtk::PACK_EXPAND_PADDING" : "Gtk::PACK_EXPAND_WIDGET")) { set_homogeneous(homogeneous); pack_start(m_button1, options, padding); pack_start(m_button2, options, padding); pack_start(m_button3, options, padding); m_pbutton4 = new Gtk::Button(Glib::ustring::format(padding) + ");"); pack_start(*m_pbutton4, options, padding); } PackBox::~PackBox() { delete m_pbutton4; }
File: main.cc (For use with gtkmm 3, not gtkmm 2)
#include "examplewindow.h" #include <gtkmm/application.h> #include <iostream> #include <cstdlib> #define GTK_APPLICATION_RECEIVES_COMMAND_LINE_ARGUMENTS 0 #if GTK_APPLICATION_RECEIVES_COMMAND_LINE_ARGUMENTS namespace { int on_command_line(const Glib::RefPtr<Gio::ApplicationCommandLine>& command_line, Glib::RefPtr<Gtk::Application>& app) { int argc = 0; char** argv = command_line->get_arguments(argc); for (int i = 0; i < argc; ++i) std::cout << "argv[" << i << "] = " << argv[i] << std::endl; app->activate(); // Without activate() the window won't be shown. return EXIT_SUCCESS; } } // anonymous namespace #endif int main(int argc, char *argv[]) { if (argc != 2) { std::cerr << "Usage: example <num>, where <num> is 1, 2, or 3." << std::endl; return EXIT_FAILURE; } #if GTK_APPLICATION_RECEIVES_COMMAND_LINE_ARGUMENTS // The command line arguments must be checked before Gtk::Application::run() // is called. The Gio::APPLICATION_HANDLES_COMMAND_LINE flag and the // on_command_line() signal handler are not necessary. This program is simpler // without them, and with argc = 1 in the call to Gtk::Application::create(). // They are included to show a program with Gio::APPLICATION_HANDLES_COMMAND_LINE. // Gio::APPLICATION_NON_UNIQUE makes it possible to run several instances of // this application simultaneously. Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.example", Gio::APPLICATION_HANDLES_COMMAND_LINE | Gio::APPLICATION_NON_UNIQUE); // Note after = false. // Only one signal handler is invoked. This signal handler must run before // the default signal handler, or else it won't run at all. app->signal_command_line().connect(sigc::bind(sigc::ptr_fun(&on_command_line), app), false); #else // Gio::APPLICATION_NON_UNIQUE makes it possible to run several instances of // this application simultaneously. int argc1 = 1; // Don't give the command line arguments to Gtk::Application. Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc1, argv, "org.gtkmm.example", Gio::APPLICATION_NON_UNIQUE); #endif ExampleWindow window(std::atoi(argv[1])); return app->run(window); //Shows the window and returns when it is closed. }
8.2.4. Πλαίσια με κουμπιά (ButtonBoxes)
Τα πλαίσια με κουμπιά (Button boxes) είναι ένας βολικός τρόπος γρήγορης τακτοποίησης μιας ομάδας κουμπιών. Ο προσανατολισμός τους μπορεί να είναι ή οριζόντιος ή κάθετος.
ButtonBoxes βοηθούν να κάνουν τις εφαρμογές σας να εμφανίζονται συνεπείς, επειδή χρησιμοποιούν τυπικές ρυθμίσεις, όπως διάκενο και συσκευασία μεταξύ κουμπιών.
Τα κουμπιά προστίθενται σε μία ButtonBox με τη μέθοδο add().
Τα πλαίσια με κουμπιά (Button boxes) υποστηρίζουν πολλές τεχνοτροπίες διάταξης. Η τεχνοτροπία μπορεί να ανακτηθεί και να αλλαχθεί χρησιμοποιώντας get_layout() και set_layout().
- 8.2.4.1. Παράδειγμα
8.2.4.1. Παράδειγμα
File: examplewindow.h (For use with gtkmm 3, not gtkmm 2)
#ifndef GTKMM_EXAMPLEWINDOW_H #define GTKMM_EXAMPLEWINDOW_H #include <gtkmm.h> class ExampleWindow : public Gtk::Window { public: ExampleWindow(); virtual ~ExampleWindow(); protected: //Signal handlers: void on_button_clicked(); //Child widgets: Gtk::Box m_VBox_Main, m_VBox; Gtk::Box m_HBox; Gtk::Frame m_Frame_Horizontal, m_Frame_Vertical; }; #endif //GTKMM_EXAMPLEWINDOW_H
File: examplebuttonbox.h (For use with gtkmm 3, not gtkmm 2)
#ifndef GTKMM_EXAMPLE_BUTTONBOX_H #define GTKMM_EXAMPLE_BUTTONBOX_H #include <gtkmm.h> class ExampleButtonBox : public Gtk::Frame { public: ExampleButtonBox(bool horizontal, const Glib::ustring& title, gint spacing, Gtk::ButtonBoxStyle layout); protected: Gtk::Button m_Button_OK, m_Button_Cancel, m_Button_Help; }; #endif //GTKMM_EXAMPLE_BUTTONBOX_H
File: examplewindow.cc (For use with gtkmm 3, not gtkmm 2)
#include "examplewindow.h" #include "examplebuttonbox.h" ExampleWindow::ExampleWindow() : m_VBox_Main(Gtk::ORIENTATION_VERTICAL), m_VBox(Gtk::ORIENTATION_VERTICAL), m_Frame_Horizontal("Horizontal Button Boxes"), m_Frame_Vertical("Vertical Button Boxes") { set_title("Gtk::ButtonBox"); add(m_VBox_Main); m_VBox_Main.pack_start(m_Frame_Horizontal, Gtk::PACK_EXPAND_WIDGET, 10); //The horizontal ButtonBoxes: m_VBox.set_border_width(10); m_Frame_Horizontal.add(m_VBox); m_VBox.pack_start(*Gtk::manage( new ExampleButtonBox(true, "Spread (spacing 40)", 40, Gtk::BUTTONBOX_SPREAD)), Gtk::PACK_EXPAND_WIDGET); m_VBox.pack_start(*Gtk::manage( new ExampleButtonBox(true, "Edge (spacing 30)", 30, Gtk::BUTTONBOX_EDGE)), Gtk::PACK_EXPAND_WIDGET, 5); m_VBox.pack_start(*Gtk::manage( new ExampleButtonBox(true, "Start (spacing 20)", 20, Gtk::BUTTONBOX_START)), Gtk::PACK_EXPAND_WIDGET, 5); m_VBox.pack_start(*Gtk::manage( new ExampleButtonBox(true, "end (spacing 10)", 10, Gtk::BUTTONBOX_END)), Gtk::PACK_EXPAND_WIDGET, 5); //The vertical ButtonBoxes: m_VBox_Main.pack_start(m_Frame_Vertical, Gtk::PACK_EXPAND_WIDGET, 10); m_HBox.set_border_width(10); m_Frame_Vertical.add(m_HBox); m_HBox.pack_start(*Gtk::manage( new ExampleButtonBox(false, "Spread (spacing 5)", 5, Gtk::BUTTONBOX_SPREAD)), Gtk::PACK_EXPAND_WIDGET); m_HBox.pack_start(*Gtk::manage( new ExampleButtonBox(false, "Edge (spacing 30)", 30, Gtk::BUTTONBOX_EDGE)), Gtk::PACK_EXPAND_WIDGET, 5); m_HBox.pack_start(*Gtk::manage( new ExampleButtonBox(false, "Start (spacing 20)", 20, Gtk::BUTTONBOX_START)), Gtk::PACK_EXPAND_WIDGET, 5); m_HBox.pack_start(*Gtk::manage(new ExampleButtonBox(false, "End (spacing 10)", 10, Gtk::BUTTONBOX_END)), Gtk::PACK_EXPAND_WIDGET, 5); show_all_children(); } ExampleWindow::~ExampleWindow() { } void ExampleWindow::on_button_clicked() { hide(); }
File: main.cc (For use with gtkmm 3, not gtkmm 2)
#include "examplewindow.h" #include <gtkmm/application.h> int main(int argc, char *argv[]) { Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.example"); ExampleWindow window; //Shows the window and returns when it is closed. return app->run(window); }
File: examplebuttonbox.cc (For use with gtkmm 3, not gtkmm 2)
#include "examplebuttonbox.h" ExampleButtonBox::ExampleButtonBox(bool horizontal, const Glib::ustring& title, gint spacing, Gtk::ButtonBoxStyle layout) : Gtk::Frame(title), m_Button_OK("OK"), m_Button_Cancel("Cancel"), m_Button_Help("Help") { Gtk::ButtonBox* bbox = 0; if(horizontal) bbox = Gtk::manage( new Gtk::ButtonBox(Gtk::ORIENTATION_HORIZONTAL) ); else bbox = Gtk::manage( new Gtk::ButtonBox(Gtk::ORIENTATION_VERTICAL) ); bbox->set_border_width(5); add(*bbox); /* Set the appearance of the Button Box */ bbox->set_layout(layout); bbox->set_spacing(spacing); bbox->add(m_Button_OK); bbox->add(m_Button_Cancel); bbox->add(m_Button_Help); }
8.2.5. Πλέγμα
Μια Grid διευθετεί δυναμικά τα θυγατρικά γραφικά συστατικά σε γραμμές και στήλες. Οι διαστάσεις του πλέγματος δεν χρειάζονται να οριστούν στον κατασκευαστή.
Τα θυγατρικά γραφικά συστατικά μπορούν να καλύψουν πολλαπλές γραμμές ή στήλες, χρησιμοποιώντας την attach(), ή να προστεθούν δίπλα σε ένα υπάρχον γραφικό συστατικό μέσα στο πλέγμα με την attach_next_to(). Μεμονωμένες γραμμές και στήλες του πλέγματος μπορούν να οριστούν ώστε να έχουν ομοιόμορφο ύψος ή πλάτος με τις set_row_homogeneous() και set_column_homogeneous().
Μπορείτε να ορίσετε τις ιδιότητες περιθωρίου και επέκτασης των θυγατρικών Widgets ώστε να ελέγχουν το διάκενό τους και τη συμπεριφορά τους, όταν το πλέγμα αυξομειώνεται.
- 8.2.5.1. Παράδειγμα
8.2.5.1. Παράδειγμα
Αυτό το παράδειγμα δημιουργεί ένα παράθυρο με τρία κουμπιά σε ένα πλέγμα. Τα πρώτα δύο κουμπιά είναι στην ανώτερη γραμμή, από αριστερά προς τα δεξιά. Ένα τρίτο κουμπί προσαρτάται κάτω από το πρώτο κουμπί, σε μια χαμηλότερη γραμμή, καλύπτοντας δύο στήλες.
File: examplewindow.h (For use with gtkmm 3, not gtkmm 2)
#ifndef GTKMM_EXAMPLEWINDOW_H #define GTKMM_EXAMPLEWINDOW_H #include <gtkmm.h> class ExampleWindow : public Gtk::Window { public: ExampleWindow(); virtual ~ExampleWindow(); private: // Signal handlers: void on_button_quit(); void on_button_numbered(const Glib::ustring& data); // Child widgets: Gtk::Grid m_grid; Gtk::Button m_button_1, m_button_2, m_button_quit; }; #endif /* GTKMM_EXAMPLEWINDOW_H */
File: examplewindow.cc (For use with gtkmm 3, not gtkmm 2)
#include <iostream> #include "examplewindow.h" ExampleWindow::ExampleWindow() : m_button_1("button 1"), m_button_2("button 2"), m_button_quit("Quit") { set_title("Gtk::Grid"); set_border_width(12); add(m_grid); m_grid.add(m_button_1); m_grid.add(m_button_2); m_grid.attach_next_to(m_button_quit, m_button_1, Gtk::POS_BOTTOM, 2, 1); m_button_1.signal_clicked().connect( sigc::bind<Glib::ustring>( sigc::mem_fun(*this, &ExampleWindow::on_button_numbered), "button 1") ); m_button_2.signal_clicked().connect( sigc::bind<Glib::ustring>( sigc::mem_fun(*this, &ExampleWindow::on_button_numbered), "button 2") ); m_button_quit.signal_clicked().connect(sigc::mem_fun(*this, &ExampleWindow::on_button_quit) ); show_all_children(); } ExampleWindow::~ExampleWindow() { } void ExampleWindow::on_button_quit() { hide(); } void ExampleWindow::on_button_numbered(const Glib::ustring& data) { std::cout << data << " was pressed" << std::endl; }
File: main.cc (For use with gtkmm 3, not gtkmm 2)
#include "examplewindow.h" #include <gtkmm/application.h> int main(int argc, char *argv[]) { Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.example"); ExampleWindow window; // Shows the window and returns when it is closed. return app->run(window); }
8.2.6. Πίνακας
Η Gtk::Table επιτρέπει την τοποθέτηση γραφικών συστατικών σε ένα πλέγμα, παρόμοιο με Gtk::Grid.
Η Gtk::Table είναι παρωχημένη από την έκδοση 3.4 της gtkmm και δεν πρέπει να χρησιμοποιηθεί σε νέο κώδικα. Χρησιμοποιήστε Gtk::Grid στη θέση του.
8.2.7. Σημειωματάριο
Μια A Notebook έχει ένα σύνολο στοιβαγμένων pages (σελίδων), που καθεμιά τους περιέχει γραφικά συστατικά. Με ετικέτα tabs (καρτέλες) επιτρέπει στον χρήστη να επιλέξει τις σελίδες. Οι Notebooks επιτρέπουν αρκετά σύνολα γραφικών συστατικών να τοποθετηθούν σε μικρό χώρο, εμφανίζοντας μόνο μια σελίδα τη φορά. Για παράδειγμα, χρησιμοποιούνται συχνά σε διαλόγους προτιμήσεων.
Χρησιμοποιήστε τις μεθόδους append_page(), prepend_page() και insert_page() για την προσθήκη σελίδων με καρτέλες στο Notebook (σημειωματάριο), παρέχοντας στο θυγατρικό γραφικό συστατικό και το όνομα για την καρτέλα.
Για να βρείτε την τρέχουσα ορατή σελίδα, χρησιμοποιήστε τη μέθοδο get_current_page(). Αυτή επιστρέφει τον αριθμό της σελίδας και έπειτα καλώντας την get_nth_page() με αυτόν τον αριθμό θα σας δώσει έναν δείκτη στο ενεργό θυγατρικό γραφικό συστατικό.
Για προγραμματιστική αλλαγή της επιλεγμένης σελίδας, χρησιμοποιήστε τη μέθοδο set_current_page().
- 8.2.7.1. Παράδειγμα
8.2.7.1. Παράδειγμα
File: examplewindow.h (For use with gtkmm 3, not gtkmm 2)
#ifndef GTKMM_EXAMPLEWINDOW_H #define GTKMM_EXAMPLEWINDOW_H #include <gtkmm.h> class ExampleWindow : public Gtk::Window { public: ExampleWindow(); virtual ~ExampleWindow(); protected: //Signal handlers: void on_button_quit(); void on_notebook_switch_page(Gtk::Widget* page, guint page_num); //Child widgets: Gtk::Box m_VBox; Gtk::Notebook m_Notebook; Gtk::Label m_Label1, m_Label2; Gtk::ButtonBox m_ButtonBox; Gtk::Button m_Button_Quit; }; #endif //GTKMM_EXAMPLEWINDOW_H
File: examplewindow.cc (For use with gtkmm 3, not gtkmm 2)
#include <iostream> #include "examplewindow.h" ExampleWindow::ExampleWindow() : m_VBox(Gtk::ORIENTATION_VERTICAL), m_Label1("Contents of tab 1"), m_Label2("Contents of tab 2"), m_Button_Quit("Quit") { set_title("Gtk::Notebook example"); set_border_width(10); set_default_size(400, 200); add(m_VBox); //Add the Notebook, with the button underneath: m_Notebook.set_border_width(10); m_VBox.pack_start(m_Notebook); m_VBox.pack_start(m_ButtonBox, Gtk::PACK_SHRINK); m_ButtonBox.pack_start(m_Button_Quit, Gtk::PACK_SHRINK); m_Button_Quit.signal_clicked().connect(sigc::mem_fun(*this, &ExampleWindow::on_button_quit) ); //Add the Notebook pages: m_Notebook.append_page(m_Label1, "First"); m_Notebook.append_page(m_Label2, "Second"); m_Notebook.signal_switch_page().connect(sigc::mem_fun(*this, &ExampleWindow::on_notebook_switch_page) ); show_all_children(); } ExampleWindow::~ExampleWindow() { } void ExampleWindow::on_button_quit() { hide(); } void ExampleWindow::on_notebook_switch_page(Gtk::Widget* /* page */, guint page_num) { std::cout << "Switched to tab with index " << page_num << std::endl; //You can also use m_Notebook.get_current_page() to get this index. }
File: main.cc (For use with gtkmm 3, not gtkmm 2)
#include "examplewindow.h" #include <gtkmm/application.h> int main(int argc, char *argv[]) { Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.example"); ExampleWindow window; //Shows the window and returns when it is closed. return app->run(window); }
8.2.8. Βοηθός
Μια Assistant χωρίζει μια σύνθετη λειτουργία σε βήματα. Κάθε βήμα είναι μια σελίδα, που περιέχει μια κεφαλίδα, ένα θυγατρικό γραφικό συστατικό και μια περιοχή ενέργειας. Η ενέργεια του βοηθού έχει πλήκτρα περιήγησης που ενημερώνουν αυτόματα ανάλογα με τον τύπο της σελίδας, που ορίστηκε με set_page_type().
Χρησιμοποιήστε τις μεθόδους append_page(), prepend_page και insert_page() για την προσθήκη σελίδων στη Assistant, παρέχοντας το θυγατρικό γραφικό συστατικό για κάθε σελίδα.
Για τον προσδιορισμό της τρέχουσας ορατής σελίδας, χρησιμοποιήστε τη μέθοδο get_current_page() και περάστε το αποτέλεσμα στη get_nth_page(), που επιστρέφει έναν δείκτη στο ενεργό γραφικό συστατικό. Για προγραμματιστική αλλαγή της τρέχουσας σελίδας, χρησιμοποιήστε τη μέθοδο set_current_page().
Για τον ορισμό του τίτλου μιας σελίδας, χρησιμοποιήστε τη μέθοδο set_page_title(). Η κεφαλίδα και οι πλευρικές εικόνες μιας σελίδας μπορούν να οριστούν με τις μεθόδους set_page_header_image() και set_page_side_image().
Για την προσθήκη γραφικών συστατικών σε μια περιοχή ενέργειας, χρησιμοποιήστε τη μέθοδο add_action_widget(). Θα συσκευαστούν δίπλα στα προεπιλεγμένα κουμπιά. Χρησιμοποιήστε τη μέθοδο remove_action_widget() για αφαίρεση των γραφικών συστατικών.
- 8.2.8.1. Παράδειγμα
8.2.8.1. Παράδειγμα
File: examplewindow.h (For use with gtkmm 3, not gtkmm 2)
#ifndef GTKMM_EXAMPLEWINDOW_H #define GTKMM_EXAMPLEWINDOW_H #include "exampleassistant.h" #include <gtkmm.h> class ExampleWindow : public Gtk::Window { public: ExampleWindow(); virtual ~ExampleWindow(); private: // Signal handlers: void on_button_clicked(); void on_assistant_apply(); // Child widgets: Gtk::Grid m_grid; Gtk::Button m_button; Gtk::Label m_label1, m_label2; Gtk::CheckButton m_check; Gtk::Entry m_entry; ExampleAssistant m_assistant; }; #endif /* GTKMM_EXAMPLEWINDOW_H */
File: exampleassistant.h (For use with gtkmm 3, not gtkmm 2)
#ifndef GTKMM_EXAMPLEASSISTANT_H #define GTKMM_EXAMPLEASSISTANT_H #include <gtkmm.h> class ExampleAssistant : public Gtk::Assistant { public: ExampleAssistant(); virtual ~ExampleAssistant(); void get_result(bool& check_state, Glib::ustring& entry_text); private: // Signal handlers: void on_assistant_apply(); void on_assistant_cancel(); void on_assistant_close(); void on_assistant_prepare(Gtk::Widget* widget); void on_entry_changed(); // Member functions: void print_status(); // Child widgets: Gtk::Box m_box; Gtk::Label m_label1, m_label2; Gtk::CheckButton m_check; Gtk::Entry m_entry; }; #endif /* GTKMM_EXAMPLEASSISTANT_H */
File: examplewindow.cc (For use with gtkmm 3, not gtkmm 2)
#include "examplewindow.h" #include "exampleassistant.h" ExampleWindow::ExampleWindow() : m_button("Show the assistant"), m_label1("State of assistant checkbutton:"), m_label2("Contents of assistant entry:") { set_title("Gtk::Assistant example"); set_border_width(12); m_grid.set_row_homogeneous(true); m_grid.attach(m_button, 0, 0, 2, 1); m_button.set_hexpand(true); m_button.set_valign(Gtk::ALIGN_CENTER); m_grid.attach(m_label1, 0, 1, 1, 1); m_label1.set_alignment(0.0, 0.5); m_grid.attach(m_label2, 0, 2, 1, 1); m_label2.set_alignment(0.0, 0.5); m_grid.attach(m_check, 1, 1, 1, 1); m_check.set_halign(Gtk::ALIGN_START); m_grid.attach(m_entry, 1, 2, 1, 1); m_entry.set_hexpand(true); add(m_grid); m_button.signal_clicked().connect(sigc::mem_fun(*this, &ExampleWindow::on_button_clicked)); m_assistant.signal_apply().connect(sigc::mem_fun(*this, &ExampleWindow::on_assistant_apply)); m_check.set_sensitive(false); m_entry.set_sensitive(false); show_all_children(); } ExampleWindow::~ExampleWindow() { } void ExampleWindow::on_assistant_apply() { bool check_state; Glib::ustring entry_text; m_assistant.get_result(check_state, entry_text); m_check.set_active(check_state); m_entry.set_text(entry_text); } void ExampleWindow::on_button_clicked() { m_assistant.show(); }
File: exampleassistant.cc (For use with gtkmm 3, not gtkmm 2)
#include <iostream> #include "exampleassistant.h" ExampleAssistant::ExampleAssistant() : m_box(Gtk::ORIENTATION_HORIZONTAL, 12), m_label1("Type text to allow the assistant to continue:"), m_label2("Confirmation page"), m_check("Optional extra information") { set_title("Gtk::Assistant example"); set_border_width(12); set_default_size(400, 300); m_box.pack_start(m_label1); m_box.pack_start(m_entry); append_page(m_box); append_page(m_check); append_page(m_label2); set_page_title(*get_nth_page(0), "Page 1"); set_page_title(*get_nth_page(1), "Page 2"); set_page_title(*get_nth_page(2), "Confirmation"); set_page_complete(m_check, true); set_page_complete(m_label2, true); set_page_type(m_box, Gtk::ASSISTANT_PAGE_INTRO); set_page_type(m_label2, Gtk::ASSISTANT_PAGE_CONFIRM); signal_apply().connect(sigc::mem_fun(*this, &ExampleAssistant::on_assistant_apply)); signal_cancel().connect(sigc::mem_fun(*this, &ExampleAssistant::on_assistant_cancel)); signal_close().connect(sigc::mem_fun(*this, &ExampleAssistant::on_assistant_close)); signal_prepare().connect(sigc::mem_fun(*this, &ExampleAssistant::on_assistant_prepare)); m_entry.signal_changed().connect(sigc::mem_fun(*this, &ExampleAssistant::on_entry_changed)); show_all_children(); } ExampleAssistant::~ExampleAssistant() { } void ExampleAssistant::get_result(bool& check_state, Glib::ustring& entry_text) { check_state = m_check.get_active(); entry_text = m_entry.get_text(); } void ExampleAssistant::on_assistant_apply() { std::cout << "Apply was clicked"; print_status(); } void ExampleAssistant::on_assistant_cancel() { std::cout << "Cancel was clicked"; print_status(); hide(); } void ExampleAssistant::on_assistant_close() { std::cout << "Assistant was closed"; print_status(); hide(); } void ExampleAssistant::on_assistant_prepare(Gtk::Widget* /* widget */) { set_title(Glib::ustring::compose("Gtk::Assistant example (Page %1 of %2)", get_current_page() + 1, get_n_pages())); } void ExampleAssistant::on_entry_changed() { // The page is only complete if the entry contains text. if(m_entry.get_text_length()) set_page_complete(m_box, true); else set_page_complete(m_box, false); } void ExampleAssistant::print_status() { std::cout << ", entry contents: \"" << m_entry.get_text() << "\", checkbutton status: " << m_check.get_active() << std::endl; }
File: main.cc (For use with gtkmm 3, not gtkmm 2)
#include "examplewindow.h" #include <gtkmm/application.h> int main(int argc, char *argv[]) { Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.example"); ExampleWindow window; // Shows the window and returns when it is closed. return app->run(window); }