1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- /home/espenr/tmp/qt-3.3.8-espenr-2499/qt-x11-free-3.3.8/tools/designer/book/chap-custom-controls.leaf:3 -->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Creating Custom Widgets</title>
<style type="text/css"><!--
fn { margin-left: 1cm; text-indent: -1cm; }
a:link { color: #004faf; text-decoration: none }
a:visited { color: #672967; text-decoration: none }
body { background: #ffffff; color: black; }
--></style>
</head>
<body>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr bgcolor="#E5E5E5">
<td valign=center>
<a href="index.html">
<font color="#004faf">Home</font></a>
| <a href="classes.html">
<font color="#004faf">All Classes</font></a>
| <a href="mainclasses.html">
<font color="#004faf">Main Classes</font></a>
| <a href="annotated.html">
<font color="#004faf">Annotated</font></a>
| <a href="groups.html">
<font color="#004faf">Grouped Classes</font></a>
| <a href="functions.html">
<font color="#004faf">Functions</font></a>
</td>
<td align="right" valign="center"><img src="logo32.png" align="right" width="64" height="32" border="0"></td></tr></table><p align="right">[<a href="designer-manual-6.html">Prev: Subclassing and Dynamic Dialogs</a>] [<a href="designer-manual.html">Home</a>] [<a href="designer-manual-8.html">Next: Creating Database Applications</a>]</p>
<h2 align="center">Creating Custom Widgets</h2>
<!-- index Custom Widgets --><!-- index Widgets!Custom --><p>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.</p>
<!-- index Previewing!Custom Widgets --><!-- index Custom Widgets!Previewing --><p><em>TQt Designer</em> provides two mechanisms for incorporating custom widgets:</p>
<ol type=1><li><p>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 <em>TQt Designer</em>, 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".</p>
<li><!-- index Plugins --><p>The new method involves embedding the widgets in a plugin. Widgets that are incorporated through plugins appear in their true form in <em>TQt Designer</em>, 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 <a href="designer-manual-7.html#2">Creating Custom Widgets with Plugins</a>.</p>
</ol><h3><a name="1"></a>Simple Custom Widgets</h3>
<!-- index Custom Widgets!Simple --><p>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 <em>TQt Designer</em>. 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 <em>TQt Designer</em> is very easy.</p>
<p>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.</p>
<h4><a name="1-1"></a>Coding the Custom Widget</h4>
<p>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 <a href="tqpushbutton.html">TQPushButton</a> widgets to form the basis of our custom widget.</p>
<p>We'll look at the header file, <tt>qt/tools/designer/examples/vcr/vcr.h</tt> first.</p>
<pre> #include <<a href="tqwidget-h.html">tqwidget.h</a>>
class Vcr : public <a href="tqwidget.html">TQWidget</a>
{
TQ_OBJECT
public:
Vcr( <a href="tqwidget.html">TQWidget</a> *parent = 0, const char *name = 0 );
~Vcr() {}
signals:
void rewind();
void play();
void next();
void stop();
};
</pre>
<!-- index Macros!TQ_OBJECT --><!-- index TQ_OBJECT --> <p>We include <tt>tqwidget.h</tt> since we'll be deriving our custom widget from <a href="tqwidget.html">TQWidget</a>. We declare a constructor where the widget will be created and the four signals we want our widget to emit.</p>
<p><b>Note:</b> Since we're using signals we must also include the <tt>TQ_OBJECT</tt> macro. This macro also ensures that information about the class is available via the <a href="metaobjects.html">Meta Object System</a> and ensures that <em>TQt Designer</em> will display the correct information about the widget.</p>
<p>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 --> <tt>.xpm</tt> images.</p>
<pre> Vcr::Vcr( <a href="tqwidget.html">TQWidget</a> *parent, const char *name )
: <a href="tqwidget.html">TQWidget</a>( parent, name )
{
<a href="qhboxlayout.html">TQHBoxLayout</a> *layout = new <a href="qhboxlayout.html">TQHBoxLayout</a>( this );
layout-><a href="ntqlayout.html#setMargin">setMargin</a>( 0 );
<a href="tqpushbutton.html">TQPushButton</a> *rewind = new <a href="tqpushbutton.html">TQPushButton</a>( TQPixmap( rewind_xpm ), 0, this, "vcr_rewind" );
layout-><a href="qboxlayout.html#addWidget">addWidget</a>( rewind );
</pre>
<p>We create a <a href="qhboxlayout.html">TQHBoxLayout</a> 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 <a href="tqpushbutton.html">TQPushButton</a> constructor passing it the appropriate embedded pixmap. We then add it to the layout. Finally we connect the button's<!-- index clicked() --> <tt>clicked()</tt> signal to the appropriate <em>signal</em>. Since the<!-- index clicked() --> <tt>clicked()</tt> signals aren't specific to our widget we want to emit signals that reflect the widget's use. The <tt>rewind()</tt>, <tt>play()</tt>, etc. signals are meaningful in the context of our widget so we propagate each button's<!-- index clicked() --> <tt>clicked()</tt> signal to the appropriate widget-specific signal.</p>
<!-- index Forms!Creating Test Harnesses --><p>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 --> <tt>.pro</tt> project file and a<!-- index main.cpp --> <tt>main.cpp</tt>. The <tt>qt/tools/designer/examples/vcr/vcr.pro</tt> project file:</p>
<pre>TEMPLATE = app
LANGUAGE = C++
TARGET = vcr
CONFIG += qt warn_on release
SOURCES += vcr.cpp main.cpp
HEADERS += vcr.h
DBFILE = vcr.db
</pre>
<p>The <tt>qt/tools/designer/examples/vcr/main.cpp</tt> file is also brief:</p>
<pre> #include <<a href="qapplication-h.html">ntqapplication.h</a>>
#include "vcr.h"
int main( int argc, char ** argv )
{
<a href="ntqapplication.html">TQApplication</a> app( argc, argv );
Vcr *vcr = new Vcr;
vcr-><a href="tqwidget.html#show">show</a>();
return app.<a href="ntqapplication.html#exec">exec</a>();
}
</pre>
<p>Once we're satisfied that the custom widget compiles and runs we are ready to incorporate it into <em>TQt Designer</em>.</p>
<p>In <a href="designer-manual-9.html#2-2">Base-class Templates</a> the creation of a container custom widget is described.</p>
<h4><a name="1-2"></a>Adding the Custom Widget to TQt Designer</h4>
<!-- index Custom Widgets!Adding to TQt Designer --><!-- index Adding!Custom Widgets to TQt Designer --><p>Click <b>Tools|Custom|Edit Custom Widgets</b> to invoke the <em>Edit Custom Widgets</em> dialog.</p>
<ol type=1><li><p>Click <b>New Widget</b> so that we are ready to add our new widget.</p>
<li><p>Change the Class name from 'MyCustomWidget' to 'Vcr'.</p>
<li><p>Click the ellipsis (<b>...</b>) button to the right of the Headerfile line edit to invoke the file Open dialog. Locate <tt>vcr.h</tt>, select it, and click <b>Open</b>. It will now appear as the header file.</p>
<li><p>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 <em>pixmap</em> or <em>iconSet</em> property.)</p>
<p>In our example we have the file <tt>qt/tools/designer/examples/vcr/play.xpm</tt> which we'll use for this purpose.</p>
<li><p>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).</p>
</ol><p>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.</p>
<p>Click the Signals tab. Click the <b>New Signal</b> button and type in the signal name 'rewind()'. Click <b>New Signal</b> again and this time type in 'play()'. Add the 'next()' and 'stop()' signals in the same way.</p>
<p>Since our example hasn't any slots or properties we've finished and can click <b>Close</b>. A new icon will appear in <em>TQt Designer</em>'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.</p>
<p>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.</p>
<a name="creatingplugins"></a><h3><a name="2"></a>Creating Custom Widgets with Plugins</h3>
<!-- index Custom Widgets!Plugins --><!-- index Plugins!Implementing Custom Widgets --><p>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 TQt programmer you can safely skip the section on creating a custom widget and go directly to <a href="designer-manual-7.html#2-2">Creating a Plugin</a>.</p>
<p>Be aware that if you use the plugin approach to custom widgets, the plugin needs to be available not only to <em>TQt Designer</em> but also to <tt>uic</tt> at compile-time.</p>
<h4><a name="2-1"></a>Creating a Custom Widget</h4>
<!-- index Creating Custom Widgets --><!-- index Widgets!Creating a Custom Widget --><!-- index Subclassing!Widgets --><p>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 <em>TQt Designer</em>. Custom widgets are generally created when you need to add new functionality to existing widgets or groups of widgets.</p>
<!-- index Properties!Creating Custom Properties --><p>We have two recommendations that you should consider when creating a custom widget for a plugin:</p>
<ol type=1><li><p>Using TQt's property system will provide <em>TQt Designer</em> users with a direct means of configuring the widget through the property editor. (See the <a href="http://doc.trolltech.com/properties.html">TQt Properties</a> documentation.)</p>
<li><p>Consider making your widget's public 'set' functions into public slots so that you can perform signal-slot connections with the widget in <em>TQt Designer</em>.</p>
</ol><p>In the course of this chapter we will create a simple but useful widget, 'FileChooser', which we'll later make available in <em>TQt Designer</em> 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 <em>TQt Designer</em> to reflect this approach. FileChooser consists of a <a href="tqlineedit.html">TQLineEdit</a> and a <a href="tqpushbutton.html">TQPushButton</a>. The <a href="tqlineedit.html">TQLineEdit</a> is used to hold a file or directory name, the <a href="tqpushbutton.html">TQPushButton</a> is used to launch a file dialog through which the user can choose a file or directory.</p>
<p align="center"><img align="middle" src="filechooser.png" width="169" height="34">
</p>
<blockquote><p align="center"><em>The FileChooser Custom Widget</em></p></blockquote>
<p>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 <a href="designer-manual-7.html#2-2">Creating a Plugin</a>. If you prefer to read how we created the widget then read on.</p>
<h5><a name="2-1-1"></a>Coding the Widget's Interface</h5>
<p>We will work step-by-step through the widget's header file, <tt>qt/tools/designer/examples/filechooser/widget/filechooser.h</tt>.</p>
<pre> #include <<a href="tqwidget-h.html">tqwidget.h</a>>
#include <<a href="tqwidgetplugin-h.html">tqwidgetplugin.h</a>>
class TQLineEdit;
class TQPushButton;
</pre>
<p>Our widget will be derived from <a href="tqwidget.html">TQWidget</a> so we include the <tt>tqwidget.h</tt> header file. We also forward declare the two classes that our widget will be built from.</p>
<pre></pre>
<!-- index Macros!TQ_OBJECT --><!-- index TQ_OBJECT --><!-- index Macros!TQ_ENUMS --><!-- index TQ_ENUMS --> <p>We include the <tt>TQ_OBJECT</tt> macro since this is required for classes that declare signals or slots. The <tt>TQ_ENUMS</tt> 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.</p>
<pre> class QT_WIDGET_PLUGIN_EXPORT FileChooser : public <a href="tqwidget.html">TQWidget</a>
{
TQ_OBJECT
TQ_ENUMS( Mode )
TQ_PROPERTY( Mode mode READ mode WRITE setMode )
TQ_PROPERTY( TQString fileName READ fileName WRITE setFileName )
public:
FileChooser( <a href="tqwidget.html">TQWidget</a> *parent = 0, const char *name = 0);
enum Mode { File, Directory };
<a href="tqstring.html">TQString</a> fileName() const;
Mode mode() const;
</pre>
<p>The constructor is declared in the standard way for widgets. We declare two public functions, <tt>fileName()</tt> to return the filename, and <tt>mode()</tt> to return the mode.</p>
<pre> public slots:
void setFileName( const <a href="tqstring.html">TQString</a> &fn );
void setMode( Mode m );
signals:
void fileNameChanged( const <a href="tqstring.html">TQString</a> & );
private slots:
void chooseFile();
</pre>
<p>The two 'set' functions are declared as public slots. <tt>setFileName()</tt> and <tt>setMode()</tt> set the filename and mode respectively. We declare a single signal, <tt>fileNameChanged()</tt>. The private slot, <tt>chooseFile()</tt> is called by the widget itself when its button is clicked.</p>
<pre> private:
<a href="tqlineedit.html">TQLineEdit</a> *lineEdit;
<a href="tqpushbutton.html">TQPushButton</a> *button;
Mode md;
};
</pre>
<p>A pointer to <a href="tqlineedit.html">TQLineEdit</a> and <a href="tqpushbutton.html">TQPushButton</a>, as well as a Mode variable are held as private data.</p>
<h5><a name="2-1-2"></a>Coding the Implementation</h5>
<p>We will work step-by-step through the implementation which is in <tt>qt/tools/designer/examples/filechooser/widget/filechooser.cpp</tt>.</p>
<pre> FileChooser::FileChooser( <a href="tqwidget.html">TQWidget</a> *parent, const char *name )
: <a href="tqwidget.html">TQWidget</a>( parent, name ), md( File )
{
</pre>
<p>The constructor passes the parent and name to its superclass, <a href="tqwidget.html">TQWidget</a>, and also initializes the private mode data, md, to File mode.</p>
<pre> <a href="qhboxlayout.html">TQHBoxLayout</a> *layout = new <a href="qhboxlayout.html">TQHBoxLayout</a>( this );
layout-><a href="ntqlayout.html#setMargin">setMargin</a>( 0 );
lineEdit = new <a href="tqlineedit.html">TQLineEdit</a>( this, "filechooser_lineedit" );
layout-><a href="qboxlayout.html#addWidget">addWidget</a>( lineEdit );
</pre>
<p>We begin by creating a horizontal box layout (<a href="qhboxlayout.html">TQHBoxLayout</a>) and add a <a href="tqlineedit.html">TQLineEdit</a> and a <a href="tqpushbutton.html">TQPushButton</a> to it.</p>
<pre> <a href="tqobject.html#connect">connect</a>( lineEdit, TQ_SIGNAL( <a href="tqlineedit.html#textChanged">textChanged</a>( const <a href="tqstring.html">TQString</a> & ) ),
this, TQ_SIGNAL( fileNameChanged( const <a href="tqstring.html">TQString</a> & ) ) );
button = new <a href="tqpushbutton.html">TQPushButton</a>( "...", this, "filechooser_button" );
button-><a href="tqwidget.html#setFixedWidth">setFixedWidth</a>( button-><a href="tqwidget.html#fontMetrics">fontMetrics</a>().width( " ... " ) );
layout-><a href="qboxlayout.html#addWidget">addWidget</a>( button );
<a href="tqobject.html#connect">connect</a>( button, TQ_SIGNAL( <a href="ntqbutton.html#clicked">clicked</a>() ),
this, TQ_SLOT( chooseFile() ) );
</pre>
<p>We connect the lineEdit's<!-- index textChanged() --> <tt>textChanged()</tt> signal to the custom widget's <tt>fileNameChanged()</tt> signal. This ensures that if the user changes the text in the <a href="tqlineedit.html">TQLineEdit</a> this fact will be propagated via the custom widget's own signal. The button's<!-- index clicked() --> <tt>clicked()</tt> signal is connected to the custom widget's <tt>chooseFile()</tt> slot which invokes the appropriate dialog for the user to choose their file or directory.</p>
<pre> <a href="tqwidget.html#setFocusProxy">setFocusProxy</a>( lineEdit );
}
</pre>
<p>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.</p>
<pre> void FileChooser::setFileName( const <a href="tqstring.html">TQString</a> &fn )
{
lineEdit-><a href="tqlineedit.html#setText">setText</a>( fn );
}
TQString FileChooser::fileName() const
{
return lineEdit-><a href="tqlineedit.html#text">text</a>();
}
</pre>
<p>The <tt>setFileName()</tt> function sets the filename in the <a href="tqlineedit.html">TQLineEdit</a>, and the <tt>fileName()</tt> function returns the filename from the <a href="tqlineedit.html">TQLineEdit</a>. The <tt>setMode()</tt> and <tt>mode()</tt> functions (not shown) are similarly set and return the given mode.</p>
<pre> void FileChooser::chooseFile()
{
<a href="tqstring.html">TQString</a> fn;
if ( mode() == File )
fn = TQFileDialog::<a href="tqfiledialog.html#getOpenFileName">getOpenFileName</a>( lineEdit-><a href="tqlineedit.html#text">text</a>(), TQString::null, this );
else
fn = TQFileDialog::<a href="tqfiledialog.html#getExistingDirectory">getExistingDirectory</a>( lineEdit-><a href="tqlineedit.html#text">text</a>(),this );
if ( !fn.<a href="tqstring.html#isEmpty">isEmpty</a>() ) {
lineEdit-><a href="tqlineedit.html#setText">setText</a>( fn );
emit fileNameChanged( fn );
}
}
</pre>
<p>When <tt>chooseFile()</tt> 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 <a href="tqlineedit.html">TQLineEdit</a> is updated with the chosen file or directory and the <tt>fileNameChanged()</tt> signal is emitted.</p>
<p>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.</p>
<h5><a name="2-1-3"></a>Testing the Implementation</h5>
<!-- index main.cpp --><!-- index Forms!Creating Test Harnesses --><p>We present a rudimentary test harness which will allow us to run our custom widget. The test harness requires two files, a <tt>main.cpp</tt> to contain the FileChooser, and a <tt>.pro</tt> file to create the Makefile from. Here is <tt>qt/tools/designer/examples/filechooser/widget/main.cpp</tt>:</p>
<pre> #include <<a href="qapplication-h.html">ntqapplication.h</a>>
#include "filechooser.h"
int main( int argc, char ** argv )
{
<a href="ntqapplication.html">TQApplication</a> a( argc, argv );
FileChooser *fc = new FileChooser;
fc-><a href="tqwidget.html#show">show</a>();
return a.<a href="ntqapplication.html#exec">exec</a>();
}
</pre>
<p>And here is <tt>qt/tools/designer/examples/filechooser/widget/filechooser.pro</tt></p>
<pre>TEMPLATE = app
LANGUAGE = C++
TARGET = filechooser
SOURCES += filechooser.cpp main.cpp
HEADERS += filechooser.h
CONFIG += qt warn_on release
DBFILE = filechooser.db
DEFINES += FILECHOOSER_IS_WIDGET
</pre>
<p>We can create the makefile using <tt>qmake</tt>: <tt>qmake -o Makefile filechooser.pro</tt>, 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.</p>
<h4><a name="2-2"></a>Creating a Plugin</h4>
<!-- index Creating Plugins --><!-- index Plugins!Creating a Plugin --><!-- index Component!Plugins --><p>TQt Plugins can be used to provide self-contained software components for TQt applications. TQt 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 <em>TQt Designer</em> custom widget plugin.</p>
<p>A <em>TQt Designer</em> custom widget plugin is always derived from <a href="tqwidgetplugin.html">TQWidgetPlugin</a>. The amout of code that needs to be written is minimal.</p>
<p>To make your own plugin it is probably easiest to start by copying our example<!-- index plugin.h --> <tt>plugin.h</tt> and<!-- index plugin.cpp --> <tt>plugin.cpp</tt> 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.</p>
<h5><a name="2-2-1"></a>The <b>CustomWidgetPlugin</b> Implementation</h5>
<p>We have called our header file<!-- index plugin.h --> <tt>plugin.h</tt> and we've called our plugin class <b>CustomWidgetPlugin</b> 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.</p>
<pre> #include <<a href="tqwidgetplugin-h.html">tqwidgetplugin.h</a>>
class CustomWidgetPlugin : public <a href="tqwidgetplugin.html">TQWidgetPlugin</a>
{
public:
CustomWidgetPlugin();
<a href="tqstringlist.html">TQStringList</a> keys() const;
<a href="tqwidget.html">TQWidget</a>* create( const <a href="tqstring.html">TQString</a> &classname, TQWidget* parent = 0, const char* name = 0 );
<a href="tqstring.html">TQString</a> group( const <a href="tqstring.html">TQString</a>& ) const;
<a href="tqiconset.html">TQIconSet</a> iconSet( const <a href="tqstring.html">TQString</a>& ) const;
<a href="tqstring.html">TQString</a> includeFile( const <a href="tqstring.html">TQString</a>& ) const;
<a href="tqstring.html">TQString</a> toolTip( const <a href="tqstring.html">TQString</a>& ) const;
<a href="tqstring.html">TQString</a> whatsThis( const <a href="tqstring.html">TQString</a>& ) const;
bool isContainer( const <a href="tqstring.html">TQString</a>& ) const;
};
</pre>
<blockquote><p align="center"><em>From <tt>qt/tools/designer/examples/filechooser/plugin/plugin.h</tt></em></p></blockquote>
<h5><a name="2-2-2"></a>The TQWidgetPlugin Functions</h5>
<!-- index plugin.cpp --><p>Create your own plugin <tt>.cpp</tt> file by copying our <tt>plugin.cpp</tt> 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 <tt>else if</tt> clauses if you have more than one custom control in your plugin implementation.</p>
<p>We'll now look at the constructor.</p>
<pre> CustomWidgetPlugin::CustomWidgetPlugin()
{
}
</pre>
<p>The constructor does not have to do anything. Simply copy ours with the class name you wish to use for your widget plugin implementation.</p>
<p>No destructor is necessary.</p>
<!-- index keys() --><p>The <tt>keys</tt> function.</p>
<pre> TQStringList CustomWidgetPlugin::<a href="tqwidgetplugin.html#keys">keys</a>() const
{
<a href="tqstringlist.html">TQStringList</a> list;
list << "FileChooser";
return list;
}
</pre>
<p>For each widget class that you want to wrap in the plugin implementation you should supply a key by which the class can be identified. This key <em>must</em> be your class's name, so in our example we add a single key, 'FileChooser'.</p>
<!-- index create() --><p>The <tt>create()</tt> function.</p>
<pre> TQWidget* CustomWidgetPlugin::<a href="tqwidgetplugin.html#create">create</a>( const <a href="tqstring.html">TQString</a> &key, TQWidget* parent, const char* name )
{
if ( key == "FileChooser" )
return new FileChooser( parent, name );
return 0;
}
</pre>
<p>In this function we create an instance of the requested class and return a TQWidget 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 <a href="http://doc.trolltech.com/plugins.html">TQt Plugin documentation</a> for more information.)</p>
<!-- index includeFile() --><p>The <tt>includeFile()</tt> function.</p>
<pre> TQString CustomWidgetPlugin::<a href="tqwidgetplugin.html#includeFile">includeFile</a>( const <a href="tqstring.html">TQString</a>& feature ) const
{
if ( feature == "FileChooser" )
return "filechooser.h";
return TQString::null;
}
</pre>
<p>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.</p>
<!-- index group() --><!-- index iconSet() --><!-- index includeFile() --><!-- index toolTip() --><!-- index whatsThis() --><p>The <tt>group()</tt>, <tt>iconSet()</tt>, <tt>toolTip()</tt> and <tt>whatsThis()</tt> functions.</p>
<pre> TQString CustomWidgetPlugin::<a href="tqwidgetplugin.html#group">group</a>( const <a href="tqstring.html">TQString</a>& feature ) const
{
if ( feature == "FileChooser" )
return "Input";
return TQString::null;
}
TQIconSet CustomWidgetPlugin::<a href="tqwidgetplugin.html#iconSet">iconSet</a>( const <a href="tqstring.html">TQString</a>& ) const
{
return TQIconSet( TQPixmap( filechooser_pixmap ) );
}
TQString CustomWidgetPlugin::<a href="tqwidgetplugin.html#includeFile">includeFile</a>( const <a href="tqstring.html">TQString</a>& feature ) const
{
if ( feature == "FileChooser" )
return "filechooser.h";
return TQString::null;
}
TQString CustomWidgetPlugin::<a href="tqwidgetplugin.html#toolTip">toolTip</a>( const <a href="tqstring.html">TQString</a>& feature ) const
{
if ( feature == "FileChooser" )
return "File Chooser Widget";
return TQString::null;
}
TQString CustomWidgetPlugin::<a href="tqwidgetplugin.html#whatsThis">whatsThis</a>( const <a href="tqstring.html">TQString</a>& feature ) const
{
if ( feature == "FileChooser" )
return "A widget to choose a file or directory";
return TQString::null;
}
</pre>
<p>We use the <tt>group()</tt> function to identify which <em>TQt Designer</em> toolbar group this custom widget should be part of. If we use a name that is not in use <em>TQt Designer</em> 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.</p>
<p>The <tt>iconSet()</tt> function returns the pixmap to use in the toolbar to represent the custom widget. The <tt>toolTip()</tt> function returns the tooltip text and the <tt>whatsThis()</tt> 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.</p>
<!-- index isContainer() --><p>The <tt>isContainer()</tt> function.</p>
<pre> bool CustomWidgetPlugin::<a href="tqwidgetplugin.html#isContainer">isContainer</a>( const <a href="tqstring.html">TQString</a>& ) const
{
return FALSE;
}
</pre>
<p>Copy this function changing the class name to suit your widget plugin implementation. It should return <tt>TRUE</tt> if your custom widget can contain other widgets, e.g. like <a href="ntqframe.html">TQFrame</a>, or <tt>FALSE</tt> if it must not contain other widgets, e.g. like <a href="tqpushbutton.html">TQPushButton</a>.</p>
<!-- index Macros!TQ_EXPORT_PLUGIN --><!-- index TQ_EXPORT_PLUGIN --><p>The <tt>TQ_EXPORT_PLUGIN</tt> macro.</p>
<pre> TQ_EXPORT_PLUGIN( CustomWidgetPlugin )
</pre>
<p>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.</p>
<p>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 <a href="http://doc.trolltech.com/plugins.html">TQt Plugin documentation</a> for more information on the plugin entry point.)</p>
<p>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.</p>
<h5><a name="2-2-3"></a>The Project File</h5>
<p>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 <tt>HEADERS</tt> and <tt>SOURCES</tt> lines.</p>
<pre>TEMPLATE = lib
LANGUAGE = C++
TARGET = filechooser
SOURCES += plugin.cpp ../widget/filechooser.cpp
HEADERS += plugin.h ../widget/filechooser.h
DESTDIR = ../../../../../plugins/designer
target.path=$$plugins.path
INSTALLS += target
CONFIG += qt warn_on release plugin
INCLUDEPATH += $$QT_SOURCE_TREE/tools/designer/interfaces
DBFILE = plugin.db
</pre>
<blockquote><p align="center"><em><tt>qt/tools/designer/examples/filechooser/plugin/plugin.pro</tt></em></p></blockquote>
<p>Change the <tt>HEADERS</tt> line to list your plugin's header file plus a header file for each of your widgets. Make the equivalent change for the <tt>SOURCES</tt> line. If you create a Makefile with <tt>qmake</tt> and make the project the plugin will be created and placed in a directory where <em>TQt Designer</em> can find it. The next time you run <em>TQt Designer</em> it will detect your new plugin and load it automatically, displaying its icon in the toolbar you specified.</p>
<h5><a name="2-2-4"></a>Using the Widget Plugin</h5>
<p>Once the plugin has been compiled it will automatically be found and loaded by <em>TQt Designer</em> the next time <em>TQt Designer</em> is run. Use your custom widget just like any other.</p>
<p>If you want to use the plugin in another of your projects you can link against it by adding an appropriate line to the project, e.g. by adding a line like this to the project's <tt>.pro</tt> file:</p>
<pre>
LIBS += filechooser.lib
</pre>
<p>When you want to distribute your application, include the compiled plugin with the executable. Install the plugin in <tt>plugins/widgets</tt> subdirectory of the TQt installation directory. 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 TQSettings, for the application to read when it runs. The application can then call TQApplication::addLibraryPath() with this path and your plugins will be available to the application. Note that the final part of the path, i.e. <tt>styles</tt>, <tt>widgets</tt>, etc. cannot be changed.</p>
<blockquote>
<p align="center"><b> Plugins and Threaded Applications</b></p>
<p>If you want to build a plugin which you want to use with a threaded TQt library (whether or not the plugin itself uses threads) you must use a threaded environment. Specifically, you must use a threaded TQt library, and you must build <em>TQt Designer</em> with that library. Your <tt>.pro</tt> file for your plugin must include the line:</p>
<pre>
CONFIG += thread
</pre>
<p><b>Do not</b> mix the normal TQt library and the threaded TQt library in an application. If your application uses the threaded TQt library, you should not link with the normal TQt library. Nor should you dynamically load the normal TQt library or dynamically load another library, e.g. a plugin, that depends on the normal TQt library. On some systems, mixing threaded and non-threaded libraries or plugins will corrupt the static data used in the TQt library.</p>
</blockquote>
<!-- eof -->
<p align="right">[<a href="designer-manual-6.html">Prev: Subclassing and Dynamic Dialogs</a>] [<a href="designer-manual.html">Home</a>] [<a href="designer-manual-8.html">Next: Creating Database Applications</a>]</p>
<p><address><hr><div align=center>
<table width=100% cellspacing=0 border=0><tr>
<td>Copyright © 2007
<a href="troll.html">Trolltech</a><td align=center><a href="trademarks.html">Trademarks</a>
<td align=right><div align=right>TQt 3.3.8</div>
</table></div></address></body>
</html>
|