Pages

Showing a table with a foreign key

Let's say we have a database table with a foreign key, like the department table I've described in this post.

Hardly what we really want is showing to the user the foreign key value. That makes little o no sense at all to him. In the current case, instead of seeing the numeric value representing the id of the location where the department insist, it would be better to see the name of the that location.

Luckly it is easy to do that with Qt: instead of using a QSqlTableModel we have to refer to the QSqlRelationalTableModel. Besides, we can do even something more interesting: giving the user the chance to see all the available choices for that field in a drop down list. Especially useful when we want to give the user to change the foreign key value.

Let's see the code for showing the department table to the user:

QSqlRelationalTableModel* departmentModel = new QSqlRelationalTableModel(this);
departmentModel->setTable("department");
departmentModel->setRelation(Department_LocationId, QSqlRelation("location", "id", "name")); // 1.
departmentModel->setSort(Department_Name, Qt::AscendingOrder);
departmentModel->setHeaderData(Department_Name, Qt::Horizontal, tr("Dept."));
departmentModel->setHeaderData(Department_LocationId, Qt::Horizontal, tr("Location"));
departmentModel->select();

ui->viewDept->setModel(departmentModel); // 2.
ui->viewDept->setItemDelegate(new QSqlRelationalDelegate(this)); // 3.
ui->viewDept->setSelectionMode(QAbstractItemView::SingleSelection);
ui->viewDept->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->viewDept->setColumnHidden(Department_Id, true);
ui->viewDept->resizeColumnsToContents();
ui->viewDept->horizontalHeader()->setStretchLastSection(true);
1. calling setRelation() we specify how to manage the foreign key. We are telling the model that instead of the location id we should go to the location table, using its id column as index and name as the actual field we want displaying.
2. viewDept is the QTableView where we are about to display the department table. Here we specify that we should use the departmentModel just created as source for the data.
3. specifying the usage of a new QSqlRelationalDelegate we are saying to the view that we want show to the user a drop down list with available choices for that field.

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

Go to the full post

The application icon

For windows this is what you have to do for having an icon associated with your application:

1. put your icon file, called something like myappico.ico, in your project source folder.

2. create a resource file, named something like myapp.rc, in the source folder.

That would be a plain text file containing just one line, something like this:

IDI_ICON1 ICON DISCARDABLE "myappico.ico"

3. in your myapp.pro, or whatever is its name, file add a line stating that it has to refer to the just created .rc file:

RC_FILE = myapp.rc

Recompile, and now your application should be associated to your new icon.

Go to the full post

Three tables for employees

As preparation for a few examples we are about to explore in the Qt database support area, I had to create three MySql tables that could be worthy to examine with a certain details.

The idea is that we are storing data for managing employees' information. We just need to keep track of the guy name, extension phone number, email, start working date, and department id.

The department id would be the foreign key that gives us access to the department table, where, besides its id, a couple of other information are stored for the department, that is its name and the location id.

This location id would be, again, a foreign key to another table, the location one, where we are about to store the id and the name od the location.

This structure will allow us to manage the employees of a firm having a few departments in different locations.

Let's see how I implemented that for MySql.

The location table is quite simple:
CREATE TABLE test.location
(
 id INTEGER PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(40) NOT NULL UNIQUE
);
The location should be specified and can't be duplicated, the id has not to be necessary provided by the user, if not specified would be MySql to take care to generate a valid value for it, by auto incrementation.

A bit more interesting the department table:
CREATE TABLE test.department 
(
  id            INTEGER PRIMARY KEY AUTO_INCREMENT,
  name          VARCHAR(40) NOT NULL UNIQUE,
  location_id   INTEGER NOT NULL,
  CONSTRAINT fk_loc_id FOREIGN KEY(location_id) REFERENCES test.location (id)
);
The point of interest here is that the location id has a constraint, a foreign key that estabilish a connection to the location id. That means that the department location_id value should match the value of an existing location id.

The other way round, the fact that location id is a foreign key for the department location_id implies that we can't change it if this would result in a broken connection between tables.

The employee table has a bit more meat, but there is not much to say more about it:
CREATE TABLE test.employee 
(
  id              INTEGER PRIMARY KEY AUTO_INCREMENT,
  name            VARCHAR(40) NOT NULL,
  department_id   INTEGER NOT NULL,
  extension       INTEGER NOT NULL,
  email           VARCHAR(40) NOT NULL UNIQUE,
  startdate       DATE NOT NULL,
  CONSTRAINT fk_dep_id FOREIGN KEY(department_id) REFERENCES test.department (id)
);
Here is department_id that is connected to the id of the department table by a foreign key relation. It is assumed that could exist more than an employee with the same name, but in any case the email should be unique.

