HOOPS/QT Integration Guide

Introduction

The following section explains how to build an application with the Qt GUI toolkit and the HOOPS 3D Application Framework. Compiling and linking is first reviewed, followed by a discussion of object relationships in the various components, and then an outline of programming steps needed to correctly create and initialize the objects and launch the Qt event loop.

Developers should start by compiling, linking and running the basic qt_simple application as the starting point for their application. It’s readable source code is located in the <hoops>/demo/qt/qt_simple directory of your HOOPS/3dAF installation while a Qt v4 variant is located in the <hoops>/demo/qt/qt_simple directory. Some familiarity with the Qt toolkit, HOOPS/3dGS and HOOPS/MVO is assumed.

Compiling and Linking

The Qt toolkit’s signals and slots mechanism requires that a pre-compilation step that builds special source files. The Qt Meta-Object Compiler (MOC), supplied as part of the Qt toolkit, must be used prior to the compilation step. Please refer to the Qt documentation for more information.

Compiler Definitions

The following definitions must be in place when compiling the HOOPS/Qt and HOOPS/MVO source code together:

General Definition

IS_QT // All HOOPS/Qt application

Window System Specific

IS_WIN // Applications built with HOOPS/Qt for MS Windows IS_X11 // Applications built with HOOPS/Qt for UNIX

Using OpenGL on UNIX

USE_GLX_VISUAL // Applications built with HOOPS/Qt for UNIX that will use OpenGL; i.e., also IS_X11

Linking

The HOOPS/Qt Widget is supplied in clear source and should be added directly to the application’s source code base. Consequently there is no special HOOPS/Qt library to be linked in with the project.

Component Object Relationships

This section discusses the relationships between the objects in the various Qt and HOOPS/3dAF components. Building an application with both these toolkits minimally involves using the following objects from each component.

Qt

Only one QApplication and at least QMainWindow (or derived class)

HOOPS/Qt

At least one HQWidget (you would typically create a custom widget derived from HQWidget)

HOOPS/MVO

HBaseModel, HBaseView, an Operator class derived from HBaseOperator. Applications that want to implement selection of geometry will also need a HSelectionSet object. These objects are all connected by private data members which store pointers to other objects in the following manner:

../../_images/h_3daf_detailed_qt.gif

Steps to Building an Application with Qt and HOOPS

Programming with an object oriented GUI framework like Qt involves creating a set of objects, defining the ways in which they are connected, the manner in which they send and receive messages, and then launching the framework’s event loop. Building an application using Qt and the HOOPS/3dAF specifically requires the following steps in this order:

Creation and Initialization of Qt Objects

QApplication

For any GUI application that uses Qt, there is precisely one QApplication object no matter how many windows the application has. It can be accessed via the global variable a, declared in QApplication.h, which must be initialized prior to the creation of any other Qt objects. The qt_simple example performs this in the function main():

int main( int argc, char **argv )
{
        ...

        // Create the one QApplication object
        QApplication * a = new QApplication(argc,argv);

        ...
}

Color Allocation and GUI Style

The QApplication object’s attributes for color allocation and GUI sytle must be configured. For Qt/HOOPS applications the color allocation must be set to “ManyColor”. The GUI Style is used to choose between Motif or Windows styles for the visual appearance and default behavior of the Qt GUI created.

Creation and Initialization of HOOPS/Qt Objects

HQApplication

One HQApplication object should be created using the constructor that accepts a pointer to a Qt QApplication object. The qt_simple exampleperforms this in the function main():

int main( int argc, char **argv )
{
        ...

        if(argc == 2)
                HQApplication * ha = new HQApplication(a, argv[1]);
        else
                HQApplication * ha = new HQApplication(a);

        ...
}

The HQApplication object should create any Qt GUI object’s to be parented off of it during its initialization. The qt_simple example performs this when a HQApplication object is being initialized by calling its private method HQApplication::load().

HQWidget

As many HQWidget objects can be created as needed to implement the GUI’s design. These are more than likely going to be created by a constructor of a top level Qt widget like QMainWindow or QDialog. The qt_simple example performs this when an HQApplication object is initialized by calling its private method HQApplication::load():

void HQApplication::load(const char * filename)
{
        ...

        SimpleHQWidget * my_widget = new SimpleHQWidget(qframe, "SimpleHQWidget", filename);

        ...
}

HQDeleter

One global pointer must be declared and initialized in the application code block. The qt_simple example performs the global declaration in the file main.cpp and the initialization in the body of the function main():

// Create a global pointer to HOOPS/Qt class HQDeleter
HQDeleter * deleter=0;

int main( int argc, char **argv )
{
        ...

        // Create an HQDeleter object and initialize the global pointer
        deleter = new HQDeleter();

        ...
}

Creation and Initialization of HOOPS/MVO Objects

HDB

One global pointer to a HOOPS/MVO HDB object should be declared and initialized in the application’s main function. The qt_simple example example:

int main( int argc, char **argv )
{
        m_pHDB = new HDB();
        m_pHDB->Init();

        ...
}

HBaseModel

Multiple HBaseModel objects can be created as needed. The qt_simple example creates one for every SimpleHQWidget object (i.e., there is a one-to-one mapping of HBaseModel to SimpleHQWidget objects) and does so in the SimpleHQWidget constructor:

SimpleHQWidget::SimpleHQWidget(QWidget* parent, const char* name, const char * filename)
        : HQWidget( parent, name )
{
        m_pHBaseModel = new HBaseModel();
        m_pHBaseModel->Init();

        ...
}

HBaseView

Multiple HBaseView objects can be created as needed, with one object usually being created for each HQWidget. The HBaseView needs a valid window id and color map passed to its constructor on object creation; information used to connect a HOOPS/3dGS output driver instance to a Qt QWidget. This requires that the QtWidget, to which the HBaseView will be attached, must already exist prior to creating the HBaseView object.

The HBaseView object should be created and initialized in an overloaded HQWidget::Init method. This method is called by the base class HQWidget in its HQWidget::paintEvent method the first time it is called, which first ensures that the widget is alive and thus the window ID is valid and the HBaseView object can be created. Here is the qt_simple example:

void SimpleHQWidget::Init()
{
        m_pHView = new HBaseView(m_pHBaseModel, NULL, NULL, NULL, GetWindowId(), GetColorMap(), GetClipOverride());
        m_pHView->Init();

        ...
}

HBaseOperator

The HBaseView class has a member HBaseView::m_pOperator that is a pointer to an HBaseOperator object. A default operator should be created during view initialization. The qt_simple example does this in the overloaded method of HQWidget::Init:

void SimpleHQWidget::Init()
{
        ...

        m_pHView->SetCurrentOperator(new HOpCameraOrbit(m_pHView));

        ...
}

HSelectionSet

Multiple HSelectionSet object can be created as needed, but usually there is a one-to-one mapping of HSelectionSet to HBaseView objects.

The qt_simple example does not create a HSelectionSet object because it does not provide any support for selection at this time.

Launching the Qt Event Loop

This is performed by calling the QApplication::exec() method. Refer to the main() function of the qt_simple example.