    <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/">
     <channel>
        <title>ACCU  :: Rapid Dialog Design Using Qt</title>
        <link>https://members.accu.org/index.php/articles/701</link>
        <description>Professionalism in Programming</description>
        <dc:language>en-us</dc:language> 
        <dc:creator>Administrator</dc:creator> 
        <admin:generatorAgent rdf:resource="http://www.xaraya.org" /> 
        <admin:errorReportsTo rdf:resource="mailto:webeditor@accu.org" />
       <sy:updatePeriod>hourly</sy:updatePeriod>
       <sy:updateFrequency>1</sy:updateFrequency>
       <docs>http://backend.userland.com/rss</docs>




<div class="xar-mod-head"><span class="xar-mod-title">Programming Topics + CVu Journal Vol 16, #5 - Oct 2004</span></div>

<table border="0" cellpadding="1" cellspacing="0">
    <tbody>
    <tr>
        <td valign="top">
            Browse in :
       </td>
       <td valign="top">

                                            <a href="https://members.accu.org/index.php/articles/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c13/">Topics</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c65/">Programming</a>
<br />

                                            <a href="https://members.accu.org/index.php/articles/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c76/">Journals</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c77/">CVu</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c100/">165</a>
<br />

                                            <a href="https://members.accu.org/index.php/articles/c65-100/">Any of these categories</a>

                    -                        <a href="https://members.accu.org/index.php/articles/c65+100/">All of these categories</a>
<br />
</td>
   </tr>
   </tbody>
</table>




<div class="xar-error">
   <p>
 <strong>Note:</strong> when you create a new publication type,
the articles module will automatically use the templates
<em>user-display-[publicationtype].xt</em>
and <em>user-summary-[publicationtype].xt</em>.
If those templates do not exist when you try to preview or display a new article,
you'll get this warning :-)  Please place your own templates in themes/<em>yourtheme</em>/modules/articles . The templates will get the extension .xt there. </p>
</div>
<div class="xar-norm xar-standard-box-padding">
   <h1><strong>Title:</strong>&nbsp;Rapid Dialog Design Using Qt</h1>
<p><strong>Author:</strong>&nbsp;</p>
<p>
<strong>Date:</strong> 03 October 2004 13:16:08 +01:00 or Sun, 03 October 2004 13:16:08 +01:00</p>
<p><strong>Summary:</strong>&nbsp;<p>In this third installment of our series on GUI programming with the Qt C++ toolkit, we're going to show how to design dialog boxes (or &quot;dialogs&quot;) using Qt.</p></p>
<p><strong>Body:</strong>&nbsp;<div class="sect1" lang="en">
<div class="titlepage">
<h2><a name="d0e18" id="d0e18"></a></h2>
</div>
<p>In this third installment of our series on GUI programming with
the Qt C++ toolkit, we're going to show how to design dialog boxes
(or &quot;dialogs&quot;) using Qt. Dialogs can be created entirely from
source code, or with <span class="emphasis"><em>Qt
Designer</em></span>, a visual GUI design tool. Whichever approach
is chosen, the result is invariably good looking, resizable,
platform-independent dialogs.</p>
</div>
<div class="sect1" lang="en">
<div class="titlepage">
<h2><a name="d0e25" id="d0e25"></a>Writing Dialogs
in Code</h2>
</div>
<p>Writing dialogs entirely in code using Qt isn't the chore you'd
expect if you're familiar with other toolkits such as Swing, GTK+
or MFC. Qt's layout manager classes take care of positioning
widgets on screen. Qt provides a horizontal box layout, a vertical
box layout and a grid layout. These can be nested to create
arbitrarily complex layouts.</p>
<div class="figure"><a name="d0e30" id="d0e30"></a>
<div class="mediaobject c2"><img src=
"resources/blanchette-figure1.png" align="middle" alt=
"Qt&rsquo;s layout managers"></div>
<p class="title c3">Figure 1. Qt's layout managers</p>
</div>
<p>Qt's layouts feature automatic positioning and resizing of child
widgets, sensible minimum and default sizes for top-level widgets,
and automatic repositioning when the contents, language or font
changes. For cross-platform applications, Qt's layouts are a huge
time-saver.</p>
<p>Layouts are also useful for internationalization. With fixed
sizes and positions, the translation text is often truncated; with
layouts, the child widgets are automatically resized. Furthermore,
if you translate your application to a right-to-left language such
as Arabic or Hebrew, layouts will automatically reverse themselves
to follow the direction of writing.</p>
<div class="figure"><a name="d0e40" id="d0e40"></a>
<div class="mediaobject c2"><img src=
"resources/blanchette-figure2.png" align="middle" alt=
"The &ldquo;Login to Database dialog under KTE"></div>
<p class="title c3">Figure 2. The &quot;Login to Database dialog under
KTE</p>
</div>
<p>To see how this works in practice, we will implement the &quot;Login
to Database&quot; dialog shown above. This is achieved by deriving from
<tt class="classname">QDialog</tt> (which in turn derives from
<tt class="classname">QWidget</tt>) and writing the code for a few
functions. Let's start with the header file:</p>
<pre class="programlisting">
// include guards omitted
#include &lt;qdialog.h&gt;