I wrote this post while reading "C++ GUI Programming with Qt 4, Second Edition" by Jasmin Blanchette and Mark Summerfield. They create their tables for SQLite 3 that uses a SQL dialect that has a few difference with the one used by MySql 5.

Go to the full post

QSqlQuery and QSqlTableModel

Once we have established a connection to a database is quite easy to perform operations on its tables.

Qt let us do it in two ways: through QSqlQuery and QSqlTableModel.

The first way makes direct usage of SQL statements: we create a QSqlQuery object, execute a SQL query on it, and check the result.

For instance, to perform a select we could do something like that:
QSqlQuery query;
query.exec("SELECT sku, name, price FROM products WHERE price < 3");

if(query.isActive() == false) // 1.
    qDebug("Database error: %s", query.lastError().text().toStdString().c_str());

while(query.next()) // 2.
{
    QString sku = query.value(0).toString();
    QString name = query.value(1).toString();
    double price = query.value(2).toDouble();

    qDebug("%s %s: %f", sku.toStdString().c_str(), name.toStdString().c_str(), price);
}
1. the flag active is set to false in case of error
2. the result of performing a select is populating the query resultset. Its next() method allows us to navigate in it.

To perform an insert we write code like this:
QSqlQuery query;
query.exec("INSERT INTO products (id, sku, name, price) "
            "VALUES (42, 'X42', 'Something wierd', 2.02)");
if(query.numRowsAffected() == -1)
{
    qDebug("Database error: %s", query.lastError().text().toStdString().c_str());
}
If the number of affected rows is -1 that means an error occurred.

It is possible to prepare a query and then binding the values on the prepared statement, using both the Oracle and the ODBC syntax.

Using QSqlTableModel we can avoid the direct usage of raw SQL statements, letting Qt to generate the actual SQL code accordingly to the database we are using.

For instance, to execute the same select as above we can write something like this:
QSqlTableModel model;
model.setTable("products");
model.setFilter("price < 3");
model.select();

for(int i = 0; i < model.rowCount(); ++i)
{
    QSqlRecord record = model.record(i);

    int id = record.value(0).toInt();
    QString sku = record.value(1).toString();
    QString name = record.value(2).toString();
    double price = record.value(3).toDouble();

    qDebug("%d %s %s: %f", id, sku.toStdString().c_str(), name.toStdString().c_str(), price);
}

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

Go to the full post

Qt and MySql

I have to use Qt and MySql. This is not exactely a piece of cake, expecially the first time you do that, because there is a number of prerequisite to be filled out before actually start programming.

You should have Qt and MySql installed and working on your machine - but, well, this is quite a natural requirement.

Then you have to build the plugin for MySql. This has to be done for any database you want to use with Qt but SQLite, that is provided by default with Qt.

Building a database plugin is not difficult, but imply a different procedure for each database and platform. Luckly it is well described in the official documentation.

I found that compiling and using a database plugin is a sensitive process, probabily the fact is that we have to work with specific concepts for an operating system, a compiler, a database, all of these viewed from the point of view of the Qt framework. An inerently complex environment, I reckon. So, I was not surprised my plugin did not working at first try. The Qt framework is not very helpful in let you know which is the actual problem, and why it does not like our beautiful plugin, but after a while you should usually get the point and make it working properly.

A few suggestions if you are stuck somewhere in the process: check if the database is properly installed and the required files are available to your compiler. Check if the plugin was correctly created (in the Qt plugins/sqldrivers folder). Check if the dependecies for the generated DLL are available. For Windows-Visual C++ you could use the utility depends.exe (Dependency Walker) to find that out. If you have a problem of this kind, usually is LibMySql.ddl that is not in a PATH visible from your environment.
Another DLL that is often reported missing, IESHIMS.DLL, actually is not a mandatory one, so you don't usually have to pay attention to it.

Done that, you are ready for writing code for accessing your database from Qt.

Fist thing: you have to tell to your project you are actually using the Qt database facility. This is done in the project (.pro) file, adding the word "sql" to the QT property, that should look something like that:

QT += core gui sql

If our mysql database is not up and running, well, it is better to start it up. If you are on Windows and you want do that by shell command remember you need to have the administrator rights to do that. So open your cmd shell window as administrator before giving the "net start mysql" command.

At this point, opening a connection to the database is not anymore a big issue.

