Learn Qt

Teaching Qt® to the world!

Flower

Archive for the ‘Tutorial’ Category

Qt Layouts – The Basics

When designing forms using Qt, you do not place the widgets at static locations. Instead, you place them in layouts. This makes the user interfaces stretchable and allows them to adapt to the current screen and contents.

There are many arguments for using flexible layouts instead of fixed locations – especially if you are planning to use Qt’s cross platform capabilities. Different systems use different fonts and different users prefer different styles.

There are a few common issues that you tend to run into when using fixed locations and sizes. The first example involves a poor translator that needs to work around small widgets by using awkward words. For instance, below, you can see the English word Previous over the Swedish translation Föregående. Let’s just hope for understanding Swedish users – or we can let the button stretch with the text.

Translations that are too large

Translations that are too large.

Another really annoying situation is when the contents of a dialog box simply is too large. For instance, the list of names below. Being able to stretch the dialog and see the full names could really help.

Too large contents.

Too large contents.

So, how do you get started with layouts? First, let’s look at the four basic types of layouts available.

Horizontal layouts simply places the contained widgets next to each other in a horizontal line.

Horizontal layout.

Horizontal layout.

Vertical layouts places the contained widgets over each other in a vertical line.

Vertical layout.

Vertical layout.

Grid layouts lets you place your widgets in a stretchable grid. You can even have widget spanning over several rows and columns.

Grid layout.

Grid layout.

Form layout is used when creating property forms. This is a special case of the grid layout with only two columns. The alignment of the labels as well as the sizing of the actual fields to fill out depends on the platform. For instance, the picture below shows the GTK+ and Plastique style (look at the labels and the size of the QComboBox).

Form layout in GTK+ and Plastique styles.

Form layout in GTK+ and Plastique styles.

You find these four in the Designer toolbar in QtCreator. So, how do you design a form using layouts? I prefer to place the widgets roughly as I want them, then to apply layouts from the inside out. That means, starting with then inner group boxes and frames, working my way out until I finally apply a layout to the form itself.

Let’s look at an example. First, the widgets are placed.

Widgets with rough placement in the form.

Widgets with rough placement in the form.

The next step is to apply a vertical layout to the group box. Simply select the group box in the form and apply the layout using the toolbar button.

The group box has been layed out.

The group box has been laid out.

Then, we apply a grid layout to the dialog. Make sure to stretch the group box to make it wider before selecting the form itself and applying the layout. If you don’t stretch the dialog, it will not span both columns, meaning that you’ll have an empty upper right corner.

The form has been layed out.

The form has been laid out.

As you can tell from the picture above, this does not give us a perfect result. There is one more thing to keep in mind. An important factor that you need to master is the use of spacers (the springs in the widget box). They work just as invisible springs, so they have a big impact on how dialogs stretch.

Let’s break the layout of the form. Simply select the form and click the break layout button in the toolbar. Then we add some springs to the dialog. We need one vertical spring to keep the group box from expanding too much, and one horizontal spring to keep the buttons from growing too wide.

fact-logoDo not use the layouts in the widget box, instead, place widgets on the form and apply layouts. This is usually much easier.

Then we have places the buttons together with the horizontal spring in a horizontal layout (simply drag to select multiple widgets, or press shift and click). Before applying a vertical layout to the entire form.

Springs have been strategicly added.

Springs have been strategicly added.

The result is a stretchable dialog that looks good both small and large.

Small.

Small.

Large.

Large.

There is more to this topic – size policies being the most important factor not mentioned here. We will return to the subject later on. In the mean time, practice on creating dialogs using layouts. It is a craft and you need to practice to master it.

The Qt Build System

One aspect of using Qt is to understand how it works. Signals and slots are great – and there are more nice features: resources, properties, meta types, etc. What is important here is that Qt is still all about C++. Writing a Qt application means writing a C++ application – Qt does not change the language.

