📄 designer-manual-5.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><!-- /home/reggie/tmp/qt-3.0-reggie-5401/qt-x11-commercial-3.0.5/tools/designer/book/chap-subclassing.leaf:3 --><html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Subclassing and Dynamic Dialogs</title><style type="text/css"><!--h3.fn,span.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-4.html">Prev: The Designer Approach</a>] [<a href="designer-manual.html">Home</a>] [<a href="designer-manual-6.html">Next: Creating Custom Widgets</a>]</p><h2 align="center">Subclassing and Dynamic Dialogs</h2><!-- index Subclassing --><!-- index Dynamic Dialogs --><!-- index Dialogs!Dynamic --><p>This chapter describes two different approaches that you can take to creating forms with <em>Qt Designer</em>. Subclassing is used to extend the functionality of a form by creating your own class based upon a form you create in <em>Qt Designer</em>. Dynamic dialogs are<!-- index .ui --> <tt>.ui</tt> 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.</p><h3><a name="1"></a>Subclassing</h3><p>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 <a href="designer-manual-4.html#3">Extending the functionality of a form</a> in <a href="designer-manual-4.html">The Designer Approach</a> chapter for details.</p><h4><a name="1-1"></a>Generating Source Code from <em>Qt Designer</em> .ui Files</h4><p><em>Qt Designer</em> reads and writes <tt>qmake</tt><!-- index .pro --> <tt>.pro</tt> (project) files which are used to record the files used to build the application and from which Makefiles are generated. <em>Qt Designer</em> also reads and writes<!-- index .ui --> <tt>.ui</tt> (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 --> <tt>.ui</tt> file is converted by the <tt>uic</tt> (user interface compiler) into a C++<!-- index .h --> <tt>.h</tt> file and a C++<!-- index .cpp --> <tt>.cpp</tt> file. These C++ files are then read by <tt>moc</tt> (meta object compiler), and finally compiled by your compiler into a working application.</p><!-- index Makefiles --><!-- index Projects!Adding Files --><!-- index Adding!Files to Projects --><p>If you create applications wholly within <em>Qt Designer</em> you only need to create a<!-- index main.cpp --> <tt>main.cpp</tt>.</p><p>If you create the <tt>main.cpp</tt> file within <em>Qt Designer</em>, it will automatically be added to your project file by <em>Qt Designer</em>. If you create the <tt>main.cpp</tt> file outside of <em>Qt Designer</em> you must add it to the project file manually by adding the following line at the end of your project's<!-- index .pro --> <tt>.pro</tt> file:</p><pre>SOURCES += main.cpp</pre><p>You can then use <tt>qmake</tt> to generate the Makefile. (For example <tt>qmake -o Makefile myproject.pro</tt>.) Running <tt>make</tt> (Linux, Unix or Borland compilers), or <tt>nmake</tt> (Visual C++), will then call <tt>uic</tt>, <tt>moc</tt> and your compiler as necessary to build your application.</p><!-- index Errors!Undefined reference --><!-- index Undefined references, Error --><!-- index qmake!HEADERS --><!-- index qmake!SOURCES --><p>If you use <em>Qt Designer</em> 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 --> <tt>.pro</tt> file so that they are compiled with the rest of your application's source files. Each<!-- index .h --> <tt>.h</tt> file that you create separately from <em>Qt Designer</em> should be added to the <tt>HEADERS</tt> line, and each<!-- index .cpp --> <tt>.cpp</tt> file should be added to the <tt>SOURCES</tt> line, just as we've done for<!-- index main.cpp --> <tt>main.cpp</tt>. 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 --> <tt>.pro</tt> file.</p><h4><a name="1-2"></a>Subclassing a Form</h4><!-- index Subclassing --><p>When subclassing a form it is helpful to use a naming convention to help us identify which files are generated from <em>Qt Designer</em>'s<!-- index .ui --> <tt>.ui</tt> files and which are hand coded.</p><p>Suppose, for example, that we are developing a dialog and writing the code directly in <em>Qt Designer</em>. We might call our dialog 'OptionsForm' and the<!-- index .ui --> <tt>.ui</tt> file, <tt>optionsform.ui</tt>. The automatically generated files will be <tt>optionsform.h</tt> and <tt>optionsform.cpp</tt>.</p><p>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 --> <tt>.ui</tt> file <tt>settingsformbase.ui</tt>. The automatically generated files would then be called <tt>settingsformbase.h</tt> and <tt>settingsformbase.cpp</tt>. We would then call our subclass 'SettingsForm' and code it in the files <tt>settingsform.h</tt> and <tt>settingsform.cpp</tt>.</p><!-- index Q_OBJECT!Macros --><!-- index Macros!Q_OBJECT --><!-- index Signals and Slots!Q_OBJECT --><p>Any subclass of a form should include the <tt>Q_OBJECT</tt> macro so that slots and signals will work correctly. Once you've created your subclass be sure to add the<!-- index .h --> <tt>.h</tt> and the<!-- index .cpp --> <tt>.cpp</tt> files to the<!-- index .pro --> <tt>.pro</tt> project file. For example we would add the following lines for our subclassed 'SettingsForm' at the end of the<!-- index .pro --> <tt>.pro</tt> file:</p><pre>HEADERS += settingsform.hSOURCES += settingsform.cpp</pre><p>The simplest way to create a new source file is by clicking <b>File|New</b> to invoke the 'New File' dialog, then click 'C++ Source' or 'C++ Header' as appropriate, then click <b>OK</b>. A new empty source window will appear. You don't need to manually edit the <tt>.pro</tt> file since <em>Qt Designer</em> will add them for you automatically.</p><p><em>Qt Designer</em> will have added</p><pre>FORMS = settingsformbase.ui</pre><p>to the project file. The <tt>settingsformbase.h</tt> and <tt>settingsformbase.cpp</tt> files will be generated from the<!-- index .ui --> <tt>.ui</tt> file automatically.</p><h4><a name="1-3"></a>A Subclassing Example</h4><p>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 --> <tt>main.cpp</tt> so that we can test it.</p><h5><a name="1-3-1"></a>Designing the Form</h5><!-- index Projects!Creating New --><p>We'll begin by creating a new project. Click <b>File|New</b>, then click the 'C++ Project' icon to invoke the <em>Project Settings</em> dialog. Click the ellipsis button to invoke the <em>Save As</em> 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 <b>Save</b> button to return to the <em>Project Settings</em> dialog, then click <b>OK</b>. Now we'll add a form to the project. Click <b>File|New</b> to invoke the <em>New File</em> dialog. The default form is Dialog which is what we want; click <b>OK</b>. 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 <tt>creditformbase.ui</tt>.</p><p>We'll now add the widgets we need.</p><ol type=1><li><p>Click the <b>Button Group</b> 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 <em>name</em> to 'creditButtonGroup' and its <em>title</em> property to 'Credit Rating'.</p><li><p>We'll now add some radio buttons. <em>Double</em> click the <b>Radio Button</b> 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 <em>double</em> click by clicking the <b>Pointer</b> (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 <em>name</em> to 'stdRadioButton' and its text to '&Standard'. Change its <em>checked</em> 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.</p><li><p>If the user chooses the special credit rating they must specify an amount. Click the <b>SpinBox</b> toolbar button and click the form just below the button group. Change the spin box's <em>name</em> to 'amountSpinBox'. Change its <em>prefix</em> to '$ ' (note the space), its <em>maxValue</em> to '100000' and its <em>lineStep</em> to '10000'. Change its <em>enabled</em> property to False.</p><li><p>Click the <b>Push Button</b> toolbar button and click the form below the spin box. Change the button's <em>name</em> to 'okPushButton', its <em>text</em> to 'OK' and its <em>default</em> property to 'True'. Add a second button to the right of the first. Change the second button's <em>name</em> to 'cancelPushButton' and its <em>text</em> to 'Cancel'.</p></ol><p>We'll now lay out the widgets and connect up the slots we need.</p><ol type=1><li><p>Click the credit rating group box then press <b>Ctrl+L</b> (lay out vertically).</p><li><p>Click the form so that the button group is no longer selected. <b>Ctrl+Click</b> the OK button and drag the rubber band to touch the Cancel button, then release. Press <b>Ctrl+H</b>.</p><li><p>Click the form, then press <b>Ctrl+L</b>.</p><!-- index Layouts!Spacers --><p>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 <b>Ctrl+B</b> (break layout). Resize both buttons to make them narrower leaving space on either side of them. Click the <b>Spacer</b> 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 <b>Ctrl+C</b> then <b>Ctrl+V</b>. 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 <b>Ctrl+H</b>. Click the form then press <b>Ctrl+L</b>.</p></ol><!-- index Signals and Slots --><p>We'll now connect the signals and slots. Press <b>F3</b> (connect signals/slots), then click the OK button. Drag to the form and release. In the <em>Edit Connections</em> dialog that pops up connect the<!-- index clicked() --> <tt>clicked()</tt> signal to the<!-- index accept() --> <tt>accept()</tt> slot. (Click the<!-- index clicked() --> <tt>clicked()</tt> signal, click the<!-- index accept() --> <tt>accept()</tt> slot, then click <b>OK</b>.) Connect the Cancel button to the<!-- index reject() --> <tt>reject()</tt> slot using the same technique.</p><p>We want the amount spin box to be enabled only if the special radio button is checked. Press <b>F3</b> (connect signals/slots), then click the special radio button. Drag to the spin box and release. In the <em>Edit Connections</em> dialog that pops up click the<!-- index toggled() --> <tt>toggled()</tt> signal and the<!-- index setEnabled() --> <tt>setEnabled()</tt> slot.</p><p>If the user checks the standard or none radio buttons we want to set the amount accordingly. Press <b>F3</b>, then click the credit rating button group. Drag to the form and release. Click the<!-- index clicked() --> <tt>clicked()</tt> signal. We want to connect this signal to our own custom slot, but we haven't created one yet. Click the <b>Edit Slots</b> button and the Edit Slots dialog will pop up. Click <b>New Slot</b> and change the Slot's name to 'setAmount()'. Click <b>OK</b>. This new slot is now available in the list of slots. Click the <tt>setAmount()</tt> slot then click <b>OK</b>.</p><p>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 <b>Ctrl+S</b>).</p><h5><a name="1-3-2"></a>Creating the Test Harness</h5><!-- index Forms!Creating Test Harnesses --><!-- index Creating Test Harnesses for Forms --><!-- index Subclassing --><p>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. Click <b>File|New</b> to invoke the 'New File' dialog, then click 'C++ Source', then click <b>OK</b>. In the editor window that pops up, enter the following code:</p><pre>#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();}</pre><p>Note that we're including <tt>creditformbase.h</tt> and instantiating a CreditFormBase object; once we've written our subclass we'll replace the header with our subclass, <tt>creditform.h</tt>, and instantiate a CreditForm.</p><p>We can now generate the application with <tt>qmake</tt>, e.g. <tt>qmake -o Makefile credit.pro</tt>, make it and run it. The form should run fine, but doesn't yet have the behaviour we require.</p><h5><a name="1-3-3"></a>Creating the Subclass</h5><p>We need to create a header and an implementation file for our subclass. The code for our subclass is minimal. The header file is <tt>qt/tools/designer/examples/credit/creditform.h</tt>:</p><pre> #include "creditformbase.h" class CreditForm : public CreditFormBase
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -