QT Designer Manual
QT Designer Manual
Preface
Introduction
This manual presents Qt Designer, a tool for designing and implementing user interfaces
built with the Qt cross-platform application development framework. Qt Designer makes it
easy to experiment with user interface design. At any time you can generate the code
required to reproduce the user interface from the files Qt Designer produces, changing your
design as often as you like. If you used the previous version you will find yourself
immediately productive in the new version since the interface is fundamentally unchanged.
But you will find new widgets and new and improved functionality which have been
developed as a result of your feedback.
Qt Designer helps you build user interfaces with layout tools that move and scale your
widgets (controls in Windows terminology) automatically at runtime. The resulting
interfaces are both functional and attractive, comfortably suiting your users operating
environments and preferences. Qt Designer supports Qt's signals and slots mechanism for
type-safe communication between widgets. Qt Designer includes a code editor which you
can use to embed your own custom slots inside the generated code. Those who prefer to
separate generated code from hand crafted code can continue to use the subclassing
approach pioneered in the first version of Qt Designer.
The manual introduces you to Qt Designer by leading you through the development of
example applications. The first six chapters are tutorials, each designed to be as self-
contained as possible. Every chapter, except the first, assumes that you are familiar with the
material in chapter one which covers the basics of building a Qt application with Qt
Designer. Here's a brief overview of the chapters:
• Chapter one, Creating a Qt Application, introduces Qt Designer and takes you step
by step through the creation of a small but fully functional application. Along the
way you will learn how to create a form and add widgets to it. In the course of this
chapter you will use the form and property editors to customize the application, and
learn how to lay out a form using the layout tools. You'll also learn how to use Qt's
signals and slots mechanism and Qt Designer's built-in code editor to make the
application functional. We will also explain how to use qmake to generate a
Makefile so that you can compile and run the application.
• In chapter two, Creating Main Windows with Actions, Toolbars and Menus, we will
create a simple text editor. Through writing this application you will learn how to
create a main window with menus and toolbars. We will see how to use Qt's built-in
functionality to handle common tasks (e.g. copy and paste handling), and how to
create our own functionality for our own menu items and toolbar buttons.
• Chapter three, The Designer Approach, provides information on the Qt Designer
approach to developing applications, and explains some of the rationale behind Qt
Designer.
• Chapter four, Subclassing and Dynamic Dialogs, will show you how to subclass a
form; this allows you to clearly separate the user interface from the underlying code
that implements its functionality. Additional information on qmake and uic is
included in this chapter. This chapter will also explain how you can dynamically
load dialogs from .ui files into your application using QWidgetFactory and how
to access the widgets and sub-widgets of these dialogs.
• Chapter five, Creating Custom Widgets, explains how you can create your own
custom widgets. Both the simple method, that was introduced with the first version
of Qt Designer, and the new more powerful method using plugins, are explained.
• Chapter six, Creating Database Applications introduces Qt's SQL classes and takes
you through an example that demonstrates how to execute SQL queries and how to
set up master-detail relationships, perform drilldown and handle foreign keys.
• Chapter seven, Customizing and Integrating Qt Designer, focuses on Qt Designer
itself, showing you how to customize Designer, how to integrate Designer with
Visual Studio and how to create Makefiles.
The remaining chapters provide reference material that explains Qt Designer's menu
options, toolbars, key bindings and dialogs in detail.
A new library libqui has also been introduced which allows you to load dialogs
dynamically at runtime from Qt Designer's .ui files. This allows you to provide your
application's users with considerable interface customizability without them needing to use
C++.
Although the new version of Qt Designer introduces new approaches and techniques you
can ignore these aspects and simply use it in exactly the same way as you used the version
supplied with Qt 2.x, if you just want a simple but powerful single dialog visual design
tool.
Qt Designer
Feedback
If you have any comments, suggestions, criticisms or even praise regarding this manual,
please let us know at [email protected]. Bug reports on Qt or Qt Designer should be
sent to [email protected]. You might also like to join the qt-interest mailing list,
which Qt Designer's developers read and contribute to; see http://www.trolltech.com/ for
further details.
Creating a Qt Application
Starting and Exiting Qt Designer
Qt Designer is controlled in the same way as any other modern desktop application. To
start Qt Designer under Windows click the Start button and click Programs|Qt
X.x.x|Designer. (X.x.x is the Qt version number, e.g. 3.0.0.) If you're running a Unix or
Linux operating system you can either double click the Qt Designer icon or enter designer
& in an xterm.
When you've finished using Qt Designer click File|Exit; you will be prompted to save any
unsaved changes. Help is available by pressing F1 or from the Help menu.
To get the most benefit from the tutorial chapters we recommend that you start Qt Designer
now and create the example applications as you read. Most of the work involves using Qt
Designer's menus, dialogs and editors, with only small amounts of code to type in.
When you start Qt Designer, by default, you will see a menu bar and various toolbars at the
top. On the left hand side are three windows, the first is the Files window, the second is the
Widgets and Source window (the Object Explorer) and the third is the Properties window.
The Files window lists the files and images associated with the project; to open any form
single click it in the Files list. The Widgets and Source window lists the current form's
widgets and slots. The Properties window is used to view and change the properties of
forms and widgets. We will cover the use of Qt Designer's windows, dialogs, menu options
and toolbar buttons as we create example applications.
In this chapter we will build an application called 'multiclip' which allows you to store and
retrieve multiple text clippings to and from the clipboard.
Adding Widgets
The multiclip application consists of a text box to display the current clipboard text (if any),
a list box showing the previous clippings, a length indicator, a checkbox and buttons. If you
run the application and resize it all the widgets will scale properly.
The Qt Designer approach to laying out a form is to place the required widgets on the form
in the approximate positions that they should occupy and then use the layout tools to size
and position them correctly. We'll now add the multiclip form's widgets.
1. We'll start with the current clipping text box. Click the Text Label toolbar button
and click towards the top left of the form. (If you hover the mouse over a toolbar
button its name will appear in a tooltip.) We won't bother renaming the label since
we'll never refer to it in code; but we need to change its text, so change its text
property to 'Current Clipping'. (See the Using the Property Editor sidebar for an
explanation of the property editor.)
Click the Line Edit toolbar button and click towards the top right of the form. Use
the Property Editor to change the widget's name to 'currentLineEdit'.
2. Now we'll add another label and the list box. Click the Text Label toolbar button
and click below the Current Clipping label. Change the text property to 'Previous
Clippings'. Don't worry about positioning the widgets precisely, nor about the fact
that they are the wrong size; the layout tools (covered in the next section) will take
care of this.
Click the List Box toolbar button and click the form below the 'Previous Clippings'
label. Change the list box's name to 'clippingsListBox'. By default Qt Designer
creates list boxes with a single initial value of 'New Item'. We don't want this value
(we'll be populating our list box in code later), so we need to remove the value.
Right click the list box then click the Edit menu item on the popup menu to invoke
the listbox's value editor dialog. Click Delete Item to delete the default item, then
click OK. (See the Value Editors sidebar.)
3. We want to know the length of the current clipping so we'll add a label and an LCD
Number widget.
Click the Text Label toolbar button and click below the Line Edit. Change its text
property's value to 'Length'. Click the LCD Number toolbar button and click below
the length label. Change the LCD Number's name to 'lengthLCDNumber'.
4. Multiclip can be made to detect clipboard changes and automatically add new
clippings. We want the user to have control over whether this should happen or not
so we will provide a check box which they can use to indicate their preference.
Click the Check Box toolbar button and click below the LCD Number. Change the
checkbox's name to 'autoCheckBox' and its text to 'A&uto Add Clippings'. Note that
the accel property automatically changes to Alt+U because the ampersand in the
text signifies a keyboard shortcut.
5. The last widgets we require are the buttons. One way to add the same kind of
widget multiple times is to add one, copy it, then paste repeatedly. We will use
another approach.
Double click the Push Button toolbar button; now click below the checkbox to
place a button. Click below the button we've just added to add a second button. Add
a third and fourth button. Now click the Pointer toolbar button to switch off
automatically adding the same widget. Change the first button's name to
'addPushButton' and its text to '&Add Clipping'. Change the second button's name
to 'copyPushButton' and its text to '&Copy Previous'. Change the third button's
name and text properties to 'deletePushButton' and '&Delete Clipping' respectively.
Similarly change the fourth button's name and text to 'quitPushButton' and '&Quit'.
All our widgets have been placed on the form with their properties changed to suit our
application's needs. In the next section we will use Qt Designer's layout tools to size and
position the widgets correctly and in such a way that when the user resizes the form the
widgets will scale properly.
Value Editors
Whilst the Property Editor is used to customize the generic properties of
widgets, value editors are used to edit values held within instances of
particular widgets. For example a QLineEdit can only contain a single line
of text, but a QListBox can contain any number of items each of which may
be a line of text, a pixmap, or both. To invoke a widget's value editor double
click the widget. (Alternatively right click the widget and a popup menu will
appear; if the first menu item is 'Edit', you can click this to access the
widget's value editor dialog.) Different widgets have different value editors.
See the Value Editors chapter for more details.
Expanding the list box half of the splitter would require us to add an init() function with
the following code:
void MulticlipForm::init()
{
QValueList< int > sizes;
sizes << 250 << 40;
Splitter->setSizes( sizes );
}
We won't add this code now since we'll deal with the code when we come to implement the
application's functionality later in the chapter.
We will create some space around the splitter by changing the margins of the layout groups
that it joins together. To click a layout either click a fraction above the layout's top red line
or click the layout's name in the Object Explorer (the Widgets and Source window). (See
Object Explorer Window sidebar for an explanation of the Object Explorer window.) Click
the layout that contains the list box, and change the layoutMargin property to 6, then press
Enter. Click the layout that contains the buttons and other widgets, and change its
layoutMargin to the same value in the same way.
The Object Explorer
View the Object Explorer (Widgets and Source) window by clicking
Window|Views|Object Explorer. The Object Explorer has two tabs, the
Widgets tab which shows the object hierarchy, and the Source tab which
shows the source code you have added to the form. Clicking the name of a
widget in the Widget tab will select the widget and show its properties in the
Property Editor. It is easy to see and select widgets in the Object Explorer
which is especially useful for forms that have many widgets or which use
layouts.
In the original version of Qt Designer if you wanted to provide code for a
form you had to subclass the form and put your code in the subclass. This
version fully supports the subclassing approach, but now provides an
alternative: placing your code directly into forms. Writing code in Qt
Designer is not quite the same as subclassing, for example you cannot get
direct access to the form's constructor or destructor. If you need code to be
executed by the constructor create a slot called void init(); if it exists it
will be called from the constructor. Similarly, if you need to be executed
before destruction create a slot called void destroy(). You can also add
your own class variables which will be put in the generated constructor's
code, and you can add forward declarations and any includes you require. To
add a variable or declaration right click the appropriate item, e.g. Class
Variables, then click New then enter your text, e.g. QString fileName. If
one or more items exist right clicking will popup a two item menu with New
and Delete as options. To edit code just click the name of a function to
invoke the code editor. Code editing and creating slots are covered later.
If you subclass the form you create your own .cpp files which can contain
your own constructor, destructor, functions, slots, declarations and variables
as your requirements dictate. (See Subclassing for more information.)
In the example we used Qt Designer's layout tools to lay out our widgets. We will use the
layout tools again in the examples presented in later chapters. If you want to use absolute
positioning, i.e. to place and size your widgets with exact pixel sizes you can easily do so.
To place a widget click it and drag it to the desired position. To resize it, click it, and drag
one of the sizing handles (these are small blue squares) until the size is right. To stop the
widget from resizing when the window is resized change the hSizeType and vSizeType
(these are properties within the sizePolicy property), to Fixed.
Previewing
Although Qt Designer presents an accurate view of our forms we often want to see what a
form looks like when it is run. It is also useful to be able to test out some aspects of the
form, for example how the form scales when resized or how the splitters work in practice.
If we're building cross-platform applications it is also useful to see how the form will look
in different environments.
To see a preview either click Preview|Preview Form or press Ctrl+T. To leave preview
mode close the window in the standard way for your environment. To view previews which
show how the application will look on other platforms click the Preview menu and click
one of the menu items that drop down.
Preview the multiclip form and try out the splitter and try resizing the form. In all
probability you moved the splitter to the right to reduce the size of the buttons to make the
form more attractive. The splitter seemed like a good idea but in practice we want the
buttons and the other widgets on the right hand side to take up a fixed amount of space. Qt
Designer makes changing layouts very easy, so we'll fix this straight away.
Click the splitter then click the Break Layout toolbar button; the splitter will be removed.
Now click the form itself, near the bottom, and drag the rubber band so that it touches both
the list box and some of the buttons, then release. The list box group and the buttons group
are selected; click the Lay Out Horizontally toolbar button. Click the form then click the
Lay Out Vertically toolbar button. The form is now laid out as we require. Preview the
form (press Ctrl+T) and try resizing it.
It would be useful if you experimented further with layouts since they work visually and
are best learnt through practice. To remove a layout click the Break Layout toolbar button;
to apply a layout select the relevant widgets or groups and click a layout button. You can
preview as often as you like and you can always undo any changes that you make.
Let's try an experiment, to see how the grid layout works. Click the list box, then press
Ctrl+B (break layout). Click one of the buttons and press Ctrl+B. Click the form at the
bottom and drag until all the widgets are touching or within the rubber band, (but excluding
the Current Clipping label and the currentLineEdit line edit); then release. Press Ctrl+G
(lay out in a grid). Click the form, then click Ctrl+L (lay out vertically). Our original
design is back -- but this time using a grid layout.
We will connect the Quit button's clicked() signal to the form's accept() slot. The
accept() slot notifies the dialog's caller that the dialog is no longer required; since our
dialog is our main window this will close the application. Preview the form (press Ctrl+T);
click the Quit button. The button works visually but does nothing. Press Esc or close the
preview window to leave the preview.
Click the Connect Signals/Slots toolbar button. Click the Quit button, drag to the form and
release. The Edit Connections dialog will pop up. The top left hand list box lists the Signals
that the widget we've clicked can emit. At the top right is a combobox which lists the form
and its widgets; any of these are candidates for receiving signals. Since we released on the
form rather than a widget the slots combobox shows the form's name, 'MulticlipForm'.
Beneath the combobox is a list box which shows the slots available in the form or widget
shown in the combobox. Note that only those slots that can be connected to the highlighted
signal are shown. If you clicked a different signal, for example the toggled() signal, the
list of available slots would change. Click the clicked() signal, then click the accept()
slot. The connection will be shown in the Connections list box. Click OK.
We will make lots of signal/slot connections as we work through the examples, including
connections to our own custom slots. Signal/slot connections (using pre-defined signals and
slots) work in preview mode. Press Ctrl+T to preview the form; click the form's Quit
button. The button now works correctly.
We'll need Qt's global clipboard object throughout the code which would mean calling
QApplication::clipboard() or qApp->clipboard() in several places. Rather than
perform all these function calls we'll keep a pointer to the clipboard in the form itself. Click
the Source tab of the Object Explorer. (If the Object Explorer isn't visible click
Window|Views|Object Explorer.) The Source tab shows us the functions in our form, the
class variables, the forward declarations and the names of the include files we've asked for.
Right click the Class Variables item, then click New on the popup menu. (If there had been
any existing variables the popup menu would also have a Delete option.) Type in
'QClipboard *cb;' and press Enter. We will create an init() function in which we will
assign this pointer to Qt's global clipboard object. We also need to declare the clipboard
header file. Right click Includes (in Declaration), then click New. Type in '<qclipboard.h>'
and press Enter. Since we need to refer to the global application object, qApp, we need to
add another include declaration. Right click Includes (in Implementation), then click New.
Type in '<qapplication.h>' and press Enter. The variable and declarations will be included
in the code generated from Qt Designer's .ui file.
We will invoke Qt Designer's code editor and write the code.
We'll create the init() function first. One way of invoking the code editor is to click the
Source tab, then click the name of the function you want to work on. If you have no
functions or wish to create a new function you need to use the Source tab. Right click the
'protected' item in the Source tab's Functions list, then left click New to launch the Edit
Slots dialog. Change the slot's name from 'newSlot' to 'init()' then click OK. You can then
click inside the editor window that appears to enter your code.
Note that you are not forced to use Qt Designer's code editor; so long as you add, delete
and rename your slots all within Qt Designer, you can edit the implementation code for
your slots using a separate external editor and Qt Designer will preserve the code you write.
void MulticlipForm::init()
{
lengthLCDNumber->setBackgroundColor( darkBlue );
currentLineEdit->setFocus();
cb = qApp->clipboard();
connect( cb, SIGNAL( dataChanged() ), SLOT( dataChanged() ) );
if ( cb->supportsSelection() )
connect( cb, SIGNAL( selectionChanged() ), SLOT(
selectionChanged() ) );
dataChanged();
}
The first couple of lines change the LCD number's background color and make the form
start with the focus in the line edit. We take a pointer to Qt's global clipboard and keep it in
our class variable, cb. We connect the clipboard's dataChanged() signal to a slot called
dataChanged(); we will create this slot ourselves shortly. If the clipboard supports
selection (under the X Window system for example), we also connect the clipboard's
selectionChanged() signal to a slot of the same name that we will create. Finally we call
our dataChanged() slot to populate the line edit with the clipboard's text (if any) when the
application begins.
Since we've referred to the dataChanged() and selectionChanged() slots we'll code
them next, starting with dataChanged().
void MulticlipForm::dataChanged()
{
QString text;
text = cb->text();
clippingChanged( text );
if ( autoCheckBox->isChecked() )
addClipping();
}
We take a copy of the clipboard's text and call our own clippingChanged() slot with the
text we've retrieved. If the user has checked the Auto Add Clippings checkbox we call our
addClipping() slot to add the clipping to the list box.
The selectionChanged() slot is only applicable under the X Window System. Users of
MS Windows can still include the code to ensure that the application works cross-platform.
void MulticlipForm::selectionChanged()
{
cb->setSelectionMode( TRUE );
dataChanged();
cb->setSelectionMode( FALSE );
}
We tell the clipboard to use selection mode, we call our dataChanged() slot to retrieve any
selected text, then set the clipboard back to its default mode.
To make the Add Clipping button functional we need to connect the button's clicked()
signal to our addClipping() slot. Click the Connect Signals/Slots toolbar button. Click
the Add Clipping button, drag to the form and release. (Make sure you drag to the form
rather than another widget -- the form will have a thin pink border during the drag. If you
make a mistake simply change the name in the Slots combobox.) The Edit Connections
dialog will appear. Click the clicked() signal and our addClipping() slot. Click OK to
confirm the connection.
The Copy Previous button is used to copy the selected clipping from the list box into the
line edit. The clipping is also placed on the clipboard. The procedure is the same as for the
Add Clipping button: first we create the slot, then we implement it and finally we connect
to it:
1. Create the slot.
Click the Edit|Slots menu item to invoke the Edit Slots dialog. Click New Slot and
replace the default 'new_slot()' name with 'copyPrevious()'. Click OK.
2. Implement the slot.
3. void MulticlipForm::copyPrevious()
4. {
5. if ( clippingsListBox->currentItem() != -1 ) {
6. cb->setText( clippingsListBox->currentText() );
7. if ( cb->supportsSelection() ) {
8. cb->setSelectionMode( TRUE );
9. cb->setText( clippingsListBox->currentText() );
10. cb->setSelectionMode( FALSE );
11. }
12. }
13. }
The code for Copy Previous checks to see if there is a selected item in the list box.
If there is the item is copied to the line edit. If we are using a system that supports
selection we have to repeat the copy, this time with selection mode set. We don't
explicitly update the clipboard. When the line edit's text is changed it emits a
dataChanged() signal which our dataChanged() slot receives. Our
dataChanged() slot updates the clipboard.
MulticlipForm clippingForm;
app.setMainWidget( &clippingForm );
clippingForm.show();
return app.exec();
}
The program creates a QApplication object and an instance of our MulticlipForm, sets the
form to be the main widget and shows the form. The app.exec() call starts off the event
loop.
Now start up a console (or xterm), change directory to the multiclip application and run
qmake. A Makefile compatible with your system will be generated:
qmake -o Makefile multiclip.pro
You can now make the application, e.g. by running make or nmake. Try compililng and
running multiclip. There are many improvement you could make and experimenting with
both the layout and the code will help you learn more about Qt and Qt Designer.
This chapter has introduced you to creating cross-platform applications with Qt Designer.
We've created a form, populated it with widgets and laid the widgets out neatly and
scalably. We've used Qt's signals and slots mechanism to make the application functional
and generated the Makefile. These techniques for adding widgets to a form and laying them
out with the layout tools; and for creating, coding and connecting slots will be used time
and again as you create applications with Qt Designer. The following chapters will present
further examples and explore more techniques for using Qt Designer.
Creating Main Windows with Actions,
Toolbars and Menus
In this chapter we will explain how to create an application's main window and how to add
actions (explained shortly), menus and toolbars. We will also demonstrate how some
common actions, like cut and paste in a QTextEdit, can be performed automatically simply
by making the appropriate signals and slots connections. We will build the richedit
application to illustrate the necessary techniques.
Creating Menus
We'll now add the actions we added to the new toolbar to a new menu and modify the
existing menus slightly.
Right click our application's menu bar and click Add Menu Item. A new menu item called
'Menu' will appear. Right click this menu item and click Rename Item. Change its name to
'F&ormat'. Click the menu item and a red bar will appear beneath it -- this is the empty
menu. Drag the alignActionGroup to the Format menu item and drop the action group on
the menu. (The menu's red bar will appear and a thick red line will be drawn where the new
menu items will appear -- drop when the red line is in the position you require.) Now if you
click the Format menu item the three alignment actions will be displayed. Just like the
toolbar we must add the bold, italic and underline actions individually. Drag the bold action
to the Format menu and move the mouse so that the red line is positioned at the bottom of
the menu, then drop the action. Repeat this process for the italic and underline actions.
We'll now deal with the separators in the menus. Firstly we'll add a separator in the Format
menu and then we'll remove some redundant separators from the other menus. Click the
Format menu and right click the bold item; click Insert Separator. Click the File menu and
right click one of the separators above the Exit action; click Delete Item. Click the Edit
menu, right click the separator at the very bottom of the menu and click Delete Item. Delete
Item can be used to delete separators, menu items and menus.
Click the Format menu and drag it to the left of the Help menu, then drop the Format menu.
(A thick red bar will appear to indicate the insertion postion.) Both menus and menu items
may be dragged and dropped to different positions in the same way.
Preview the application and try clicking the alignment and font style toolbar buttons and
menu items. Qt will automatically keep the state of the menu items and the toolbar buttons
synchronized.
We'll have to write the code to set the alignment ourselves; we'll cover this in Aligning
Text.
Connecting for Font Names and Sizes
We'll start by dealing with font size since it's easiest. Click the Connect Signals/Slots
toolbar button then click the spinbox and drag to the text edit widget; release on the text
edit. Click the valueChanged(int) signal and on the textEdit's setPointSize(int) slot.
Click OK and font sizes are done. (Since font sizes are handled purely through built-in
signals and slots they work in preview mode.)
Connect the fontComboBox's activated() signal to the textEdit's setFamily() slot. This
connection will handle updating the textEdit's font family with the user's choice of font.
Note that when you invoke the Edit Connections dialog the first signal that is highlighted is
activated(int). Since the setFamily() slot takes a QString argument it does not appear
in the list of slots. Only those slots which are compatible with the highlighted signal are
shown, in this case, slots which take no argument or which take an integer argument. Click
the activated(const QString&) signal and the list of slots will change to those which
take no argument or which take a QString argument; the list will now include
setFamily() since this takes a QString argument. We will have to populate the combobox
with the font names for the user to choose from in code. (See the init() function in
Changing Fonts.) It's a good idea to connect the fontComboBox's activate() signal to the
textEdit's setFocus() slot; this will ensure that after the user has changed font the focus
will return to the text.
The richedit application is nearly complete. We will have to write code to handle text
alignment, font family and file loading and saving. We will also write the code for
application exit to deal correctly with any unsaved changes.
if ( textEdit->isModified() ) {
switch( QMessageBox::information(
this, "Rich Edit",
"The document contains unsaved changes.\n"
"Do you want to save the changes?",
"&Save", "&Don't Save", "&Cancel " + action,
0, // Enter == button 0
2 ) ) { // Escape == button 2
case 0: // Save; continue
fileSave();
break;
case 1: // Do not save; continue
break;
case 2: // Cancel
continueAction = 0;
break;
}
}
return continueAction;
}
The saveAndContinue() function is included for completeness.
Aligning Text
void EditorForm::changeAlignment(QAction * align)
{
if ( align == leftAlignAction )
textEdit->setAlignment( Qt::AlignLeft );
else if ( align == rightAlignAction )
textEdit->setAlignment( Qt::AlignRight );
else if ( align == centerAlignAction )
textEdit->setAlignment( Qt::AlignCenter );
}
We compare the chosen alignment action's pointer to the the pointers stored in the form and
if we get a match set the appropriate alignment in the textEdit widget.
Changing Fonts
QFontDatabase fonts;
fontComboBox->insertStringList( fonts.families() );
QString font = textEdit->family();
font = font.lower();
for ( int i = 0 ; i < fontComboBox->count(); i++ ) {
if ( font == fontComboBox->text( i ) ) {
fontComboBox->setCurrentItem( i );
break;
}
}
}
The first line sets the focus as we've already mentioned. We then create a QFontDatabase
object and insert its list of font families into the fontComboBox. Finally we set the
fontComboBox's current item to the textEdit's current font.
EditorForm richeditForm;
app.setMainWidget( &richeditForm );
richeditForm.show();
return app.exec();
}
All that's left to do is to generate the Makefile, compile and run. The Makefile is created
with qmake: qmake -o Makefile richedit.pro.
The richedit application demonstrates how easy it is to create a Qt application's main
window with menus and dockable toolbars. A great deal of functionality was obtained by
connecting the appropriate built-in signals and slots. The remaining functionality was
achieved by connecting built-in signals to our own custom slots. We could continue
developing the application, for example updating the fontComboBox, the font size spinbox
and the actions with the font attributes as the user moves the cursor through their text. But
our objective has been to demonstrate the creation of a main window with actions, menus
and toolbars so we must stop at this point and leave further development and
experimentation to you.
The Designer Approach
Introduction
In Qt 2.x, Qt Designer was a visual form designer for editing files in the .ui file format. Qt
Designer's primary goal was to turn the most tedious part of GUI programming -- dialog
design -- into a pleasant experience. From an architectural point of view, Qt Designer in 2.x
is a fairly simple program. It reads and writes .ui files. Each .ui file contains an XML
description of a single dialog form. A second utility -- the user interface compiler uic -- is
used during the build process of an application to generate C++ code from those XML
descriptions.
For Qt 3.0 our ambitions for Qt Designer have grown beyond single dialog editing. In
addition to many new design features like the ability to creating main windows and actions,
the new version introduces:
• project management for the user interface part of your application;
• code in forms Qt Designer provides a code editor so that you can code your slots
directly; the code is stored in .ui.h files and eliminates the need for sub-classing
(although you can still subclass if you prefer);
• dynamic form loading allows you to load .ui files at runtime which provides great
scope for design customisation separate from the underlying code.
The purpose of this chapter is to explain the motivation for making these changes, describe
the new concepts involved and show how these features work internally.
Qt Designer is and remains a visual design tool: it is not a complete integrated development
environment. Our policy is to make GUI development as easy and powerful as possible
without locking our users into any particular tool: Qt Designer makes it easy to create and
modify GUI designs, but you can still achieve the same results directly in code using a
plain text editor if you prefer.
To make working more convenient, Qt Designer now includes a C++ editor (as a plugin). If
you want to create or edit a form, use Qt Designer. If you want edit code for that form, you
can use the C++ editor in Qt Designer as well. This built-in editor has certain benefits
stemming from its tight integration with the visual form design process that we will explain
later. However, if you prefer using the editor you're used to, vim, emacs, notepad,
Microsoft Visual Studio, etc. you can still do so.
Project management
Reading and writing single, non-connected .ui files is conceptually simple and worked
fairly well in Qt 2.x. However, it lacked certain features that made us introduce project
management for the GUI part of an application in Qt Designer. The main benefits of project
management are:
• Grouping forms that belong together.
• Sharing images between different forms.
• Sharing database information between different forms.
The following sections explain these benefits in more detail, and why project management
is required to achieve them.
Grouping forms
Grouping forms means that Qt Designer maintains a list of the .ui files that belong to the
same project. This makes it easy to switch between forms with a single mouse click.
.pro files
Qt Designer needs to store information on projects, for example, the list of forms, the
image collection and information about available databases and how to access them. The
majority of Qt users already use a project file format to create cross-platform makefiles:
tmake (and with Qt 3.0 qmake) project .pro files. These files already contain the list of
forms, .ui files, used in the project for uic.
We've extended the sections in the .pro file to include the extra information that Qt
Designer needs to manage projects. For example, when you add a form to your project in
Qt Designer, it is automatically added to the FORMS section of the project file, and thus
qmake will generate the required build rules without any further work. Similarly, the images
are added to the IMAGES section and thus gets automatically compiled into your
executable.
We don't force you to use qmake; if you prefer another build system, for example
automake/autoconf or jam, you can still continue to use it. Look upon the .pro file as a file
that describes the GUI part of your application. All you need to do -- as previously -- is add
the .ui files and the images collection to your own Makefiles.
Here the user wrote an additional class FormImpl, which is split into the header file
formimpl.h and the implementation file formimpl.cpp. The header file includes the uic
generated form.h and reimplements all the custom slots. This is possible because uic
generated custom slots are virtual. In addition to implementing custom slots, this approach
gives the user a way to do extra initialization work in the constructor of the subclass, and
extra cleanups in the destructor.
Because of these benefits and its flexibility, this approach became the primary way of using
Qt Designer in Qt 2.x.
Note: To keep the namespace clean, most users did not follow the Form and FormImpl
naming scheme shown in the figure, but instead named their Qt Designer forms FormBase
and their subclasses Form. This made a lot of sense, because they always subclassed and
were using those subclasses in application code.
The form.ui.h file has a special position among all other files. It is a shared source file
that gets written and read by both the user and Qt Designer. As such it is an ordinary
revision controlled source file and not generated by uic. Qt Designer's responsibility is to
keep the file in sync with the custom slot definitions of the associated form:
1. Whenever the users adds a new slots to the form, Qt Designer adds a stub to the
.ui.h file.
2. Whenever the user changes a custom slot's signature, Qt Designer updates the
corresponding implementation.
3. Whenever the user removes a custom slot, Qt Designer removes it from the .ui.h
file.
This way integrity is guaranteed, there is no more need for subclassing and no more danger
of forgotten or misspelled slots in subclasses.
You can edit .ui.h files either directly in Qt Designer with the built-in C++ editor plugin,
or with whatever editor you prefer. You should only put slot implementations in the .ui.h
file and you should always add, delete or rename slots within Qt Designer. You can edit the
implementations of the slots either within Qt Designer or using your own editor; if you use
your own editor Qt Designer will keep your changes.
Construction and destruction
The ui.h extension approach has one disadvantage compared to subclassing. The ui.h file
only contains custom slot implementations, but the objects are still entirely constructed and
destructed inside the generated form.cpp code. This leaves the user without the possibility
of doing further form initializations or cleanups that you normally would do within the
constructor and destructor functions of a C++ class.
To work around this limitation, we created the init/destroy convention. If you add a slot
Form::init() to your form, this slot will be called automatically at the end of the
generated form constructor. Similarly, if you add a slot Form::destroy() to your form, the
slot will automatically be invoked by the destructor before any form controls get deleted.
(These slots should return void.) If you prefer to use your own editor you must still create
these functions in Qt Designer; once created you can then write your implementation code
either using Qt Designer's C++ editor plugin or using your own editor.
This dynamic approach keeps the GUI design and the code separate and is useful in
environments where the GUI may have to change more often than the underlying
application logic. Ultimately, you can provide users of your application the ability to
modify the graphical user interface without the need for a complete C++ development
environment.
Since the .ui file is not compiled it cannot include any C++ code, (e.g. custom slot
implementations). We provide a way of adding those implementations via a controlling
QObject subclass that you pass as receiver to the widget factory.
This concept and its usage is explained in detail in the Subclassing and Dynamic Dialogs
chapter.
Subclassing and Dynamic Dialogs
This chapter describes two different approaches that you can take to creating forms with Qt
Designer. Subclassing is used to extend the functionality of a form by creating your own
class based upon a form you create in Qt Designer. Dynamic dialogs are .ui files which
can be executed by a Qt application; this keeps the GUI design and the code separate and is
useful in environments where the GUI may have to change more often than the underlying
application logic.
Subclassing
We'll start with a general description of how to subclass a form and follow with a short
example. Note that subclassing has some disadvantages compared with putting your code
into a form directly; see Extending the functionality of a form in The Designer Approach
chapter for details.
If you create applications wholly within Qt Designer you only need to create a main.cpp.
If you create the main.cpp file within Qt Designer, it will automatically be added to your
project file by Qt Designer. If you create the main.cpp file outside of Qt Designer you
must add it to the project file manually by adding the following line at the end of your
project's .pro file:
SOURCES += main.cpp
You can then use qmake to generate the Makefile. (For example qmake -o Makefile
myproject.pro.) Running make (Linux, Unix or Borland compilers), or nmake (Visual
C++), will then call uic, moc and your compiler as necessary to build your application.
If you use Qt Designer to create your main window and dialogs, but also add other C++
files, or if you subclass any of your forms you will need to add these files to the .pro file
so that they are compiled with the rest of your application's source files. Each .h file that
you create separately from Qt Designer should be added to the HEADERS line, and each .cpp
file should be added to the SOURCES line, just as we've done for main.cpp. If you get
undefined reference errors it is worth checking that you've added the names of all your
header and implementation files to the .pro file.
Subclassing a Form
When subclassing a form it is helpful to use a naming convention to help us identify which
files are generated from Qt Designer's .ui files and which are hand coded.
Suppose, for example, that we are developing a dialog and writing the code directly in Qt
Designer. We might call our dialog 'OptionsForm' and the .ui file, optionsform.ui. The
automatically generated files will be optionsform.h and optionsform.cpp.
If we were developing another dialog, but this time one that we intended to subclass, we
want to make it easy to distinguish between the automatically generated files and our hand
coded files. For example, we might call our dialog 'SettingsFormBase' and the .ui file
settingsformbase.ui. The automatically generated files would then be called
settingsformbase.h and settingsformbase.cpp. We would then call our subclass
'SettingsForm' and code it in the files settingsform.h and settingsform.cpp.
Any subclass of a form should include the Q_OBJECT macro so that slots and signals will
work correctly. Once you've created your subclass be sure to add the .h and the .cpp files
to the .pro project file. For example we would add the following lines for our subclassed
'SettingsForm' at the end of the .pro file:
HEADERS += settingsform.h
SOURCES += settingsform.cpp
The simplest way to create a new source file is by clicking File|New to invoke the 'New
File' dialog, then click 'C++ Source' or 'C++ Header' as appropriate, then click OK. A new
empty source window will appear. You don't need to manually edit the .pro file since Qt
Designer will add them for you automatically.
Qt Designer will have added
FORMS = settingsformbase.ui
to the project file. The settingsformbase.h and settingsformbase.cpp files will be
generated from the .ui file automatically.
A Subclassing Example
We will write a small example dialog to show the use of subclassing in practice. The dialog
will present a choice of customer credit ratings with an option of choosing a 'special' rating
for which a specific amount must be given. We'll implement the functionality in a subclass.
We'll start by creating the base form and connecting its signals and slots, then we'll create
the subclass and a simple main.cpp so that we can test it.
Designing the Form
We'll begin by creating a new project. Click File|New, then click the 'C++ Project' icon to
invoke the Project Settings dialog. Click the ellipsis button to invoke the Save As dialog;
navigate to the project's directory (creating it if necessary). Make sure you're in the project's
directory, then enter a project name of 'credit.pro'. Click the Save button to return to the
Project Settings dialog, then click OK. Now we'll add a form to the project. Click File|New
to invoke the New File dialog. The default form is Dialog which is what we want; click
OK. Resize the form to make it smaller; it should be about 2 inches (5 cm) square. Change
the form's name to 'CreditFormBase' and the caption to 'Credit Rating'. Save the form as
creditformbase.ui.
If the user checks the standard or none radio buttons we want to set the amount
accordingly. Press F3, then click the credit rating button group. Drag to the form and
release. Click the clicked() signal. We want to connect this signal to our own custom slot,
but we haven't created one yet. Click the Edit Slots button and the Edit Slots dialog will
pop up. Click New Slot and change the Slot's name to 'setAmount()'. Click OK. This new
slot is now available in the list of slots. Click the setAmount() slot then click OK.
We'll subclass the form to set the amount in the spin box depending on which radio button
is checked. Save the form as 'creditformbase.ui' (press Ctrl+S).
Creating the Test Harness
Although we intend our dialog to be used within an application it is useful to create a test
harness so that we can develop and test it stand-alone. Right click the 'Source Files' entry in
the Files window then click Add new source file to project. This will invoke the Save As
dialog; enter 'main.cpp' and click Save. In the editor window that pops up, enter the
following code:
#include <qapplication.h>
#include "creditformbase.h"
CreditFormBase creditForm;
app.setMainWidget( &creditForm );
creditForm.show();
return app.exec();
}
Note that we're including creditformbase.h and instantiating a CreditFormBase object;
once we've written our subclass we'll replace the header with our subclass, creditform.h,
and instantiate a CreditForm.
We can now generate the application with qmake, e.g. qmake -o Makefile credit.pro,
make it and run it. The form should run fine, but doesn't yet have the behaviour we require.
Creating the Subclass
We need to create a header and an implementation file for our subclass. The code for our
subclass is minimal. The header file is
qt/tools/designer/examples/credit/creditform.h:
#include "creditformbase.h"
CreditForm::~CreditForm() { /* NOOP */ }
void CreditForm::setAmount()
{
if ( stdRadioButton->isChecked() )
amountSpinBox->setValue( amountSpinBox->maxValue() / 2 );
else if ( noneRadioButton->isChecked() )
amountSpinBox->setValue( amountSpinBox->minValue() );
}
We call setAmount() in the constructor to ensure that the correct amount is shown when
the form starts based on whichever radio button we checked in Qt Designer. In
setAmount() we set the amount if the standard or none radio button is checked. If the user
has checked the special radio button they are free to change the amount themselves.
To be able to test our subclass we change main.cpp to include creditform.h rather than
creditformbase.h and change the instantiation of the creditForm object:
#include <qapplication.h>
#include "creditform.h"
CreditForm creditForm;
app.setMainWidget( &creditForm );
creditForm.show();
return app.exec();
}
If you created the creditform.h and creditform.cpp files in Qt Designer, they are
already in the project file, but if you created them manually you must also update the
project file by adding these two new lines at the end:
HEADERS += creditform.h
SOURCES += creditform.cpp
To test the form rerun qmake to regenerate the Makefile, then make and run.
The subclassing example we've used is simple, but this reflects subclassing forms in Qt: it
is easy to do.
We'll create a main.cpp file to use as a test harness, and manually create a project file.
Creating main.cpp
The main.cpp is quite standard. It will invoke the form we're going to create in Qt
Designer as its main form. This form will then load and execute the dynamic dialog.
#include <qapplication.h>
#include "mainform.h"
return app.exec();
}
We create a new instance of our MainForm class, set it to be the main widget, show it and
enter the event loop in the app.exec() call.
1. Open the receiver.pro project file in Qt Designer. We'll create a dialog as our
main window which we'll use to invoke the dynamic dialog. Press Ctrl+N to launch
the New File dialog and click OK to get the default which is a dialog. Change the
dialog's name to 'MainForm' and its caption to 'Main Form'. Add two buttons, one
called 'creditPushButton' with the text '&Credit Dialog', and the other called
'quitPushButton' with the text '&Quit'. (For each button click the Push Button
toolbar button, then click the form. Change the properties in the property window to
those we've just described.)
2. We will now add a couple of labels so that we can show the settings the user chose
in the dynamic dialog. Click the Text Label toolbar button, then click the form
below the Credit Dialog button. Change the label's text to 'Credit Rating'. Add
another text label below the Quit button. Change its name to 'ratingTextLabel' and
its text to 'Unrated'.
3. We'll now lay out the widgets. Click the form then press Ctrl+G (lay out in a grid).
4. We'll now handle the signals and slots connections. Press F3 (connect signals/slots).
Click the Credit Dialog button, drag to the form and release. Click the clicked()
signal. We'll need to implement a custom slot. Click Edit Slots to invoke the Edit
Slots dialog. Click New Slot and type in the Slot name 'creditDialog()'. Click OK.
The new slot is now in the list of slots; click the creditDialog() slot to make the
connection then click OK. Connect the Quit button's clicked() signal to the
dialog's accept() function. (Press F3. Click the Quit button and drag to the form;
release. Click the clicked() signal and the accept() slot, then click OK.)
Save the form and call it mainform.ui. (Press Ctrl+S and enter the filename.) In the next
section we'll write the code for loading and launching the dynamic dialog directly in Qt
Designer.
Loading and Executing a Dynamic Dialog
We'll now add the code to invoke the credit dialog. Before we can do this we need to add
the widget factory's header file to the form. Click the Source tab in the Object Hierarchy.
Right click Included (in Implementation), then click New. Type in '<qwidgetfactory.h>',
then press Enter. Because we will need to access the spin box in the dynamic dialog we
must add its header file. Right click Included (in Implmentation), then click New. Type in
'<qspinbox.h>', then press Enter.
In our main form we created a slot called creditDialog(). We will implement this slot
directly in Qt Designer and use it to load and execute the dynamic dialog. The code is taken
from qt/tools/designer/examples/receiver1/mainform.ui.h which contains the
C++ implementation of mainform.ui's slots.
void MainForm::creditDialog()
{
QDialog *creditForm = (QDialog *)
QWidgetFactory::create( "../credit/creditformbase.ui" );
// Set up the dynamic dialog here
if ( creditForm->exec() ) {
// The user accepted, act accordingly
QSpinBox *amount = (QSpinBox *) creditForm->child(
"amountSpinBox", "QSpinBox" );
if ( amount )
ratingTextLabel->setText( amount->text() );
}
delete creditForm;
}
The create() function is a static QWidgetFactory function. It loads the specified .ui file
and returns a pointer to the toplevel QWidget created from the .ui file. We have cast the
pointer to QDialog since we know that the creditformbase.ui file defines a QDialog.
After creating the dialog we exec() it. If the user clicked OK the dialog returns Accepted
and we enter the body of the if statement. We want to know the amount of credit that the
user selected. We call the child() function on the dialog passing it the name of the widget
we're interested in. The child() function returns a pointer to the widget with the name we
passed, or returns 0 if no widget of that name was found. In the example we call child() to
get a pointer to the 'amountSpinBox'. If the pointer we get back is not 0 we set the rating
text to the amount in the dialog's spin box. At the end we delete the dynamic dialog.
Deleting the dialog ensures that we free up its resources as soon as it is no longer required.
We used the child() to gain access to a widget within the dynamic dialog, passing it the
name of the widget we were interested in. In some situations we might not know what a
widget is called. We can access the first widget of a specified class by calling child() with
a null widget name and a classname, e.g. child(0,"QPushButton"). This will return a
pointer to the first QPushButton it finds (or 0 if there isn't one). If you want pointers to all
the widgets of a given class you can call the QObject::queryList() function, passing it
the name of the class. It returns a QObjectList pointer which points to every object in the
dialog that is derived from the given class. See the online QObject documentation for
further details.
Implementing Slots for Dynamic Dialogs
There is one outstanding issue that we haven't addressed: the dynamic dialog does not have
the behaviour of the original credit dialog because we have not implemented the
setAmount() slot. We can implement slots for dynamic dialogs by creating a QObject
subclass. We then create an instance of this subclass and pass a pointer to it to the
QWidgetFactory::create() function which will connect the dynamic dialog's signals to
the slots implemented in our subclass.
if ( creditForm->exec() ) {
// The user accepted, act accordingly
QSpinBox *amount = (QSpinBox *) creditForm->child(
"amountSpinBox", "QSpinBox" );
if ( amount )
ratingTextLabel->setText( amount->text() );
}
delete receiver;
delete creditForm;
}
We create a new instance of our 'Receiver' subclass. (We'll write the code for this class
shortly.) We then create the QDialog using QWidgetFactory::create(). This call differs
from our previous example because we pass in the subclass object so that the create()
function can set up the signals/slots connections automatically for us. Since our slot must
access the widgets in the dynamic form we pass a pointer to the form to the receiver object
through our setParent() function. The remainder of the function is the same as before
except that we delete our receiver object.
We'll now look at the implementation of our 'Receiver' subclass. The code is taken from
qt/tools/designer/examples/receiver2/receiver.h and the corresponding
receiver.cpp file. We'll start with the header file.
#include <qobject.h>
#include <qdialog.h>
QRadioButton *radio =
(QRadioButton *) p->child( "stdRadioButton", "QRadioButton"
);
if ( radio && radio->isChecked() ) {
if ( amount )
amount->setValue( amount->maxValue() / 2 );
return;
}
radio =
(QRadioButton *) p->child( "noneRadioButton", "QRadioButton"
);
if ( radio && radio->isChecked() )
if ( amount )
amount->setValue( amount->minValue() );
}
Since we may be updating the amount spin box we need to get a pointer to it. We call
child() on the pointer p which points to the dynamic dialog assigned in the setParent()
call. We cast the resulting pointer to the correct type so that we can call any functions
relevant to that type. In the example we call child() to get a pointer to the amount spin
box, and then call child() again to get a pointer to the 'stdRadioButton'. If we get a pointer
to the radio button and the button is checked we set the amount providing we have a pointer
to the amount spin box. If this radio button was checked we're finished so we return. If the
'stdRadioButton' isn't checked we get a pointer to the 'noneRadioButton' and set the amount
if this button is checked. We do nothing if the 'specialRadioButton' is checked because the
user is free to enter a value of their choice.
Compiling vs Dynamically Loading Dialogs
The differences between using a 'compiled in' .ui file and a dynamically
loaded .ui file are these:
• Dynamic dialogs cannot have any C++ code in the .ui file; any
custom slots must be implemented via a QObject subclass.
Compiled dialogs can contain code either in the .ui file or in a
subclass.
• Dynamic dialogs will load slower because the .ui file must be read
and a QWidget instance instantiated based on the .ui file's parse
tree. Compiled code will load much faster because no file reading or
parsing is necessary. Note that the user may not notice any difference
in speed since the difference may be mere fractions of a second.
class QLineEdit;
class QPushButton;
Our widget will be derived from QWidget so we include the qwidget.h header file. We
also forward declare the two classes that our widget will be built from.
We include the Q_OBJECT macro since this is required for classes that declare signals or
slots. The Q_ENUMS declaration is used to register the Mode enumeration. Our widget has
two properties, mode, to store whether the user should select a File or a Directory and
fileName which stores the file or directory they chose.
class FileChooser : public QWidget
{
Q_OBJECT
Q_ENUMS( Mode )
Q_PROPERTY( Mode mode READ mode WRITE setMode )
Q_PROPERTY( QString fileName READ fileName WRITE setFileName )
public:
FileChooser( QWidget *parent = 0, const char *name = 0);
signals:
void fileNameChanged( const QString & );
private slots:
void chooseFile();
The two 'set' functions are declared as public slots. setFileName() and setMode() set the
filename and mode respectively. We declare a single signal, fileNameChanged(). The
private slot, chooseFile() is called by the widget itself when its button is clicked.
private:
QLineEdit *lineEdit;
QPushButton *button;
Mode md;
};
A pointer to QLineEdit and QPushButton, as well as a Mode variable are held as private
data.
Coding the Implementation
We will work step-by-step through the implementation which is in
qt/tools/designer/examples/filechooser/widget/filechooser.cpp.
FileChooser::FileChooser( QWidget *parent, const char *name )
: QWidget( parent, name ), md( File )
{
The constructor passes the parent and name to its superclass, QWidget, and also initializes
the private mode data, md, to File mode.
QHBoxLayout *layout = new QHBoxLayout( this );
layout->setMargin( 0 );
if ( !fn.isEmpty() ) {
lineEdit->setText( fn );
emit fileNameChanged( fn );
}
}
When chooseFile() is called it presents the user with a file or directory dialog depending
on the mode. If the user chooses a file or directory the QLineEdit is updated with the
chosen file or directory and the fileNameChanged() signal is emitted.
Although these two files complete the implementation of the FileChooser widget it is good
practice to write a test harness to check that the widget behaves as expected before
attempting to put it into a plugin.
Testing the Implementation
We present a rudimentary test harness which will allow us to run our custom widget. The
test harness requires two files, a main.cpp to contain the FileChooser, and a .pro file to
create the Makefile from. Here is
qt/tools/designer/examples/filechooser/widget/main.cpp:
#include <qapplication.h>
#include "filechooser.h"
Creating a Plugin
Qt Plugins can be used to provide self-contained software components for Qt applications.
Qt currently supports the creation of five kinds of plugins: codecs, image formats, database
drivers, styles and custom widgets. In this section we will explain how to convert our
filechooser custom widget into a Qt Designer custom widget plugin.
A Qt Designer custom widget plugin is always derived from QWidgetPlugin. The amout
of code that needs to be written is minimal.
To make your own plugin it is probably easiest to start by copying our example plugin.h
and plugin.cpp files and changing 'CustomWidgetPlugin' to the name you wish to use for
your widget plugin implementation class. Below we provide an introduction to the header
file although it needs no changes beyond class renaming. The implementation file requires
simple changes, mostly more class renaming; we will review each function in turn and
explain what you need to do.
The CustomWidgetPlugin Implementation
We have called our header file plugin.h and we've called our plugin class
CustomWidgetPlugin since we will be using our plugin class to wrap our custom widgets.
We present the entire header file to give you an impression of the scope of the
implementation required. Most of the functions require just a few lines of code.
#include <qwidgetplugin.h>
Create your own plugin .cpp file by copying our plugin.cpp file and changing all
occurrences of 'CustomWidgetPlugin' to the name you wish to use for your widget plugin
implementation. Most of the other changes are simply replacing the name of our custom
control, 'FileChooser', with the name of your custom control. You may need to add extra
else if clauses if you have more than one custom control in your plugin implementation.
The iconSet() function returns the pixmap to use in the toolbar to represent the custom
widget. The toolTip() function returns the tooltip text and the whatsThis() function
returns the Whats This text. Copy each of these functions changing the class name, key and
the string you return to suit your own widget plugin implementation.
target.path=$$plugins.path
isEmpty(target.path):target.path=$$QT_PREFIX/plugins
INSTALLS += target
TEMPLATE = lib
CONFIG += qt warn_on release plugin
INCLUDEPATH += $(QTDIR)/tools/designer/interfaces
DBFILE = plugin.db
PROJECTNAME = Plugin
LANGUAGE = C++
qt/tools/designer/examples/filechooser/plugin/plugin.pro
Change the HEADERS line to list your plugin's header file plus a header file for each of your
widgets. Make the equivalent change for the SOURCES line. If you create a Makefile with
qmake and make the project the plugin will be created and placed in a directory where Qt
Designer can find it. The next time you run Qt Designer it will detect your new plugin and
load it automatically, displaying its icon in the toolbar you specified.
Using the Widget Plugin
Once the plugin has been compiled it will automatically be found and loaded by Qt
Designer the next time Qt Designer is run. Use your custom widget just like any other.
When you want to distribute your application, include the compiled plugin with the
executable. Install the plugin in $QTDIR/plugins/widgets. If you don't want to use the
standard plugin path, have your installation process determine the path you want to use for
the plugin, and save the path, e.g. using QSettings, for the application to read when it runs.
The application can then call QApplication::addLibraryPath() with this path and your
plugins will be available to the application. Note that the final part of the path, i.e. styles,
widgets, etc. cannot be changed.
Creating Database Applications
This chapter shows you how to use Qt's data-aware widgets from within Qt Designer. It
demonstrates INSERT, UPDATE and DELETE in both QDataTables (tables) and
QDataBrowsers (forms). It also shows how to code Master-Detail relationships and
Drilldown. A simple approach to foreign key handling is presented here; a more
sophisticated approach is shown in the online SQL module documentation.
If you wish to run the examples or create your own applications using these widgets you
need access to an SQL database and a Qt database driver that can connect to the database.
At the time of writing the drivers that Qt supports are QODBC3 (Open Database
Connectivity), QOCI8 (Oracle), QPSQL7 (PostgreSQL 6 and 7) and QMYSQL3 (MySQL).
Although you can use the Qt data-aware widgets to browse and edit data in SQL databases
without having to write any SQL, a basic understanding of SQL is highly recommended.
We assume that you have some familiarity with SELECT, INSERT, UPDATE and DELETE
statements. We also assume a basic understanding of the concepts of normalisation and of
primary and foreign keys. A standard text covering SQL databases is An Introduction to
Database Systems (7th ed.) by C. J. Date, ISBN 0201385902.
In the following text we describe the creation of a 'book' database application. The
application demonstrates how to use QDataTables including in-place record editing and
how to set up master-detail relationships between QDataTables. It also explains how to
drill down from a QDataTable to another widget, for example, to a QDataBrowser or a
QDataView and how to perform record editing in a QDataBrowser. A great deal of
functionality is available from the classes directly in Qt Designer although subclassing is
always available for finer control. If you want to build the 'book' examples you will need to
create the example schema on your database.
The Book Application
The Example Schema
Note that the examples in this chapter all use the tables, views and records
which are defined in the qt/tools/designer/examples/book/book.sql
file. This file has been tested with PostgreSQL 6 and PostgreSQL 7. You
may need to modify the SQL in this file to recreate the example database on
your own system.
Qt Designer can remember database connection settings in qmake project files. Create a
new project, e.g. click File|New, then click the 'C++ Project' icon to invoke the Project
Settings dialog. Click the ellipsis button to invoke the Save As dialog; navigate to the
project's directory (creating it if necessary). Make sure you're in the project's directory, then
enter a project name of 'book.pro'. Click the Save button to return to the Project Settings
dialog, then click OK. Next time you start Qt Designer instead of opening individual .ui
files open the .pro project file instead and Qt Designer will automatically reload the
project's connection settings. To activate the connection click Project|Database
Connections. The connections previously saved with the project will be listed in the left
hand list box. Click the connection you wish to use and then click Connect. This
connection will be used from now on, e.g. for previewing QDataTables. Opening a project
file also causes Qt Designer to load in the list of forms associated with the project into the
Form List window. In most of the explanation that follows we will assume that you use
project files and have clicked Connect so that there is always a connection available when
you work in Qt Designer.
return TRUE;
}
We call addDatabase() passing it the name of the driver we wish to use. We then set the
connection information by calling the set... functions. Finally we attempt to open the
connection. If we succeed we return TRUE, otherwise we output some error information
and return FALSE. From qt/tools/designer/examples/book/book1/main.cpp
int main( int argc, char *argv[] )
{
QApplication app( argc, argv );
if ( ! createConnections() )
return 1;
BookForm bookForm;
app.setMainWidget( &bookForm );
bookForm.show();
return app.exec();
}
All the examples presented in this chapter call createConnections() after creating the
QApplication object in their main.cpp file and make use of the default connection. If you
need to connect to multiple databases use the two-argument form of addDatabase(),
passing it both the name of the driver and a unique identifier. This is explained further in
the Qt SQL Module documentation.
You do not need to keep a reference to database connections. If you use a single database
connection, this becomes the default connection and database functions will use this
connection automatically. We can always get a pointer to any of our connections by calling
QSqlDatabase::database().
If you create a main.cpp file using Qt Designer, this file will not include
createConnections(). We do not include this function because it needs the username and
password for the database connection, and you may prefer to handle these differently from
our simple example function. As a result, applications that preview correctly in Qt Designer
will not run unless you implement your own database connections function.
Using QDataTable
QDataTables may be placed on any form to provide browsing of database tables and
views. QDataTables can also be used to update or delete records in-place, i.e. inside the
cells themselves. Inserting records via a QDataTable usually requires connecting to the
primeInsert() signal, so that we can generate primary keys for example, or provide
default values. If we wish to present records using a form view (perhaps combining data
from several tables and views) we might use several QDataBrowsers and QDataViews.
To turn the form we've created into an executable application we must add the main.cpp
file to the project file and make the project. We should also do some renaming to make
things easier to understand.
1. Click on the form and change its name to 'BookForm' and its caption to 'Book'.
Click on the QDataTable and change its name to 'AuthorDataTable'.
2. Click File|Save All.
3. Open the project file, e.g. book.pro, in a plain text editor and add the line: SOURCES
+= main.cpp at the end of the file.
4. Run qmake to generate the make file, e.g. qmake -o Makefile book.pro, then
make and run the book program.
This example shows how easy it is to use QDataTable to show the contents of a database
table or view. You can use the application we've just built to update and delete author
records. In the examples that follow we will cover insertions, setting up master-detail
relationships, drilldown and foreign key lookups.
A Note on Foreign Keys
In most relational databases tables contain fields which are foreign keys into
other tables. In our 'book' database example the authorid in the book table is
a foreign key into the author table. When we present a form to the end user
we do not usually want the foreign key itself to be visible but rather the text
associated with it. Thus, we would want the author's name to appear rather
than the author id when we show book information. In many databases, this
can be achieved by using a view. See your database's documentation for
details.
4. On the SQL page we will leave the Filter (WHERE clause) empty. Move the
title field to the Sort By list box and click Next. Now click Finish.
5. Change this QDataTable's name to "BookDataTable".
4. Shift+Click the top QDataTable so that both QDataTables are selected and then
click the Lay Out Vertically (in Splitter) toolbar button.
5. Click on the form and click the Lay Out Vertically toolbar button.
Run the form by clicking Preview|Preview Form. All the authors are displayed in the top
QDataTable and all the books are displayed in the bottom QDataTable. However we only
want the books of the currently selected author showing in the bottom QDataTable. We
will deal with this by filtering the records in the book table according to the author selected
in the author table.
Using the Table Editor
Edit Table Dialog
QDataTables are created and set up using the SQL Table Wizard. Like any
other Qt Designer widget their properties may be changed in the Properties
window. Some of the column and row based properties can also be be
changed using the Edit Table dialog. This dialog is invoked by right clicking
the QDataTable and left clicking the Edit menu item. The right hand half
of the Edit Table dialog is where we choose the fields we wish to display,
their order and their labels. The procedure for creating columns is as
follows:
1. Click the New Column button.
2. Drop down the Field combobox to list the available fields.
3. Click the field you wish to include at this point.
4. Optionally edit the Label if the default isn't appropriate.
5. Optionally click the Pixmap ellipsis (...) button to choose a pixmap to
be displayed to the left of the column's label. (The ellipsis button
appears when you click in the Value part of the Properties list by a
pixmap or iconSet property.)
Repeat the steps listed above for each column you wish to add. Once all the
fields have been added you can change their ordering by using the blue up
and down arrow buttons. At any point you can press Apply to see how the
table will look. Finally click the OK button to save the properties you have
set. You can always return to the table editor to change these settings later.
Filtering One QDataTable by Another
To filter the book table's records we need to capture the author QDataTable's
currentChanged() signal and change the BookDataTable's filter accordingly.
1. Click Edit|Slots. In the Edit Slots dialog click New Slot and enter a slot name of
newCurrentAuthor(QSqlRecord*). Click OK.
1. We need to make a new slot to connect the Edit Books' button's clicked() signal
to. Click on the Book form to make it Qt Designer's active form. Invoke the Edit
Slots dialog and create a new slot called editClicked(). Now click the Connect
Signals/Slots toolbar button. Click the Edit Books button and drag to the form;
release the mouse on the form. In the Edit Connections dialog connect the
clicked() signal to the editClicked() slot. Click OK to leave the dialog.
2. In the Object Hierarchy window click Source and then click the editClicked
function. We need to change it to the following:
3. void BookForm::editClicked()
4. {
5. EditBookForm *dialog = new EditBookForm( this, "Edit Book
Form", TRUE );
6. QSqlCursor cur( "book" );
7. dialog->BookDataBrowser->setSqlCursor( &cur );
8. dialog->BookDataBrowser->setFilter( BookDataTable->filter()
);
9. dialog->BookDataBrowser->setSort(QSqlIndex::fromStringList(
10. BookDataTable->sort(), &cur ) );
11. dialog->BookDataBrowser->refresh();
12. int i = BookDataTable->currentRow();
13. if ( i == -1 ) i = 0; // Always use the first row
14. dialog->BookDataBrowser->seek( i );
15. dialog->exec();
16. delete dialog;
17. BookDataTable->refresh();
18. }
We create our dialog as before. We also create a cursor over the book table and set
the dialog's QDataBrowser, BookDataBrowser, to use this new cursor. We set the
QDataBrowser's filter and sort to those that applied to the main form's book
QDataTable. We refresh the QDataBrowser and seek to the same record the user
was viewing on the main form. Then we exec the dialog and delete it when the user
has finished with it. Finally we update the BookDataTable in the main form to
reflect any changes that were made in the dialog.
19. Because our code refers to a class declared in editbook.h and to a QDataBrowser
we need to add two additional include files. Click on the BookForm, then click on
the Source tab of the Object Hierarchy window. Right click the 'Includes (In
Declaration)' item and click New. Type in "editbook.h". Now add a second
include, this time, <qdatabrowser.h>.
Now when we navigate through the author and book records in the BookForm we can click
the Edit Books button to launch our Edit Books dialog. Although the dialog supports
UPDATE, DELETE and navigation over the book table, we cannot edit the foreign keys nor
perform inserts. We will deal with insertion in the same way as we did with the
QDataTable, then we will handle the foreign key relationship to author.
Inserting into a QDataBrowser
We will create a slot to receive the Edit Books form's primeInsert() signal so that we can
insert a unique primary key.
1. Click on the Edit Books form, then create a new Slot called
primeInsertBook(QSqlRecord*).
Click Edit|Slots, then click the New Slot button and type the new slot name in the
Slot Properties Slot edit box. Click OK.
3. In the Object Hierarchy window click Source and then click the primeInsertBook
slot. We need to change it to the following:
4. void EditBookForm::primeInsertBook( QSqlRecord * buffer )
5. {
6. QSqlQuery query;
7. query.exec( "UPDATE sequence SET sequence = sequence + 1
WHERE tablename='book';" );
8. query.exec( "SELECT sequence FROM sequence WHERE
tablename='book';" );
9. if ( query.next() ) {
10. buffer->setValue( "id", query.value( 0 ) );
11. }
12. }
13. We will also tidy up the user interface slightly. Click the Update button and set its
default property to True. Connect the Close button's clicked() signal to the
EditBookForm's accept() slot.
Handling Foreign Keys in a QDataBrowser
Qt's SQL module provides two approaches to dealing with foreign keys. The most powerful
and flexible is to subclass widgets and use property maps to relate the widgets to the
database. This approach is described in the Qt SQL Module documentation, particularly the
StatusPicker example. A simpler approach that can be taken wholly within Qt Designer is
presented here.
We will add a new field to the EditBookForm so that authors can be edited along with the
title and price. Once we've handled the visual design we'll write the code to make it all
work.
1. First we'll add the new widgets. Click the BookDataBrowser and click the Break
Layout toolbar button. Resize the form to make it larger and drag each set of
buttons down to make some room below the title and price QLineEdits. Click the
Text Label toolbar button and click on the form beneath the Price label. Click the
Text Label and change its text to 'Author'. Click the ComboBox toolbar button and
click on the form beneath the price QLineEdit. In the Property Window change the
ComboBox's name to ComboBoxAuthor and change its sizePolicy hSizeType to
Expanding.
2. Now we'll lay out the dialog. Shift+Click the Author label and the ComboBox then
click the Lay Out Horizontally toolbar button. Now click the BookDataBrowser
and click the Lay Out in a Grid toolbar button.
We need to write some code so that the ComboBox will be populated with author names
and scroll to the current book's author. We also need to ensure that we put the author's id
into the book table's authorid field when a book record is inserted or updated. We'll ensure
the code is executed at the right time by putting it in slots and connecting signals to our
slots.
3. All that remains is to write the underlying code. All the code snippets are taken
from qt/tools/designer/examples/book/book7/editbook.ui.
1. We start with the init() function; this is called after the dialog is
constructed and we will use it to populate the ComboBox with author names.
2. void EditBookForm::init()
3. {
4. QSqlQuery query( "SELECT surname FROM author ORDER BY
surname;" );
5. while ( query.next() )
6. ComboBoxAuthor->insertItem( query.value( 0
).toString());
7. }
Here we execute a query to get a list of author names and insert each one
into the ComboBox.
8. We next write the code which will be executed just before a record is
updated (or inserted) in the database.
9. void EditBookForm::beforeUpdateBook( QSqlRecord * buffer
)
10. {
11. QSqlQuery query( "SELECT id FROM author WHERE
surname ='" +
12. ComboBoxAuthor->currentText() + "';" );
13. if ( query.next() )
14. buffer->setValue( "authorid", query.value( 0 )
);
15. }
We look up the id of the ComboBox's current author and place it in the
update (or insert) buffer's authorid field.
16. As the user navigates through the records we ensure that the ComboBox
reflects the current author.
17. void EditBookForm::primeUpdateBook( QSqlRecord *
buffer )
18. {
19. // Who is this book's author?
20. QSqlQuery query( "SELECT surname FROM author WHERE
id='" +
21. buffer->value( "authorid" ).toString() + "';"
);
22. QString author = "";
23. if ( query.next() )
24. author = query.value( 0 ).toString();
25. // Set the ComboBox to the right author
26. for ( int i = 0; i < ComboBoxAuthor->count(); i++
) {
27. if ( ComboBoxAuthor->text( i ) == author ) {
28. ComboBoxAuthor->setCurrentItem( i ) ;
29. break;
30. }
31. }
32. }
Firstly we look up the book's author and secondly we iterate through the
ComboBox's items until we find the author and set the ComboBox's current
item to the matching author.
If the author name has changed or been deleted the query will fail and no author id will be
inserted into the buffer causing the INSERT to fail. An alternative is to record the author id's
as we populate the ComboBox and store them in a QMap which we can then look up as
required. This approach requires changes to the init(), beforeUpdateBook() and
primeInsertBook() functions and the addition of a new function, mapAuthor(). The
relevant code from qt/tools/designer/examples/book/book8/editbook.ui is shown
below.
1. First we need to create a class variable to map author names to author id's. Click in
the Source tab of the Object Hierarchy, then right click the Class Variables item and
click New. Type in 'QMap<QString,int> authorMap;'.
When you enter -> or . the editor will pop up a command completion list; use the arrow
keys to move to the item you want and press Return, or press Esc to ignore the list.
Simple Templates
These templates are most useful when you want to create a whole set of forms which all
have some common widgets. For example, you might have a project that will require many
forms, all of which need to be branded with a company name and logo.
First we'll create the simple template.
1. Click File|New to invoke the New File dialog. Click the Dialog template then click
OK.
2. Click the Text Label toolbar button, then click near the top left of the form. Change
the font Point Size property to 16 and change the text property to your or your
company's name. Click the Line toolbar button, then click the form below the label;
click Horizontal on the pop-up menu.
3. Select the label and the line. (Ctrl+Click the form, then drag the rubber band so that
it touches or includes the line and the label.) Press Ctrl+L to lay them out
vertically.
4. Click the Save toolbar button. In the Save As dialog, navigate to Qt Designer's
templates directory, e.g. (qt/tools/designer/templates. Type in the name
'Simple_Dialog.ui' and click Save.
5. Right click the form in the Forms list, then click Remove form from project.
Now that we have the simple template we are ready to use it. Click File|New to invoke the
New File dialog. One of the templates that will appear is 'Simple Dialog'. Click the simple
dialog, then click OK. A new form will appear with the same widgets and layout as the
template. Add any other widgets and functionality. When you attempt to save the form you
will be prompted for a new form name.
Base-class Templates
These templates are useful when you want to provide some default functionality that all the
forms based on the base class can inherit. In our example we'll use a class called
SizeAware that remembers and restores its size as the basis of a template. We won't
describe the class itself, but will focus instead on making use of it as a Qt Designer
template. The source for the class is in qt/tools/designer/examples/sizeaware.
The template can either be based on a custom widget or on any existing container widget.
If you want to base the template on a custom widget you must first add it to Qt Designer's
custom widgets. Click Tools|Custom|Edit Custom Widgets to invoke the Edit Custom
Widgets dialog. (This dialog is explained in more detail in Simple Custom Widgets.) Click
New Widget. Change the Class from 'MyCustomWidget' to 'SizeAware'. Click the
Headerfile ellipsis button and select the file
qt/tools/designer/examples/sizeaware/sizeaware.h. Check the Container Widget
checkbox. This class provides two properties. Click the Properties tab. Click New Property
and change the property name to 'company'. Click the New Property again and change the
property name to 'settingsFile'. Click Close.
To create a template, based on an existing widget or on your own custom widget, click
File|Create Template to invoke the Create Template dialog. Change the Template Name
to 'SizeAware' and click the SizeAware base class, then click Create. The dialog will create
the template and close itself immediately. Close Qt Designer and restart it.
A new template, 'SizeAware' is now available from the list of templates. Click File|New,
click SizeAware and click OK. Note that the two properties, company and settingsFile, are
available in the Properties window. Any forms based on this template will remember their
size and resize when reloaded. (In practical applications having one settingsFile per form is
not recommended, so this template would only really be useful for applications that have a
single main window.)
• Generate Qt Project -- Runs qmake (or the functionally equivalent tmake) with a
.pro file
Double clicking a .ui file in the workspace overview will now launch Qt Designer.
If you create a .cpp file which contains the Q_OBJECT macro you will need an additional
file which is generated by the moc to be included in your project. For example, if you have
'file.cpp', then the last line would be #include "file.moc" and the additional file would
be called 'file.moc'. To ensure that Visual Studio executes the moc and generates this file
you must create a custom dependency. Double click the .cpp file (in your project
workspace) that contains the Q_OBJECT macro. Click the Add MOC toolbar button; this
will create an empty .moc file in your project workspace. Right click the newly created
.moc file, then click Settings from the pop-up menu to invoke the Project Settings dialog.
Click the Custom Build tab. Click the Dependencies button to pop up the User Defined
Dependencies dialog. Type in $(InputDir)\$(InputPath), then press Return. Click OK
to leave the Dependencies dialog, then click OK to leave the Project Settings dialog.
If you wish to delete the add-in remove it from the toolbar then delete the qmsdev.dll file
from the add-ins directory.
Qt Designer produces .ui files which are used to generate .h and .cpp files for the
compiler to compile. The .ui files are processed by uic. Classes which inherit from
QObject, e.g. those which use slots and signals, require an additional .cpp file to be
generated. These files are generated by the moc and are named 'moc_file.cpp' where the
original .cpp file is called 'file.cpp'. If your .cpp file contains the Q_OBJECT macro an
additional file 'file.moc' should be generated which must be #included in the .cpp,
normally at the end. This requires an extra dependency being created.
main.o: main.cpp
g++ -o main.o main.cpp
moc_myform.o: moc_myform.cpp
g++ -o moc_myform.o moc_myform.cpp
moc_myform.cpp: myform.h
moc myform.h -o moc_myform.cpp
myform.o: myform.cpp
g++ -o myform.o myform.cpp
myform.h: myform.ui
uic myform.ui -o myform.h
Note that you may need to include the full path to the commands in your Makefile, and
under Windows the filenames are moc.exe and uic.exe.
In Unix/Linux environments the make command may be able to do more for us, so we
should be able to use a simpler Makefile like this:
myapp: moc_myform.o myform.o main.o
g++ -lq -o $@ $^
%.o: %.cpp
g++ -o $^ $@
moc_%.cpp: %.h
moc $^ -o $@
myform.h: myform.ui
uic myform.ui -o myform.h
To see more sophisticated Makefiles simply generate them using qmake on any of your Qt
projects or any of the examples supplied with Qt.
The import filter does a good job of importing .dlg files; the result is almost identical to
what you get in Qt Architect. However, the C++ code that uses the dialogs will probably
need some adaptation.
There are a few drawbacks to converting Qt Architect files to Qt Designer's format due to
differences between the two tools; these are listed below:
• Layout spacing and margins
If the .dlg file layouts use the Qt Architect defaults for layout spacing and margins,
Qt Designer will override these with its standard defaults. You can change the
"layoutSpacing" and "layoutMargin" properties manually afterwards if necessary.
• Layout stretches and spacings
Qt Architect gives access to more features of Qt's layout system than Qt Designer,
namely stretches and spacings. Qt Designer will attempt to cope with .dlg files that
use these features, but sometimes the resizing will not be what you want. The
solution typically involves setting the "sizePolicy" properties of some widgets and
inserting or deleting spacers.
• Mixing managed and unmanaged widgets
Qt Architect allows a widget to have some child widgets managed by a layout and
other child widgets with fixed positions. When presented with a .dlg file that uses
this facility, Qt Designer will silently put the fixed position widgets into the layout.
• Pixmaps
Qt Designer has been tested with Glade files up to version 0.6.0 and might work with later
versions as well.
Although Glade does not target Qt, the layout system and the widget set of GTK+ are
similar to those of Qt, so the filter will retain most of the information in the .glade file.
There are some considerations regarding the conversion of Glade files, as listed below:
• Ampersands (&) in labels
Qt displays an ampersand when a QLabel has no buddy. (A buddy is a widget that
accepts focus on behalf of a QLabel.) Glade allows GtkLabel widgets with an
(underlined) accelerator key but with no buddy. This is an error since users expect
underlined characters to be accelerators. In this situation, Qt displays the ampersand
itself instead of underlining the accelerator key. You should go over these QLabel
widgets and set their "buddy" property.
• Layout placeholders
GTK allows a layout position to be occupied by a placeholder. Qt Designer converts
those placeholders into QLabels whose text is "?" in red, so that you can find them
and fix them manually.
• GTK+ or GNOME widget with no Qt equivalent
Qt has equivalents for most GTK+ widgets, but Glade also supports GNOME,
whose goal is to provide a complete desktop environment. Because Qt's scope is
narrower, when Qt Designer encounters a widget it cannot convert, it replaces it
with a label that indicates the problem. For example, a GnomePaperSelector will be
replaced by a QLabel whose text is "GnomePaperSelector?" in red. If you are
porting to KDE, you might want to use the corresponding KDE widget.
Other GTK+/GNOME widgets are only supported in certain contexts. For example,
the GnomeDruid can be embedded in another widget, whereas the corresponding
QWizard class cannot.
• Message boxes and other high-level dialogs
Glade supports editing of GnomeMessageBox, GtkFileSelection,
GtkFontSelectionDialog and others. This is trivially achieved in Qt by means of a
QMessageBox dialog, a QFileDialog, a QFontDialog, etc., in C++ code.
• Stand-alone popup menus
Qt Designer only supports popup menus inside a QMainWindow. If you need a
stand-alone popup menu (presumably a context menu), you can easily write code
that does this using QPopupMenu.
• Size policy parameters
Glade provides size policies in the "Place" tab of the property editor. Qt Designer
does not attempt to make use of the padding, expand, shrink and fill information, as
the Qt defaults are usually good enough. In a few cases, you might have to set the
"sizePolicy" property manually to obtain the effect you want.
• GNOME standard icons
GNOME provides a large set of standard icons. Qt Designer will ignore references
to these. If you are porting to KDE, you might want to manually set the standard
KDE icons.
• Packer layout
GTK+ provides a class called GtkPacker that provides for exotic layouts; Qt
provides no QPackerLayout and never will. Qt Designer will treat packer layouts
as if they were vertical layouts and you will probably have to change them to
whatever combination of layouts that produces the right effect.
• Incorrectly-justified text after conversion
The "hAlign" property is sometimes set wrongly, in which case you have to change
it manually. It is caused by a quirk in Glade.
Reference: Key Bindings
• Ctrl+A -- Selects all GUI elements in the active form.
• Ctrl+B -- Breaks the selected layout so that you can add or delete GUI elements.
• Ctrl+C -- Copies the selected GUI elements from the active form into the clipboard.
• Alt+E -- Pulls down the Edit menu.
• Alt+F -- Pulls down the File menu.
• Ctrl+G -- Applies a grid layout to the selected container, or creates a new container
containing the selected GUI elements and applies a grid layout to this container.
• Ctrl+H -- Applies a horizontal box layout to the selected container, or creates a new
container containing the selected GUI elements and applies a horizontal box layout
to this container.
• Alt+H -- Pulls down the Help menu.
• Ctrl+J Adjusts the size of the selected GUI element (or elements) so that it has the
minimal size needed for displaying itself properly.
• Ctrl+L -- Applies a vertical box layout to the selected container, or creates a new
container containing the selected GUI elements and applies a vertical box layout to
this container.
• Alt+L -- Pulls down the Layout menu.
• Ctrl+M -- Opens an online version of this manual in Qt Assistant.
• Ctrl+N -- Invokes the New File dialog.
• Ctrl+O -- Invokes the Open File dialog.
• Alt+P -- Pulls down the Preview menu.
• Ctrl+R -- Checks the accelerators in the active form for duplicates.
• Ctrl+S -- Saves the active form.
• Ctrl+T -- Previews the active form in the default GUI style of the platform.
• Alt+T -- Pulls down the Tools menu.
• Ctrl+V -- Pastes the GUI element (or elements) in the clipboard into the active form
at the position it had in its original form plus a little offset. Does nothing if the
clipboard does not contain a GUI element.
• Alt+W -- Pulls down the Window menu.
• Ctrl+X -- Cuts the selected GUI element (or elements) from the active form and
puts it into the clipboard.
• Ctrl+Y -- Redoes the last undo action.
• Ctrl+Z -- Undoes the last action.
• Del -- Deletes the selected GUI elements from the active form.
• F1 -- Opens the introductory page of the Qt Designer manual in Qt Assistant.
• Shift-F1 -- Turns on What's This mode, which lets you click on a GUI element in Qt
Designer to get a small description window for this element.
• F2 -- Activates the pointer tool that lets you select GUI elements.
• F3 -- Activates the connection tool that lets you edit the connections between
signals and slots in a form.
• F4 -- Activates the tab order tool that lets you change the tab order of the GUI
elements on the active form.
• Ctrl+F4 -- Closes the active window.
• Ctrl+F6 -- Activates the next window in the order of window creation.
• Ctrl+Shift-F6 -- Activates the previous window in the order of window creation.
Reference: Menu Options
Introduction
Qt Designer provides menu options that invoke actions that are used to help create
applications. Many menu options lead to dialog boxes that provide specific functionality.
The most common menu options also have corresponding toolbar buttons. This chapter
explains each menu option and its use. For menu options that invoke a dialog box or which
have a corresponding toolbar button, there is a cross-reference to the detailed explanation
that appears in the relevant chapter.
• Window|Close
Click this menu option (or press Ctrl+F4) to close the window that is currently
active.
• Window|Close All
Click this menu option to close all the windows that are currently open.
• Window|Next
Click this menu option (or press Ctrl+F6) to make the next window active. The
order is the order in which the windows were opened.
• Window|Previous
Click this menu option (or press Ctrl+Shift+F6) to make the previous window
active. The order is the order in which the windows were opened.
• Window|Tile
Click this menu option to arrange all the open files and forms side by side so that
each window is visible.
• Window|Cascade
Click this menu option to stack all the open file and forms, one on top of the other,
but with an overlap so that each window's title bar is visible.
• Window|Views|File Overview
Click this menu option to make the File Overview Window visible, or to hide it if it
is already visible. If the window is currently visible, a check mark will appear next
to the name in the menu.
• Window|Views|Property Editor/Signal Handlers
Click this menu option to make the Property Editor/Signal Handlers Window
visible, or to hide it if it is already visible. If the window is currently visible, a
check mark will appear next to the name in the menu.
• Window|Views|Object Explorer
Click this menu option to make the Object Explorer Window visible, or to hide it if
it is already visible. If the window is currently visible, a check mark will appear
next to the name in the menu.
• Window|Views|Line Up
Click this menu option to eliminate any extra space between toolbars and line them
up next to each other all at once, rather than moving each individual toolbar into
place.
• Window|Toolbars|File
Click this menu option to make the File toolbar buttons visible, or to hide them if
they are already visible. If the toolbar buttons are currently visible, a check mark
will appear next to the name in the menu.
• Window|Toolbars|Edit
Click this menu option to make the Edit toolbar buttons visible, or to hide them if
they are already visible. If the toolbar buttons are currently visible, a check mark
will appear next to the name in the menu.
• Window|Toolbars|Search
Click this menu option to make the Search toolbar buttons visible, or to hide them if
they are already visible. if the toolbar buttons are currently visible, a check mark
will appear next to the name in the menu.
• Window|Toolbars|Layout
Click this menu option to make the Layout toolbar buttons visible, or to hide them if
they are already visible. If the toolbar buttons are currently visible, a check mark
will appear next to the name in the menu.
• Window|Toolbars|Tools
Click this menu option to make the Tools toolbar buttons visible, or to hide them if
they are already visible. If the toolbar buttons are currently visible, a check mark
will appear next to the name in the menu.
• Window|Toolbars|Buttons
Click this menu option to make the Buttons toolbar buttons visible, or to hide them
if they are already visible. If the toolbar buttons are currently visible, a check mark
will appear next to the name in the menu.
• Window|Toolbars|Containers
Click this menu option to make the Containers toolbar buttons visible, or to hide
them if they are already visible. If the toolbar buttons are currently visible, a check
mark will appear next to the name in the menu.
• Window|Toolbars|Views
Click this menu option to make the Views toolbar buttons visible, or to hide them if
they are already visible. If the toolbar buttons are currently visible, a check mark
will appear next to the name in the menu.
• Window|Toolbars|Database
Click this menu option to make the Database toolbar buttons visible, or to hide them
if they are already visible. If the toolbar buttons are currently visible, a check mark
will appear next to the name in the menu.
• Window|Toolbars|Input
Click this menu option to make the Input toolbar buttons visible, or to hide them if
they are already visible. If the toolbar buttons are currently visible, a check mark
will appear next to the name in the menu.
• Window|Toolbars|Display
Click this menu option to make the Display toolbar buttons visible, or to hide them
if they are already visible. If the toolbar buttons are currently visible, a check mark
will appear next to the name in the menu.
• Window|Toolbars|Custom
Click this menu option to make the Custom toolbar buttons visible, or to hide them
if they are already visible. If the toolbar buttons are currently visible, a check mark
will appear next to the name in the menu.
• Window|Toolbars|Help
Click this menu option to make the Help toolbar buttons visible, or to hide them if
they are already visible. If the toolbar buttons are currently visible, a check mark
will appear next to the name in the menu.
• Window|Toolbars|Line Up
Click this menu option to eliminate extra space between toolbars and line them up
next to each other all at once, rather than moving each individual toolbar into place.
• Window|n
Click one of the numbered menu options that list the currently open files and forms
to switch to the named file or form.
The Help Menu
File Toolbuttons
Edit Toolbuttons
Search Toolbuttons
Tools
• Pointer
Click this toolbar button (or press F2) to de-select any selected widget toolbar
button. The pointer is also used to stop inserting new widgets if you double clicked
a widget toolbar button. Press the Esc key to return to the pointer at any time.
• Connect Signals and Slots
Click this toolbar button (or press F3) to connect signals and slots. Then click on a
widget and drag the connection line to the widget (or the form) that you want to
connect to. Release the mouse button and the Edit Connections Dialog will appear.
• Tab Order
Click this toolbar button (or press F4) to set the tab order for all the widgets on the
form that can accept keyboard focus. Click this toolbar button and blue circles with
numbers on them appear next to the widgets. Click the widget that you want to be
first in the tab order, then click the widget that should be next in the tab order, and
continue until all the widgets have the tab order numbers you want. If you make a
mistake, double click the first widget and start again. Press Esc to leave tab order
mode. If you want to revert your changes, leave tab order mode, then undo.
Buttons
Buttons
• PushButton
Click this toolbar button, then click the form, to place a Pushbutton on the form.
• ToolButton
Click this toolbar button, then click the form, to place a Toolbutton on the form.
• RadioButton
Click this toolbar button, then click the form, to place a Radiobutton on the form. It
is recommended that you place RadioButtons inside ButtonGroups so that Qt will
automatically ensure that only one RadioButton in the group is active at any one
time.
• CheckBox
Click this toolbar button, then click the form, to place a CheckBox on the form.
Containers
Containers
• GroupBox
Click this toolbar button, then click the form, to place a GroupBox on the form.
• ButtonGroup
Click this toolbar button, then click the form, to place a ButtonGroup on the form.
• Frame
Click this toolbar button, then click the form, to place a Frame on the form.
• TabWidget
Click this toolbar button, then click the form, to place a TabWidget on the form. To
add or remove tabs, right click the tab widget and choose 'Add Page' or 'Remove
Page'.
Views
Views
• ListBox
Click this toolbar button, then click the form, to place a ListBox on the form.
• ListView
Click this toolbar button, then click the form, to place a ListView on the form.
• Icon View
Click this toolbar button, then click the form, to place an IconView on the form.
• Table
Click this toolbar button, then click the form to place a Table on the form.
Database Toolbuttons
Database
• DataTable
Click this toolbar button, then click the form, to place a DataTable on the form.
• DataBrowser
Click this toolbar button, then click the form, to place a DataBrowser on the form.
• DataView
Click this toolbar button, then click the form, to place a DataView on the form.
Input Toolbuttons
Input
• LineEdit
Click this toolbar button, then click the form, to place a LineEdit on the form.
• SpinBox
Click this toolbar button, then click the form, to place a SpinBox on the form.
• DateEdit
Click this toolbar button, then click the form, to place a DateEdit on the form.
• TimeEdit
Click this toolbar button, then click the form, to place a TimeEdit on the form.
• DateTimeEdit
Click this toolbar button, then click the form, to place a DateTimeEdit on the form.
• TextEdit
Click this toolbar button, then click the form, to place a TextEdit on the form.
• ComboBox
Click this toolbar button, then click the form, to place a ComboBox on the form.
• Slider
Click this toolbar button, then click the form, to place a Slider on the form.
• ScrollBar
Click this toolbar button, then click the form, to place a Scrollbar on the form.
• Dial
Click this toolbar button, then click the form, to place a Dial on the form.
Display Toolbuttons
Display
• TextLabel
Click this toolbar button, then click the form, to place a TextLabel on the form.
• PixmapLabel
Click this toolbar button, then click the form, to place a PixmapLabel on the form.
• LCDNumber
Click this toolbar button, then click the form, to place a LCDNumber on the form.
• Line
Click this toolbar button, then click the form, to place a Line on the form.
• ProgressBar
Click this toolbar button, then click the form, to place a ProgressBar on the form.
• TextBrowser
Click this toolbar button, then click the form, to place a TextBrowser on the form.
Custom
• My Custom Widget
Click this toolbar button, then click the form, to place a Custom Widget on the
form. Note: this toolbar button only appears if you have created a custom widget
using Tools|Custom|Edit Custom Widgets.
Layout Toolbuttons
Help Toolbutton
Save As
Save As
Click File|Save As to invoke the Save As dialog. Use this dialog to save files to a directory.
The Save As dialog shows the current directory and default file type. To choose a different
directory, click the 'Look In' combobox. Choose a file and the name will appear in the 'File
Name' combobox. To choose a different file type, click the 'File Type'combobox. Click the
'Create New Folder' toolbar button to create a new directory. Click the 'List View' toolbar
button to view folders and files in a list with only the names showing. Click the 'Details'
toolbar button to view the folders and file names along with their size, type, date, and
attributes. Click the Size, Type, Date, or Attributes column headers to sort the folders or
files.
Click Save to save the selected file. Click Cancel to leave the dialog without saving the
file.
Note: For Windows, the System File Dialogs are used.
Create Template
Preferences Dialog
Click Edit|Preferences to invoke the Preferences dialog. This dialog has a tab for 'General'
preferences. If you have the C++ Editor plugin, the dialog will also have a tab for the C++
Editor.
Add Dialog
Click Project|Add File to invoke the Add dialog. Use this dialog to add files to the current
project.
The Add dialog defaults the directory and file type. To choose a different directory, click
the 'Look In' combobox. Choose a file and the name will appear in the 'File Name'
combobox. To choose a different file type, click the 'File Type' combobox. Click the
'Create New Folder' toolbar button to create a new directory. Click the 'List View' toolbar
button to view folders and files in a list with only the names showing. Click the 'Details'
toolbar button to view the folders and file names along with their size, type, date, and
attributes. Click the Size, Type, Date, or Attributes column headers to sort the folders or
files.
Click Open to open the selected file. Click Cancel to leave the dialog without opening a
file.
Manage Image Collection
Click the C++ Tab to change the qmake options. See the qmake documentation for details
on what these options mean. Click the 'Template' combobox and choose application or
library to create makefiles for building applications or libraries. Click the 'Config'
combobox to select the project configuration and compiler options for all platforms, or
specific platforms. Type the Config value in the line edit. Click the 'Libs' combobox to
select a platform. Type the libraries in the line edit. Click the 'Defines' combobox and select
a platform. 'Defines' values are added as compiler pre-processor macros. Type the 'Defines'
values in the line edit. Click the 'Includepath' combobox to select a platform. Includepath
specifies the directories that should be searched for include files when compiling the
project. Type the 'Includepath' values in the line edit.
Cick OK to accept changes to the project settings. Click Cancel to exit the dialog without
making any changes to the project settings.
Replace Text
Replace Text Dialog
Click Search|Replace (or press Ctrl+R) to invoke the Replace Text Dialog. Use this dialog
to replace text in a project file.
To replace text, type the text you would like to replace in the 'Find' combobox. Type the
new text in the 'Replace' combobox. You can make the search more specific by checking
any or all of the checkboxes in the 'Options' section. Click the 'Whole words only' checkbox
to narrow the search to whole words. Click 'Case Sensitive' to search for text that identical
to the text you typed in the combobox. Click 'Start at Beginning' to start the search from the
beginning of the file. The 'Direction' section offers the 'Forward' radio button and the
'Backward' radio button to specify the direction to perform the search in the file.
Click the Replace button to search and replace the text. When the text is found, it is
highlighted in the file. Continue clicking Replace button to search and replace each
occurrence of the text in the file. Click Replace All button to replace all occurences of the
search text in the file at once.
Click the Close button to leave the dialog.
Goto Line
Qt Designer Dialog
Click Help|About Qt... to invoke the Qt Designer Dialog. This dialog provides
information about Qt.
Click the 'x' located at the title of the dialog to close the dialog.
Click OK to accept the configurations and Qt Designer will create a default main.cpp file.
Click Cancel to leave the dialog.
Note for database programmers: If you create a main.cpp file using Qt Designer, this file
will not include the createConnections() function. We do not include this function
because it needs the username and password for the database connection, and you may
prefer to handle these differently from our simple example function. As a result,
applications that preview correctly in Qt Designer will not run unless you implement your
own database connections function.
Save Project Settings
Save Form
Text Dialog
The Text dialog is used to type text.
Click OK to accept the text. Click Cancel to leave the dialog without saving any text.
Title Dialog
Title Dialog
Use this dialog to change the title of a selected widget by typing the new title in the line
edit.
Click OK to accept changes to the title. Click Cancel to leave the dialog without making
changes to the title.
Page Title Dialog
Edit Listbox
Edit Iconview
Right click or double click an iconview widget on the form and select 'Edit' to invoke the
Edit Iconview dialog. Use the dialog to add, change, or remove items from the iconview. To
add an item to the iconview, click the New Item button. To change the name of the item,
click the 'Text' line edit and type a new name. To add a pixmap, click the (ellipsis) button,
which invokes the Choose an Image Dialog. To remove a pixmap, click the Delete Pixmap
button. To delete an item from the iconview, click the item and then click the Delete Item
button.
Click Apply to accept changes to the iconview widget. Click OK to leave the dialog once
the changes have been accepted. Click Cancel to leave the dialog without saving any
changes.
Edit Table
Right click or double click a table widget on the form and select 'Edit' to invoke the Edit
Table dialog. Use the dialog to add, change, or remove columns or rows from the table.
Edit Table- Columns Tab
Setup Toolbar
The 'Setup Toolbar' wizard page is used to populate a toolbar with actions from each of the
default action categories. Click the Category combobox to select which set of actions you
wish to work on. The Actions listbox lists the actions available for the current category.
The Toolbar listbox lists the toolbar buttons you want to create. Click the blue left and right
arrow buttons to move actions into or out of the Toolbar list box. Click the blue up and
down arrow buttons to move actions up and down within the Toolbar list box. Note that the
'<Separator>' item in the Actions list box may be moved to the Toolbar list box as often as
required and will cause a separator to appear in the finished toolbar.
Click Back if you want to return to the 'Choose available menus and toolbars' wizard page.
Click Finish to populate the main window and to exit the wizard. Click Cancel on any of
the wizard pages to leave the wizard without making any changes.
Widget Tab
Click the Widgets tab to view all the widgets for the current form. The widgets are listed by
name and class. Click a widget in the list to highlight it in the corresponding form.
Source Tab
Source Tab
Click the Source tab to view the current form's slots, forward declarations, includes, and
class variables. The Source tab uses a tree view to display its information. Items which
have a '+' sign have sub-items which are revealed by clicking the '+'. Right click any item in
the tree view to popup a context menu.
To edit or add slots, right click the Slots folder and select 'Edit' to invoke the Edit Slots
Dialog. Right click the Public, Protected, or Private subdirectories and click 'New' to
invoke the Edit Slots Dialog. Right click a slot in the list to invoke a menu with additional
options for the slot. To add new slots, choose 'New' from the menu, which invokes the Edit
Slots Dialog. To change the properties of the selected slot, choose 'Properties' which
invokes the Edit Slots Dialog. To open the C++ editor and jump to the implementation of
the selected slot, choose 'Goto Implementation'. To remove the selected slot, choose
'Delete'. Signals can be added or deleted in the same way as slots.
Right click 'Forward Declarations', 'Includes (in declaration)', 'Class Variables', and
'Includes (in implementation)' to invoke a context menu with the 'new' or 'edit' options.
Choose 'New' to invoke a line edit for typing a declaration, variable, or include. Right click
'Forward Declarations' and choose 'Edit' to invoke the Edit Forward Declarations Dialog.
Right click 'Includes (in declaration)' and choose'Edit' to invoke the Edit Includes (in
Declaration) Dialog. Right click 'Class variables' and choose 'Edit' to invoke the Edit Class
Variables Dialog. Right click 'Includes (in Implementation)' and choose 'Edit' to invoke the
Edit Includes (in Implementation) Dialog.