So, how does all of this work? Let’s start by having a look at how a C++ application is built.

The C++ build system

The C++ build system

The source code of a C++ application can be divided into headers (*.h) and sources (*.cpp). There are other extensions such as hxx, hpp, hh, cc, cxx and so on, but I hope that you get the picture. The headers are included by the sources, the sources are compiled into objects and these objects are linked to a executable (or library, etc).

So, what does Qt add to this to let us write nice things as signals and slots? First, macros, meaning that what you write is transformed into plain vanilla C++. Secondly, code generators, completing your application with the C++ code needed to make things work smoothly. Let’s start by looking at the big picture.

The Qt build system

The Qt build system

Comparing the C++ build system to the Qt build system, you can see that the C++ build system, i.e. the gray boxes, are left unmodified. We are still building C++ code here. However, we add more sources and headers. There are three code generators involved here:

The meta-object compiler (moc in the illustration) – the meta-object compiler takes all classes starting with the Q_OBJECT macro and generates a moc_*.cpp C++ source file. This file contains information about the class being moc’ed such as class name, inheritance tree, etc, but also implementation of the signals. This means that when you emit a signal, you actually call a function generated by the moc.

The user interface compiler (uic in the illustration) – The user interface compiler takes designs from Designer and creates header files. These header files are then included into source files as usual, making it possible to call setupUi to instanciate a user interface design.

The Qt resource compiler (rcc in the illustration) – The resource compiler is something we have not talked about yet. It makes it possible to embedd images, text files, etc into your executable, but still to access them as files. We will look at this later, I just want to include it in this picture where it belongs.

I hope these two illustrations clarifies what Qt really does to add new nice keywords to C++. If you are curious – feel free to read some of the generated files. Just don’t alter them – they are regenerated each time you build your application.

fact-logoIf you are using QtCreator, the moc files are generated in the debug and release sub-directories of your project directory. The uic files are stored in the root of the project directory. The rcc files are generally boring, but I’m sure that you can find them in your project directory hierarcy somewhere.

A First Look at Signals and Slots

Signals and slots is one of the key components that makes Qt unique. It allows you to connect events to slots so that you can react to button clicks, checkboxes being checked, text being edited – but also to values being changed, timers timing out, and so much more.

To make your Qt application do something, all you have to do is to connect signals to slots. This can be done in three ways. Last time we had a look at two of them, lets repeat:

Connecting by name. This means naming the slot on_widget_signal. This connection is made when you call setupUi and lets you connect simple triggering events to a slot. The slot’s name isn’t always the best from a readability and reusability standpoint, but it is quick and easy. Also, you can make this type of connections by right clicking in the Designer view of QtCreator.

Connecting using the connect method. By specifying a signal source object, the signal name, a destination object and a slot name you can connect any signal to any slot.

Then, there is the last way:

Connecting using Designer. This is when you actually “draw” your connections in Designer, and this is what we will look at today.

The last blog entries have been using the QtCreator wizard’s QMainWindow based template. This time around, we will use th QWidget based template. To create such a project, simply run through the wizard for creating a new Qt 4 Gui project and make sure to use a QWidget instead of a QMainWindow as the base class.

widget-tempate

Creating a GUI project based on a QWidget.

Then located with widget.ui file and double click it to open the Designer view. Here, drag and drop a QPushButton onto the widget and change its text to “Close”. You can either right click and choose to change its text, or you simply double click it and edit the text in place.

A widget with a QPushButton.

A widget with a QPushButton.

This gives you a basic widget to work from. Now comes the fun part. Until now, you’ve been working in the widget editing mode of Designer. Now it is time to edit some signals and slots, so locate the mode changing buttons in the tool bar and switch to the signals/slots editing mode.

The edit signals/slots working mode.

The edit signals/slots working mode.

In this working mode, Designer no longer lets you move widgets about. Instead, you can drag (click and hold) from one widget to another to make a signal/slot connection. Start by dragging from the QPushButton to the QWidget itself (the actual form).

