PDA

View Full Version : Multiple SoQt Viewers



Gawain
10th December 2007, 13:35
I need at least two SoQtExaminerViewer. Each viewer should have it's own window, own event handler method (e.g. mouse, keyboard) and scene graph.
The problem I have now is that only one viewer is really working. For one viewer everything is fine and the right points get updated by a click. By not working I mean that clicking does not update the viewer where I clicked but instead the not active viewer gets updated. This is quite a little bit strange to me because the methods I use for updating the dispay and handling the mouse events are not the same for the viewers.

Any ideas?

high_flyer
10th December 2007, 14:21
impossible with out seeing the code.
start with the signal slot connection and or the event handling code.
the QThread::run() implementation would also help.

Gawain
10th December 2007, 14:37
Posted wrong code. Sorry.

My main stuff:


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

QWidget *mainwin = SoQt::init(argc, argv, argv[0]);
if (mainwin==0)
exit(1);

HBWindow*window=new HBWindow(mainwin,"HBWindow");

JEWindow*jew = new JointEditorWindow(0, "JEWindow");
jew->showMaximized();

window->showMaximized();

//SoQt::show(mainwin);
SoQt::mainLoop();

return 0;
}


Then the HBWindow as well as the JEWindow are basically the same. The both are inherited from QMainWindow and create a layout and add some attributs etc. to it. JEWindow looks exactly the same. _viewer is globally defined to be a class of SkelDisplay(...)


HBalanceWindow::HBalanceWindow
(
QWidget *parent, const char *name
)
: QMainWindow(parent,name)
{
// Creates the layout for the main window
QWidget *main_window_layout = new QWidget;
QHBoxLayout *layout = new QHBoxLayout;
_viewer = new SkelDisplay(main_window_layout, this);
_attributs = new AttributsWidget(main_window_layout, this);
layout->addWidget(_viewer);
layout->addWidget(_attributs);
setCentralWidget(main_window_layout);
main_window_layout->setLayout(layout);
}


The more interesting part is probably inside the SkelDisplay(...) method. Here I create the SoQT Viewer as well as the callbacks. The callbacks are defined as static methods. There is no QtThread.



SkelDisplay::SkelDisplay
(
QWidget *parent,
QWidget *main_win
)
:
QWidget(parent)
{
// Create the render view
//
_ivviewer = new SoQtExaminerViewer(this);
_ivviewer->setBackgroundColor(SbColor(0., 0., 0.));

_iv_root = new SoSeparator;
_iv_root->ref();

//Add some stuff to the _iv_root
...

_iv_root->addChild(complexity);

// Adds an event callback to catch mouse button hits
//
SoEventCallback *event_CB = new SoEventCallback;
_iv_root->addChild(event_CB);

// Set up the event callback. We want to pass the object itself
// as the callback func must be declared static
event_CB->addEventCallback(SoMouseButtonEvent::getClassTypeI d(),
mouse_pressed_CB,
this);

_ivviewer->setSceneGraph(_iv_root);
.....
}


I put some printf(...) statements so check if there is no confusion between the methods call. This seems to work. But at the end the update of the right window fails.

Thanks.

high_flyer
10th December 2007, 14:45
By not working I mean that clicking does not update the viewer where I clicked but instead the not active viewer gets updated.


event_CB->addEventCallback(SoMouseButtonEvent::getClassTypeI d(),
mouse_pressed_CB,
this);
Hmm... if getClassTypeId is static, then how will it deliver the correct Id?
Can you show the inside of SoMouseButtonEvent::getClassTypeId()?

Gawain
10th December 2007, 15:04
Doesn't

event_CB->addEventCallback(SoMouseButtonEvent::getClassTypeI d(), mouse_pressed_CB, this);

not only tell to add a callback function to the hierarchy that will handle a mouse event? At least thats my understanding. Of course the other class does the same like but there the callback method has another name.

The method that handles the mouse event looks like:


static void mouse_pressed_CB
(
void *user_data,
SoEventCallback *event_CB
)
{
const SoEvent *event = event_CB->getEvent();

SkelDisplay*ui = (SkelDisplay*) user_data;

// Check for left mouse button being pressed
//
if (SO_MOUSE_PRESS_EVENT(event, BUTTON1))
ui->mouse_button1_pressed(event);
printf("aa\n");
else if (SO_MOUSE_PRESS_EVENT(event, BUTTON2))
ui->mouse_button2_pressed(event); //DAR
else if (SO_MOUSE_PRESS_EVENT(event, BUTTON3))
{
if (ui->get_current_joint())
ui->mouse_button3_pressed(event);
else
QMessageBox::about(ui, "Error", "Error");
}
}

void SkeletonDisplay::mouse_button1_pressed
(
const SoEvent *event
)
{
}


Inside the mouse_button1_pressed I compute the distances based on the camera position to the points and select the one with the smallest distance. I have a printf(...) made for both mouse callback functions but could it happen that one overwrites the other, although they have different names?

high_flyer
10th December 2007, 15:20
Doesn't
Qt Code:


1.
event_CB->addEventCallback(SoMouseButtonEvent::getClassTypeI d(), mouse_pressed_CB, this);

not only tell to add a callback function to the hierarchy that will handle a mouse event? At least thats my understanding.
I don't know, its your code, and you didn't show it! :)
And in that respect, since your code is Qt code also in your call back, may I ask why are you making all of this so complicated, and not using Qt's oh so convenient ready made functions?

