\chapter Creating Custom Widgets

\index Custom Widgets
\index Widgets!Custom
Custom widgets are created in code. They may comprise a combination of
existing widgets but with additional functionality, slots and signals,
or they may be written from scratch, or a mixture of both.

\index Previewing!Custom Widgets
\index Custom Widgets!Previewing
\QD provides two mechanisms for incorporating custom widgets:
\list 1
\i

The original method involves little more than completing a dialog box.
Widgets incorporated this way appear as flat pixmaps when added to a
form in \QD, even in preview mode. They only appear in their true form
at runtime. We'll explain how to create custom widgets using the
original approach in "Simple Custom Widgets".

\i

\index Plugins
The new method involves embedding the widgets in a plugin. Widgets that
are incorporated through plugins appear in their true form in \QD, both
when laying out the form and in preview mode. This approach provides
more power and flexibility than the original method and is covered in
\l {Creating Custom
Widgets with Plugins}.
\endlist

\section1 Simple Custom Widgets

\index Custom Widgets!Simple
There are two stages to creating a custom widget. Firstly we must create
a class that defines the widget, and secondly we must incorporate the
widget into \QD. Creating the widget has to be done whether we are
creating a simple custom widget or a plugin, but for simple custom
widgets the incorporation into \QD is very easy.

We will create a VCR style widget comprising four buttons, rewind,
play, next and stop. The widget will emit signals according to which
button is clicked.

\section2 Coding the Custom Widget

A custom widget may consist of one or more standard widgets placed
together in a particular combination, or may be written from scratch. We
will combine some \Class QPushButton widgets to form the
basis of our custom widget.

We'll look at the header file,
\File qt/tools/designer/examples/vcr/vcr.h first.

\quotefile vcr/vcr.h
\skipto #include
\printuntil };

\index Macros!Q_OBJECT
\index Q_OBJECT
We include \File qwidget.h since we'll be deriving our
custom widget from
\Class QWidget. We declare a constructor where the
widget will be created and the four signals we want our widget to emit.
Since we're using signals we must also include the
\c Q_OBJECT macro.

The implementation is straightforward. The only function we implement is
the constructor. The rest of the file consists of include statements and
embedded \index .xpm
\File .xpm images.

\quotefile vcr/vcr.cpp
\skipto Vcr::Vcr
\printto connect

We create a \Class QHBoxLayout in which we'll place the
buttons. We've only shown the rewind button in the code above since all
the others are identical except for the names of the buttons, pixmaps
and signals. For each of the buttons we require we call the
\Class QPushButton constructor passing it the
appropriate embedded pixmap. We then add it to the layout. Finally we
connect the button's \index clicked()
\SignalOrSlot clicked() signal to the
appropriate \e signal. Since the
\index clicked()
\SignalOrSlot clicked() signals aren't specific to our widget we
want to emit signals that reflect the widget's use. The
\SignalOrSlot rewind(), \SignalOrSlot play(), etc. signals
are meaningful in the context of our widget so we propagate each
button's \index clicked()
\SignalOrSlot clicked() signal to the appropriate
widget-specific signal.

\index Forms!Creating Test Harnesses
The implementation is complete, but to make sure that our widget
compiles and runs we'll create a tiny test harness. The test harness
will require two files, a \index .pro
\File .pro project file and a
\index main.cpp
\File main.cpp. The
\File qt/tools/designer/examples/vcr/vcr.pro project file:

\include vcr/vcr.pro

The \File qt/tools/designer/examples/vcr/main.cpp file is
also brief:

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

Once we're satisfied that the custom widget compiles and runs we are
ready to incorporate it into \QD.

In \l {Base-class Templates}
the creation of a container custom widget is described.

\section2 Adding the Custom Widget to Qt Designer

