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.
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
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
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
Powered by vBulletin® Version 4.2.5 Copyright © 2024 vBulletin Solutions Inc. All rights reserved.