PDA

View Full Version : Connecting child and parent



maverick_pol
16th July 2007, 15:16
Hi gusy,

I have a strange problem.
I have 2 classes:

1) ClassOne : public QWidget {;}
2) ClassTwo : public QGraphicsScene {;} // call it objectTwo

I need to connect an action from the QGraphicsScene Context menu to a slot from the ClassOne(which is set as parent for the ClassTwo).

I tried both:

in the ClassOne:

connect(objectTwo->m_action,SIGNAL(triggered()),this,SLOT(vslot()));

in the ClassTwo:

connect(m_action,SIGNAL(triggered()),this->parent(),SLOT(vslot()));

Both do not work: nothing happens or there are run-time bugs.

Any idea.

Could you give a simple example how to connect child's action to it's parent slot?

Thanks.

Maverick

guilugi
16th July 2007, 15:18
Did you ensure that the macro Q_OBJECT is declared in both classes ?

If so, are your slots methods declared as slots ? :)

maverick_pol
16th July 2007, 15:21
Yes. I have declared the Q_Object macros + declared slots as...slots ;)

Maverick

guilugi
16th July 2007, 15:22
Is your code small enough to post it here, so I can test ?

maverick_pol
16th July 2007, 15:25
/// After running the application when I try to trigger the action I got a breakpoint

.....
if (!check_signal_macro(sender, signal, "connect", "bind"))
return false;
const QMetaObject *smeta = sender->metaObject(); // Here Is the breakpoint and the problem
++signal; //skip code
int signal_index = smeta->indexOfSignal(signal);
if (signal_index < 0) {
// check for normalized signatures
....

maverick_pol
16th July 2007, 15:35
class MyScene: public QGraphicsScene
{
Q_OBJECT
Q_CLASSINFO("version", "1.0.0");

public:
MyScene(VPFPrimitives* primitives, QObject* parent = 0);
~MyScene() {}

protected:

void contextMenuEvent( QGraphicsSceneContextMenuEvent * contextMenuEvent);
void vCreateContextMenuConnections();

private:
VPFPrimitives* m_VPFPrimitives;
QMenu* m_contextMenu;
QAction* m_actionContextZI;

friend class FundGC;
};
class GC: public QWidget
{
Q_OBJECT
Q_CLASSINFO("version", "1.0.0");

public :
GC(QGraphicsView*,QWidget* parent = 0);
~GC();
private:
MyScene* m_scene;
VPFPrimitives* m_VPFPrimitives;
private slots:
void vZoom();

};





And the implementation:



MyScene::MyScene(VPFPrimitives* primitives,QObject* parent): QGraphicsScene(parent)
{
m_VPFPrimitives = primitives;
vCreateContextMenuConnections();
}
/*! Creating context menu for the graphics Scene*/
void MyScene::contextMenuEvent( QGraphicsSceneContextMenuEvent * contextMenuEvent)
{
m_contextMenu = new QMenu();/*!< Context Menu */
m_actionContextZI = new QAction("Zoom In",this);
m_contextMenu->addAction(m_actionContextZI);
m_contextMenu->exec(contextMenuEvent->screenPos());

}

void MyScene::vCreateContextMenuConnections()
{
connect(m_actionContextZI,SIGNAL(triggered()),this->parent(),SLOT(this->parent()->vZoom()));
}
void GC::vZoom()
{
QMessageBox::warning(this,"yes","working");
}

The code is quite long; I have pasted the most important parts

guilugi
16th July 2007, 15:49
It won't work since your slot is private..make it public (I think) !

maverick_pol
16th July 2007, 16:01
I have made the slot public, but still it does not work.

Maverick

guilugi
16th July 2007, 16:09
Do you have some warnings like "No such slots..." ?

Your parent object is a QObject, but you may have to cast it to GC object...


GC *wparent = (GC*)(this->parent());


And use wparent in your connect.

jpn
16th July 2007, 16:11
There is a logical mistake; m_actionContextZI does not exist by the time vCreateContextMenuConnections() gets called. Also, you might want to allocate the menu on the stack or create it only once (preferable with a parent).

guilugi
16th July 2007, 16:12
Oh yes, right, you got it jpn

maverick_pol
16th July 2007, 16:22
Good idea, I have changed it before, but now I have a different problem(also connected with this task). My signal/slot are connected. I test it using a messageBox. WHen I trigger the action for the first time nothing happens. When I do it the second time 2 messageboxes show, when I trigger it the third time, 3 mb appear...etc.


Any idea ;)

Maverick

guilugi
16th July 2007, 16:27
Seems like multiple connect definitions...
You must make sure that connect is called once only at initialization.

Try to call disconnect after your context menu has been executed.

maverick_pol
16th July 2007, 16:46
Here is the final version and the correct one(not the only solution)


void GScene::contextMenuEvent( QGraphicsSceneContextMenuEvent * contextMenuEvent)
{
m_contextMenu = new QMenu();
m_actionContextZI = new QAction("Zoom In",this);
m_contextMenu->addAction(m_actionContextZI);
connect(m_actionContextZI,SIGNAL(triggered()),this->parent()>parent(),SLOT(vZoomIn())); // this line can't be the last
m_contextMenu->exec(contextMenuEvent->screenPos());
}


THanks guys for your help.

Maverick

jpn
16th July 2007, 16:58
Sorry, but I'm not exactly sure about "correct". ;) Notice that there is a memory leak. A new menu is being created every time a context menu is requested but never freed.

maverick_pol
16th July 2007, 17:03
Yes, you're right.

QMenu* m_contextMenu = new QMenu();/*! QAction* m_actionContextZI = new QAction("Zoom In",this);
m_contextMenu->addAction(m_actionContextZI);
connect(m_actionContextZI,SIGNAL(triggered()),this->parent()>parent(),SLOT(vZoomIn()));
m_contextMenu->exec(contextMenuEvent->screenPos());


Is this good?

Thanks

jpn
16th July 2007, 21:23
Well, a new menu is still created again and again upon every context menu request. All previously created menus remain alive as hidden eating up memory more and more.

Actually I meant something like this:


void GScene::contextMenuEvent( QGraphicsSceneContextMenuEvent * event )
{
QMenu menu(event->widget());
menu.addAction("Zoom In", receiver, SLOT(zoom()));
menu.exec(event->screenPos()); // QMenu::exec() blocks
} // a local variable "QMenu menu" gets automatically destructed


Or alternatively something like this:


GScene::GScene()
{
// ...
// a method that creates the menu and establishes connections _once_
createContextMenu();
}

void GScene::contextMenuEvent( QGraphicsSceneContextMenuEvent * event )
{
m_contextMenu->exec(event->screenPos());
}


However, if a single action context menu is all you need, using Qt::ActionsContextMenu is the simplest way:


graphicsView->setContextMenuPolicy(Qt::ActionsContextMenu);
graphicsView->addAction(m_actionContextZI);


Oh, and by the way, I suggest searching the forums for "signal chaining". It might be a bit more elegant and reliable way to establish connections instead of writing "parent()->parent()".

maverick_pol
17th July 2007, 08:11
Thanks for advice.

Maverick