Qt Development with Visual Studio .NET

For Windows developers, Qt offers C++ performance, API stability, ease of use, and portability. Thanks to the Qt 4 Visual Studio Integration, it is now easier than ever for Windows developers to write cross-platform, high-performance C++ GUI applications using their favorite IDE.

Overview of the Qt Visual Studio Integration

Qt Designer in Visual Studio The Qt 4 GUI project wizard Integrated documentation

The Visual Studio integration, introduced with Qt 4.0, takes advantage of Visual Studio's highly extensible architecture to make C++ application development on Windows faster, easier, and more intuitive than ever before. The integration includes the following features:

Example: A Regexp Tester Application

To illustrate how the Visual Studio integration works, we are going to present and explain a very small application that lets the user try out a regular expression. The application, depicted below, is a dialog box with three QLabels, three QLineEdits, and two QPushButtons. The user can enter a regular expression pattern and some text on which the regular expression should be run; the part of the text that matches is shown in the lower-most QLineEdit.

The RegExp Tester application

The first step is to create a skeleton project. To do so, we invoke the New Project dialog in Visual Studio and click the Qt Projects folder. Then we select the Qt Application item and type "RegExpTester" as the project name. This pops up the Qt Application wizard.

Starting a new project

The wizard includes a page to let us specify which Qt modules we want to link against, followed by a page that enables us to specify the name of the skeleton class that will be generated by the wizard. For our example, we need to change the base class of the generated class so that it is QDialog rather than QMainWindow.

We will now create the dialog using the integrated Qt Designer form editor. To invoke the form editor, we click on the regexptester.ui file in the Visual Studio Solution Explorer. Then we drag the widgets we need from the Qt Toolbox onto the form and position them approximately as shown below.

Composing the user interface in Qt Designer

The next step is to edit the widgets' properties using the Property Browser. The following table lists the properties to set.

WidgetPropertyValue
First labelObjectName"patternLabel"
Text"Pattern:"
Second labelObjectName"textLabel"
Text"Text:"
Third labelObjectName"resultLabel"
Text"Result:"
First line editObjectName"patternEdit"
Second line editObjectName"textEdit"
Third line editObjectName"resultEdit"
Editablefalse
First buttonObjectName"resetButton"
Text"Reset"
Second buttonObjectName"closeButton"
Text"Close"

We need to add layouts to the form to make it look better and to make it resizable. First, we need a horizontal layout to position the Reset and Close buttons side by side. We also need a spacer to push the buttons to the right of the layout. To add a spacer, we drag the Vertical Spacer item from the Qt Toolbox onto the form, next to the push buttons. Then we select the spacer and the buttons and click Form Editor|Layout Horizontally from the Qt entry in the menu bar.

The entire window also needs a layout that will take care of positioning the other widgets as well as the button sub-layout. To add this layout, we select the labels, the line edits and the button layout, then click Form Editor|Layout in a Grid. We can click Form Editor|Preview Form at any time to preview the form without compiling it.

So far, the dialog does nothing. Let's start by making the Close button work. Basically, we can connect the button's clicked() signal to the form's accept() slot. This can be done through the form editor:

If we build and run the application now, the Close button will close the window and cause the application to terminate.

Let's now implement the rest of the dialog functionality. We want the contents of the Result line edit to be updated whenever the user edits the text in one of the two other line edits. This is achieved by adding a slot (called updateResult()) to the form and by connecting the two line edits' textChanged() signals to that slot. The signals are emitted whenever the text changes; the connection ensures that the slot is invoked to recompute the Result line edit's contents based on the new text in the Pattern and Text fields.

For that, we need to edit the regexptester.h and regexptester.cpp files that were generated by the Qt Application wizard. Here's the header file, after we added the slot declaration:

    #ifndef REGEXPTESTER_H
    #define REGEXPTESTER_H
    
    #include <QtGui/QDialog>
    #include "ui_regexptester.h"
    
    class RegExpTester : public QDialog
    {
        Q_OBJECT
    
    public:
        RegExpTester(QWidget *parent = 0);
    
    private slots:
        void updateResult();
    
    private:
        Ui::RegExpTesterClass ui;
    };
    
    #endif

The RegExpTester class inherits from QDialog (the class we specified in the project wizard) and represents the entire dialog.

The header file includes a file called ui_regexptester.h. That file is generated by uic based on regexptester.ui, which stores the form we designed using the form editor. The uic-generated ui_regexptester.h file declares a class called Ui::RegExpTester. In the private section of the RegExpTester class, there is a member variable of type Ui::RegExpTester called ui.

The updateResult() slot needs to be implemented and connected to the Pattern and Text line edit's textChanged() signals. This is done in the regexptester.cpp file listed below. The code that needs to be added to the wizard-generated skeleton is shown in bold.

    #include "regexptester.h"
    
    RegExpTester::RegExpTester(QWidget *parent)
        : QDialog(parent)
    {
        ui.setupUi(this);
        connect(ui.patternEdit, SIGNAL(textChanged(QString)),
                this, SLOT(updateResult()));
        connect(ui.textEdit, SIGNAL(textChanged(QString)),
                this, SLOT(updateResult()));
    }
    
    void RegExpTester::updateResult()
    {
       QRegExp regExp(ui.patternEdit->text());
       if (regExp.indexIn(ui.textEdit->text()) != -1) {
           ui.resultEdit->setText(regExp.cap(0));
       } else {
           ui.resultEdit->setText("<no match>");
       }
    }

The constructor calls setupUi() on the Ui::RegExpTester object to create the form's widgets and layouts. Then, we connect the Pattern line edit's textChanged() signal to our updateResult() slot, and we do the same with the Text line edit.

In the updateResult() slot, we apply the regular expression pattern onto the specified text. If the regular expression matches, we show the matched text in the Result line edit; otherwise, we show "<no match>".

Our dialog is almost fully functional. The only remaining issue is that the Reset button still does nothing. The solution is to add a reset() slot and connect it to the Reset button's clicked() signal in the constructor. The slot is implemented as follows:

    void RegExpTester::reset()
    {
        ui.patternEdit->clear();
        ui.textEdit->clear();
        updateResult();
    }

Summary

MFC's future is uncertain, and Microsoft is already preparing to replace its successor, Windows Forms, with WPF ("Avalon"). The uncertainty surrounding these three APIs has alienated many Windows developers, who are now looking at Qt as a more stable alternative. With the Qt 4 Visual Studio Integration, Windows developers can easily leverage their existing skills to develop cross-platform, high-performance object-oriented GUI applications.


This document is licensed under the Creative Commons Attribution-Share Alike 2.5 license.

Copyright © 2006 Trolltech Trademarks