Chapter 6. Creating Database Applications

Table of Contents
Setting Up Database Connections
Using QDataTable
Using QDataBrowser and QDataView

This chapter shows you how to use Qt's data-aware widgets from within Qt Designer. It demonstrates INSERT, UPDATE and DELETE in both QDataTables (tables) and QDataBrowsers (forms). It also shows how to code Master-Detail relationships and Drilldown. A simple approach to foreign key handling is presented here; a more sophisticated approach is shown in the online SQL module documentation.

If you wish to run the examples or create your own applications using these widgets you need access to an SQL database and a Qt database driver that can connect to the database. At the time of writing the drivers that Qt supports are QODBC3 (Open Database Connectivity), QOCI8 (Oracle), QPSQL6 (PostgreSQL 6), QPSQL7 (PostgreSQL 7) and QMYSQL3 (MySQL).

Although you can use the Qt data-aware widgets to browse and edit data in SQL databases without having to write any SQL, a basic understanding of SQL is highly recommended. We assume some familiarity with SELECT, INSERT, UPDATE and DELETE statements. We also assume a basic understanding of the concepts of normalisation and of primary and foreign keys. A standard text covering SQL databases is An Introduction to Database Systems (7th ed.) by C. J. Date, ISBN 0201385902.

In the following text we describe the creation of a 'book' database application. The application demonstrates how to use QDataTables including in-place record editing and how to set up master-detail relationships between QDataTables. It also explains how to drill down from a QDataTable to another widget, for example to a QDataBrowser or a QDataView and how to perform record editing in a QDataBrowser. A great deal of functionality is available from the classes directly in Qt Designer although subclassing is always available for finer control. If you want to build the 'book' examples you will need to create the example schema on your database.

Figure 6-1. The Book Application

Setting Up Database Connections

There are two aspects of database connections that we must consider. Firstly the connection we wish to use within Qt Designer itself, and secondly the connection we wish to use in the applications that we create.

Setting Up Qt Designer's Connections

Figure 6-2. Database Connections Dialog

Choose Edit|Database Connections from the menu bar. The Database Connections dialog will appear. Click New Connection. For applications that use a single database it will probably be most convenient to use the default connection name of '(default)'. If you use more than one database then each one must be given a unique name. A driver must be chosen from the Driver combo box. The database name may be available in the Database Name combo box or may have to be typed in. The database name, username, password and hostname should be provided by your database system administrator. When the Connection information has been completed click Connect. If the connection is made the connection name will appear in the list box on the left hand side of the dialog. You can now close the dialog; the connection settings will remain in force until you change or delete them or exit from Qt Designer.

Qt Designer can remember database connection settings in qmake project files. Create a new project, e.g. click File|New Project and complete the Project Settings dialog. Next time you start Qt Designer instead of opening individual .ui files open the .pro project file instead and Qt Designer will automatically reload the project's connection settings. To activate the connection click Edit|Database Connections. The connections previously saved with the project will be listed in the left hand list box. Click the connection you wish to use and then click Connect. This connection will be used from now on, e.g. for previewing QDataTables. Opening a project file also causes Qt Designer to load in the list of forms associated with the project into the Form List window. In most of the explanation that follows we will assume that you use project files and have clicked Connect so that there is always a connection available when you work in Qt Designer.

Setting Up Connections for Applications

The applications you create must make their own connections to the SQL database.

Example 6-2. createConnections() function

bool createConnections()
{
    // create the default database connection
    QSqlDatabase *defaultDB = QSqlDatabase::addDatabase( "QPSQL6" );
    if ( ! defaultDB ) {
        qWarning( "Failed to connect to driver" );
        return FALSE;
    }
    defaultDB->setDatabaseName( "book" );
    defaultDB->setUserName( "bookuser" );
    defaultDB->setPassword( "bookpw" );
    defaultDB->setHostName( "bookhost" );
    if ( ! defaultDB->open() ) {
	qWarning( "Failed to open books database: " +
		  defaultDB->lastError().driverText() );
	qWarning( defaultDB->lastError().databaseText() );
	return FALSE;
    }

    return TRUE;
}
We call addDatabase passing it the name of the driver we wish to use. We then set the connection information by calling the set... functions. Finally we attempt to open the connection. If we succeed we return TRUE, otherwise we output some error information and return FALSE.

Example 6-3. From qt/tools/designer/eg/book/book1/main.cpp

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

    if ( ! createConnections() ) 
        return 1;

    BookForm bookForm;
    app.setMainWidget( &bookForm );
    bookForm.show();

    return app.exec();
}
All the examples presented in this chapter call createConnections after creating the QApplication object in their main.cpp file and make use of the default connection. If you need to connect to multiple databases use the two-argument form of addDatabase, passing it both the name of the driver and a unique identifier. This is explained further in the Qt SQL Module documentation.

Note that you do not need to keep a reference to database connections. If you use a single database connection, this becomes the default connection and database functions will use this connection automatically. We can always get a pointer to any of our connections by calling QSqlDatabase::database().