\chapter Subclassing and Dynamic Dialogs

\index Subclassing
\index Dynamic Dialogs
\index Dialogs!Dynamic
This chapter describes two different approaches that you can take to
creating forms with \QD. Subclassing is used to extend the functionality
of a form by creating your own class based upon a form you create in
\QD. Dynamic dialogs are 
\index .ui 
\File .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.

\section1 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 \l{Extending the functionality of a form} in \l{The Designer
Approach} chapter for details.

\section2 Generating Source Code from \QD .ui Files

\QD reads and writes \Cmd qmake \index .pro
\File .pro (project)
files which are used to record the files used to build the application
and from which Makefiles are generated. \QD also reads and writes
\index .ui
\File .ui (user interface) files. These are XML files
that record the widgets, layouts, source code and settings you've used
for a form. Every \index .ui
\File .ui file is converted by
the \Cmd uic (user interface compiler) into a C++ \index .h
\File .h
file and a C++ \index .cpp
\File .cpp file. These C++ files are then
read by \Cmd moc (meta object compiler), and finally compiled by your
compiler into a working application.

\index Makefiles
\index Projects!Adding Files
\index Adding!Files to Projects
If you create applications wholly within \QD you only need to create a
\index main.cpp
\File main.cpp.

If you create the \File{main.cpp} file within \QD, it will
automatically be added to your project file by \QD. If you create the
\File{main.cpp} file outside of \QD you must add it to the project
file manually by adding the following line at the end of your
project's 
\index .pro 
\File .pro file: 
\code
SOURCES += main.cpp
\endcode

You can then use \Cmd qmake to generate the Makefile. (For example \c
{qmake -o Makefile myproject.pro}.) Running \Cmd make (Linux, Unix or
Borland compilers), or \Cmd nmake (Visual C++), will then call \Cmd
uic, \Cmd moc and your compiler as necessary to build your
application.

\index Errors!Undefined reference
\index Undefined references, Error
\index qmake!HEADERS
\index qmake!SOURCES
If you use \QD 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 \index .pro
\File .pro file so that they are
compiled with the rest of your application's source files. Each
\index .h
\File .h file that you create separately from \QD should
be added to the \c {HEADERS} line, and each
\index .cpp
\File .cpp file should be added to the
\c {SOURCES} line, just as we've done for
\index main.cpp
\File 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 \index .pro
\File .pro file.

\section2 Subclassing a Form

\index Subclassing
When subclassing a form it is helpful to use a naming convention
to help us identify which files are generated from \QD's
\index .ui
\File .ui files and which are hand coded.

Suppose, for example, that we are developing a dialog and writing the
code directly in \QD. We might call our dialog 'OptionsForm' and the
\index .ui
\File .ui file, \File optionsform.ui. The
automatically generated files will be \File optionsform.h
and \File 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
\index .ui
\File .ui file \File settingsformbase.ui.
The automatically generated files would then be called
\File settingsformbase.h and
\File settingsformbase.cpp. We would then call our
subclass 'SettingsForm' and code it in the files
\File settingsform.h and
\File settingsform.cpp.

\index Q_OBJECT!Macros
\index Macros!Q_OBJECT
\index Signals and Slots!Q_OBJECT
Any subclass of a form should include the \c {Q_OBJECT}
macro so that slots and signals will work correctly. Once you've created
your subclass be sure to add the \index .h
\File .h and the
\index .cpp
\File .cpp files to the \index .pro
\File .pro project
file. For example we would add the following lines for our subclassed
'SettingsForm' at the end of the \index .pro
\File .pro file:
\code
HEADERS += settingsform.h
SOURCES += settingsform.cpp
\endcode
The simplest way to create a new source file is by clicking
\Menu{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
\File{.pro} file since \QD will add them for you automatically.

\QD will have added
\code
FORMS = settingsformbase.ui
\endcode

to the project file. The \File settingsformbase.h and
\File settingsformbase.cpp files will be generated from
the \index .ui
\File .ui file automatically.

\section2 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
\index main.cpp
\File main.cpp so that we can test it.

\section3 Designing the Form

\index Projects!Creating New
We'll begin by creating a new project.
Click \Menu {File|New}, then click the 'C++ Project' icon to invoke
the \Dialog{Project Settings} dialog. Click the ellipsis button to
invoke the \Dialog{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 \Button Save button to return to the \Dialog{Project Settings}
dialog, then click \OK.
Now we'll add a form to the project.
Click \Menu File|New to invoke the \Dialog {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 \File creditformbase.ui.

We'll now add the widgets we need.
\list 1
\i

Click the \Toolbutton {Button Group} toolbar button, then click
near the top left of the form. Resize the button group so that it takes
up approximately half the form. Change the button group's \Property name to
'creditButtonGroup' and its \Property title property to 'Credit Rating'.

\i

We'll now add some radio buttons. \e Double click the
\Toolbutton {Radio Button} toolbar button. Click towards the
top of the Credit Rating button group and a radio button will appear.
Click below this button, to create a second radio button, then click
below the second button to create a third. Now we will switch off the
effect of the \e double click by clicking the
\Toolbutton Pointer (arrow) toolbar button. The pointer will now
behave normally, i.e. clicking the form will no longer create
more radio buttons.
Change the first radio button's \Property name to
'stdRadioButton' and its text to '\&Standard'. Change its \Property checked
property to True. Change the second
button's name to 'noneRadioButton' and its text to '\&None'. Change
the third radio button's properties to 'specialRadioButton' and
'Sp\&ecial' respectively.

\i

If the user chooses the special credit rating they must specify an amount.
Click the \Toolbutton SpinBox toolbar button and click the
form just below the button group. Change the spin box's \Property name to
'amountSpinBox'. Change its \Property prefix to '$ ' (note the space), its
\Property maxValue to '100000' and its \Property lineStep to '10000'.
Change its \Property enabled property to False.

\i

Click the \Toolbutton {Push Button} toolbar button and click
the form below the spin box. Change the button's \Property name to
'okPushButton', its \Property text to 'OK' and its \Property default
property to 'True'. Add
a second button to the right of the first. Change the second button's
\Property name to 'cancelPushButton' and its \Property text to 'Cancel'.

\endlist

We'll now lay out the widgets and connect up the slots we need.
\list 1
\i

Click the credit rating group box then press \Key Ctrl+L (lay out
vertically).

\i

Click the form so that the button group is no longer selected.
\Key Ctrl+Click the OK button and drag the rubber band to touch the Cancel
button, then release. Press \Key Ctrl+H.

\i

Click the form, then press \Key Ctrl+L.

\index Layouts!Spacers
The widgets will be laid out vertically, each one stretching to fill
up the maximum space both vertically and horizontally. The buttons
look rather large since they've expanded to take up the full width of
the form. It might look more attractive to make the buttons smaller
using spacers. Click the OK button, then press \Key Ctrl+B (break
layout). Resize both buttons to make them narrower leaving space on
either side of them. Click the \Toolbutton Spacer toolbar button then
click to the left of the OK button; click Horizontal from the pop up
spacer menu. Copy this spacer and place the copy between the two
buttons. Copy the spacer again and place the copy to the right of the
Cancel button. (For the second and third spacers, click on the first
spacer, press \Key Ctrl+C then \Key Ctrl+V. Drag the new spacer to
the desired position.) Ctrl+Click the left most spacer and drag the
rubber band so that it touches the buttons and the spacers, then
release. Press \Key Ctrl+H. Click the form then press \Key Ctrl+L.

\endlist

\index Signals and Slots
We'll now connect the signals and slots. Press \Key F3
(connect signals/slots), then click the OK button. Drag to the form and
release. In the \Dialog {Edit Connections} dialog that pops up connect the
\index clicked()
\SignalOrSlot clicked() signal to the \index accept()
\SignalOrSlot accept() slot. (Click the
\index clicked()
\SignalOrSlot clicked() signal, click the \index accept()
\SignalOrSlot accept() slot, then click \OK.)
Connect the Cancel button to the \index reject()
\SignalOrSlot reject() slot using the same
technique.

We want the amount spin box to be enabled only if the special radio
button is checked. Press \Key F3 (connect signals/slots),
then click the
special radio button. Drag to the spin box and release. In the
\Dialog {Edit Connections} dialog that pops up click the \index toggled()
\SignalOrSlot toggled()
signal and the \index setEnabled()
\SignalOrSlot setEnabled() slot.

If the user checks the standard or none radio buttons we want to set the
amount accordingly. Press \Key F3,
then click the credit rating button group. Drag to the form and release.
Click the \index clicked()
\SignalOrSlot clicked() signal.
We want to connect this signal to our own custom slot, but we
haven't created one yet. Click the \Button {Edit Slots}
button and the Edit Slots dialog will pop up. Click
\Button {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
\SignalOrSlot 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
\Key {Ctrl+S}).

\section3 Creating the Test Harness

\index Forms!Creating Test Harnesses
\index Creating Test Harnesses for Forms
\index Subclassing
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 \Menu{Add new source file to project}. This will invoke the
\Dialog{Save As} dialog; enter 'main.cpp' and click \Button Save. In
the editor window that pops up, enter the following code:
\code
#include <qapplication.h>
#include "creditformbase.h"

int main( int argc, char *argv[] ) 
{
    QApplication app( argc, argv );

    CreditFormBase creditForm;
    app.setMainWidget( &creditForm );
    creditForm.show();

    return app.exec();
}
\endcode

Note that we're including \File creditformbase.h and
instantiating a CreditFormBase object; once
we've written our subclass we'll replace the header with our subclass,
\File creditform.h, and instantiate a CreditForm.

We can now generate the application with \Cmd qmake, e.g.
\c {qmake -o Makefile credit.pro}, make it and run it.
The form should run fine, but doesn't yet have the behaviour we require.

\section3 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
\File qt/tools/designer/examples/credit/creditform.h:

\quotefile credit/creditform.h
\skipto #include
\printuntil };

\index Macros!Q_OBJECT
\index Q_OBJECT
We've declared the slot, \SignalOrSlot setAmount(),
that we created in \QD. The \c {Q_OBJECT} macro is
included because it is essential for classes that use signals and slots.

The implementation in
\File qt/tools/designer/examples/credit/creditform.cpp is
simple:

\quotefile credit/creditform.cpp
\skipto #include
\printuntil amountSpinBox
\printuntil }

We call \SignalOrSlot setAmount() in the constructor to ensure
that the correct amount is shown when the form starts based on whichever
radio button we checked in \QD. In \SignalOrSlot 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.

\index Makefiles
\index qmake!HEADERS
\index qmake!SOURCES
To be able to test our subclass we change \index main.cpp
\File main.cpp
to include \File creditform.h rather than
\File creditformbase.h and change the instantiation of
the creditForm object:

\quotefile credit/main.cpp
\skipto #include
\printuntil }

