Autore: Fabio Di Matteo
Ultima revisione: 17/02/2018 - 17:01
Gtkmm è l'interfaccia C++ ufficiale del popolare toolkit grafico GTK+. Include le typesafe callback e un completo set di widget facilmente estendibili grazie all'ereditarietà (tratto da wikipedia).
In questo tutorial andremo a vedere come realizzare una finestra con un bottone , che al click incrementa il contenuto di una label. Come da figura. l'interfaccia grafica realizzata con Glade verra' caricata dal file gui.ui .
main.cc
#include <gtkmm.h> #include "mainwindow.hpp" int main(int argc, char *argv[]) { auto app = Gtk::Application::create(argc, argv, "org.gtkmm.example"); mainWindow mainw; return app->run(*mainw.window1); }
mainwindow.hpp
#ifndef MAINWINDOW_HPP #define MAINWINDOW_HPP #include <gtkmm.h> class mainWindow { public: Glib::RefPtr<Gtk::Builder> builder; Gtk::Window *window1; Gtk::Button *button1; Gtk::Label *label1; mainWindow(); protected: void on_button_clicked(); private: /* add your private declarations */ }; #endif /* MAINWINDOW_HPP */
mainwindow.cpp
#include "mainwindow.hpp" #include <iostream> mainWindow::mainWindow() { auto builder = Gtk::Builder::create(); try { builder->add_from_file("gui.ui"); } catch(const Glib::FileError& ex) { std::cerr << "FileError: " << ex.what() << std::endl; } catch(const Glib::MarkupError& ex) { std::cerr << "MarkupError: " << ex.what() << std::endl; } catch(const Gtk::BuilderError& ex) { std::cerr << "BuilderError: " << ex.what() << std::endl; } builder->get_widget("window1", window1); builder->get_widget("button1", button1); builder->get_widget("label1", label1); button1->signal_clicked().connect( sigc::mem_fun(*this, &mainWindow::on_button_clicked) ); } void mainWindow::on_button_clicked() { static int c; c++; label1->set_text("You have clicked "+std::to_string(c)+" times!"); }
makefile
all: g++ mainwindow.cpp main.cc `pkg-config gtkmm-3.0 --cflags --libs` -o simple
gui.ui
<?xml version="1.0" encoding="UTF-8"?> <!-- Generated with glade 3.20.2 --> <interface> <requires lib="gtk+" version="3.20"/> <object class="GtkWindow" id="window1"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkBox"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="orientation">vertical</property> <child> <object class="GtkLabel" id="label1"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">You have clicked 0 times</property> <attributes> <attribute name="scale" value="5"/> </attributes> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkButton" id="button1"> <property name="label" translatable="yes">Cliccami</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">1</property> </packing> </child> <child> <placeholder/> </child> </object> </child> <child type="titlebar"> <placeholder/> </child> </object> </interface>
La struttura del progetto:
. ├── compile_resources.sh ├── main.cc ├── mainwindow.cpp ├── mainwindow.hpp ├── meson.build ├── res │ ├── gui.ui │ └── resources.xml └── resources.cpp
meson.build
project('GTKmm', 'cpp') gtkmm = dependency('gtkmm-3.0') os=build_machine.system() if os == 'linux' executable('simple-meson', 'main.cc','resources.cpp','mainwindow.cpp', dependencies : gtkmm) endif if os == 'windows' executable('simple-meson', 'main.cc','resources.cpp','mainwindow.cpp', dependencies : gtkmm, link_args : ['-mwindows']) endif
main.cpp
#include <gtkmm.h> #include "mainwindow.hpp" int main(int argc, char *argv[]) { auto app = Gtk::Application::create(argc, argv, "org.gtkmm.example"); mainWindow mainw; return app->run(*mainw.window1); }
mainwindow.hpp
#ifndef MAINWINDOW_HPP #define MAINWINDOW_HPP #include <gtkmm.h> class mainWindow { public: Glib::RefPtr<Gtk::Builder> builder; Gtk::Window *window1; Gtk::Button *button1; Gtk::Label *label1; mainWindow(); protected: void on_button_clicked(); private: /* add your private declarations */ }; #endif /* MAINWINDOW_HPP */
mainwindow.cpp
#include "mainwindow.hpp" #include <iostream> mainWindow::mainWindow() { auto builder = Gtk::Builder::create(); try { builder->add_from_resource("/app/res/gui.ui"); } catch(const Glib::FileError& ex) { std::cerr << "FileError: " << ex.what() << std::endl; } catch(const Glib::MarkupError& ex) { std::cerr << "MarkupError: " << ex.what() << std::endl; } catch(const Gtk::BuilderError& ex) { std::cerr << "BuilderError: " << ex.what() << std::endl; } builder->get_widget("window1", window1); builder->get_widget("button1", button1); builder->get_widget("label1", label1); button1->signal_clicked().connect( sigc::mem_fun(*this, &mainWindow::on_button_clicked) ); } void mainWindow::on_button_clicked() { static int c; c++; label1->set_text("You have clicked "+std::to_string(c)+" times!"); }
compile_resources.sh
#!/bin/bash cd res echo "Building resources.cpp ..." glib-compile-resources --generate-source resources.xml mv resources.c ../resources.cpp
gui.ui
<?xml version="1.0" encoding="UTF-8"?> <!-- Generated with glade 3.20.2 --> <interface> <requires lib="gtk+" version="3.20"/> <object class="GtkWindow" id="window1"> <property name="can_focus">False</property> <child> <object class="GtkBox"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="orientation">vertical</property> <child> <object class="GtkLabel" id="label1"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">You have clicked 0 times</property> <attributes> <attribute name="scale" value="5"/> </attributes> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkButton" id="button1"> <property name="label" translatable="yes">Cliccami</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">1</property> </packing> </child> <child> <placeholder/> </child> </object> </child> <child> <placeholder/> </child> </object> </interface>