Accordingly to Jasmin and Mark, this is typically done in the application main function. I wouldn't stress much this point, and I just would say that is good enough for us to do that there.

It's only a toy connection, so we don't pay much attention to security, reusability and other issues like those, and so we just write this simple function:

bool createConnection()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("localhost");
db.setDatabaseName("test");
db.setUserName("root");
db.setPassword("password");
if(db.open() == false)
{
QMessageBox::critical(0, QObject::tr("Database Error"), db.lastError().databaseText());
return false;
}
return true;
}

It is worth noting that we specify the database brand calling the QSqlDatabase::addDatabase() static function, and then, after setting the usual parameters required for estabilishing a connection, we try to open it.

This function is used in this way:

#include <QtGui/QApplication>
#include <QtGui/QMessageBox>
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlError>

#include "MainWindow.h"

namespace
{
bool createConnection()
{
// ...
}
}

int main(int argc, char *argv[])
{
QApplication app(argc, argv);

if(createConnection() == false)
return 1;

MainWindow mw;
mw.show();

return app.exec();
}

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

Go to the full post

Item views

The chapter 10 of C++ GUI Programming with Qt 4, Second Edition is dedicated to the classes used for displaying data in Qt.

Basically, there are two families of classes that couls be used for this task, the *Widget (QListWidget, QTableWidget, QTreeWidget) ones are simpler, and require to be feeded with the items we want to show to the user. The data are owned directly by the class.

The *View classes (QListView, QTableView, QTreeView) use a more modern approach. It's a sort of Model-View-Controller (MVC) schema slightly modified to make lighter the Controller module - here called "Delegate". The Model takes care of the data management, the View is responsible for making the data available to the user, the Delegate make possible a custom control on the View using the Model. Usually, if our client require a "normal" behavior, we don't need to mess about with the delegate, since a default one would suffice.

I suggest you reading "C++ GUI Programming with Qt 4, Second Edition" by Jasmin Blanchette and Mark Summerfield for more details on the matter.

Go to the full post

Ticker: timer event

In the chapter seven of C++ GUI Programming with Qt 4, Second Edition is described a custom widget, named Ticker, used for showing how to use timer events.

I have used it as central widget in my simple test application, where originally I put a QLabel and, well, it works fine.

Its idea is that it contains a text, and the id of a timer. The timer is started and stopped when the ticker is showed and hidden. Any time a Timer event, for the current ticker timer, reach the ticker itself the text is scrolled on the left.

To use the ticker as central widget in my application I used this piece of code:
Ticker* pTicker = new Ticker(this);
pTicker->setText(hello);
QMainWindow::setCentralWidget(pTicker);
And this is the Ticker class definition:
#ifndef TICKER_H
#define TICKER_H

#include <QWidget>

class Ticker : public QWidget
{
Q_OBJECT
public:
  explicit Ticker(QWidget* parent = 0);

  void setText(const QString& text);
  QString text() const { return text_; }

protected:
  void paintEvent(QPaintEvent*);
  void timerEvent(QTimerEvent* event);
  void showEvent(QShowEvent*);
  void hideEvent(QHideEvent*);

private:
  QString text_;
  int offset_;
  int timerId_;
};

#endif // TICKER_H

Notice that we have reimplemented four event handlers: show and hide will be used to start and stop the timer; timer for doing the actual job any ticked time; paint to redesign the widget any time is required.

Here is the implementation code for the class:
#include <QtGui>
#include "Ticker.h"

Ticker::Ticker(QWidget *parent) : QWidget(parent),
offset_(0), timerId_(0) // 1
{}

void Ticker::setText(const QString& text) // 2
{
  text_ = text;
  update();
  updateGeometry();
}

void Ticker::paintEvent(QPaintEvent*) // 3
{
  QPainter painter(this);

  int textWidth = fontMetrics().width(text_);
  if (textWidth < 1)
    return;
  int x = -offset_;
  while (x < width())
  {
    painter.drawText(x, 0, textWidth, height(), Qt::AlignLeft | Qt::AlignVCenter, text_);
    x += textWidth;
  }
}

void Ticker::showEvent(QShowEvent *) // 4
{
  timerId_ = startTimer(30);
}

void Ticker::timerEvent(QTimerEvent *event) // 5
{
  if(event->timerId() == timerId_)
  {
    ++offset_;
    if(offset_ >= fontMetrics().width(text_))
      offset_ = 0;
    update();
  }
  else
    QWidget::timerEvent(event);
}