Dragging from the button to the widget.

Dragging from the button to the widget.

When you release the button, a dialog showing the available signals will appear. Pick the clicked() signal and connect it to the close() slot. You will have to check the show signals and slots inherited from QWidget check box in order to see the slot.

Connecting a signal to a slot (notice the checked box).

Connecting a signal to a slot (notice the checked box).

That was it – you’ve made a connection. Save the widget.ui file and build and run the application and you can test your button.

Making it Work

So, the last time around, we had a look at the template application generated by QtCreator. This time I promised that it would do something. All this starts in the designer view of QtCreator (you get there by double clicking on mainwindow.ui). Lets go through the different parts of the window one by one, just so that you get a grip of what’s going on.

qtcreator-designer-details

The parts of the Designer in QtCreator.

The widget list is where all the available widgets are shown. It can be shown in two modes – list mode and icon mode. I prefer the icon mode (used in the picture) but the list mode can be better when you are getting started. Simply right click to get a menu where you can change the mode. To add a widget to your form, simply drag from here and drop it where you want it.

The properties shows the settings for the current widget. Try selecting a widget in your form, or even the form it-self, and you get a whole bunch of properties that you can tweak here.

The object hierarcy shows how everything relates to each other. For instance, all widgets will be placed within your QMainWindow instance (called MainWindowClass). If you use group boxes or tabbed interfaces, you will see that your widgets are placed in a hierarcy tree here.

The action list contains actions, which is a special class, making it possible to use the same object in a toolbar, menubar and keyboard short-cuts. This is really convenient when building classic desktop applications.

The Designer toolbar is simply the toolbar beloning to the Designer, which is the tool that you are using when editing .ui files. Here, you can change between the working modes of designer (edit, connections, buddies and tab order), as well as applying and breaking up layouts.

Encircled by all these docked lists and toolbars is your form, the main window, dialog or widget that you actually are designing. In this case, we are working with a main window.

fact-logoWhat is the difference between a widget, dialog and main window then? Everything visible on screen is a widget. This includes buttons, labels, group boxes as well as top-level windows. So what does a dialog or a main window bring in addition to this? The dialog can be used in a modal (that is blocking) way, i.e. you show the dialog and wait for a result. A main window can be used to dock windows into, can have a tool bar, menu bar and a status bar. Then the question – when do I create a widget then? You can either create it to join together a set of widgets and use them to populate dialogs, main windows and other widgets, or you can use a widget as a base for a simple window, where you don’t need the extra bells and whistles of the main window.

So, the goal of today is to get the application to actually do something. We will split this into two sub-goals: run some code of our own and to make a connection to one of Qt’s slots. The first step to achieve this is to add some actions for the user to use to trigger our application.

In the menu bar of the form it says “Type Here”. Double click at the text and write “File”. This lets you open the menu and type more. Create two entries – “Exit” and “Hello Qt”. Each of these entries will appear as actions in the action list. There you can associate them with keyboard short-cuts and change texts and icons (icons requires resources, which we have not looked at yet, so just skip that part for now).

qtcreator-action-menuitems

The menu items have been added.

For the actionHello_Qt action, right click and select Go to slot…. A list of signals now appears. Pick triggered() from that list. This will bring you to mainwindow.cpp, in a method called on_actionHello_Qt_triggered. This method will be executed when the user triggers the action.

qtcreator-action-go-to-slot

Choose to go to slot... for the actionHello_Qt.

In the slot, we simply change the title of the window to read “Hello Qt!” using the code below. Now, try building your application and run it. Choosing the “Hello Qt” menu entry will change the title of the window. So, mission accomplished, the application now does something.

void MainWindow::on_actionHello_Qt_triggered()
{
  setWindowTitle( tr("Hello Qt!") );
}

