Trang chủ‎ > ‎IT‎ > ‎Programming‎ > ‎GUI Programming‎ > ‎

Throwing MFC Out of Windows

For years, Qt has advertised itself as a better MFC than MFC. Thanks to the Qt 4 Visual Studio Integration, it is now easier than ever for a Windows developer to develop cross-platform, high-performance C++ graphical user interface applications from his favorite IDE.
Wednesday, April 18th, 2007

For years, Qt has advertised itself as a better MFC than MFC. Thanks to the Qt 4 Visual Studio Integration, it is now easier than ever for a Windows developer to develop cross-platform,  high-performance C++ graphical user interface applications from his favorite IDE.

Qt is a C++ application development framework developed by  Trolltech, a Norwegian software company. While Qt mainly focuses on  enabing the development of graphical user interfaces, it also provides excellent support for networking, multithreading, SQL operations (including "i">ODBC), XML, and "i">Unicode.

For Windows developers, Qt offers the following advantages:

*Enhanced C++performance. Qt is written in C/C++ (with parts in assembly language) and is highly-optimized to minimize memory usage and maximize speed. Applications based on Qt are native, compiled C++ applications that outperform those applications developed with
Java and C#.

* Stability. Since its introduction in 1995, Qt has been actively developed and maintained by Trolltech. The current version, Qt 4.1, was released in December 2005 and supports advanced features, such as semi-transparent controls, antialiased drawing, and bidirectional text rendering.

*Ease of use. Qt has a clean, object-oriented, C++ design, and provides a powerful signal and slot mechanism similar to C#’ s events and delegates. Signals and slots are flexible, fully object-oriented and implemented in C++ through a separate tool called moc (the meta-object compiler).

* Portability. Qt provides a uniform application programming interface for Microsoft Windows, from "i">Windows 98 to Windows XP, Mac OS X, Linux, Solaris, HP-UX, IRIX, AIX, and many other Unix variants. Qt’s” write once, compile everywhere” philosophy lets you develop applications on Windows and deploy them later on other platforms.

Internally, Qt emulates the various platforms’ controls using platform-specific APIs such as GDI+ and the Windows XP theming engine. This enables Qt to accurately reproduce the look-and-feel of each supported platform, and allows programmers to extend or customize Qt’s built-in controls by re-implementing virtual functions. It’s even possible to implement a custom style to give all controls a custom look-and-feel, and to distribute it as a plug-in.

Although Qt is cross-platform, it includes a few Windows-specific modules, notably an MFC-to-Qt migration framework and a COM/ActiveX integration (to create and embed ActiveX controls). Today, Qt is used by companies as diverse as AT& T, IBM, NASA and Xerox, and mass-market applications such as Adobe Photoshop Album and Google Earth are developed using it. In addition, the open source edition of Qt is the foundation of KDE,
one of the two major Linux/Unix desktop environments.

Overview of the Qt 4 Visual Studio Integration

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:

*Fully integrated form editor with layout support. Since version 2.2, Qt includes a powerful visual user interface design tool called Qt Designer, with support for automatic layouts and dynamic, XML-based user interfaces. The integration encapsulates Qt Designer in Visual Studio, with Qt properties displayed in the standard Property Browser (see
Figure One).

FIGURE ONE: The integrated form editor

*Wizards for creating new Qt projects. The wizards let you specify the Qt modules you want to use and generate skeleton classes to get you started (see Figure 2).

FIGURE TWO: The Qt Application wizard

*Automated build setup for Qt-specific build steps. Qt includes three tools that generate C++ code behind the scenes: "i">moc (the meta-object compiler), "i">uic (the user interface compiler), and "i">rcc (the resource compiler). These are invoked automatically by the integration when necessary.

*An integrated resource management system. Adding new resources to a Qt project is comparable to adding resources to a standard C++ project. The main difference is that cross-platform "i">.qrc files (Qt resource files) are used rather than Windows .rc files.

*Integrated Qt documentation. Qt’s comprehensive API documentation is integrated with the Visual Studio online help (see Figure Three).

FIGURE THREE: The Qt reference documentation

A Regular Expression Tester

To illustrate how the Visual Studio integration works, let’s create a very small application to let the user try a regular expression against a string. The application, depicted in Figure Four, is a dialog box with three QLabels, three "i">QLineEdits, and two QPushButtons. The user can enter a regular expression pattern and some text on which the regular expression is run; the part of the text that matches is shown in the bottom-most QLineEdit.

FIGURE FOUR: RegExpTester application

The first step is to create a skeleton project. Invoke the New Project dialog in Visual Studio and click the Qt Projects folder (see Figure Five). Next, select the Qt Application item and type” RegExpTexter” as the project name. This pops up the wizard shown in Figure Two.

FIGURE FIVE:
Creating a new Qt project

The wizard includes a page to specify which Qt modules you want to link against, followed by a page that enables you to specify the name of the skeleton class to be generated by the wizard. For this example, change the base class of the generated class so that it’s QDialog, not QMainWindow, because the application is a simple dialog-style application with no menus or toolbars.

We’ll now design 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 controls we need from the Qt Toolbox onto the form and position them approximately as shown in Figure 6. (Qt’s layout system will lay them out precisely later on.)

FIGURE SIX: Placing controls on a form

The next step is to edit the controls’ properties using the Property Browser. Table One lists the properties that need to be set.

TABLE ONE: Setting the controls’ properties
Control Property Value
First label ObjectName “patternLabel”

Text “Pattern:”
Second label ObjectName “textLabel”