class QLabel;
class QLineEdit;
class QPushButton;

class LoginDialog : public QDialog {
  Q_OBJECT

public:
  LoginDialog(QWidget *parent = 0);
private slots:
  void enableLoginButton();

private:
  QLineEdit *dbNameLineEdit;
  QLineEdit *userNameLineEdit;
  QLineEdit *passwordLineEdit;
  QLineEdit *hostNameLineEdit;
  QLineEdit *portLineEdit;
  QLabel *dbNameLabel;
  QLabel *userNameLabel;
  QLabel *passwordLabel;
  QLabel *hostNameLabel;
  QLabel *portLabel;
  QPushButton *loginButton;
  QPushButton *cancelButton;
};
</pre>
<p>The <tt class="classname">LoginDialog</tt> class has a typical
Qt widget constructor that accepts a parent widget (or window), a
slot called <tt class="methodname">enableLoginButton()</tt>, and a
dozen data member that keep track of the dialog's child widgets.
The <tt class="function">Q_OBJECT</tt> macro at the top of the
class definition is necessary because we are using Qt's &quot;signals
and slots&quot; mechanism in the class.</p>
<p>Let's now review the implementation file:</p>
<pre class="programlisting">
#include &lt;qlabel.h&gt;
#include &lt;qlayout.h&gt;
#include &lt;qlineedit.h&gt;
#include &lt;qpushbutton.h&gt;
#include &quot;logindialog.h&quot;

LoginDialog::LoginDialog(QWidget *parent)
               : QDialog(parent) {
  dbNameLabel
    = new QLabel(tr(&quot;&amp;Database name:&quot;), this);
  userNameLabel
        = new QLabel(tr(&quot;&amp;User name:&quot;), this);
  passwordLabel
         = new QLabel(tr(&quot;&amp;Password:&quot;), this);
  hostNameLabel
        = new QLabel(tr(&quot;&amp;Host name:&quot;), this);
  portLabel = new QLabel(tr(&quot;P&amp;ort:&quot;), this);
  // more follows
</pre>
<p>The constructor passes on the <i class=
"parameter"><tt>parent</tt></i> parameter to the base class
constructor. If <i class="parameter"><tt>parent</tt></i> is
non-null, the dialog automatically centers itself on top of the
parent window and shares that window's taskbar entry. In addition,
if the dialog is modal (which is achieved by calling <tt class=
"methodname">setModal()</tt> or <tt class="methodname">exec()</tt>
on the dialog), the user won't be allowed to interact with the
parent window until the user closes the dialog.</p>
<p>Next, the constructor creates five QLabel widgets showing the
texts &quot;<span class="underline">D</span>atabase name:&quot;,
&quot;<span class="underline">U</span>ser name:&quot;, &quot;<span class=
"underline">P</span>assword:&quot;, &quot;<span class="underline">H</span>ost
name:&quot; and &quot;P<span class="underline">o</span>rt:&quot;. The ampersand
character ('<tt class="literal">&amp;</tt>') indicates which letter
is the shortcut key. The <tt class="function">tr()</tt> function
that surrounds the string literals marks the strings as
translatable.</p>
<p>The second argument to the QLabel constructor is the parent
widget or window, in this case the dialog (<tt class=
"varname">this</tt>). Child widgets are shown on screen inside
their parent.</p>
<pre class="programlisting">
  dbNameLineEdit = new QLineEdit(this);
  userNameLineEdit = new QLineEdit(this);
  passwordLineEdit = new QLineEdit(this);
  passwordLineEdit-&gt;setEchoMode(
                         QLineEdit::Password);
  hostNameLineEdit = new QLineEdit(this);
  portLineEdit = new QLineEdit(this);

  dbNameLabel-&gt;setBuddy(dbNameLineEdit);
  userNameLabel-&gt;setBuddy(userNameLineEdit);
  passwordLabel-&gt;setBuddy(passwordLineEdit);
  hostNameLabel-&gt;setBuddy(hostNameLineEdit);
  portLabel-&gt;setBuddy(portLineEdit);
  // more follows
</pre>
<p>We create five <tt class="classname">QLineEdit</tt> widgets and
set the &quot;Password&quot; widget's echo mode to <tt class=
"varname">QLineEdit::Password</tt>, so that characters typed by the
user are replaced by asterisks or bullets. After creating the
widgets, we call <tt class="function">setBuddy()</tt> to create
associations between the labels and the line editors. When the user
presses a label's shortcut key (for example, Alt+P for
&quot;Password:&quot;), the associated line editor gets the focus.</p>
<pre class="programlisting">
  connect(dbNameLineEdit,
         SIGNAL(textChanged(const QString &amp;)),
         this, SLOT(enableLoginButton()));
  connect(userNameLineEdit,
         SIGNAL(textChanged(const QString &amp;)),
         this, SLOT(enableLoginButton()));
  connect(passwordLineEdit,
         SIGNAL(textChanged(const QString &amp;)),
         this, SLOT(enableLoginButton()));
  connect(hostNameLineEdit,
         SIGNAL(textChanged(const QString &amp;)),
         this, SLOT(enableLoginButton()));
  connect(portLineEdit,
         SIGNAL(textChanged(const QString &amp;)),
         this, SLOT(enableLoginButton()));
  // more follows