To deal with the problem, I suggest to strip the problem to parts.
Go from the general to the specific of what you need to achieve and explain it in such part..
One step at a time.

Let me try to recap what I understood:
You have two similar windows, and what is wrong about it, is when you click in one of them, the other gets updates with what should have been updates in the one you clicked in, is that correct?

Gawain
10th December 2007, 15:46
Unfortunately, there is already a big part written with this callback function and I have to take that code :(

Probably, I expressed myself not clearly enough. Lets say you have two windows HBWindow which calls SkelDisplay and JEWindow which calls JEDisplay. Clicking with the mouse will always update the JEWindow still you have clicked in the HBWindow. But the JEWindow is fine. The window you create later in the main will be the one that is working properly with the mouse while the other isn't. What lets me conclude that it has something to be with the callbacks is that creating a list (QComboBox) for selecting the points works always fine.

No idea if there can only be one callback for mouse handling....

What would you suggest as the proper method for Qt4? What would be the proper way using SoQt and a mouse handler from Qt4?

high_flyer
10th December 2007, 15:51
could you show addEventCallback()?

The proper way to deal with mouse events in Qt is by reimplementing mousePressEvent() and friends.

Gawain
10th December 2007, 16:02
Here we go:


void addEventCallback(SoType eventtype, SoEventCallbackCB * f,
void * userdata = NULL);


void
SoEventCallback::addEventCallback(SoType eventtype, SoEventCallbackCB * f,
void * userdata)
{
struct CallbackInfo cb;
cb.func = f;
cb.eventtype = eventtype;
cb.userdata = userdata;

this->callbacks.append(cb);
}


This comes from Coin3D SoEventCallback. I haven't implemented this myself!!

I have just to re-implement for every QWidget the mousePressEvent(...) and it should work? If it would be so simple, I could think about it. But may be there are some problems with these SoQtExaminerViewer that intercepts the mousePressEvent(...). I will try, if this would do the job.

high_flyer
10th December 2007, 16:41
I have just to re-implement for every QWidget the mousePressEvent(...) and it should work?
Well, it depends what you mean with "should work".
mousePressEvent() and the other event handlers will be called by Qt when a the relevant event happens (i.e pressing the mouse on the widget).
In that event handler you can do anything you want that should happen in that event.
So yes, that is as simple as that, didn't I say so? ;)

The question which is hard for me to answer is, how will it effect your code?.
It seems to me, that your code is implementing an event loop and handler (don't forget that Qt's eent handling is working in parallel, which might be part of the problem) so if you go the Qt way, you will have to do adjustments - what is the extent of those adjustments, is hard for me to say.

Is addEventCallback() static or not?

Gawain
11th December 2007, 10:33
addEventCallback(...) is not static. What has to be static is the callback function you add when calling the method addEventCallback(...).
I made some further tests. And for instance I would say that SoQt is not able to handle different SoQtExaminerViewer.

Another problem I have remarked is that the SoQtExaminerViewer only appears when the parent is a QMainWindow. Otherwise, I t does not work for me. But it is possible to have several QMainWindow instances at the same time right?

high_flyer
11th December 2007, 11:08
I made some further tests. And for instance I would say that SoQt is not able to handle different SoQtExaminerViewer.
Well in Qt you can use an object as an event filter to other objects, so it should be possible to install and even filter in one window for the others, where you can then manually decided which event should go where.
Have a look at installEventFilter (http://doc.trolltech.com/4.3/qobject.html#installEventFilter)


But it is possible to have several QMainWindow instances at the same time right?
At least I am not aware of anything that speaks against this possibility, but I would suggest that in such a case it would look like a bad design.
Better sort out the event flow in your application.

Gawain
12th December 2007, 09:22
Thanks. I will probably use the EventFilter.
The source of my problem is the Open Inventor implementation from SoQt/Coin3D. When you have two different hierarchies, a SoNode::getByName(...) seems not work properly. It is not ensured from which SoNode is returned. It can be from any hierarchy even if these hierarchies are in different classes and namespaces.

high_flyer
12th December 2007, 09:33
The source of my problem is the Open Inventor implementation from SoQt/Coin3D. When you have two different hierarchies, a SoNode::getByName(...) seems not work properly. It is not ensured from which SoNode is returned. It can be from any hierarchy even if these hierarchies are in different classes and namespaces.
Well this is quite abstract for me, since I don't know your code.
Over a forum it is hard to look for problems in cases like these based on symptoms, because the complexity, and the inability to see the full code.
You should try and debug your problem and reduce it to an specific problem domain, not a symptom.
Probably then we will be more able to help.
Good luck!

pdolbey
14th December 2007, 16:54
Posted wrong code. Sorry.
.... _viewer is globally defined to be a class of SkelDisplay(...)


From this I imply that you have something like this sitting on its own outside of a class declaration


SkelDisplay _viewer;


If this is accurate, then you only have one instance of _viewer throughout your application. Every time you construct a window you reassign the _viewer to be a new SkelDisplay with a new SoQtExaminer, orphaning any previous objects refernced by _viewer. From your symptoms, this looks to be exactly what's happening.

What happens if you make _viewer a member variable of HBalanceWindow?

Pete

p.s. You can tidy up your code by making "mouse_pressed_CB" a static method of SkelDisplay instead of being classless. The lets "mouse_pressed_CB" have access to the protected members of your "ui" object if it needs. I have done this with a similar OpenCASCADE callback and it works well. It also means you can use the same pattern and naming convention with other classes.