\index Custom Widgets!Adding to Qt Designer
\index Adding!Custom Widgets to Qt Designer
Click \Menu {Tools|Custom|Edit Custom Widgets} to
invoke the \Dialog {Edit Custom Widgets} dialog.
    \list 1
    \i

	Click \Button {New Widget} so that we are ready to add our new widget.

    \i

	Change the Class name from 'MyCustomWidget' to 'Vcr'.

    \i

	Click the ellipsis (\Button {...}) button to the right of
	the Headerfile line edit to invoke the file Open dialog. Locate
	\File vcr.h, select it, and click
	\Button Open. It will now appear as the header file.

    \i
	If you have a pixmap that you want to use to identify your
	widget on the toolbar click the ellipsis button
	to the right of Pixmap property. (The ellipsis button appears
	when you click in the Value part of the Properties list by a
	\Property pixmap or \Property iconSet property.)

	In our example we have the file
	\File qt/tools/designer/examples/vcr/play.xpm which we'll use
	for this purpose.

    \i

	Since we know the minimum sensible size for our widget we'll put
	these values into the Size Hint spin boxes. Enter a width of 80 (in
	the left hand spin box), and a height of 20 (in the right hand
	spin box).

    \endlist

The remaining items to be completed will depend on the characteristics
of the widget you've created. If, for example, your widget can be used
to contain other widgets you'd check the Container Widget checkbox. In
the case of our Vcr example the only items we need to add are its
signals.

Click the Signals tab. Click the \Button {New Signal}
button and type in the signal name 'rewind()'. Click \Button {New Signal}
again and this time type in 'play()'. Add the
'next()' and 'stop()' signals in the same way.

Since our example hasn't any slots or properties we've finished and can
click \Button Close. A new icon will appear in \QD's
toolbars which represents the new widget. If you create a new
form you can add Vcr widgets and connect the Vcr's signals to your
slots.

Incorporating custom widgets that have their own slots and properties is
achieved in a similar way to adding signals. All the required
information is in our custom widget's header file.

\target creatingplugins
\section1 Creating Custom Widgets with Plugins

\index Custom Widgets!Plugins
\index Plugins!Implementing Custom Widgets
This section will show you how to write a custom widget and how to embed
the custom widget into a plugin. There are no restrictions or special
considerations that must be taken into account when creating a widget
that is destined to become a plugin. If you are an experienced Qt
programmer you can safely skip the section on creating a custom widget
and go directly to \l {Creating a
Plugin}.

    \section2 Creating a Custom Widget

    \index Creating Custom Widgets
\index Widgets!Creating a Custom Widget
\index Subclassing!Widgets
A custom widget is often a specialization (subclass) of another
    widget or a combination of widgets working together or a blend of
    both these approaches. If you simply want a collection of widgets
    in a particular configuration it is easiest to create them, select
    them as a group, and copy and paste them as required within \QD.
    Custom widgets are generally created when you need to add new
    functionality to existing widgets or groups of widgets.

    \index Properties!Creating Custom Properties
We have two recommendations that you should consider when creating a
    custom widget for a plugin:
	\list 1
	\i

	Using Qt's property system will provide \QD users with a direct
	means of configuring the widget through the property editor.
	(See the \link http://doc.trolltech.com/properties.html Qt Properties \endlink documentation.)

	\i

	Consider making your widget's public 'set' functions into
	public slots so that you can perform signal-slot connections
	with the widget in \QD.

	\endlist

    In the course of this chapter we will create a simple but useful
    widget, 'FileChooser', which we'll later make available in \QD as a
    plugin. In practice most custom widgets are created to add
    functionality rather than to compose widgets, so we will create our
    widget in code rather than using \QD to reflect this approach.
    FileChooser consists of a \Class QLineEdit and a
    \Class QPushButton. The \Class QLineEdit is used to hold a file or
    directory name, the \Class QPushButton is used to launch a file
    dialog through which the user can choose a file or directory.

    \img filechooser.png
    \caption The FileChooser Custom Widget

    If you've followed the manual up to this point you may well be able
    to create this custom widget yourself. If you're confident that you
    can make your own version of the widget, or have another widget that
    you want to turn into a plugin, skip ahead to \l {Creating a Plugin}. If you prefer to
    read how we created the widget then read on.

	\section3 Coding the Widget's Interface

	We will work step-by-step through the widget's header file,
	\File qt/tools/designer/examples/filechooser/widget/filechooser.h.

\quotefile filechooser/widget/filechooser.h
\skipto #include
\printuntil class QPushButton

	Our widget will be derived from \Class QWidget so we include
	the \File qwidget.h header file. We also forward declare the two
	classes that our widget will be built from.

\skipto class FileChooser
\printto public

	\index Macros!Q_OBJECT
	\index Q_OBJECT
	\index Macros!Q_ENUMS
	\index Q_ENUMS
	We include the \Func Q_OBJECT macro since this is required for
	classes that declare signals or slots. The \Func 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.

\printto public slots:

	The constructor is declared in the standard way for widgets. We
	declare two public functions, \Func fileName() to return the
	filename, and \Func mode() to return the mode.

\printto private:

	The two 'set' functions are declared as public slots.
	\SignalOrSlot setFileName() and \SignalOrSlot setMode() set the filename and mode
	respectively. We declare a single signal, \SignalOrSlot fileNameChanged(). The
	private slot, \SignalOrSlot chooseFile() is called by the widget itself
	when its button is clicked.

\printuntil };

	A pointer to \Class QLineEdit and \Class QPushButton, as well
	as a Mode variable are held as private data.

	\section3 Coding the Implementation

	We will work step-by-step through the implementation which is in
	\File qt/tools/designer/examples/filechooser/widget/filechooser.cpp.


\quotefile filechooser/widget/filechooser.cpp
\skipto FileChooser::
\printuntil {

	The constructor passes the parent and name to its superclass,
	\Class QWidget, and also initializes the private mode data, md,
	to File mode.

\printto connect(

	We begin by creating a horizontal box layout
	(\Class {QHBoxLayout}) and add a \Class QLineEdit and a
	\Class QPushButton to it.

\printto setFocusProxy

	We connect the lineEdit's \index textChanged()
\SignalOrSlot textChanged() signal to the custom
	widget's \SignalOrSlot fileNameChanged() signal. This ensures that if the
	user changes the text in the \Class QLineEdit this fact will be
	propagated via the custom widget's own signal. The button's
	\index clicked()
\SignalOrSlot clicked() signal is connected to the custom widget's
	\SignalOrSlot chooseFile() slot which invokes the appropriate dialog for
	the user to choose their file or directory.

\printline setFocusProxy
\printline }

	We set the lineEdit as the focus proxy for our custom widget.
	This means that when the widget is given focus the focus
	actually goes to the lineEdit.

\skipto ::setFileName
\printuntil text()
\printline }

	The \Func setFileName() function sets the filename in the
	\Class QLineEdit, and the \Func fileName() function returns the
	filename from the \Class QLineEdit. The \Func setMode() and
	\Func mode() functions (not shown) are similarly set and return the
	given mode.

\printline ::chooseFile
\printuntil fileNameChanged
\printline }
\printline }

	When \Func 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 \Class QLineEdit is updated with the
	chosen file or directory and the \Func 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.

	\section3 Testing the Implementation

	\index main.cpp
	\index Forms!Creating Test Harnesses
	We present a rudimentary test harness which will allow us
	to run our custom widget. The test harness requires two
	files, a \File main.cpp to contain the FileChooser, and a \c .pro
	file to create the Makefile from. Here is
	\File qt/tools/designer/examples/filechooser/widget/main.cpp:

\quotefile filechooser/widget/main.cpp
\skipto #include
\printuntil }

	And here is \File qt/tools/designer/examples/filechooser/widget/filechooser.pro

\include filechooser/widget/filechooser.pro

	We can create the makefile using \Cmd qmake:
	\c {qmake -o Makefile filechooser.pro}, then we can make and run
	the harness to test our new widget. Once we're satisfied that
	the custom widget is robust and has the behaviour we require we
	can embed it into a plugin.

    \section2 Creating a Plugin

    \index Creating Plugins
\index Plugins!Creating a Plugin
\index Component!Plugins
    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 \QD custom widget
    plugin.

    A \QD custom widget plugin is always derived from \Class
    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 \index plugin.h
\File plugin.h and \index plugin.cpp
\File 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.

	\section3 The \Class CustomWidgetPlugin Implementation

	We have called our header file 
\index plugin.h
	\File plugin.h and we've
	called our plugin class \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.

\quotefile filechooser/plugin/plugin.h
\skipto #include
\printuntil };
\caption From \File qt/tools/designer/examples/filechooser/plugin/plugin.h

	\section3 The QWidgetPlugin Functions

	\index plugin.cpp
	Create your own plugin \c {.cpp} file by copying our
	\File 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 \c {else if} clauses if you have more than one custom
	control in your plugin implementation.
    
	    We'll now look at the constructor.