fact-logoWhy did we just put the string in a the tr function? This has to do with the internationalizations tools that Qt provides. We will look at this at a later point, for now, just try to keep in mind that all strings that are shown to the users should be enclosed in a tr-call.

The actionHello_Qt‘s triggered signal was automatically connected to the slot that we provided. This might be conventient in many situations, but I prefer to give my slots names from what they do, not what they are connected to. This not only makes the code more readable, it also allows me to re-use the same slot for several signals.

In order to be able to do this, one must make the connections manually and this is what I intend to do for the actionExit. Looking at the constructor below, we find all user interface elements defined using Designer through the ui member variable. Before the elements of the ui variable are valid, we must call the setupUi function. Just after that call is the natural place to make manual connections as well as populating and initializing a user interface.

In this case we connect the triggered() signal from the actionExit user interface element to the close slot of this, i.e. the window. This simply means that when the user activates the exit action, the window will close, thus exiting the application. As the close slot is called close and not on_actionExit_triggered, we must make the connection manually. Naming the slot close not only forces us to make a manual connection, it also makes the use of the slot more clear – especially when called from within other code as an ordinary member function.

MainWindow::MainWindow(QWidget *parent)
  : QMainWindow(parent), ui(new Ui::MainWindowClass)
{
  ui->setupUi(this);

  connect( ui->actionExit, SIGNAL(triggered()), this, SLOT(close()) );
}

This concludes the activities for today. Next time I plan to look more in depth at signals and slots.

Disecting Your First Application

Last time, you installed QtCreator and then generated your first application. It everything worked out ok, you should now have your very own, completely empty QMainWindow on the screen. That is all great, but what did you really do? Let’s go through the generated code so that you understand what really happened.

Your very first Qt application.

Your very first Qt application.

The application consists of one class and a main function to get everything going. Let’s start by having a look at the main function show below.

main.cpp

#include <QtGui/QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  MainWindow w;
  w.show();
  return a.exec();
}

What it does is that is creates an instance of QApplication. Every Qt application needs one, and only one, QApplication instance. It represents the application it self and contains the main event-loop.

fact-logoWhat is an event-loop? you might ask. It is just what it sounds like – a loop waiting for events. For instance keyboard presses, mouse activity, network packages, timer event, etcetera. The event-loop collectes these events and passes them to the appropriate receiver. This could be the widget in focus, a QTcpSocket instance waiting for a package, a QTimer object, and so on. This means that you do not have to write a loop waiting for events, instead, you let Qt handle it and pass it to your objects.

When the QApplication has been created, a MainWindow is created. This is your class – we’ll look at it later on. The MainWindow is then shown before the exec method of the application is called. When calling exec, the event-loop is entered and the application comes to life.

So, what about the MainWindow class? The entire class declaration is show below, but lets focus on one part at a time.

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtGui/QMainWindow>

namespace Ui
{
  class MainWindowClass;
}

class MainWindow : public QMainWindow
{
  Q_OBJECT

public:
  MainWindow(QWidget *parent = 0);
  ~MainWindow();

private:
  Ui::MainWindowClass *ui;
};

#endif // MAINWINDOW_H

The header file starts with the inclusion of the base class, QMainWindow, and the forward declaration of the Ui::MainWindowClass.

fact-logoForward declarations is a way to tell the C++ compiler that there is a class with a name. We can use this name to define pointers, but not to work with the class itself. When working with the class, we must first include the actual class declaration. How can we define pointers to a class that has not been properly declared then? All pointers are the same size (one memory address), so the compiler can still allocate enough memory for it regardless of what it points to. And what’s the point? We don’t have to include a reference to another headerfile in our header file. This saves opening a file and parsing it when compiling, thus improving build time performance.