void Ticker::hideEvent(QHideEvent*) // 6
{
  killTimer(timerId_);
  timerId_ = 0;
}

1. the offset is going to change to draw the text any time in a different position, giving the impression of a scrolling text; the timer id is set initially to zero because this means "no timer", that is exactely what we want.
2. when the user sets a text in the ticker we call update(), that is going to generate a repaint event, and updateGeometry(), to ensure the text is displayed as correctly as possible.
3. the handler for Paint event uses a QPainter object to put in the widget as many copy of the Ticker's text as required to fill its width. Notice that anytime it starts too much on the left (-offset_) giving the idea that the text is scrolling.
4. when the Ticker widget becomes visible, the timer is started, with a period of 30 milliseconds.
5. since there could be many active timer, before doing anything in the timeEvent() we should ensure that the timer id for the current event is the same of the stored timer for the Ticker. If this is the case, we increase the current offset - but when it reaches the size of the text, we reset it to zero - and then call update() to notify that we require the widget to be repainted. This will generate a Paint event, and so the scrolling of the text using the new offset.
6. when the Ticker is not visible we kill the timer. Notice that the timer functionality are part of the QObject interface.

I suggest you reading "C++ GUI Programming with Qt 4, Second Edition" by Jasmin Blanchette and Mark Summerfield for more details on the matter.

Go to the full post

An improved HexSpinBox

We get a change request for our hexadecimal spin box. The user would like to use the keyboard to change its value, and actually he wants to use the plus and minus key to increase/decrease the value by one unit and the tab and shift-tab (AKA backtab) to increase/decrease by 16 (0x10) units.

The first requirement is a normal one, and would be resolved implementing in our class a redefinition for the keyPressEvent() virtual function, as showed below.

The second requirement is a bit wierd. Usually we want tab and backtab be reserved for shifting among the various write-accessible widget in our window, so it is not often a good idea to change its default meaning. But in this case our user is quite sure he wants this behaviour, and it is not a big issue to make him happy: we just have to reimplement the event() virtual function in our class in this way:

bool HexSpinBox::event(QEvent *event)
{
if(event->type() == QEvent::KeyPress) // 1.
{
QKeyEvent* keyEvent = dynamic_cast<QKeyEvent *>(event); // 2.
if(keyEvent)
{
switch(keyEvent->key()) // 3.
{
case Qt::Key_Tab:
setValue(value() + 0x10);
return true;
case Qt::Key_Backtab:
setValue(value() - 0x10);
return true;
}
}
}
return QSpinBox::event(event); // 4.
}

1. the event() function is called for each event is fired when the widget is in focus. Currently we are interested in changing its behaviour for a specific KeyPress event, so we check that the current managed event is such an event.
2. QKeyEvent is the event used to describe the KeyEvents. So it is actually a bit paranoid to dynamic_cast the event to this type, since there should be no way a KeyPress is associated to something different to a QKeyEvent. But the universe is big and an extra-check here is not that expensive, so I went for it.
3. we check the key the user has pressed, and increase the current value for our spin box accordingly to the requirements.
4. finally we pass the control to the superclass implementation for this function.

For the "normal" keys (not the tab-associated ones, I mean) the job is even easier. No need of downcasting, since the keyPressEvent() function already knows the right type of associated events:

void HexSpinBox::keyPressEvent(QKeyEvent *event)
{
switch(event->key())
{
case Qt::Key_Plus:
setValue(value() + 1);
break;
case Qt::Key_Minus:
setValue(value() - 1);
break;
default:
QSpinBox::keyPressEvent(event);
}
}

So it is just a matter of checking the key actually pressed, changing the current value accordingly, and finally calling the superclass implementation for the function.

I suggest you reading "C++ GUI Programming with Qt 4, Second Edition" by Jasmin Blanchette and Mark Summerfield for more details on the matter.

Go to the full post

Stacked layouts

A common way for putting a lot of information in a single dialog is using the concept of stacked layouts.

The idea is that we have a number of panels one over the other, each of one carrying some relevant information. Obviously, if don't want the user getting confused and probably angry with us, such information splitting should be done with a clear logic, and should be easy to access to any sub-panel.

To do that is a common pattern using together QListWidget and QStackedWidget.
The list provides a way for selecting a sub-panel, and the stacked widget organizes the stack itself.

It is very easy to manage gtaphically this couple of widgets through Qt Designer. Basically, the point is making a connection between the two widgets using as signal QListWidget::currentRowChanged(int) and as slot QStackedWidget::setCurrentIndex(int). Moreover we just have to set the currentRow for the list to 1, so that we initialize the mapping, and that is it.