If you created the \File{creditform.h} and \File{creditform.cpp} files
in \QD, 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:
\code
HEADERS += creditform.h
SOURCES += creditform.cpp
\endcode

To test the form rerun \Cmd 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.

\target dynamicdialogs
\section1 Creating Dynamic Dialogs from .ui Files

\index Dynamic Dialogs
\index Dialogs!Dynamic
\index Code Editing!Not in Dynamic Dialogs
Qt programs are capable of
loading \QD \index .ui
\File .ui files and instantiating the forms
represented by the \index .ui
\File .ui files. Since the
\index .ui
\File .ui file is not compiled it
cannot include any C++ code, (e.g. slot implementations). In this
section we will explain how to load a dynamic dialog and how to create a
class that can be used to implement the dynamic dialog's custom slots.

We will use the credit form that we created in the subclassing section
as our example form. We will start by simply instantiating and running
the form and then we'll cover how to implement custom slots.

We'll create a \index main.cpp
\File main.cpp file to use as a test
harness, and manually create a project file.

\section2 Creating the Project File

The project file
\File qt/tools/designer/examples/receiver1/receiver.pro looks like
this:
\code
TEMPLATE    = app
CONFIG     += qt warn_on release
TARGET      = receiver
SOURCES    += main.cpp
unix:LIBS  += -lqui
win32:LIBS += $(QTDIR)/lib/qui.lib
FORMS      = mainform.ui
LANGUAGE    = C++
INCLUDEPATH += $(QTDIR)/tools/designer/uilib
\endcode

We do \e not include the
\File creditformbase.ui file since this file will be read
at runtime, as we'll see shortly. We must include the
\Func qresource library since the functionality we
require is not part of the standard Qt library.

\section2 Creating main.cpp

The \index main.cpp
\File main.cpp is quite standard. It will invoke the
form we're going to create in \QD as its main form. This form will then
load and execute the dynamic dialog.

