PDA

View Full Version : What's wrong with my actions???



fullmetalcoder
3rd March 2007, 17:49
In a custom tree model I have enabled context menu handling at node level and the code looks like that :


pMenu = new QMenu("Actions");
setupMenu(pMenu);

QAction *a = pMenu->exec(p);

qDebug("action triggered : %s", a ? qPrintable(a->text()) : "");
//pMenu->deleteLater();

if ( a )
a->trigger();


setupMenu() is a virtual function that is in charge of setting up the menu content :


QAction *a;

a = new QAction(QIcon(":/"), tr("&Remove"), m);
connect(a , SIGNAL( triggered() ),
this, SLOT ( deleteLater() ) );

m->addAction(a);

m->addSeparator();

a = new QAction(QIcon(":/folder.png"), tr("A&dd folder"), m);
connect(a , SIGNAL( triggered() ),
this, SLOT ( addFolder() ) );

m->addAction(a);

a = new QAction(QIcon(":/add.png"), tr("Add &file"), m);
connect(a , SIGNAL( triggered() ),
this, SLOT ( addFile() ) );

m->addAction(a);

a = new QAction(QIcon(":/file.png"), tr("&New file"), m);
connect(a , SIGNAL( triggered() ),
this, SLOT ( newFile() ) );

m->addAction(a);

m->addSeparator();

a = new QAction(QIcon(":/clear.png"), tr("&Clear"), m);
connect(a , SIGNAL( triggered() ),
this, SLOT ( clear() ) );

m->addAction(a);


When I play with my model on a QTreeView the context menu gets displayed correctly. Then if I trigger an action by clicking on a menu item I get a correct message on the console output ( i.e : "action triggered : x") but the triggered signal is never emitted (or never forwarded to the slots I have connected to it even when I call trigger() programmatically ...

I'm using Qt 4.2.2 under Linux. Any hints???

jacek
3rd March 2007, 19:01
What is "this" in setupMenu()? What method you invoke "setupMenu(pMenu);" from?

fullmetalcoder
4th March 2007, 08:40
I have a node (the typename doesn't matter here) inheriting from QObject. It has a void contextMenuEvent(const QPoint& p) called from the view (first block of code) and the setupMenu() is also a member of this class. The puzzling thing is that I tried substituting signal/slots with QMetaObject::invokeMethod but it did not give any result either...:(

EDIT :
Yeah!!! I've solved it! My fix is (very) dirty but inheritance-aware as I needed and AFAIK the Trolls have no reason changing the syntax of the meta-object system before a while...
I suppose the problem comes from the fact that my nodes are created in a separate thread (to avoid GUI freeze) which gets destroyed afterward (thus no event loop is running). So I added a "QHash<QAction*, const char*> slot_table;" member which is filled in the setupMenu() method with appropriate action-method name pairs. Then, after menu execution I use the following code :


QAction *a = m.exec(p);

if ( a && slot_table.contains(a) )
{
int idx = metaObject()->indexOfSlot(slot_table[a]);
qt_metacall(QMetaObject::InvokeMetaMethod, idx, 0);
}

jacek
4th March 2007, 14:37
I suppose the problem comes from the fact that my nodes are created in a separate thread (to avoid GUI freeze) which gets destroyed afterward (thus no event loop is running).
If the is no event loop running in that thread, queued connections won't work.


So I added a "QHash<QAction*, const char*> slot_table;" member which is filled in the setupMenu() method with appropriate action-method name pairs.
Isn't that an equivalent of adding Qt::DirectConnection to connect statements?

fullmetalcoder
4th March 2007, 15:12
If the is no event loop running in that thread, queued connections won't work.

Isn't that an equivalent of adding Qt::DirectConnection to connect statements?
Well, I expected my slots to be called directly but I think I now understand why they were not even if it looks strange... My nodes have been created in a given (now defunct) thread and some of their methods are called from the GUI thread. In this case created objects will be attached to the GUI thread (or am I missing something??) and it will cause Queued Connections by default which won't work properly...

jacek
4th March 2007, 16:30
My nodes have been created in a given (now defunct) thread and some of their methods are called from the GUI thread.
Maybe it will be enough if you simply move those objects to the GUI thread using QObject::moveToThread()?

fullmetalcoder
4th March 2007, 18:49
Maybe it will be enough if you simply move those objects to the GUI thread using QObject::moveToThread() (http://doc.trolltech.com/latest/qobject.html#moveToThread)?
I thought about that already but did not find any convininent way to do it in my code... Anyway I'm done now.:D