Qt

I recently started programming with Qt because I wanted to use the same source code for other platforms like Windows and Mac. Qt is based on C++. In Qt, methods can be slots which can be called automatically when a signal arrives to the class where the slot is declared in. There is a function called connect() which you can use to connect signals with slots.

Install

To install the SDK and demos on Ubuntu:

aptitude install qdevelop qtcreator qt4-demos

You can find the demos and examples in /usr/lib/qt4. There are 2 programming environments: qdevelop (older, with more features) and qtcreator (newer, with less features). The company recommends qtcreator. Double clicking on a .ui file within qdevelop or qtcreator, opens qt-designer which is a GUI designer. You can drag widgets onto the form, and in the context menu you can "go to slot", which creates a slot in your source code and brings up the editor with the cursor in the slot's body, so you can implement it right away. The .ui file is automatically converted to a C++ class in the source code, and the class you are editing is a subclass from it, so you won't lose any changes when code is regenerated using the .ui file. Buiding and running is done with the "play" buttons in the lower left corner.

Windows specific

For Windows, go to the site and choose Downloads. Download Qt SDK for Windows. The install path is not allowed to have any spaces, so you cannot install Qt under "Program Files". Also, the installer says it needs 1Gb, but it actually needs twice as much while installing. Under Windows, stdin and stdout are not working, so don't bother using cin and cout. For debugging, #include <QDebug> and use qDebug() instead of cout. Additionally you can use qDebug the same way as printf(). To run the executable without the developing environment, you need to copy minwm10.dll, QtCore4.dll, QtGui4.dll and possibly other DLL files from C:\\qt\2009.003\qt\bin to the folder where your executable is located. Any output of qDebug() gets lost, because this only works within the developing environment.

Programming tips:

  • For handling strings the QString class is used. Many functions in the examples directory return QString objects (not pointers to QString objects) which implies copying and seems to be a good alternative for allocating memory in the function and freeing it somewhere else. To get the raw char* ascii string, use .toAscii().constData().
  • In C++ the const keyword is used commonly. The const keyword always applies to the word immediately to the left of the const keyword, except when there is nothing there; then it applies to the word immediately to the right of the const keyword. When the const keyword is applied at the end of a method prototype, then it means the method will not alter any variables of its own class.
  • Use QMessageBox() to display a simple messagebox with Ok-button.
    QMessageBox msgBox;
    msgBox.setText("Some message.");
    msgBox.exec();
    
    Cancel and other buttons are possible. See documentation.
  • to open additional windows use QDialog. These can be created and designed in qtcreator: just add a new file and choose for a new form class. Use QDialog::exec() to display modal dialogs or QDialog::show() to display modeless windows. When the dialog exits using done(value), then this value is passed as return value of exec().
  • for intercepting window close events (in order to close other windows, or to prevent closing and display a warning dialog), override the protected closeEvent() function. See the docs of QWidget.
  • To invoke a slot manually use QMetaObject::invokeMethod().
  • You can attempt to typecast a pointer of an object to a pointer of a subclass of that object using qobject_cast<some_class *>(pointer_to_some_object). When some_class is not the class or a subclass of some_object, 0 is returned. This can be used to check if an object belongs to a given (sub)class:
    bool foo = qobject_cast<some_class *>(pointer_to_some_object);
    

Accessing databases

Here is some code for accessing a MySQL database:

QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "somename");
db.setHostName("hostname");
db.setDatabaseName("databasename");
if (!db.open("username", "password"))
{
   qDebug("error: %s\n", db.lastError().text().toAscii().constData());
   return;
}
qDebug("connection opened\n");
QSqlQuery query("select field1, field2 from sometable", db);
if (!query.isActive())
{
   qDebug("error in query: %s\n", query.lastError().text().toAscii().constData());
   return;
}
qDebug("processing");
// Show first field of all rows
while (query.next())
   qDebug("%s\n", query.value(0).toString().toAscii().constData());
qDebug("Done\n");
query.finish();
db.close();

For GUI applications it is preferred to use the model/view approach that Qt provides. The next example shows the QSqlQueryModel which provides a read-only model for the result of an SQL query. This model is viewed using a tableView (which was created within qtcreator), but other view widgets may also be used. The code below shows the modified mainwindow.cpp.

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlQueryModel>
#include <QtSql/QSqlError>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_actionQuit_triggered()
{
    this->close();
}

void MainWindow::on_okButton_clicked()
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
    QSqlQueryModel *model = new QSqlQueryModel;

    db.setHostName("hostname");
    db.setDatabaseName("databasename");
    db.setUserName("username");
    db.setPassword("password");
    if (!db.open())
    {
        qDebug() << db.lastError().text();
        return;
    }
    model->setQuery("SELECT name, address FROM adresses", db);
    model->setHeaderData(0, Qt::Horizontal, tr("Name"), Qt::DisplayRole);
    model->setHeaderData(1, Qt::Horizontal, tr("Address"), Qt::DisplayRole);

    ui->tableView->setModel(model);
}

Windows specific

For MySql support under Windows, there is extra (10 minutes) of work to be done. The instructions below apply for Qt 4.5.

  • go to the MYSQL download section and choose community server, windows and download the windows essentials.
  • double click on it, change the install path to C:\MYSQL, disable the server installation if you do not intend to use it, enable the clients and the development headers and libraries.
  • copy C:\MYSQL\BIN\LIBMYSQL.DLL to C:\QT\2009.03\QT\BIN.
  • open QT command prompt
  • type:
    cd %QTDIR%\src\plugins\sqldrivers\mysql
    qmake "INCLUDEPATH+=C:\MySQL\include" "LIBS+=C:\MYSQL\lib\opt\libmysql.lib" mysql.pro
    mingw32-make debug release
    
  • copy *.a and *.dll from both the DEBUG and RELEASE folders in C:\QT\2009.03\QT\SRC\PLUGINS\SQLDRIVERS\MYSQL to C:\QT\2009.03\QT\PLUGINS\SQLDRIVERS.