Well, actually, we still have to put meaningfull information in the list and the panels, but the structure is there.

If the data you should show to the user is not such a big deal, and you are thinking just of a few tabs, a good alternative is QTabWidget, where we have access to a configurable list of stacked panels accessed by tabs.

I suggest you reading "C++ GUI Programming with Qt 4, Second Edition" by Jasmin Blanchette and Mark Summerfield for more details.

Go to the full post

An hexadecimal spin box

The fifth chapter of "C++ GUI Programming with Qt 4, Second Edition" is dedicated to custom widget. The first part is an interesting example that shows how to extends a specific widget by subclassing it.

The specific case treated is this: we know the widget QSpinBox and we like it, but we would like to use it to choose an hexadecimal value, and this kind of customization could not be get by setting of properties of the standard widget.

A solution to this problem is subclassing QSpinBox modifying the original behavior as requested.

Subclassing a widget has just one difference from the normal C++ inheritance mechanism, that is the use of the Q_OBJECT macro, a requirement for every QObject subclass:

// ...
#include
// ...

class HexSpinBox : public QSpinBox
{
Q_OBJECT
public:
HexSpinBox(QWidget *parent = 0);

// ...
};

Here we need to add a private custom data member, a validator that we are going to use to ensure our spin box would accept only hexadecimal values:

// ...
class QRegExpValidator;
// ...

class HexSpinBox : public QSpinBox
{
// ...
private:
QRegExpValidator *validator;

};

In the constructor we reset the default range for the spin box, and instantiate the validator:

HexSpinBox::HexSpinBox(QWidget *parent) : QSpinBox(parent)
{
setRange(0, 255);
validator = new QRegExpValidator(QRegExp("[0-9A-Fa-f]{1,8}"), this);
}

The validator would ensure that the user could insert only hexadecimal values. Notice that the number of digit allowed, 1 to 8, does not make perfect sense, when the range is set in the interval [0, 255]. It would made more sense to set it to 1 to 2 and change it accordingly when the range changes.

For instance, that would be the code that should be execute to rearrange the validator when the maximum value changes:

int digits = 1;
while(max /= 16)
++digits;
QString s = QString("[0-9A-Fa-f]{1,%1}").arg(digits);
QRegExp re(s);

validator->setRegExp(re);

To make our class working properly we need to redefine a few protected function:

protected:
QValidator::State validate(QString &text, int &pos) const;
int valueFromText(const QString &text) const;
QString textFromValue(int value) const;

The first one is used by the spin box to check if the character the user is trying to insert is admissible. We check it using our validator:

QValidator::State HexSpinBox::validate(QString &text, int &pos) const
{
return validator->validate(text, pos);
}

The second one is used internally to let the arrows in the spin box to work correctly, converting the increased (or decreased) integer value in its correct representation:

QString HexSpinBox::textFromValue(int value) const
{
return QString::number(value, 16).toUpper();
}

The third one is used by the spin box to convert the string input by the used in the number that is going to be stored internally as the current value:

int HexSpinBox::valueFromText(const QString &text) const
{
return text.toInt(0, 16);
}

Notice that QString::toInt() requires as first parameter a pointer to a bool where the function stores true if the call succeeded. Since we have no use in this check - there is no way to signal to the valueFromText() caller the possible function failure but throwing an exception, that would be something unexpected and, well, a bit to strong as a reaction - we can simply pass a NULL pointer instead.

I suggest you reading "C++ GUI Programming with Qt 4, Second Edition" by Jasmin Blanchette and Mark Summerfield for more details.

Go to the full post

The status bar

The status bar is the space at the bottom of the main window that is used to provide some additional information to the user.

It quite easy to use it in Qt, it is available in any QMainWindow, and it is showed automatically since the first time we gain access to it, calling the member function statusBar().

We have seen in a previous post how to let an action to put a message on the status bar, this is the so called "status tip" access to the status bar, and here is how we tell to an action what we what to be showed to the user when it is ready to be called:

QAction* actNew = new QAction(tr("&New"), this);
// ...
actNew->setStatusTip(tr("Set new message text"));
// ...


The normal access to the status bar is slightly complex. First thing we have to specify where we want to put the message. This means that usually we create a label and say to the status bar that that label has to be showed in its area.

Here we want just a simple status bar message, so we change the definition of our main window class definition adding a label and a couple of private functions to create and update the status bar, in this way:

#include
#include

class QCloseEvent;
class QAction;