</pre>
<p>We connect the <tt class="function">textChanged()</tt> signal of
each line editor to the dialog's <tt class=
"methodname">enableLoginButton()</tt> slot. Whenever the user types
in some text, the <tt class="function">textChanged()</tt> signal is
emitted and the <tt class="methodname">enableLoginButton()</tt>
slot is called. Based on the contents of the line editors,
<tt class="methodname">enableLoginButton()</tt> enables or disables
the dialog's &quot;Login&quot; button. Disabled widgets are typically greyed
out.</p>
<pre class="programlisting">
  loginButton = new QPushButton(tr(&quot;Login&quot;),
                                this);
  cancelButton = new QPushButton(tr(&quot;Cancel&quot;),
                                 this);
  loginButton-&gt;setDefault(true);
  loginButton-&gt;setEnabled(false);

  connect(loginButton, SIGNAL(clicked()),
          this, SLOT(accept()));
  connect(cancelButton, SIGNAL(clicked()),
          this, SLOT(reject()));
  // more follows
</pre>
<p>We create the &quot;Login&quot; and &quot;Cancel&quot; buttons, make &quot;Login&quot; the
default button (meaning that pressing Enter will effectively click
that button), and disable it. Then we connect the &quot;Login&quot; button's
<tt class="function">clicked()</tt> signal and <tt class=
"classname">QDialog</tt>'s <tt class="methodname">accept()</tt>
slot, and connect the &quot;Cancel&quot; button's <tt class=
"function">clicked()</tt> signal and <tt class=
"classname">QDialog</tt>'s <tt class="methodname">reject()</tt>
slot. Both slots close the dialog, but they set <tt class=
"classname">QDialog</tt>'s return code to a different value, which
applications can query afterwards.</p>
<p>Now that we're done with creating the child widgets, we must set
their positions and sizes relative to the parent widget. This could
be done using <tt class="methodname">QWidget::setGeometry()</tt>,
but the result would be a hard-coded, unresizable dialog.
Furthermore, determining pixel coordinates for the dialog's widgets
is a tedious task that is better performed by a machine.</p>
<p>To obtain the desired result, we need two layout managers, one
nested into the other. The dialog's main layout (the outer layout)
is a grid layout with six rows and two columns. The inner layout is
a horizontal box layout that contains the &quot;Login&quot; and &quot;Cancel&quot;
buttons. The inner layout occupies the bottom row of the grid.</p>
<p>Here comes the code:</p>
<pre class="programlisting">
  QHBoxLayout *buttonLayout = new QHBoxLayout;
  buttonLayout-&gt;addStretch(1);
  buttonLayout-&gt;addWidget(loginButton);
  buttonLayout-&gt;addWidget(cancelButton);

  QGridLayout *mainLayout
                      = new QGridLayout(this);
  mainLayout-&gt;setMargin(10);
  mainLayout-&gt;setSpacing(5);
  mainLayout-&gt;addWidget(dbNameLabel, 0, 0);
  mainLayout-&gt;addWidget(dbNameLineEdit, 0, 1);
  mainLayout-&gt;addWidget(userNameLabel, 1, 0);

  mainLayout-&gt;addWidget(userNameLineEdit, 1, 1);
  mainLayout-&gt;addWidget(passwordLabel, 2, 0);
  mainLayout-&gt;addWidget(passwordLineEdit, 2, 1);
  mainLayout-&gt;addWidget(hostNameLabel, 3, 0);
  mainLayout-&gt;addWidget(hostNameLineEdit, 3, 1);
  mainLayout-&gt;addWidget(portLabel, 4, 0);
  mainLayout-&gt;addWidget(portLineEdit, 4, 1);
  mainLayout-&gt;addMultiCellLayout(buttonLayout,
                                 5, 5, 0, 1);
  // more follows