\quotefile filechooser/plugin/plugin.cpp
\skipto CustomWidgetPlugin
\printuntil }

	    The constructor does not have to do anything. Simply copy
	    ours with the class name you wish to use for your widget
	    plugin implementation.

	    No destructor is necessary. 

	    \index keys()
	    The \Func keys function.

\quotefile filechooser/plugin/plugin.cpp
\skipto ::keys
\printuntil }

	    For each widget class that you want to wrap in the plugin
	    implementation you should supply a key, (often the
	    class name), by which the class can be identified. In our
	    example we add a single key, 'FileChooser'.

	    \index create()
	    The \Func create() function.

\skipto ::create
\printuntil }

	    In this function we create an instance of the requested
	    class and return a QWidget pointer to the newly created
	    widget.  Copy this function changing the class name and
	    the feature name and create an instance of your widget
	    just as we've done here.
	    (See the \link
	    http://doc.trolltech.com/plugins.html Qt Plugin
	    documentation \endlink for more information.)

	    \index includeFile()
	    The \Func includeFile() function.

\skipto ::includeFile
\printuntil }

	    This function returns the name of the include file for the
	    custom widget. Copy this function changing the class name,
	    key and include filename to suit your own custom widget.

	    \index group()
	    \index iconSet()
	    \index includeFile()
	    \index toolTip()
	    \index whatsThis()
	    The \Func group(), \Func iconSet(), 
	    \Func toolTip() and \Func whatsThis() functions.

\quotefile filechooser/plugin/plugin.cpp
\skipto ::group
\printuntil ::iconSet
\printuntil ::toolTip
\printuntil ::whatsThis
\printuntil }

	    We use the \Func group() function to identify which \QD toolbar
	    group this custom widget should be part of. If we
	    use a name that is not in use \QD will create a new toolbar
	    group with the given name. Copy this function, changing the
	    class name, key and group name to suit your own
	    widget plugin implementation.

	    The \Func iconSet() function returns the pixmap to
	    use in the toolbar to represent the custom widget. The
	    \Func toolTip() function returns the tooltip text and the
	    \Func 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.

	    \index isContainer()
	    The \Func isContainer() function.

\printline ::isContainer
\printuntil }

	    Copy this function changing the class name to suit your
	    widget plugin implementation. It should return \c {TRUE}
	    if your custom widget can contain other widgets, e.g. like
	    \Class QFrame, or \c {FALSE} if it must not contain other
	    widgets, e.g. like \Class QPushButton.

	    \index Macros!Q_EXPORT_PLUGIN
	    \index Q_EXPORT_PLUGIN
	    The \Func Q_EXPORT_PLUGIN macro.

\skipto Q_EXPORT_PLUGIN
\printline Q_EXPORT_PLUGIN

	    This macro identifies the module as a
	    plugin -- all the other code simply implements the relevant
	    interface, i.e. wraps the classes you wish to make
	    available.

	    This macro must appear once in your plugin. It should be
	    copied with the class name changed to the name of your
	    plugin's class. (See the
	    \link http://doc.trolltech.com/plugins.html
	    Qt Plugin documentation \endlink
	    for more information on the plugin entry point.)

	    Each widget you wrap in a widget plugin implementation
	    becomes a class that the plugin implementation offers.
	    There is no limit to the number of classes that you may
	    include in an plugin implementation.

	\section3 The Project File

	The project file for a plugin is somewhat different from an
	application's project file but in most cases you can use our
	project file changing only the \c {HEADERS} and \c {SOURCES}
	lines.

\include filechooser/plugin/plugin.pro
\caption \File qt/tools/designer/examples/filechooser/plugin/plugin.pro

	Change the \c {HEADERS} line to list your plugin's header file
	plus a header file for each of your widgets. Make the equivalent
	change for the \c {SOURCES} line. If you create a Makefile with
	\Cmd qmake and make the project the plugin will be created and
	placed in a directory where \QD can find it. The next time you
	run \QD it will detect your new plugin and load it
	automatically, displaying its icon in the toolbar you specified.

	\section3 Using the Widget Plugin

	Once the plugin has been compiled it will automatically be
	found and loaded by \QD the next time \QD 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
	\c{$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. \c styles, \c widgets, etc. cannot be
	changed.