\quotefile receiver1/main.cpp
\skipto #include
\printuntil }

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
\File app.exec() call.

\section2 Creating the Main Form

\section3 Designing the Form

    \list 1
    \i

	Open the \index receiver.pro
\File receiver.pro project file in \QD. We'll create a
	dialog as our main window which we'll use to invoke the dynamic
	dialog. Press \Key Ctrl+N to launch the \Dialog {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
	\Toolbutton {Push Button} toolbar button, then click the form.
	Change the properties in the property window to those we've just
	described.)

    \i

	We will now add a couple of labels so that we can show the
	settings the user chose in the dynamic dialog. Click the
	\Toolbutton {Text Label} toolbar button, then click the
	form below the Credit Dialog button. Change the label's \Property text to
	'Credit Rating'. Add another text label below the Quit button.
	Change its \Property name to 'ratingTextLabel' and its \Property text
	to 'Unrated'.

    \i

	We'll now lay out the widgets. Click the form then press
	\Key Ctrl+G (lay out in a grid).

    \i

	\index Signals and Slots!Connecting to Close a Dialog
We'll now handle the signals and slots connections. Press
	\Key F3 (connect signals/slots). Click the Credit Dialog
	button, drag to the form and release. Click the
	\index clicked()
\SignalOrSlot clicked() signal. We'll need to implement a custom
	slot. Click \Button {Edit Slots} to invoke the \Dialog {Edit Slots}
	dialog. Click \Button {New Slot} and type in the Slot name
	'creditDialog()'. Click \OK. The new slot is now in
	the list of slots; click the \SignalOrSlot creditDialog() slot to
	make the connection then click \OK. Connect the Quit button's
	\index clicked()
\SignalOrSlot clicked() signal to the
	dialog's \index accept()
\SignalOrSlot accept() function. (Press
	\Key F3. Click the Quit button and drag to the form;
	release. Click the \index clicked()
\SignalOrSlot clicked() signal and the
	\index accept()
\SignalOrSlot accept() slot, then click \OK.)

    \endlist

Save the form and call it \File mainform.ui. (Press
\Key Ctrl+S and enter the filename.) In the next section
we'll write the code for loading and launching the dynamic dialog
directly in \QD.

\section3 Loading and Executing a Dynamic Dialog

\index Dynamic Dialogs!Loading and Executing
\index Dialogs!Dynamic
\index Forms!Forward declarations
\index Forward declarations
\index Includes
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 \Button New. Type in
'\c {<qwidgetfactory.h>}', then press
\Key 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
'\c {<qspinbox.h>}', then press
\Key Enter.

In our main form we created a slot called \SignalOrSlot
creditDialog(). We will implement this slot directly in \QD and use it
to load and execute the dynamic dialog. The code is taken from \File
qt/tools/designer/examples/receiver1/mainform.ui.h which contains the
C++ implementation of \File{mainform.ui}'s slots.

\quotefile receiver1/mainform.ui.h
\skipto ::creditDialog
\printuntil delete creditForm
\printline }

The \index create()
\Func create() function is a static
\Class QWidgetFactory function. It loads the specified
\index .ui
\File .ui file and returns a pointer to the toplevel
\Class QWidget created from the \index .ui
\File .ui
file. We have cast the pointer to \Class QDialog since
we know that the \File creditformbase.ui file defines a
\Class QDialog. After creating the dialog we
\index exec()
\Func exec() it. If the user clicked
\Button OK the dialog returns Accepted and we enter the
body of the \c {if} statement. We want to know the amount
of credit that the user selected. We call the
\index child()
\Func child() function on the dialog passing it the name
of the widget we're interested in. The \index child()
\Func 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
\index child()
\Func 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 \index child()
\Func 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
\index child()
\Func child() with a null widget name and a classname,
e.g. \c {child(0,"QPushButton")}. This will return a
pointer to the first \Class 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 \index QObject::queryList()
\Func QObject::queryList()
function, passing it the name of the class. It returns a
\Class QObjectList pointer which points to every object
in the dialog that is derived from the given class. See the online
\link http://doc.trolltech.com/qobject.html QObject \endlink
documentation for further details.

\section3 Implementing Slots for Dynamic Dialogs

