Next Previous Contents

3. Usage

3.1 The Test Program

  1. You find datawidget in the datawidget-0.2/datawidget directory.
  2. The menu offers a connect item. Type your DSN into popup window. If you use Mysql: don't delete the OPTIONS=1!
  3. Test 0 creates a DBDataSource object. Closing the window destroys it.
  4. Test 1 allows editing of database records. - Edit the name of a database table and the primaries. - Click select.
  5. Test 2 also allows editing of database records. - Edit the name of a database table and the primaries. - Click select.
  6. Test 3, 4 are widget tests. - Edit the name of a database table and the primaries. - Click select.
  7. Test 5 shows comboboxes with translations and lookup tables. - Edit the name of a database table and the primaries. - Click select.
  8. Test 6 binds parameters to the '?' - Edit the name of a database table and the primaries, add a parameter for each '?'. - Click select.
  9. Test 7 connects a datail table to a master table.

The DBDataSource manager also allows update on joined queries, but it is not tested.

You find the text of the generated sql statements in the unixODBC trace.

3.2 Defining queries

The current interface accepts a query string, a table name, the prinary keys and the list of columns.

The DBDataSource methods are:
void setQuery(const QString query, bool removeTables = false);
void addTable(const char *table, const char *primaries, const char *columns);

A comfortable wrapper should encapsulate the sql details. But up to now this is what you get:

3.3 Connecting datasouces.

You can connect a detail datasouce to a master datasource. The result set of the detail source is restricted to the detail records of the current record of the master source. Look at DataWidgetTest7 for an example.

The DBDataSource method:
void setMaster(DBDataSource *master, const char *join, const char *init);

A detail datasource needs a query with a '?' for each foreign key eg. "select id, mid, avarchar from detail where mid = ?". You have to assign the master column positions to the parameter positions. The string "join" describes the assignment - pairs of index=index seperated by blanks eg. "1=0 2=1". The first one is the index of the field of the master datasource. The second is the index of the parameter.

If you assign master column position to detail colum positions, appending a new record will initialize the foreign keys from the corresonding fields. The string "Init" consists of pairs of index=index seperated by blanks eg. "1=0 2=1". The first one is the index of the field of the master datasource. The second is the index of the field of the detail source.

3.4 Getting started - a minimal application

This chapter shows a tiny application.

It uses Mysql via a odbc DSN "mysqltest". The "Test Database" chapter shows the create statement of the "master" table. I hope, after reading the demo, you understand the datasouredemo classes.

demo.h declares a qt widget class:


// The demo application uses some qt classes.
#include <qapp.h>
#include <qmainwindow.h>
#include <qmessagebox.h>
#include <qlayout.h>

// It opens a odbc connection.
#include <sql.h>
#include <dbrecordodbc3.h>

// The DataWidget classes 
#include <dbdatasource.h>
#include <dbgrid.h>
#include <dblineedit.h>
#include <dbnavigator.h>

// A simple Qt Widget
class Demo : public QMainWindow
{
  Q_OBJECT

  SQLHENV henv;
  SQLHDBC hdbc;
  DBDataSource *data;

public:
  Demo();
  ~Demo();

protected slots:
  void dataStateChanged();
};

demo.cpp creates the data-aware widgets. They are left to cope on their own.
#include "demo.h"

// The constructor creates a databasec connection, a DBDataSource
// manager and some widgets.

Demo::Demo()
{
  // of cause, you can use SQLAllocEnv, SQLAllocConnect, SQLDriverConnect
  QString error;
  if ( !DBRecordODBC3::connect("DSN=mysqltest;OPTION=1", &henv, &hdbc, &error) )
    QMessageBox::critical( this, "Database Error", error);

  // create a datasource
  data = new DBDataSource(new DBRecordODBC3(henv, hdbc));
  connect(data, SIGNAL(stateChanged()), this, SLOT(dataStateChanged()));
  
  data->setQuery("select id, anint, avarchar from master order by anint");
  data->addTable("master", "id=0", 0);
  data->open();
  data->first();

  // a layout
  QGridLayout *lo1 = new QGridLayout (this, 3, 1, 4);
  lo1->setRowStretch(0, 1);
  lo1->addRowSpacing(1, 20);
  lo1->addRowSpacing(2, 20);

  // create some widgets
  DBGrid *g1 = new DBGrid(data, this);
  lo1->addWidget(g1, 0, 0);
  g1->addColumn(0);
  g1->addColumn(1);
  g1->addColumn(2);

  DBLineEdit *ed1 = new DBLineEdit(data, 2, this);
  lo1->addWidget(ed1, 1, 0);

  DBNavigator *nav1 = new DBNavigator(data, this);
  lo1->addWidget(nav1, 2, 0);
}

// The destructor closes the database connection.

Demo::~Demo()
{
  delete data;
  SQLDisconnect(hdbc);
  SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
  SQLFreeHandle(SQL_HANDLE_ENV, henv);
}

// This slot shows the errormessages.

void Demo::dataStateChanged()
{
  if ( data->isError() )
    QMessageBox::critical(this, "Error", data->getErrorInfo());
}

// This it the usual Qt main function. 

int main( int argc, char ** argv ) {
  QApplication a( argc, argv );
  a.setFont(QFont("helvetica",12));
    
  Demo *demo = new Demo();
  a.setMainWidget(demo);
  demo->show();
  return a.exec();
}

The linker needs a -ldatawidget and a -lodbc. You have to adjust the -L and the -I parameters.
moc demo.h -o demo.moc.cpp 
cc demo.cpp demo.moc.cpp -o demo -ldatawidget -lodbc -lqt -lX11 
                         -I/usr/lib/qt/include  -I/usr/X11R6/include -L/usr/X11R6/lib

3.5 Test Database

The default values of the query strings go with this database:


#
# Table structure for table 'master'
#
CREATE TABLE master (
  id int NOT NULL auto_increment,
  anint int,
  avarchar varchar(100),
  areal real,
  anamount decimal(14,2),
  adate date,
  atime time,
  adatetime datetime,
  anbool tinyint(1),
  atext text,
  ablob blob,
  PRIMARY KEY (id)
);

#
# Dumping data for table 'master'
#

INSERT INTO master VALUES (1,0,'',1.2346,0.00,'1903-02-01','04:05:06','1909-08-07 10:11:12',0,'','');
 
#
# Table structure for table 'detail'
#
CREATE TABLE detail (
  mid int(10) NOT NULL,
  id int(5) NOT NULL auto_increment,
  avarchar varchar(255),
  KEY id (id),
  PRIMARY KEY (mid,id)
);

#
# Table structure for table 'lookup'
#
CREATE TABLE lookup (
  id smallint(1) NOT NULL auto_increment,
  info varchar(255),
  PRIMARY KEY (id)
);

#
# Dumping data for table 'lookup'
#

INSERT INTO lookup VALUES (1,'lookup one');
INSERT INTO lookup VALUES (2,'lookup two');
INSERT INTO lookup VALUES (3,'lookup three');
INSERT INTO lookup VALUES (4,'lookup four');
INSERT INTO lookup VALUES (5,'lookup five');
INSERT INTO lookup VALUES (6,'lookup six');
INSERT INTO lookup VALUES (7,'lookup seven');


Next Previous Contents