C++ GUI Programming with Qt 3
Videoteka Manager Application
Videoteka Manager Application
The Task ............................................................................................................................................................3
The Database......................................................................................................................................................3
The tables ...........................................................................................................................................................3
customers.......................................................................................................................................................3
films ..............................................................................................................................................................4
rents ..............................................................................................................................................................4
sequence ........................................................................................................................................................4
Working with Database.......................................................................................................................................4
MySQL .........................................................................................................................................................4
Creating the Videoteka database.....................................................................................................................5
ODBC: Open Database Connectivity..............................................................................................................5
Database Registration ....................................................................................................................................6
Available drivers in Qt: ..................................................................................................................................6
A Qt/Sql modul..............................................................................................................................................6
The QSqlQuery class .....................................................................................................................................6
The QSqlCursor class ....................................................................................................................................7
The Project .........................................................................................................................................................7
Creating the “Videoteka” project ....................................................................................................................7
Creating the Main Window.............................................................................................................................7
Previewing the Main Window.........................................................................................................................7
Adding main program to the project................................................................................................................8
Connecting to the Databases...........................................................................................................................8
Updating Customers’ Table............................................................................................................................9
Creating new Action..................................................................................................................................9
Creating the CustomersForm.....................................................................................................................9
Bringing up the CustomersForm..............................................................................................................10
Slot: slotTableCustomers(QAction *)..................................................................................................10
Connection.........................................................................................................................................10
Implementation...................................................................................................................................10
Storing default values into the record.......................................................................................................11
Slot: slotPrimeInsert( QSqlRecord *bufferr ).......................................................................................11
Connection.........................................................................................................................................11
Implementation...................................................................................................................................11
Controlling data entry..............................................................................................................................11
Function: setMode( QSqlRecord * buffer )..........................................................................................11
Slot: slotCurrentChanged( QSqlRecord * buffer ) ...............................................................................12
Connection.........................................................................................................................................12
Implementation...................................................................................................................................12
Compile & Run.......................................................................................................................................12
Updating Films’ Table .................................................................................................................................13
FilmSqlCursor class ................................................................................................................................14
Definition...........................................................................................................................................14
Implementation...................................................................................................................................14
FilmDataTable class ...............................................................................................................................15
Definition...........................................................................................................................................15
CEEPUS H81 Network
Page 1
C++ GUI Programming with Qt 3
Videoteka Manager Application
Implementation...................................................................................................................................16
The Constructor ............................................................................................................................16
The Destructor ..............................................................................................................................16
Implementation of Destroctor....................................................................................................16
The Slots.......................................................................................................................................17
Implementation of slotPrimeInsert() slot....................................................................................17
Implementation of slotCurrentChanged() slot ............................................................................17
Implementation of slotBeforeUpdate() slot ................................................................................17
The Protected Functions ................................................................................................................17
Implementation of setMode() function.......................................................................................17
The Overloaded (virtual) Functions................................................................................................18
Reimplementation of paintField() function.................................................................................18
FilmSqlEditorFactory class (embedded class!!!).......................................................................................18
Definition...........................................................................................................................................18
Implementation...................................................................................................................................18
ReadOnlyEdit class .................................................................................................................................19
Definition...........................................................................................................................................19
Implementation...................................................................................................................................19
TypePicker class .....................................................................................................................................19
Definition...........................................................................................................................................19
Implementation...................................................................................................................................19
Workbook’s programs can be downloaded from the people.inf.elte.hu/nacsa/qt/lessons/ site.
Examples are created on Qt 3.3.1.
Prepared by:
Rozália Szabó-Nacsa
email: nacsa@inf.elte.hu
home page: people.inf.elte.hu/nacsa
Documentations:
Jasmin Blanchette, Mark Summerfield: C++ GUI Programming with Qt 3
Daniel Solin: Qt Programming
Customizing and Integrating Qt Designer
www.trolltech.com:
Quick Start
Budapest, April 2005.
CEEPUS H81 Network
Page 2
C++ GUI Programming with Qt 3
Videoteka Manager Application
The Task
Let’s create a Videoteka Manager Application.
The Main Window
Menu: Tables/Customers
Menu: Tables/Films
The Database
Name of the database: videoteka
The tables
customers
Table to store customers data
//create table customers (customer_id int(4) primary key not null, code varchar(8), name varchar(20), address varchar(20));
Fields:
customer_id:
int(4), not null; primary key /number to identify customer/
code:
varchar(8) /an easy code (memo) for customer/
name:
varchar(20) /customer’s name/
address: varchar(20) /customer’s address/
CEEPUS H81 Network
Page 3
C++ GUI Programming with Qt 3
Videoteka Manager Application
films
Table to store films’ data
//create table films (film_id int(4) primary key not null, title varchar(20), type char(3), amount int(2), rented int(2));
Fields:
film_id:
title:
type:
amount:
rented:
int(4), not null; not null; primary key /number to identify film’s record/
varchar(20) /film’s title/
char(3) /type of storage: VHS or DVD/
int(2) /owned peaces /
int(2) /how many pieces are rented at the moment/
(This data can be calculated from the table rents, but because of the
simplicity we store this here, too. This field is updated when the rent is
registered in the database.)
rents
Table to record rents.
// create table rents (rent_id int(4) primary key not null, customer_id int(4) not null, film_id int(4) not null, rented_date date
not null, received_date date );
Fields:
rent_id:
int(4), not null; not null; primary key /number to identify rent’s record/
(A customer can rent the same film in more exemplars.
customer_id:
int(4), nem nulla /vevő azonosító: ki kölcsönöz?/
film_id:
int(4), nem nulla /film azonosító: mit kölcsönöz/
out_date date, not null /date of the rent/
in_date:
date /date when customer receives the film/
sequence
Table to store the greatest, used sequence number for each table.
Fileds:
tablename: varchar(10), primary key, not null
sequence: int(4).
Working with Database
MySQL
In this workbook we are using the MySql DBMS. MySQL related information can be found on the
www.mysql.com site. First you have to install mysql (mysql-4.0.21-win.zip) then its ODBC driver (MyODBCstandard-3.51.9-win.exe).
CEEPUS H81 Network
Page 4
C++ GUI Programming with Qt 3
Videoteka Manager Application
Creating the Videoteka database
drop database videoteka;
create database videoteka;
use videoteka;
create table films (film_id int(4) primary key not null, title varchar(20),
type char(3), amount int(2), rented int(2));
insert into films values (1,'Film1','DVD',1,0);
insert into films values (2,'Film1','VHS',1,1);
insert into films values (3,'Film2','DVD',1,0);
insert into films values (4,'Film2','VHS',2,2);
create table customers (customer_id int(4) primary key not null, code
varchar(8), name varchar(20), address varchar(20));
insert into customers values (10,'Peter','Pet',"Peter's street 1.");
insert into customers values (11,'Kate','Kat',"Kate's street 13.");
insert into customers values (12,'Michel','Mic',"Michel's street 123.");
create table rents (rent_id int(4) primary key not null, customer_id int(4)
not null, film_id int(4) not null, rented_date date not null, received_date
date );
insert into rents values (101,10,1,'2004-12-12','2004-12-13');
insert into rents values (102,11,2,'2004-12-13',NULL);
insert into rents values (103,10,4,'2004-12-14',NULL);
insert into rents values (104,11,4,'2004-12-15',NULL);
create table sequence (tablename varchar(10), sequence int(4));
insert into sequence values ('films',4);
insert into sequence values ('customers',12);
insert into sequence values ('rents',104);
Identifications (*_id) in each table should be unique. In table sequence we keep track on the last id number for
each table of DBMS.
ODBC: Open Database Connectivity
First database related applications were developed by writing database dependent fuction calls directly into the
code. (Application Program Interface calls). Moving this application into a new environment programmers had to
rewrite this calls (API calls), in spite of the fact, that these calls were very similar.
Later developers decided to introduce a standard for database managing in order to minimize of rewriting process.
The first standard for database managing was the SQL (Standard Query Language) volt. This language was
developed by IBM and ORACLE implemented it. Nowadays almost each DBMS makes it possible to manage its
database using SQL language.
ODBC is another standard for database managing. Hereby they defined standard function calls to manage
database. Using this technique we need a driver implementing these standard functions inside. Using ODBC we
can perfom the same function calls independently from the database type, because database specific features are
handled via driver. Using open database connectivity programmer uses always the same function calls, so his/her
program can run in another environment without modification of the source if there is an odbc driver in this
environment. Such a calls are for example iterator functions: MoveFirst(), MoveNext(). The only condition of
portability is to have the appropriate driver.
CEEPUS H81 Network
Page 5
C++ GUI Programming with Qt 3
Videoteka Manager Application
Database Registration
The activity, when we connect a databes with a drive is called “database registration”
In order to registrate a database you have to make the next steps:
1.
Control Panel/Felügyeleti eszközök/ODBC datasources
2.
Felhasználói DSN fül / Add button
3.
Driver kiválasztása (MySQL ODBC 3.51) / Befejezés gomb
4.
DSN (Data Source Name) configuration
DSN information
Data Source Name: Videoteka
Description: MySQL ODBC 3.51 Driver DSN
MySQL connection parameters
Host: localhost
Database name: videoteka
User: nacsa
Pasword: xxxx
Port: 3306
OK / OK
Available drivers in Qt:
•
•
•
•
•
•
•
•
QDB2 - IBM DB2 Driver (v7.1 and higher)
QIBASE - Borland Interbase Driver
QMYSQL3 - MySQL Driver
QOCI8 - Oracle Call Interface Driver, version 8 and 9
QODBC3 - Open Database Connectivity Driver
QPSQL7 - PostgreSQL v6.x and v7.x Driver
QSQLITE - SQLite Driver
QTDS7 - Sybase Adaptive Server and Microsoft SQL Server Driver
A Qt/Sql modul
Qt's SQL classes help us to integrate the database to our Qt applications.
Qt/Sql classes: QSql, QSqlDriverPlugin, QSqlFieldInfo, QSqlQuery, QSqlCursor, QSqlEditorFactory, QSqlForm,
QSqlRecord, QSqlDatabase, QSqlError, QSqlIndex, QSqlRecordInfo, QSqlDriver, QSqlField, QSqlPropertyMap,
QSqlResult.
Classes to handle user interfaces: QSqlEditorFactory, QSqlForm, QSqlPropertyMap, QDataTable,
QDataBrowser, QDataView
Classes to maintane database: QSqlDataBase, QSqlCursor, QSqlQuery, QSqlError, QSqlField, QSqlFieldInfo,
QSqlIndex, QSqlRecord, QSqlRecordInfo
In QSqlQuery class we can use pure SQL commands while in QSqlCursor class Sql commands are created using
the the settings given by different function calls.
The QSqlQuery class
The QSqlQuery class provides a means of executing and manipulating SQL statements. QSqlQuery encapsulates
the functionality involved in creating, navigating and retrieving data from SQL queries which are executed on a
QSqlDatabase. Successfully executed SQL statements set the query's state to active (isActive() returns TRUE);
otherwise the query's state is set to inactive. In either case, when executing a new SQL statement, the query is
positioned on an invalid record; an active query must be navigated to a valid record (so that isValid() returns
TRUE) before values can be retrieved. Navigating records is performed with the following functions: next(),
prev(), first(), last(), seek(int).
CEEPUS H81 Network
Page 6
C++ GUI Programming with Qt 3
The QSqlCursor class
Videoteka Manager Application
The QSqlCursor class provides browsing and editing of SQL tables and views. A QSqlCursor is a database record
(see QSqlRecord) that corresponds to a table or view within an SQL database (see QSqlDatabase). There are two
buffers in a cursor, one used for browsing and one used for editing records. Each buffer contains a list of fields
which correspond to the fields in the table or view.
When positioned on a valid record, the browse buffer contains the values of the current record's fields from the
database. The edit buffer is separate, and is used for editing existing records and inserting new records.
For browsing data, a cursor must first select() data from the database. After a successful select() the cursor is
active (isActive() returns TRUE), but is initially not positioned on a valid record (isValid() returns FALSE). To
position the cursor on a valid record, use one of the navigation functions, next(), prev(), first(), last(), or seek().
Once positioned on a valid record, data can be retrieved from the browse buffer using value(). If a navigation
function is not successful, it returns FALSE, the cursor will no longer be positioned on a valid record and the
values returned by value() are undefined.
For editing records (rows of data), a cursor contains a separate edit buffer which is independent of the fields used
when browsing. The functions insert(), update() and del() operate on the edit buffer. This allows the cursor to be
repositioned to other records while simultaneously maintaining a separate buffer for edits. You can get a pointer to
the edit buffer using editBuffer(). The primeInsert(), primeUpdate() and primeDelete() functions also return a
pointer to the edit buffer and prepare it for insert, update and delete respectively. Edit operations only affect a
single row at a time. Note that update() and del() require that the table or view contain a primaryIndex() to ensure
that edit operations affect a unique record within the database.
The Project
Creating the “Videoteka” project
Start the Qt Designer and make a new project. The name of the project is “words” and we will save it
into the words directory.
Start Qt Designer
File/New/C++ project/OK
Project file: (brows into the appropriate directory) videoteka.pro
OK
Creating the Main Window
1.
2.
File/New/Main Window/OK
Choose available menus and toolbars page:
File actions: menu – off; Toolbar – off; Create Slots … – off
Edit actions: menu – off; Toolbar – off; Create Slots … – off
Help actions: menu – on; Toolbar – on; Create Slots …– on
We don’t want to have any help actions on the toolbar
Set the Main Window’s property according to the table below.
Name
MainForm
Qt Class
QMainWindow
Properties
Caption: Videoteka Manager
Previewing the Main Window
You can preview the main window’s functionality in Qt Designer via Ctrl+T. Check the menus’ and the
toolbar’s behaviour.
CEEPUS H81 Network
Page 7
C++ GUI Programming with Qt 3
Adding main program to the project
Videoteka Manager Application
Before compiling and building your project, you should add the main.cpp program.
3.
4.
5.
Project Overview: MainForm::mainform.ui
File/New/C++ Main File (main.cpp)/OK
Configure Main-File page
File name: main.cpp
Main Form: MainForm
main.cpp
# include <qapplication.h>
# include "mainform.h"
int main( int argc, char ** argv )
{
QApplication a( argc, argv );
MainForm w;
w.show();
a.connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) );
return a.exec();
}
Connecting to the Databases
Making a database connection you have to activate the driver in the project, set up the connection information, and
open the connection in your project.
connection.h
# define DB_SOURCE_DRIVER
# define DB_SOURCE_DBNAME
# define DB_SOURCE_USER
# define DB_SOURCE_PASSWD
# define DB_SOURCE_HOST
bool createConnections();
"QODBC3"
"videoteka"
"nacsa"
"1234"
"localhost"
connection.cpp
# include <qsqldatabase.h>
# include "connection.h"
bool createConnections() {
QSqlDatabase *source = QSqlDatabase::addDatabase( DB_SOURCE_DRIVER);
source->setDatabaseName( DB_SOURCE_DBNAME );
source->setUserName( DB_SOURCE_USER );
source->setPassword( DB_SOURCE_PASSWD );
source->setHostName( DB_SOURCE_HOST );
if ( ! source->open() ) {
qWarning( "Failed to open database: " +
source->lastError().driverText() );
qWarning( source->lastError().databaseText() );
return FALSE;
}
return TRUE;
}
Database connection is established by createConnections() function. First we activate the driver by calling
QSqlDatabase::addDatabase() function passing the name of used driver. (QODBC3). Then we give the databes
name (setDatabaseName), user’s name (setUserName) the password (setPassword), and the host nevet
(setHostName). Finally we open the database (open()).
CEEPUS H81 Network
Page 8
C++ GUI Programming with Qt 3
Videoteka Manager Application
Using database we have to modify the main.cpp, too
main.cpp
# include <qapplication.h>
# include "mainform.h"
# include "connection.h"
int main( int argc, char ** argv )
{
QApplication a( argc, argv );
if(!createConnections() ) return 1;
MainForm w;
w.show();
a.connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) );
return a.exec();
}
Updating Customers’ Table
Creating new Action
1.
2.
Action Editor/Right Click/New Action
Properties:
name: tableCustomersAction
text: Customer
menuText: &Customer
accel: CTRL+C
Additianally you can add two more actions in advance using the Action Editor window in Qt Designer
according to the table below.
Name
Qt Class
Properties
tableCustomersAction QAction
text: Customers;menuText: &Customers; accel: CTRL+C
tableRentsAction
text: Rents;menuText: &Rents; accel: CTRL+R
QAction
tableFilmsAction
text: Films;menuText: &Films; accel: CTRL+F
QAction
Creating the CustomersForm
Create a widget, named CustpmersForm, representing the main window.
File/New/Widget/OK
name: CustomersForm
caption: Customers Table
File/Save As : customersform.ui
Add a QDataTable widget on the CustomersForm.
1.
2.
3.
Select Project Overview: MainForm::mainform.ui
Toolbox/Database/DataTable/Click
Click on the CustomersForm
Answer the Data Table Wizard’s question. (Use the presentation’s slides ☺)
Choose the Database and Table Page:
Click on Setup Database Connections …/New Connection
Name: (default)
Driver: QODBC3
Database Name: videoteka
Username: nacsa
Password: ****
Hostname: localhost
Port: Default
CEEPUS H81 Network
Page 9
C++ GUI Programming with Qt 3
Videoteka Manager Application
Choose the Database and Table Page
Table: customers / Next
Displayed Fields: name, address, code / Next
Table Properties Page:
Read Only – off
Confirm Inserts: off
Confirm Updates: off
Confirm Deletes: on
Confirm Cancels: off
Allow column sorting: on / Next
SQL Page
Sort by: name ASC /Next
Finish Page
AutoEditing: on / Finish
Arrange the Form
Select the CustomersForm
Layou/Lay out Verically
Test the CustomersForm with Ctrl+T command. Note that the customers table can be seen and can be modified.
Bringing up the CustomersForm
We have created the CustomersForm. Let’s ‘activate” it.
Slot: slotTableCustomers(QAction *)
1.
2.
Project Overview: MainForm:mainform.ui
Object Explorer/Members/Functions/Right Click/Edit/New Function
Function: slotTableCustomers(QAction *)
Specifier: Virtual
Access: Public
Type: Slot
Connection
1.
2.
Project Overview: MainForm:mainform.ui
Object Explorer/Members/Functions/Right Click/Edit/Connections
Sender: tableCustomersAction
Signal: activated()
Receiver: MainForm
Slot: slotTableCustomers()
Implementation
mainform.ui.h
void MainForm::slotTableCustomers()
{
statusBar()->message(tr(QString::fromUtf8("Loading Table of Customers . . .")));
setCaption(tr(QString::fromUtf8("Videoteka: Table of Customers ")));
CustomersForm *customersForm = new CustomersForm(this, "CustomersForm");
customersForm->show();
setCentralWidget(customersForm);
statusBar()->message(tr(QString::fromUtf8("Ready")));
}
CEEPUS H81 Network
Page 10
C++ GUI Programming with Qt 3
Videoteka Manager Application
Do not forget to add the necessary includes!!!
☺
Project Overview: MainForm:mainform.ui
Object Explorer/Members/Includes (in Implementation):
“customersform.h”
<qmessagebox.h>
We are using the CustomersForm and QMessageBox in this function, so we have to add the definition of this
class to the project.
Storing default values into the record
Inserting a new customer we have to insert the appropriate customer’s id using our sequence table. The correct
moment to do this is when the table emits a primeInsert() signal.
Slot: slotPrimeInsert( QSqlRecord *bufferr )
primeInsert(QSqlRecord*) signal is emitted after the cursor is primed for insert by the table, when an insert action
is beginning on the table. The buffer parameter points to the edit buffer being inserted. Connect to this signal in
order to prime the record buffer with default data values.
1.
2.
Project Overview: CustomersForm:customersform.ui
Object Explorer/Members/Functions/Right Click/Edit/New Function
Function: slotPrimeInsert( QSqlRecord *buffer )
Specifier: Virtual
Access: Public
Type: Slot
Connection
1.
2.
Project Overview: CustomersForm:customersform.ui
Object Explorer/Members/Functions/Right Click/Edit/Connections
Sender: dataTable
Signal: pimeInsert( QSqlRecord *)
Receiver: CustomersForm
Slot: slotPrimeInsert( QSqlRecord *)
Implementation
cutomersform.ui.h
void CustomersForm::slotPrimeInsert( QSqlRecord *buffer )
{
QSqlQuery query;
query.exec("UPDATE sequence SET sequence = sequence + 1 WHERE tablename ='customers';");
query.exec("SELECT sequence FROM sequence WHERE tablename ='customers';");
if (query.next()) {
buffer->setValue("customer_id", query.value(0));
}
}
Controlling data entry
A customer can be deleted from customers table only if he/she has no rented films.
Function: setMode( QSqlRecord * buffer )
3.
4.
Project Overview: CustomersForm:customersform.ui
Object Explorer/Members/Functions/Right Click/Edit/New Function
Function: setMode( QSqlRecord * buffer )
Specifier: Virtual
Access: Protected
Type: Function
CEEPUS H81 Network
Page 11
C++ GUI Programming with Qt 3
Videoteka Manager Application
Slot: slotCurrentChanged( QSqlRecord * buffer )
currentChanged(QSqlRecord *) signal is emitted whenever a new row is selected in the table. The record
parameter points to the contents of the newly selected record.
1.
2.
Project Overview: CustomersForm:customersform.ui
Object Explorer/Members/Functions/Right Click/Edit/New Function
Function: slotCurrentChanged( QSqlRecord * buffer )
Specifier: Virtual
Access: Public
Type: Slot
Connection
1.
2.
Project Overview: CustomersForm:customersform.ui
Object Explorer/Members/Functions/Right Click/Edit/Connections
Sender: dataTable
Signal: currentChanged ( QSqlRecord *)
Receiver: CustomersForm
Slot: slotCurrentChanged ( QSqlRecord *)
Implementation
cutomersform.ui.h
void CustomersForm::slotCurrentChanged( QSqlRecord * buffer )
{
setMode(buffer);
}
void CustomersForm::setMode( QSqlRecord * buffer )
{
if (buffer == 0) return;
QSqlQuery query;
int count_rent=0;
query.exec( "SELECT count(*) FROM rents WHERE customer_id=" +
buffer->value("customer_id").toString() + ";" );
if (query.next())
count_rent = query.value(0).toInt();
if ( count_rent == 0)
dataTable->sqlCursor ()->setMode( QSqlCursor::Insert | QSqlCursor::Delete | QSqlCursor::Update );
else
dataTable->sqlCursor ()->setMode( QSqlCursor::Insert | QSqlCursor::Update );
}
Compile & Run
1.
2.
3.
4.
„Jump” into the videoteka directory. (If you are not there ☺)
Generate the platform dependent make file: qmake -o Makefile videoteka.pro
Build the program: nmake
Run the program (videoteka)
CEEPUS H81 Network
Page 12
C++ GUI Programming with Qt 3
Videoteka Manager Application
Updating Films’ Table
To update films table we have got a much more sophisticated table. We have got a Combo Box to enter type, two
calculated fileds, some fields can not be modified and the ‘Available” field shows a comment instead of zero value.
To create and manage such a table you have to use directly the Sql classes with inheritance.
We use the QSqlCursor class to represent data and the QDataTable class to display data. In order to add our
special functions we create an inherited a FilmSqlCursor and a FilmDataTable classes.
CEEPUS H81 Network
Page 13
C++ GUI Programming with Qt 3
Videoteka Manager Application
FilmSqlCursor class
Add the filmsqlcursor.h and filmsqlcursor.cpp files to your project.
Definition
filmsqlcursor.h
# ifndef FILMSQLCURSOR_H
# define FILMSQLCURSOR_H
# include <qsqlcursor.h>
class FilmSqlCursor : public QSqlCursor {
public:
FilmSqlCursor();
protected:
QVariant calculateField(const QString &name);
};
# endif
() is a protected virtual function which is called whenever a field needs to be
calculated. If calculated fields are being used, derived classes must reimplement this function and return the
appropriate value for field name. The default implementation returns an invalid QVariant.
The function calculateField
Implementation
filmsqlcursor.cpp
# include "filmsqlcursor.h"
FilmSqlCursor::FilmSqlCursor(): QSqlCursor("films")
{
QSqlFieldInfo available("available", QVariant::Int);
append(available);
setCalculated(available.name(),TRUE);
}
QVariant FilmSqlCursor::calculateField(const QString &name)
{
if (name == "available") {
QSqlQuery query;
int available=0;
query.exec("SELECT (amount - rented) FROM films WHERE film_id=" +
field("film_id")->value().toString() + ";");
if (query.next())
available = query.value(0).toInt();
return QVariant(QString::number(available));
}
return QVariant(QString::null);
}
calculateField()
sets field name to be calculated. If the field name does not exist, nothing happens. The value
of a calculated field is set by the calculateField() virtual function which you must reimplement Calculated fields do
not appear in generated SQL statements sent to the database.
CEEPUS H81 Network
Page 14
C++ GUI Programming with Qt 3
Videoteka Manager Application
FilmDataTable class
Add the filmdatatable.h and filmdatatable.cpp files to your project.
The QDataTable class provides a flexible SQL table widget that supports browsing and editing. QDataTable
supports various functions for presenting and editing SQL data from a QSqlCursor in a table. When displaying
data, QDataTable only retrieves data for visible rows. When displaying editable cursors, cell editing will be
enabled. QDataTable can be used to modify existing data and to add new records. When a user makes changes to
a field in the table, the cursor's edit buffer is used. The table will not send changes in the edit buffer to the
database until the user moves to a different record in the grid or presses Enter. Note that if autoEdit() is FALSE
navigating to another record will cancel the insert or update.
Since the data table can perform edits, it must be able to uniquely identify every record so that edits are correctly
applied. Because of this the underlying cursor must have a valid primary index to ensure that a unique record is
inserted, updated or deleted within the database otherwise the database may be changed to an inconsistent state.
Definition
filmdatatable.h
# include <qdatatable.h>
# include <qpainter.h>
# include <qsqleditorfactory.h>
# include <qsqlpropertymap.h>
class FilmSqlCursor;
class FilmSqlEditorFactory : public QSqlEditorFactory
{
Q_OBJECT
public:
QWidget *createEditor( QWidget *parent, const QSqlField *field );
};
class FilmDataTable : public QDataTable
{
Q_OBJECT
public:
FilmDataTable(QWidget * parent =0 , const char * name =0 );
~FilmDataTable();
void paintField(
QPainter * p, const QSqlField* field, const QRect & cr, bool );
public slots:
void slotPrimeInsert(QSqlRecord*);
void slotCurrentChanged(QSqlRecord* buffer);
void slotBeforeUpdate(QSqlRecord* buffer);
private:
void setMode(QSqlRecord* buffer);
private:
FilmSqlCursor *cursor;
QSqlPropertyMap *propMap;
FilmSqlEditorFactory *editorFactory;
};
QDataTable creates editors using the default QSqlEditorFactory. Different editor factories can be used by calling
installEditorFactory(). A property map is used to map between the cell's value and the editor. You can use your
own property map with installPropertyMap().
The contents of a cell is available as a QString with text() or as a QVariant with value(). The current record is
returned by currentRecord(). Use the find() function to search for a string in the table.
CEEPUS H81 Network
Page 15
C++ GUI Programming with Qt 3
Videoteka Manager Application
Implementation
The Constructor
filmdatatable.cpp (constructor)
# include "filmdatatable.h"
# include "filmsqlcursor.h"
# include <qmessagebox.h>
# include "typepicker.h"
# include "readonlyedit.h"
FilmDataTable::FilmDataTable(
QWidget * parent, const char * name) :
QDataTable( parent, name )
{
cursor = new FilmSqlCursor();
setSqlCursor(cursor);
//addColumn( "film_id", "Id" );
addColumn( "title", tr(QString::fromUtf8("Title")) );
addColumn( "type", tr(QString::fromUtf8("Type")) );
addColumn( "amount", tr(QString::fromUtf8("Amount")) );
addColumn( "rented", tr(QString::fromUtf8("Rented")) );
addColumn( "available", tr(QString::fromUtf8("Available")) );
refresh();
setConfirmDelete(TRUE);
setAutoEdit(TRUE);
propMap = new QSqlPropertyMap();
propMap->insert( "TypePicker", "type" );
installPropertyMap( propMap );
editorFactory = new FilmSqlEditorFactory();
installEditorFactory( editorFactory );
// signals and slots connections
connect( this, SIGNAL( primeInsert(QSqlRecord*) ), this, SLOT( slotPrimeInsert(QSqlRecord*) ) );
connect( this, SIGNAL( currentChanged(QSqlRecord*) ), this, SLOT( slotCurrentChanged(QSqlRecord*) )
);
connect( this, SIGNAL(beforeUpdate(QSqlRecord*) ), this, SLOT(slotBeforeUpdate(QSqlRecord*) ) );
}
The Destructor
Implementation of Destroctor
filmdatatable.cpp
FilmDataTable::~FilmDataTable()
{
if (propMap) delete propMap;
if (editorFactory) delete editorFactory;
if (cursor) delete cursor;
//May be it’s not necessary.
}
CEEPUS H81 Network
Page 16
C++ GUI Programming with Qt 3
Videoteka Manager Application
The Slots
Implementation of slotPrimeInsert() slot
This slot is used to prepare the record to be inserted.
filmdatatable.cpp
void FilmDataTable::slotPrimeInsert(QSqlRecord * buffer)
{
QSqlQuery query;
query.exec("UPDATE sequence SET sequence = sequence + 1 WHERE tablename ='films';");
query.exec("SELECT sequence FROM sequence WHERE tablename ='films';");
if (query.next()) {
buffer->setValue("film_id", query.value(0));
buffer->setValue("amount",1);
buffer->setValue("rented",0);
buffer->setValue("available",1);
buffer->setValue("type","DVD");
}
}
Implementation of slotCurrentChanged() slot
filmdatatable.cpp
void FilmDataTable::slotCurrentChanged(QSqlRecord* buffer)
{
setMode(buffer);
}
Implementation of slotBeforeUpdate() slot
filmdatatable.cpp
void FilmDataTable::slotBeforeUpdate(QSqlRecord* buffer)
{
if(buffer->value("amount").toInt() < buffer->value("rented").toInt()) {
buffer->setValue("amount",buffer->value("rented"));
QMessageBox::information( this, tr(QString::fromUtf8("Videoteka: Updating Table of Films")),
tr(QString::fromUtf8("Amount can not be less then number of rented films.!")));
}
}
The Protected Functions
Implementation of setMode() function
filmdatatable.cpp
void FilmDataTable::setMode(QSqlRecord* buffer)
{
if (buffer == 0) return;
QSqlQuery query;
int count_rented=0;
query.exec( "SELECT rented FROM films WHERE film_id=" +
buffer->value("film_id").toString() + ";" );
if (query.next())
count_rented = query.value(0).toInt();
if ( count_rented == 0)
cursor->setMode( QSqlCursor::Insert | QSqlCursor::Delete | QSqlCursor::Update );
else
cursor->setMode( QSqlCursor::Insert | QSqlCursor::Update );
}
CEEPUS H81 Network
Page 17
C++ GUI Programming with Qt 3
Videoteka Manager Application
The Overloaded (virtual) Functions
Reimplementation of paintField() function
If you want to draw custom field content you must reimplement this function to do the custom drawing.
filmdatatable.cpp
void FilmDataTable::paintField( QPainter * p, const QSqlField* field,const QRect & cr, bool b)
{
if ( !field )
return;
if ( field->name() == "available" ) {
QString text;
if(field->value().toInt() == 0)
text="* Out of stock*";
else
text = field->value().toString();
p->drawText( 2,2, cr.width()-4, cr.height()-4, fieldAlignment( field ), text );
} else {
QDataTable::paintField( p, field, cr, b) ;
}
}
FilmSqlEditorFactory class (embedded class!!!)
The QSqlEditorFactory class is used to create the editors used by QDataTable.QSqlEditorFactory is used by
QDataTable to automatically create appropriate editors for a given QSqlField. If you want to create different
editors instead of the default one you have to subclass QSqlEditorFactory and reimplement the createEditor()
function.
Definition
filmdatatable.h (Definition of the FilmSqlEditorFactory class !!!)
...
class FilmSqlEditorFactory : public QSqlEditorFactory
{
Q_OBJECT
public:
QWidget *createEditor( QWidget *parent, const QSqlField *field );
};. . .
Implementation
filmdatatable.cpp (Implementation of the FilmSqlEditorFactory class’s functions !!!)
...
QWidget *FilmSqlEditorFactory::createEditor(
QWidget *parent, const QSqlField *field )
{
if ( field->name() == "rented" ) {
QWidget *editor = new ReadOnlyEdit( parent );
return editor;
}
if ( field->name() == "type" ) {
QWidget *editor = new TypePicker( parent );
return editor;
}
if ( field->name() == "available" ) {
QWidget *editor = new ReadOnlyEdit( parent );
return editor;
}
return QSqlEditorFactory::createEditor( parent, field );
}. . .
CEEPUS H81 Network
Page 18
C++ GUI Programming with Qt 3
Videoteka Manager Application
ReadOnlyEdit class
Definition
readonlyedit.h
# include <qlineedit.h>
class ReadOnlyEdit : public QLineEdit {
Q_OBJECT
public:
ReadOnlyEdit( QWidget *parent=0, const char *name=0 );
};
Implementation
readonlyedit.cpp
# include "readonlyedit.h"
ReadOnlyEdit::ReadOnlyEdit( QWidget *parent, const char *name ) :
QLineEdit( parent, name )
{
setReadOnly(TRUE);
}
TypePicker class
Definition
typepicker.h
# include <qcombobox.h>
class TypePicker : public QComboBox
{
Q_OBJECT
Q_PROPERTY( QString type READ Type WRITE setType )
public:
TypePicker( QWidget *parent=0, const char *name=0 );
QString Type() const;
void setType( QString type );
};
Implementation
typepicker.cpp
# include "typepicker.h"
# include <qsqlcursor.h>
TypePicker::TypePicker( QWidget *parent, const char *name )
: QComboBox( parent, name )
{
insertItem("DVD");
insertItem("VHS");
setCurrentText("DVD");
}
QString TypePicker::Type() const
{
return currentText();
}
void TypePicker::setType( QString type )
{
setCurrentText( type );
}
CEEPUS H81 Network
Page 19
Download PDF
Similar pages