class WinMain : public QMainWindow
{
Q_OBJECT
public:
explicit WinMain(QWidget* parent = 0);

private:
// ...
void createStatusBar();
void updateStatusBar(QString message);

QLabel lblMessage; // status bar message

// ...
};

What we want to show normally in the status bar, is just the same message we show to the user in the central widget, so I just slightly changed the function called by the main window constructor to initialize and update the status bar - in the meantime I have also changed the name of the function itself, giving it a more meaningful name:

void WinMain::setCentralWidget()
{
QString hello("Hello Qt!");
QLabel* pLb = new QLabel(this);
pLb->setText(hello);

QFont f("Times", 15, 0, true);
pLb->setFont(f);
pLb->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);

QMainWindow::setCentralWidget(pLb); // 1.

createStatusBar();
updateStatusBar(hello);
}

1. since I gave name "setCentralWidget()" to this function, to call the QMainWindow setCentralWindow() I now have to specify the fully qualified named.

The createStatusBar() function has actually a misleading name, since it does not properly create the status bar, just add the label to the status bar itself:

void WinMain::createStatusBar()
{
statusBar()->addWidget(&lblMessage, 1);
}

The "1" passed as second parameter to the addWidget() has the meaning of reserving all the room on the status bar to this widget, and not just the minimal required space.

Updating the status bar is just a matter of updating the label whose address we passed to it:

void WinMain::updateStatusBar(QString message)
{
lblMessage.setText(message);
}

There is a third way of putting a message on the status bar: showing a temporary message.

Let's say that we want to show a temporary message when the dialog used to change the text in the central widget is active. We have a couple of choices: does we want to show the message for a short period, let say a second, or do we want to keep the message on for all the time the dialog is there?
We can do both way using the same function, just passing or not an optional parameter that specify the time, in millisecs, we want to keep the message visible. But remember, if you don't specify the time, you should remember to explicitly turn off the message.

I rewrote the newMessage function adding this functionality:

void WinMain::newMessage()
{
// statusBar()->showMessage("Gimme a new message");
statusBar()->showMessage("Gimme a new message", 1000);

DlgMessage dlgMessage(this);
// ...

// statusBar()->clearMessage();
}

I should use the couple of function showMessage() - clearMessage(), or just the showMessage() with the time specified as second parameter.

Go to the full post

A modal dialog

We want to improve our application, giving the user a way to insert a text in the main window background, and even chosing if the text should be showed in a normal font or in italic.

A dialog is nothing more than a window used for letting the user a chance to input some values required by the application, and a modal dialog is just a dialog that takes the control of the application. That is, when we open a modal dialog we have no chance of going on doing some other stuff in our application. We have to close it (confirming or canceling our input) before continuing.

We have already seen how to design a dialog with Qt Designer, so I'm not about to say much on the matter. Just assume we have a dialog, DlgMessage, that shows us a line edit, to input the message, a check box, to specify if we want the text displayed in italic or not, and the standard OK/Cancel buttons.

The only slightly interesting stuff on our new DlgMessage class is that it would have a couple of methods that the user code would use to retrive the useful values.

Here is how looks the class definition:

class DlgMessage : public QDialog
{
Q_OBJECT
public:
explicit DlgMessage(QWidget *parent = 0);
~DlgMessage();

QString getMessage();
bool getItalic();
protected:
void changeEvent(QEvent *e);

private:
Ui::DlgMessage *ui;
};

All the code above is generated by Qt Creator (good guy) but the two methods getMessage()and getItalic(), that we implement in this way:

QString DlgMessage::getMessage()
{
return ui->lineEdit->text();
}

bool DlgMessage::getItalic()
{
return ui->checkBox->isChecked();
}

Even though I didn't said much about the DlgMessage implementation details, I'd say this piece of code is quite straightforward.

Given that, the changes we have to introduce in WinMain are minimal and well localized:

void WinMain::newMessage()
{
DlgMessage dlgMessage(this); // 1.

if(dlgMessage.exec()) // 2.
{
QLabel* pLb = dynamic_cast<QLabel*>(centralWidget());
if(pLb == 0)
QMessageBox::information(this, this->windowTitle(), "No label available", QMessageBox::Ok);
else // 3.
{
QFont f(pLb->font());
f.setItalic(dlgMessage.getItalic());
pLb->setFont(f); // 4.

pLb->setText(dlgMessage.getMessage()); // 5.
}
}
}