When the inclusions and forward declarations are done our class, the MainWindow, is declared. It inherits QMainWindow and has a constructor, a destructor and a pointer to a member ui, of the type Ui::MainWindowClass. Nothing odd about this. The constructor makes it possible to pass a parent widget to our class. One more thing, the first line of the class declaration contains the macro Q_OBJECT. We will look closer at this in a later blog post. For now, just remember that it is important to have it there as soon as you inherit QObject directly or indirectly (QMainWindow inherits QWidget that inherits QObject – you can find this just at the top of the documentation page for each class, the line starting with “Inherits…”).

So, over the the MainWindow implementation. The first couple of lines are just includes the MainWindow header file and the ui_mainwindow.h header file. The latter contains the Ui::MainWindowClass class. The file is actually generated from the mainwindow.ui file that we will look at later on. To give you the big picture, the .ui file is created by “painting” the user interface visually. This is where that design enters the code so that you can actually do something with it.

mainwindow.cpp – part 1

#include "mainwindow.h"
#include "ui_mainwindow.h"

After the includes follows the constructor and destructor. All they do is that they create and delete the ui member variable. The constructor also passes its arguments to the parent class and calls ui->setupUi, passing itself (this) to the function as an argument. This creates the designed user interface inside the MainWindow.

mainwindow.cpp – part 2

MainWindow::MainWindow(QWidget *parent)
  : QMainWindow(parent), ui(new Ui::MainWindowClass)
{
  ui->setupUi(this);
}

MainWindow::~MainWindow()
{
  delete ui;
}

So, finally, I spoke of painting the user interface, creating the .ui file. Try double clicking the mainwindow.ui file in the QtCreator file list. This will show you something like the view below. This is the Designer view of QtCreator, where you can drag, drop and fiddle around with your user interface designs.

The Designer view of QtCreator.

The Designer view of QtCreator.

Actually getting a design in place and making it do something is what we will look at in the next installment. Hope to see you then!

Getting Qt

Before you can start learning Qt, you need to download it. The easiest way to do this is to visit http://www.qtsoftware.com and visit their download section. The most likely download you want to make if you’re new to Qt is the open source SDK. It includes everything and can be downloaded for free.

The SDK download page at Qt Software.

The SDK download page at Qt Software.

You’ll find different versions for different platforms – simply pick the one suitable for you. Or, if you’re on Linux, check to see if your distribution has it prepackaged.

Linux TipsAre you running Linux and are unsure about your platform being 32-bit or 64-bit? Simply run uname -m from the console. If the output contains i386 or i686, you’re running 32-bit Linux. If it contains x86_64 or 64bit, then you’re running 64-bit Linux.

Now, all you have to do is to step through the installer to install QtCreator, the latest version of Qt along with all the tools.

fact-logoRunning the installer can be tricky. For instance, on Linux, you might have to make the file run-able by applying chmod +x on it. On Vista, you need to ensure that you have write permissions in the directory where the installer is placed (so that it can extract itself).

As soon as QtCreator is installed, launch it (there should be a desktop shortcut, a start menu entry, or you can simply run it from the command prompt – the choices are endless). This will bring you to the front page shown below (you will probably not have any projects to choose from though).

The QtCreator frontpage.

The QtCreator frontpage.

The front page lets you go through the getting started guide. Do that – it is valuable reading. You can also check out the QtCreator videos posted by Qt Software at YouTube.

When you have looked at videos and browsed the documentation, it is time to actually try your install. Start by selecting File – New…, then create a Qt4 Gui Application.

Creating a Gui Project using QtCreator.

Creating a Gui Project using QtCreator.

The project will be generated from a wizard. Simply go through it, changing as little as possible along the way. This means specifying where your project should reside, click Next tree times and then clicking Finish.

This project should build out of the box, so simply click the big green arrow in the lower left corner (the one without a small bug on it) and wait. In a couple of seconds you should be faced with an empty window titled MainWindow. Congratulations – you’ve just build a Qt application!

Your very first Qt application.

Your very first Qt application.

You are currently browsing the archives for the Tutorial category.