\index Signals and Slots!Dynamic Dialogs
\index 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 \SignalOrSlot setAmount() slot. We
can implement slots for dynamic dialogs by creating a
\Class QObject subclass. We then create an instance of
this subclass and pass a pointer to it to the
\index QWidgetFactory::create()
\Func QWidgetFactory::create()
function which will connect the dynamic dialog's signals to the slots
implemented in our subclass.

We need to create a \Class QObject subclass and
change our \Func creditDialog() to create an instance of
our subclass that can be passed to the
\index QWidgetFactory::create()
\Func QWidgetFactory::create()
function. Here is the modified \Func creditDialog()
function from the
\File qt/tools/designer/examples/receiver2/mainform.ui.h file that
contains the code for \File{mainform.ui}'s slots:
\quotefile receiver2/mainform.ui.h
\skipto ::creditDialog
\printuntil delete creditForm
\printline }

We create a new instance of our 'Receiver' subclass. (We'll write the
code for this class shortly.) We then create the
\Class QDialog using
\index QWidgetFactory::create()
\Func QWidgetFactory::create(). This call differs from our
previous example because we pass in the subclass object so that the
\index create()
\Func 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 \Func setParent() function. The remainder of
the function is the same as before except that we delete our receiver
object.

\index Dynamic Dialogs
We'll now look at the implementation of our 'Receiver' subclass. The code
is taken from
\File qt/tools/designer/examples/receiver2/receiver.h and the
corresponding \File receiver.cpp file. We'll start with
the header file.

\include receiver2/receiver.h

\index Macros!Q_OBJECT
\index Q_OBJECT!Macros
Our class must be a \Class QObject subclass and because
we're using signals and slots it must include the
\c {Q_OBJECT} macro. We declare a function and the
\Func setAmount() slot that we wish to implement as well
as a private \Class QDialog pointer.

We'll discuss the implementation of each function in \File
receiver.cpp separately.

\quotefile receiver2/receiver.cpp
\skipto ::setParent
\printuntil }

The \Func setParent() function assigns a pointer to the
dynamic dialog to our private pointer. We could not do this in a
constructor call because we have to construct our Receiver object before
we call \index QWidgetFactory::create()
\Func QWidgetFactory::create(), since we must
pass the Receiver object to the \index create()
\Func create() function.
Once we've called \index create()
\Func create() we then have a pointer
to the dynamic dialog which we can then pass via
\Func setParent() to our Receiver class. In the subclass
version of this example we called \Func setAmount() in
the constructor; but we cannot do that here because the implementation
of \Func setAmount() depends on knowledge of the dynamic
dialog which is not available at construction time. Because of this we
call \Func setAmount() in the
\Func setParent() function.

\quotefile receiver2/receiver.cpp
\skipto ::setAmount
\printuntil minValue
\printline } 

Since we may be updating the amount spin box we need to get a pointer to
it. We call \index child()
\Func child() on the pointer
\c {p} which points to the dynamic dialog assigned in the
\Func 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 \index child()
\Func child() to get a
pointer to the amount spin box, and then call
\index child()
\Func 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.

\sidebar Compiling vs Dynamically Loading Dialogs

\index Dynamic Dialogs!Compared with Compiling
\index Dynamic Dialogs!Subclassing
\index Subclassing!Dynamic Dialogs
The differences between using a 'compiled in' \index .ui
\File .ui
file and a dynamically loaded \index .ui
\File .ui file are these:
\list
\i

Dynamic dialogs cannot have any C++ code in the \index .ui
\File .ui
file; any custom slots must be implemented via a
\Class QObject subclass. Compiled dialogs can contain
code either in the \index .ui
\File .ui file or in a subclass.

\i

Dynamic dialogs will load slower because the \index .ui
\File .ui
file must be read and a \Class QWidget instance
instantiated based on the \index .ui
\File .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.

\i

Dynamic dialogs allow you to change the \index .ui
\File .ui file
independently of the code so long as none of the changes impact the
code. This means that you can change the appearance of the form, e.g.
move widgets and lay them out differently. If you want to change a
compiled dialog you must change the \index .ui
\File .ui file and
recompile. If you are building an application and want your customers to
be able to customize aspects of the user interface you can give them a
copy of \QD and use dynamic dialogs.

\endlist

\endsidebar