</pre>
<p>We start by creating the <tt class="classname">QHBoxLayout</tt>
that contains the buttons. We insert a stretch item, the &quot;Login&quot;
button and the &quot;Cancel&quot; button into the layout. The layout will
place them side by side. The stretch item is there to fill the
space on the left of the buttons; without it, <tt class=
"classname">QHBoxLayout</tt> would stretch the &quot;Login&quot; and &quot;Cancel&quot;
buttons to fill the entire width of the dialog.</p>
<p>Then we create a <tt class="classname">QGridLayout</tt>. We set
the layout's margin to 10 pixels and the spacing between widgets in
the layout to 5 pixels. Then we add the widgets to the layout. The
<tt class="function">addWidget()</tt> function takes a widget, a
row and a column as parameters. At the very end, we insert the
<tt class="classname">QHBoxLayout</tt> into the <tt class=
"classname">QGridLayout</tt> using <tt class=
"methodname">addMultiCellLayout()</tt>, and specify that it should
extend from row 5 to row 5 and from column 0 to column 1; i.e.
occupy cells (5, 0) and (5, 1).</p>
<p>Here comes the rest of the constructor, where we set the window
title:</p>
<pre class="programlisting">
  setCaption(tr(&quot;Login to Database&quot;));
}
</pre>
<p>The constructor code might have felt a bit long. The good news
is that we're pretty much finished now. The only missing part is
the <tt class="methodname">enableLoginButton()</tt> slot:</p>
<pre class="programlisting">
void LoginDialog::enableLoginButton() {
  loginButton-&gt;setEnabled(
        !dbNameLineEdit-&gt;text().isEmpty()
        &amp;&amp; !userNameLineEdit-&gt;text().isEmpty()
        &amp;&amp; !passwordLineEdit-&gt;text().isEmpty()
        &amp;&amp; !hostNameLineEdit-&gt;text().isEmpty()
        &amp;&amp; !portLineEdit-&gt;text().isEmpty());
}
</pre>
<p>When the user edits the contents of one of the line editors, the
<tt class="methodname">enableLoginButton()</tt> slot is called. The
slot sets the button's state to enabled if and only if all the
<tt class="classname">QLineEdit</tt>s contain some text.</p>
<p>At this point, you might wonder why <tt class=
"classname">LoginDialog</tt> has no destructor. After all, who will
delete all the objects created with new in the constructor? The
answer is that when you create a widget or layout with a parent,
the parent assumes ownership for the child. There is therefore no
need for a <tt class="classname">LoginDialog</tt> destructor that
simply deletes the child widgets and layouts; this is exactly what
the <tt class="classname">QWidget</tt> destructor does. (Recall
that <tt class="classname">LoginDialog</tt> inherits <tt class=
"classname">QDialog</tt>, which inherits <tt class=
"classname">QWidget</tt>.)</p>
</div>
<div class="sect1" lang="en">
<div class="titlepage">
<h2><a name="d0e245" id="d0e245"></a>Designing
Dialogs Visually With Qt Designer</h2>
</div>
<p>Qt Designer is a visual GUI design tool included with Qt.
Although Qt's nice API makes it easy to write dialogs purely in
code, most Qt developers find that Qt Designer is faster to use and
allows them to make prototypes very quickly. In addition, if you
work in an organisation where the user interface design is done by
a team of designers, the designers can use Qt Designer themselves
to create the dialogs instead of producing specifications that the
developers then need to implement.</p>
<div class="figure"><a name="d0e250" id="d0e250"></a>
<div class="mediaobject c2"><img src=
"resources/blanchette-figure3.png" align="middle" alt=
"Qt Designer in action"></div>
<p class="title c3">Figure 3. Qt Designer in action</p>
</div>
<p>To show how Qt Designer works, we will use it to redo the &quot;Login
to Database&quot; dialog.</p>
<p>Creating a dialog in Qt Designer usually consists of the
following steps:</p>
<div class="itemizedlist">
<ul type="disc">
<li>
<p>Put child widgets on the form.</p>
</li>
<li>
<p>Set up their properties.</p>
</li>
<li>
<p>Group them into layouts.</p>
</li>
<li>
<p>Specify the tab order.</p>
</li>
</ul>
</div>
<p>The first step, putting the required child widgets on the form,
is accomplished by clicking the desired widget from the toolbox on
the left of Qt Designer's main window followed by clicking the
desired position on the form. For the moment, we don't need to
worry too much about the precise position and size of the child
widgets; soon enough, we will put them in layouts, which will take
care of those aspects automatically.</p>
<p>We also need a stretch item to fill the extra space in the
buttons' layout. It is represented by a blue &quot;spring&quot; in Qt
Designer. Next, we must set the child widgets' properties using the
property editor located on the right side of Qt Designer's main
window. Start by renaming all the widgets so that they have the
same names as in the previous example. Then click the background of
the form and set the form's &quot;name&quot; property to &quot;LoginDialogBase&quot;
and its &quot;caption&quot; property to &quot;Login to Database&quot;.</p>
<p>The following table summarises the properties to set for each
widget:</p>
<div class="informaltable">
<table border="1" cellspacing="0">
&lt;colgroup&gt;
&lt;col&gt;
&lt;col&gt;
&lt;col&gt;&lt;/colgroup&gt;
&lt;thead&gt;
<tr>
<th align="left">Widget</th>
<th align="left">Property</th>
<th align="left">Value</th>
</tr>
&lt;/thead&gt;
&lt;tbody&gt;
<tr>
<td align="left">dbNameLabel</td>
<td align="left">text</td>
<td align="left">&quot;&amp;Database name:&quot;</td>
</tr>
<tr>
<td align="left">userNameLabel</td>
<td align="left">text</td>
<td align="left">&quot;&amp;User name:&quot;</td>
</tr>
<tr>
<td align="left">passwordLabel</td>
<td align="left">text</td>
<td align="left">&quot;&amp;Password:&quot;</td>
</tr>
<tr>
<td align="left">hostNameLabel</td>
<td align="left">text</td>
<td align="left">&quot;&amp;Host name:&quot;</td>
</tr>
<tr>
<td align="left">portLabel</td>
<td align="left">text</td>
<td align="left">&quot;P&amp;ort:&quot;</td>
</tr>
<tr>
<td align="left">passwordLineEdit</td>
<td align="left">echoMode</td>
<td align="left">Password</td>
</tr>
<tr>
<td rowspan="3" align="left">loginButton</td>
<td align="left">text</td>
<td align="left">&quot;Login&quot;</td>
</tr>
<tr>
<td align="left">default</td>
<td align="left">Truex</td>
</tr>
<tr>
<td align="left">enabled</td>
<td align="left">Falsex</td>
</tr>
<tr>
<td align="left">cancelButton</td>
<td align="left">text</td>
<td align="left">&quot;Cancel&quot;</td>
</tr>
&lt;/tbody&gt;
</table>
</div>
<p>We need to set the labels' &quot;buddies&quot;. This is done by setting
the &quot;buddy&quot; property of each label to the corresponding widget.
Once the properties are set, the dialog should look like the one
shown in Figure 4.</p>
<div class="figure"><a name="d0e358" id="d0e358"></a>
<div class="mediaobject c2"><img src=
"resources/blanchette-figure4.png" align="middle" alt=
"The dialog with properties set"></div>
<p class="title c3">Figure 4. The dialog with properties set</p>
</div>
<p>The next step is to put the widgets inside layouts. This is done
by selecting multiple widgets and choosing &quot;Lay Out Horizontally&quot;,
&quot;Lay Out Vertically&quot; or &quot;Lay Out in a Grid&quot; from the &quot;Layout&quot;
menu.</p>
<p>First, we select the stretch item and the two buttons, and click
&quot;Lay Out Horizontally&quot;. The resulting layout is rendered as a red
frame in Qt Designer, to make it tangible. Then we click the
background of the form and click &quot;Lay Out in a Grid&quot;. This will
produce the layout shown in Figure 5.</p>
<div class="figure"><a name="d0e368" id="d0e368"></a>
<div class="mediaobject c2"><img src=
"resources/blanchette-figure5.png" align="middle" alt=
"The dialog with layout"></div>
<p class="title c3">Figure 5. The dialog with layout</p>
</div>
<p>If a layout doesn't turn out quite right, we can always click
&quot;Undo&quot;, then roughly reposition the widgets being laid out and try
again. When everything else is done, we are ready to set the
dialog's tab order. This is done by pressing F4, clicking the
widgets in the order we want them to be in the tab chain, and
pressing Esc to terminate. Qt Designer will display the tab order
as numbers in blue circles.</p>
<p>We can now save the dialog as a <tt class="filename">.ui</tt>
file that contains the dialog in an XML format that Qt Designer can
load and save. This file is converted to C++ using a separate tool
called uic (User Interface Compiler). Assuming the <tt class=
"filename">.ui</tt> file is called <tt class=
"filename">logindialogbase.ui</tt>, the resulting C++ code would
appear in the <tt class="filename">logindialogbase.h</tt> and
<tt class="filename">logindialogbase.cpp</tt> files.</p>
<p>The dialog looks identical to the one we developed earlier
purely in code, but right now if the user fills in the line editors
or presses &quot;Cancel&quot;, nothing happens! This is solved by subclassing
the <tt class="literal">uic</tt>-generated class and adding the
missing functionality there, as follows.</p>
<pre class="programlisting">
// Header file:

// include guards omitted

#include &quot;logindialogbase.h&quot;

class LoginDialog : public LoginDialogBase {
  Q_OBJECT
public:
  LoginDialog(QWidget *parent = 0);
private slots:
  void enableLoginButton();
};
</pre>
<pre class="programlisting">
// Implementation file:

#include &lt;qlabel.h&gt;
#include &lt;qlayout.h&gt;
#include &lt;qlineedit.h&gt;
#include &lt;qpushbutton.h&gt;
#include &quot;logindialog.h&quot;

LoginDialog::LoginDialog(QWidget *parent)
    : LoginDialogBase(parent) {
  connect(dbNameLineEdit,
      SIGNAL(textChanged(const QString &amp;)),
      this, SLOT(enableLoginButton()));
  connect(userNameLineEdit,
      SIGNAL(textChanged(const QString &amp;)),
      this, SLOT(enableLoginButton()));
  connect(passwordLineEdit,
      SIGNAL(textChanged(const QString &amp;)),
      this, SLOT(enableLoginButton()));
  connect(hostNameLineEdit,
      SIGNAL(textChanged(const QString &amp;)),
      this, SLOT(enableLoginButton()));
  connect(portLineEdit,
         SIGNAL(textChanged(const QString &amp;)),
         this, SLOT(enableLoginButton()));
  connect(loginButton, SIGNAL(clicked()),
         this, SLOT(accept()));
  connect(cancelButton, SIGNAL(clicked()),
         this, SLOT(reject()));
}
</pre>
<p>The <tt class="methodname">enableLoginButton()</tt> slot is not
listed here, since it's identical to the slot of the same name in
the original version of the <tt class="classname">LoginDialog</tt>
class.</p>
<p>One of the main advantages of Qt Designer is that the code
generated by <tt class="literal">uic</tt> is kept totally separate
from the application's hand-written code. This gives you the
flexibility to change your user interface without needing to
rewrite the code or fearing that your modifications to generated
code will be lost.</p>
<p>This completes our review of creating dialogs with Qt. In the
next article, we will see how to create custom widgets with any
look and behaviour we want.</p>
</div>
</p>
<p><strong>Notes:</strong>&nbsp;</p>
<p><em>More fields may be available via dynamicdata ..</em></p>
</div>
</channel>
</rss>
