From Qt Designer to Qt Creator

In the previous post we designed a custom dialog using Qt Designer, now we complete it using Qt Creator.

We had saved our dialog as DlgGoToCell.ui in the source folder of the project that we have previously created with Qt Creator, now we add it (as an existing file) to the project. Creator will put it in a specific "Forms" folder. Now it could be modified directly from Creator visually - through an embedded version of the Designer.

We immediately use this chance, since I forgot to do something: the OK button should be by default disabled. So, now we edit - visually - DlgGoToCell.ui to do this: after selecting the OK button, find among the property "enabled" and remove the tick from its check box. We see that now the OK button is showed grayed.

It is important to notice that, from the C++ point of view, what we have created with Qt Designer is not related in any way to QDialog, even after the conversion operated by qmake we have a class, Ui::DlgGoToCell, that is not part of the Qt class hierarchy.

What we are going to do, is to use what we have done to set the user interface of a standard QDialog. Something like that:

#include <QApplication>
#include <QDialog>

#include "ui_DlgGoToCell.h" // 1.

int b202(int argc, char** argv)
{
QApplication app(argc, argv);

Ui::DlgGoToCell ui; // 2.
QDialog* dialog = new QDialog();
ui.setupUi(dialog); // 3.
dialog->show();

return app.exec();
}

1. this is the file generated by qmake from DlgGoToCell.ui, basically a conversion from XML to C++ of what we had written.
2. that is the class containing the information of our dialog design.
3. in this way we create a connection between the UI and the QDialog.

That should work fine, but we want to add more meat to our dialog. To do that we use multiple inheritance to create a class that derives from both QDialog and Ui::DlgGoToCell, and add to it our required functionality:
  • the user can OK only after entering a valid cell address
  • we want to accept as valid cell address a letter (lower or uppercase) and a number in the range [1..999].
  • clicking on the buttons should work as expected (close the window and pass the status to the caller)

Here is the code for the include file:

#ifndef DLGGOTOCELL_H
#define DLGGOTOCELL_H

#include <QDialog>
#include "ui_DlgGoToCell.h"

class DlgGoToCell : public QDialog, public Ui::DlgGoToCell
{
Q_OBJECT
public:
explicit DlgGoToCell(QWidget* parent = 0);

private slots:
void on_where_textChanged(); // 1.
};

#endif // DLGGOTOCELL_H

// 1. why we create a function with such a name? Because we want to use a Qt functionality that generates signal-slot connection implicitly, if we use the correct names. In this case we are asking that this slot would be connected to the signal textChanged() for the member named "where".

And here is the implementation:

#include
#include "DlgGoToCell.h"

DlgGoToCell::DlgGoToCell(QWidget *parent) : QDialog(parent)
{
setupUi(this); // 1.

QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}"); // 2.
where->setValidator(new QRegExpValidator(regExp, this));

connect(btnOK, SIGNAL(clicked()), this, SLOT(accept())); // 3.
connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
}

void DlgGoToCell::on_where_textChanged() // 4.
{
btnOK->setEnabled(where->hasAcceptableInput());
}

1. this call initialize the form and create the connection required for our on_where_textChanged()
2. that is the regular expression that satisfy our requirement on the input validation. We use it to create a QRegExpValidator that we'll pass to our line edit through the setValidator() method. Passing this to the QRegExpValidator constructor we ensure that the object will be removed when the dialog will be destroyed.
3. the connections between the clicked() signals of the buttons and the QDialog slot accept() and reject() make our buttons act as expected, closing the dialog and returning to the caller the expected status.
4. that's the slot that would be called for the signal textChanged() our line edit. It sets the button OK as enabled only if where has a valid string in it.

Now we have to rewrite the main, to use our new class:

#include <QApplication>
#include "DlgGoToCell.h"

int b202b(int argc, char** argv)
{
QApplication app(argc, argv);

DlgGoToCell* dialog = new DlgGoToCell();
dialog->show();

return app.exec();
}


I wrote this post as homework while reading "C++ GUI Programming with Qt 4, Second Edition" by Jasmin Blanchette and Mark Summerfield.

No comments:

Post a Comment