The newMessage() slot contains all the required changes.
1. We create an instance of our dialog. Since this dialog has a very short life - at the end of this function there is no interest in keeping it alive - we put it on the stack.
2. Calling exec() we are specifying that we want to executing it in modal way. We'll see in another post how to make available to the user a non-modal dialog.
3. After we have ensured that the central widget is what we actually expect, we are about to do the real job.
4. We create a local copy of the font used by the label, set its italic attribute accordingly to the user requirement - notice the call to the DlgMessage::getItalic() function - and say to the label to use this font instead of the old one.
5. We retrieve the message as specified by the user in the DlgMessage, using its getMessage() function, and say the label to use it as its text.

Go to the full post

Action!

Working with the menu bar, context menus and tool bars with Qt require a bit of planning and coding. Sure it is more fun and fast doing that graphically by Qt Designer, but doing it in the hard way, writing any required piece of code, it is useful to understand how it actually works.

So, let's say I want to put on my main window a File menu on the menu bar with just two commands: one to display a different message on the central widget (that is just a label), and one to terminate the application.

Then I want a context menu acting when I right click on the central widget, proposing a very simple popup menu containig just one item, the command to put a different message in the label.

And finally I want to create a tool bar where I'm going to put again the new message command.

All this stuff is not complicated, it just need to be done step by step.

First step: slots. Remember that a slot, in the Qt jargon, is a function that could be connected to a signal, to be executed consequentely. In this case we want just two of them: one for putting a new text on the label in the central widget and one for closing the application. For the latter there is nothing to do, there is already a QMainWindow::close() slot, we just have to use it. But still we have to create a slot for the first one. Let's call it newMessage() and declare it as a private slot in our class definition:

// ...

class WinMain : public QMainWindow
{
Q_OBJECT
public:
explicit WinMain(QWidget* parent = 0);

// ...

private slots:
void newMessage();
};

Then we implement it like this:

void WinMain::newMessage()
{
QLabel* pLb = dynamic_cast<QLabel*>(centralWidget());
if(pLb == 0)
QMessageBox::information(this, this->windowTitle(), "No label available", QMessageBox::Ok);
else
pLb->setText("Hello again Qt!");
}

I am quite sure that our central widget is actually a label, but better be a little paranoid, when it doesn't hurt, and besides, in the future someone could change the code for some unforseen reason, and could actually happen this function would be called when no central window is set, or when it refers to something else than a QLabel. So I perform a dynamic cast on the central widget object and I check if it succeed. In case of failure I display a pretty useless information message to the user, so he could aptly complain about that with the programmer. If everything works as expected we'll change the message in the label. It would be more useful to ask the user what message he actually wants to display, but that would be too much work for this post, we'll do that in the next one.

We can pass now to the second step: actions.

The class QAction is acting as a controller in our context. It mediates between the graphic representation (a menu item) and the actual slot we want to execute. Besides, it contains all the information that the view requires to display itself properly.

But I think it is easier to actually see the code for our two actions than talking more on it:

QAction* actNew = new QAction(tr("&New"), this);
actNew->setIcon(QIcon(":/images/new.png"));
actNew->setShortcut(QKeySequence::New);
actNew->setStatusTip(tr("Set new message text"));
connect(actNew, SIGNAL(triggered()), this, SLOT(newMessage()));

QAction* actExit = new QAction(tr("E&xit"), this);
connect(actExit, SIGNAL(triggered()), this, SLOT(close()));

The first action is a bit complex. It has an associated icon, a shortcut and even a status tip for being showed in the status bar, when available. But we don't really need always all this stuff and, as we see for the second action, we could just give the action a name - using, if we want, an ampersand to specify the key for speed selection - and then connect the triggered() signal of the action itself with the slot we want to execute.

The third step requires we create widgets that actually use our actions.

Here is what we do for the menu bar:

QMenu* pFMenu = menuBar()->addMenu(tr("&File"));
pFMenu->addAction(actNew);
pFMenu->addSeparator();
pFMenu->addAction(actExit);

The function QMainWindow::menuBar() makes available the window menu bar. We call on it the addMenu() function, specifying the name of the menu we want to create, and a new menu is born.
Then we add the actions we want to display in the menu and, as we see, we can even add a separator.

There are different ways to create a context menu, but probably the easiest one requires to set the context menu policy of the widget to ActionsContextMenu and simply add the actions we want to display to the widget itself.

Here is what to do to add the context menu to the central widget:

if(centralWidget())
{
centralWidget()->addAction(actNew);
centralWidget()->setContextMenuPolicy(Qt::ActionsContextMenu);
}

Again a (paranoid) check on the central widget. In any case, checking it is very cheap, and that could save us from an embarassing core dump.

