My first Qt GUI application

People know Qt as a library for creating GUI programs. So what I think your first question might be: How do I create some GUI program with Qt? OK, let's go to do it.

Dialog creation

First we need to create a main window of our application. Go to QTDIR\bin and launch designer.exe. We will probably be faced with New Form Dialog, just click Cancel. Then go to Edit -> User Interface Mode and choose Docked Window (this preference is of course a matter of taste, but for me is essential :-). You can also disable Action/Resources/Signal-slot editor from Tools, we won't need them for now.

Now go File -> New Form and choose Widget and click Create. Your screen should look like this:

First thing you should do is change objectName of this widget to something reasonable, ie. myQtAppDLG.

Then change by giving the window a title, put it in the windowTitle property in Property Editor (ie. My first Qt GUI App).

Your task is to create some form like this:

We use Label, Combo Box, Text Edit, Spin Box, Check Box. Drag and drop appropriate widget from left menu to our form. We name (objectName) Browse button "pushButton_browse", Do something button "pushButton_do"... We'll need object names later when connecting with functions (slots).

To preview form, press Ctrl+R.

Final form: myqtapp.ui. If you open it in a text editor you'll see it's XML.

Application sources

If we are happy with our form, it's time to create header file for this dialog. Open your favorite text editor and save the following lines as myqtapp.h

#ifndef MYQTAPP_H
#define MYQTAPP_H
 
#include "ui_myqtapp.h"
 
 
class myQtApp : public QWidget, private Ui::myQtAppDLG
{
    Q_OBJECT
 
public:
    myQtApp(QWidget *parent = 0);
 
 
public slots:
    void getPath();
    void doSomething();
    void clear();
    void about();
};
 
 
#endif

Let's look at this code line by line.

#ifndef MYQTAPP_H
#define MYQTAPP_H

This macro says if MYQTAPP_H is not defined, then define it and process code. It ensures that we define class only once even if this header is included from multiple sources in our application.

#include "ui_myqtapp.h"

This line is particularly important to understand. Our form created in designer is called myqtapp.ui. Forms in .ui (XML) format are converted during build process into C++ header files by UIC (User Interface Compiler). As Qt documentation says in the UIC documentation: The UIC reads an XML format user interface definition (.ui) file as generated by Qt Designer and creates a corresponding C++ header file.

If your form filename is myform.ui, uic generates ui_myform.h. No matter what name of your class (objectName) is.

It's actually a C++ definition of your dialog. To modify this header file makes no sense because it is recreated during the build process and any changes are lost.

class myQtApp : public QWidget, private Ui::myQtAppDLG

myQtApp is name of our class. myQtAppDLG is class name of the form we created in Designer. This line says our class inherit from QWidget (We have chosen QWidget then creating form. For a dialog based form, QDialog would go here.) and also private from Ui::myQtAppDLG. This is actually our form included from ui_myqtapp.h. It means we can access widgets in our form from member functions of myQtApp class. This is called The Multiple Inheritance Approach in Qt documentation.

