📜 ⬆️ ⬇️

Writing an application on GTK + using C ++ and GTKMM library

Epigraph


Once, my wife asked me to write a simple program for her that can calculate the area of ​​figures, perimeters, and other parameters if there is sufficient data. For example, the area of ​​a triangle is needed, its sides are indicated. Enter the sides, press the button and get the area. Or only the side and two corners are indicated. In general, any data sufficient to calculate the rest.
It is worth noting that I’ve been the last 5 years only a web developer, mostly PHP, although of course sometimes you need to do something in ruby ​​and perl. In general, the language for me is not particularly a problem, the main thing is to understand the meaning of the processes in the computer, and then at least Assembler (once even engaged in disassembling and small patching applications under Windows). But still, when I wrote desktop applications, I don’t remember. But then I decided to write a desktop one, so that my wife would be comfortable using it in the absence of the Internet and did not need to install a web server with PHP on her laptop. In addition, I have long wanted to try my hand at using C ++. Well. My wife is on a laptop Linux Ubuntu. The graphics system is Unity based on Gnome3. And where Gnome is, GTK + is there.
And so it was decided to write a desktop application for Linux using Gtk +. Interesting? Welcome under the cut!

Understanding the GTK + Library


It is worth noting that most libraries and applications in Linux are made using a procedural approach. I have an object-oriented thinking that is so ingrained that without the full use of the OOP, I am terribly uncomfortable. I decided to wrap the function calls of GTK + into my own self-signed classes. Understandably, I did it completely unprofessional, without using C ++ specific constructs. Needless to say, Stroustrup was read by less than half, and all my OOP comes from where I started using it - from PHP. Ugly, but it worked. It was easier to draw elements, display a window, handle events. But still not that. Having implemented the application in this way, I left it for a year. Froze But suddenly I came across the GTKMM library - the official C ++ - interface for the GTK + GUI library. So I took this abandoned application and began to convert it. Naturally, I threw out the main self-written classes, as I replaced them with the GTKMM classes. Here I want to share my experience of acquaintance with this wonderful library with you, my dear readers. So let's get started.
Immediately I apologize for omitting the creation of the interface of our application at the beginning, although I think that it is with the creation of the appearance (or rather the location of the controls on the form, in order to further revive them), but the application has been written and drawn in the first version occurred by calling certain functions. Now it was decided to use GtkBuilder, but more on that later.
Point of entry

The entry point to a C ++ application is the main() function. In our application, it will load our form from the GtkBuilder file, display it, and start the message loop of the application.
Initialize the application
 Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.apmpc.geometry"); 

Next, create our form
 builder = Gtk::Builder::create_from_file(UI_FILE); 

We will bind the form to the class - handler (the class is used its own, which is a successor from the Gtk::Window , so we will use the get_widget_derived method.
 builder->get_widget_derived("MainWindow", appwindow); 

For reference, if you want to describe handlers as functions and do not want to produce classes for a small application, a small form or for religious reasons, you can use an object of the Gtk::Window class, as specified in the documentation, in which case the get_widget method will be used.
Well, the final point - the launch of the application message cycle
 return app->run(*appwindow); 

application

Late, but still slightly describe in more detail the components of the application. It consists of two forms. The first is the main window. On it are located buttons of figures.

Click on the button - choose a shape. Then the second form opens - the shape window.

On the left are the input fields for the values ​​and the result, on the right, the figure of the selected shape. The design took into account the expansion of functionality, the addition of shapes, so the buttons for selecting shapes are created when the main window is started.
For the main form window, the MainWindow class is created, inheriting from the Gtk::Window . In the constructor of this class, the shape buttons are created. The storage of button pointers is the m_pvShapeButtons vector.
 m_pvShapeButtons.push_back(new Gtk::Button(CShape::getShapeName(i+1))); 

For each button, the MainWindow::onShapeButtonClick(int iShape) method is MainWindow::onShapeButtonClick(int iShape)
 m_pvShapeButtons.at(i)->signal_clicked().connect( sigc::bind<int> (sigc::mem_fun( *this, &MainWindow::onShapeButtonClick), (i+1) ) ); 

I need to pass the shape index to the clicked event handling method, since there is a single class for handling the CShape . It contains information about the other classes of shapes that are inherited from the CShape class. They already contain information about data entry fields, names of these fields and formulas for calculation.
Well, do not forget to attach a button to the container and display
 m_pShapeButtonBox->pack_end(*m_pvShapeButtons.at(i)); m_pvShapeButtons.at(i)->show(); 

When you click on the button, we open another window. By index, we define the shape and display the data entry fields. The input field consists of three parts - the Gtk::Box container containing the label Gtk::Label for displaying the name of the input field and the text input field Gtk::Entry . It was decided to combine all this into one class called CEditBox . It will also contain the methods necessary for data input and output with type conversion.

In the ShapeWindow constructor, create the required number of CEditBox for the selected shape. Draw a shape on the right side of the window where the object of the CCanvas class is CCanvas , which is inherited from Gtk::DrawingArea . Drawing occurs on the onDraw event. The shape information is contained in the shape class. The draw method of the shape class calls the CCanvas class CCanvas for drawing graphic primitives (Lines, circles, text)

Conclusion


That's all that I would like to report about my first application on GTK + using GTKMM, and indeed in C ++. All code is on github . Further plans are to make the implementation of the calculation of the parallelogram area, add the ability to collect the debian package and put it on ppa. I will be glad to answer all questions and comments on this article.

UPD. Fixed a functional approach to procedural. As it turned out, the phrase functional approach, or more precisely, functional programming is used in cases when functions are calculated in a mathematical sense, and not functions as subroutines, as I originally thought. For an example, languages ​​which use the functional approach: LISP, Erlang, Scala. C and C ++ are procedural languages.

')

Source: https://habr.com/ru/post/146799/


All Articles