Finally, let's have a look at the tool bar:

QToolBar* pTB = addToolBar(tr("&File"));
pTB->addAction(actNew);

A window could have many tool bars. To add a new one we just call the QMainWindow::addToolBar() function, and then add the action we want to the returned QToolBar.

Go to the full post

The central widget

The central area of a QMainWindow is taken by a widget that, not surprisingly, is called central widget.

Let's say the widget we want to show to the user in our main window is just a label saying hello.

What we have to do is creating a label on the heap, passing to the constructor a pointer to the main window, delegating in this way to Qt the nuisance of removing it from the memory when required, set it how we like and then passing its pointer to the QMainWindow::setCentralWidget() method.

That is, something like that:
void WinMain::sayHello()
{
  QLabel* pLb = new QLabel(this);
  pLb->setText("Hello Qt!");
  pLb->setFont(QFont("Times", 15, 0, true));
  pLb->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);

  setCentralWidget(pLb);
}
It is worthy noticing the call to QLabel::setAlignment() where we pass the alignment mode we want to use for our label. Since we want to apply more than one value, actually we want the text in the label to be centered both horizontally and vertically, we OR the required modes.

Go to the full post

Qt Settings

It is a common request for an application to need a way of keep persistent a bunch of configuration values between to different executions.

For instance, we could want to store the application's main window position and size, so that we could reopen that window keeping the same aspect.

Qt offers a class for this task: QSetting.

Its behaviour depends on the operating system on which the application runs, for the Windows systems the values are stored in the registry.

For instance this function writes the position and the size of the current widget (in our case the main window) in the registry under the key "Computer\HKEY_CURRENT_USER\Software\Trolltech\Hello Qt":

void WinMain::writeSettings()
{
QSettings settings("Trolltech", "Hello Qt");
settings.setValue("pos", pos());
settings.setValue("size", size());
}

The QSettings setValue() method accepts in input a QString, the key where to store the value, and a QVariant, the value we want actually store.

QVariant is a sort of union type that allow us to manage unrelated types without using void pointer. So we can use setValue() for both the position (a QPoint object) and the size (a QSize instance) still having a good level of type safety.

We should call writeSettings when we are closing the main window, typically in the closeEvent() function, doing something like this:

void WinMain::closeEvent(QCloseEvent* event)
{
if(confirmed())
{
writeSettings();
event->accept();
}
else
event->ignore();
}

Simmetrically, we usually call in the main window constructor a function that would read and use the previously stored values, if any:

WinMain::WinMain(QWidget *parent) : QMainWindow(parent)
{
// ...
readSettings();
// ...
}

That function should be something like this:

void WinMain::readSettings()
{
QSettings settings("Trolltech", "Hello Qt");

QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
resize(size);

QSize size = settings.value("size", QSize(200, 200)).toSize();
move(pos);
}

The value() method gets the value specified by the first parameter. If such key is not available the second parameter is returned, in this way we can define a default value.

Instead of using the toPoint(), toSize(), and all the other similar functions to extract the actual object from the variant, it is possible to use a template version of the value function, in this way:

QPoint pos = settings.value("pos", QPoint(200, 200)).value<QPoint>();

Go to the full post

Qt Resources

Almost any application has a few associated resources, term that in this context is used to identify external files containing non mutable information used by the application.

A typical example of a resource is an icon that is associated to the main window to be displayed on the title bar. So here we'll see how to use a previously created image for this task.

First thing, we put our image in a subfolder of our development directory. Let's say now we have it in ".\images\app.png".

In Qt Creator we create form the menu File a new file, let's say we call it "MyApp.qrc", specifying we want it to be a Qt Resource file, and we want it added to the project.

We open our newly created resource file and we add the app.png file to the contained list of files. We could use a prefix to partition the list in groups, but for the moment this is not a concern for us.

Before we can access the resources listed in the resouce file, we should say in the code that we want to use it. We do that through a macro that we call just at the beginnig of the main function:

int main(int argc, char** argv)
{
Q_INIT_RESOURCE(MyApp);
// ...

Given that, now we can write in the constructor of our main window something like that:

WinMain::WinMain(QWidget *parent) : QMainWindow(parent)
{
setWindowIcon(QIcon(":/images/app.png"));
// ...

We call the QWidget method setWindowIcon() to define the associated icon. It accepts in input a reference to a QIcon, that could be created by passing a file name. If the file name starts with a colon-slash (:/) the QIcon understands we are not passing a real file name, but a resource name.

Go to the full post