Text “Text:”
Third label ObjectName “resultLabel”

Text “Result:”
First line edit ObjectName “patternLineEdit”
Second line edit ObjectName “textLineEdit”
Third line edit ObjectName “resultLineEdit”

Editable false
First button ObjectName “resetButton”

Text “Reset”
Second button ObjectName “closeButton”

Text “Close”

You need to add layouts to the form to make it look better and to make it resizable. First, add a horizontal layout to position the Reset and Close buttons side by side. You also need a spacer to push the buttons to the right of the layout. To add a spacer, drag the Vertical Spacer item from the Qt Toolbox onto the form, next to the push buttons. Then 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 controls as well as the button sub-layout. To add this layout, select the labels, the line edits, and the button layout, then click Form Editor& gt; Layout in a Grid. This gives the form shown in Figure Seven.

FIGURE SEVEN: The form with layouts

Qt’s layouts automatically assign reasonable positions and sizes to the controls they are responsible for, based on their needs. This is especially useful in internationalized applications: With fixed sizes and positions, the translation text is often truncated; with layouts, the child widgets are automatically resized. Layouts can also run right-to-left, to accommodate languages such as Arabic and Hebrew.

You can click Form Editor& gt; Preview Form at any time to preview the form without compiling it. If you build the application now, the result is the dialog depicted in Figure
Four.

However, the dialog is inoperative. Let’s start by making the Close button work. You can connect the button’s clicked() signal to the form’s accept() slot. This can be done through the
form editor.

1.Click the Edit Connections toolbar button to enter the connection mode.

2.Click the form’s Close button and hold the left mouse button pressed, then move the cursor to an empty area of the form and release the mouse button (see Figure Eight). This invokes the Configure Connection dialog, which lists the available signals and slots.

3.Choose the "c">clicked() signal and the accept() slot and click OK.

FIGURE EIGHT: Connecting a signal to a slot visually

Qt controls emit” signals” when state changes take place, for example when the text changes in a line edit, or when a new item is selected in a list box. These signals can be” connected” to slots (member functions), so that when a signal is emitted, any slots it is connected to are called. Controls that are connected to one another are independent components since they don’t need to know anything about each other.

If you build and run the application now, the Close button closes the window and causes the application to terminate.

More Fun With Dialogs

Let’s continue and implement the rest of the dialog functionality. The contents of the Result line need 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 "c">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, you must edit the "i">regexptester.h and "i">regexptester.cpp files that were generated by the Qt Application wizard. Listing One shows the header file after adding the slot declaration. Notice the particular syntax for declaring a slot; this is Qt-specific and is
converted into standard C++ by the C++ preprocessor.

LISTING ONE: The form’s header file

#ifndef REGEXPTESTER_H
#define REGEXPTESTER_H

#include <QtGui/QDialog>
#include “ui_regexptester.h”

class RegExpTester : public QDialog
{
Q_OBJECT

public:
    RegExpTester(QWidget *parent = 0, Qt::WFlags flags = 0);
    ~RegExpTester();

private slots:
    void updateResult();

private:
   Ui::RegExpTesterClass ui;
};

#endif // REGEXPTESTER_H

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

The first unusual thing to notice about the class definition is the Q_OBJECT macro. This signifies that the class has some Qt extensions to C++ that will be discussed shortly. The private slots are private member functions that can also be called by Qt’s signals and slots mechanism.

The header file includes a file called "i">ui_regexptester.h. That file is generated by the uic program based on the "i">regexptester.ui, an XML file that 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 "c">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 in "i">Listing Two. Again, the code that needs to be added to the wizard-generated skeleton is shown in bold.

LISTING TWO: The form’s source file

#include “regexptester.h”

RegExpTester::RegExpTester(QWidget *parent, Qt::WFlags flags)
: QDialog(parent, flags)
{
   ui.setupUi(this);
   connect(ui.patternLineEdit, SIGNAL(textChanged(QString)), this, SLOT(updateResult()));
   connect(ui.textLineEdit, SIGNAL(textChanged(QString)), this, SLOT(updateResult()));
}

RegExpTester::~RegExpTester()
{
}

void RegExpTester::updateResult()
{
    QRegExp regExp(ui.patternLineEdit->text());
    if (regExp.indexIn(ui.textLineEdit->text()) != -1)
        ui.resultLineEdit->setText(regExp.cap(0));
    else
        ui.resultLineEdit->setText(“<no match>”);
}

The constructor calls setupUi() on the Ui::RegExpTester object to create the form’s controls and layouts. Then, the Pattern line edit’s textChanged() signal is connected to the updateResult() slot. The same is done with the Text line edit.

In the updateResult() slot, the regular expression pattern is applied to the specified text. If the regular expression matches, the matched text is shown in the Result line edit; otherwise, it shows”& lt;no match& gt;”.

The 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.patternLineEdit->clear();
    ui.textLineEdit->clear();
    updateResult();
}

This completes the small sample application. But what about Q_OBJECT, private slots, and other Qt keywords? The C preprocessor turns them all into pure C++ so the compiler never sees them. The machinery to handle Qt’s extensions is generated behind the scenes by "i">moc, which reads your source files and generates some additional source files to implement what we’ve used.

Goodbye, MFC

Microsoft is giving up MFC and is preparing to replace its successor, Windows Forms, with the Avalon framework. 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, a Windows developer can easily leverage his or her existing C++ skills to develop cross-platform, high-performance object-oriented, GUI applications.

Comments