There is also an alternative to this approach called The Single Inheritance Approach. Have a look, you may find it more convenient than multiple inheritance approach (but I don't believe it :-).

	Q_OBJECT

This macro expands to some definitions which are needed for signals/slots mechanism (we'll cover this later).

Important note: If Q_OBJECT macro wasn't present and you add it, do not forget to re-run "qmake" to adjust your Makefile. It will probable cause "undefined reference to vtable" errors during compilation. A lot of beginners have problems with this.

public:
    myQtApp(QWidget *parent = 0);

Defines public construtor, every class must have this. QWidget *parent = 0 is an optional argument (myQtApp() constructor would also work). You may wonder what it is good for. Actually this is a customary form of widget constructor. Usually main windows and dialogs have no parent (i.e. parent == 0 ), but if somebody has a dialog that is used frequently (for example a "Find" dialog), he might want to create it once and then he might give it a parent, so that it will be destroyed automatically by Qt.

public slots:
    void getPath();
    void doSomething();
    void clear();
    void about();

Defines some member functions of class called slots. Signals can be connected to these slots (function). When a signal is emitted, the function connected to it will trigger. We will see that later.

Ok, now let's create myqtapp.cpp file (implementation of our class defined in myqtapp.h).

#include <QtGui> 
#include "myqtapp.h"
 
// if we include <QtGui> there is no need to include every class used: <QString>, <QFileDialog>,...
 
myQtApp::myQtApp(QWidget *parent)
{
    setupUi(this); // this sets up GUI
 
    // signals/slots mechanism in action
    connect( pushButton_browse, SIGNAL( clicked() ), this, SLOT( getPath() ) ); 
    connect( pushButton_do, SIGNAL( clicked() ), this, SLOT( doSomething() ) ); 
    connect( pushButton_clear, SIGNAL( clicked() ), this, SLOT( clear() ) ); 
    connect( pushButton_about, SIGNAL( clicked() ), this, SLOT( about() ) ); 
}
 
 
void myQtApp::getPath()
{
    QString path;
    
    path = QFileDialog::getOpenFileName(
        this,
        "Choose a file to open",
        QString::null,
        QString::null);
 
    lineEdit->setText( path );
}
 
 
void myQtApp::doSomething()
{
    int value1, value2;
    Qt::CheckState state;
    QString str;
 
    textEdit->append( "Path to file: " + lineEdit->text() );
 
    value1 = spinBox1->value();
    value2 = spinBox2->value();
 
    textEdit->append( "Number 1 value: " + QString::number(value1) );
    textEdit->append( "Number 2 value: " + QString::number(value2) );
 
    state = checkBox->checkState();
 
    str = "Checkbox says: ";
    if ( state == Qt::Checked ) str += "yes"; 
    else str += "no";
    textEdit->append( str );
 
    textEdit->append( "ComboBox current text: " + comboBox->currentText() );
    textEdit->append( "ComboBox current item: " + QString::number(comboBox->currentIndex()) );
}
 
 
void myQtApp::clear()
{
    textEdit->clear();
}
 
 
void myQtApp::about() 
{
    QMessageBox::about(this,"About myQtApp",
                "This app was coded for educational purposes.\n"
                "Number 1 is: " + QString::number(spinBox1->value()) + "\n\n"
                "Bye.\n");
}

We need to create main.cpp

#include <QApplication>
 
#include "myqtapp.h"
 
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    myQtApp *dialog = new myQtApp;
 
    dialog->show();
    return app.exec();
}

Now we have all we need to create the project file myqtapp.pro

HEADERS     = myqtapp.h 
SOURCES     = myqtapp.cpp main.cpp
FORMS       = myqtapp.ui

# install
target.path = myqtapp
sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS *.pro
sources.path = .
INSTALLS += target sources

It is possible to generate the .pro file automaticly with qmake -project command.

Compilation

Applicaton zipped: my_first_qt_app.zip

Run windows cmd, go to the directory with application sources and type:

qmake
make

After successful compilation and linking, myqtapp.exe will be created in "debug" folder.

Congratulations, you have done your first Qt GUI application!

Things to notice and tips

If you create new form in designer, you can choose from:

Our form is resizeable. You can easily convert the form to unresizeable by setting minimumSize and maximumSize property the same values as geometry.

Forms with QWidget base class have minimize, maximize and close button by default.

You may wish, for example, to disable the maximize button. You can achieve this by setting windows flags. Add these lines to the constructor of myQtApp:

// constructor code
setupUi( this );
 
Qt::WindowFlags flags;
flags = Qt::Window | Qt::WindowMinimizeButtonHint;
setWindowFlags( flags );

Result:

Have a look at Qt doc http://doc.trolltech.com/4.2/qwidget.html#windowFlags-prop

You may want window to start at the center of the screen. This code does the job. Add it after line setupUi( this ); in the constructor.

QDesktopWidget *desktop = QApplication::desktop();
    
int screenWidth, width; 
int screenHeight, height;
int x, y;
QSize windowSize;
 
screenWidth = desktop->width(); // get width of screen
screenHeight = desktop->height(); // get height of screen
 
windowSize = size(); // size of our application window
width = windowSize.width(); 
height = windowSize.height();
 
// little computations
x = (screenWidth - width) / 2;
y = (screenHeight - height) / 2;
y -= 50;
 
// move window to desired coordinates
move ( x, y );