PDA

View Full Version : Problem with QGraphicsProxyWidget implementation



papillon
22nd April 2014, 22:30
Hi, I subclassed a QGraphicsProxyWidget and I can successfully add it to the scene. However, I cannot move it around, and it seems that no mouse events are triggered.

Here is my implementation:

proxy.h


class GENProxy : public QGraphicsProxyWidget
{
public:
GraphicsItem *parent = 0, QGraphicsScene *scene = 0);
protected:
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
void mousePressEvent(QGraphicsSceneMouseEvent * event);
.....
}


proxy.cpp


#include "proxy.h"
.....
GENProxy::GENProxy(QGraphicsItem *parent, QGraphicsScene *scene) : QGraphicsProxyWidget(parent)
{
QGroupBox *groupBox = new QGroupBox("Contact Details");
QLabel *numberLabel = new QLabel("Telephone number");
QLineEdit *numberEdit = new QLineEdit;
QFormLayout *layout = new QFormLayout;
layout->addRow(numberLabel, numberEdit);
groupBox->setLayout(layout);
QGraphicsProxyWidget *w = scene->addWidget(groupBox);
w->setFlag(QGraphicsItem::ItemIsMovable,true);
w->setFlag(QGraphicsItem::ItemIsSelectable,true);
w->setFlag(QGraphicsItem::ItemIsFocusable,true);
w->setFocus();
}


main.cpp


QGraphicsScene *myScene=new QGraphicsScene;
QGraphicsView *myView = new QGraphicsView(myScene);
myView->setRenderHint(QPainter::Antialiasing);
myView->setSceneRect(0, 0, 800, 800);
myView->setBackgroundBrush(Qt::gray);
QVBoxLayout* vlayout = new QVBoxLayout(mainClass.Interface.terraformTab);
vlayout->addWidget(myView);
GENProxy *a = new GENProxy(0, myScene);


As a matter of fact, the only signal showing activity is itemChange, but I can't set the focus or move the proxy around, and signals attached to the proxy embedded widgets aren't firing either (avoided to put those in the above code).
I followed also another thread here (http://www.qtcentre.org/threads/31916-Problem-with-QGraphicsScene-QGraphicsProxyWidget-and-setting-widget-focus) but couldn't come up with a solution.
Thanks for any help.

anda_skoa
23rd April 2014, 08:55
I think instead of addWidget() you want to call setWidget() on your proxy class.

Cheers,
_

papillon
23rd April 2014, 23:29
I modified the code using setWidget(), but still can't move the proxy (actually the proxy widget doesn't show at all).

Also, the code I used for adding widget to a proxy comes directly from Qt documentation: http://qt-project.org/doc/qt-4.8/qgraphicsproxywidget.html

I couldn't find many examples out there, please guys let me know if you can spot the issue or if somebody actually managed to do something like this. thanks

anda_skoa
24th April 2014, 09:43
The code you refer to is an example how to add a widget and get an automatically generated proxy item back.
A convenience technique if all you need is the item. But you seem to want a special subclass.

If you want to go with the inner proxy widget item, then your outer item type doesn't need to be a proxy. You can just use a normal QGraphicsItem and the parent for the proxy generated by the scene's convenience method.

Cheers,
_

papillon
26th April 2014, 12:24
Thanks for the help, but I still don't understand how to achieve this.
I have modified the code so that there it uses a QGraphicsItem, which actually works as expected and allows me to move the item around if I use QPaint items, but doesn't as I try to use or add a QGraphicsProxyWidget (see proxy.cpp for the relevant code).

proxy.h


class GENBlock : public QGraphicsPathItem
{
public:
GraphicsItem *parent = 0, QGraphicsScene *scene = 0, QString nodeType = "");
protected:
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
.....
}

proxy.cpp


#include "proxy.h"
.....
GENBlock::GENBlock(QGraphicsItem *parent, QGraphicsScene *scene) : QGraphicsPathItem(parent, scene)
{
// THIS ITEM IS DRAWN AND DRAGGABLE AS EXPECTED //
QPainterPath p;
p.addRoundedRect(-50, -15, 100, 30, 5, 5);
setPath(p);
setPen(QPen(Qt::darkGreen));
setBrush(Qt::green);
setFlag(QGraphicsItem::ItemIsMovable);
setFlag(QGraphicsItem::ItemIsSelectable);
//////////////////////////////////////////////////////////////////

// THIS ITEM IS DRAWN BUT DOESN'T RESPOND TO MOUSE EVENTS //
QGroupBox *groupBox = new QGroupBox("Contact Details");
QLabel *numberLabel = new QLabel("Telephone number");
QLineEdit *numberEdit = new QLineEdit;
QFormLayout *layout = new QFormLayout;
layout->addRow(numberLabel, numberEdit);
groupBox->setLayout(layout);
QGraphicsProxyWidget *w = scene->addWidget(groupBox);
w->setFlag(QGraphicsItem::ItemIsMovable,true);
w->setFlag(QGraphicsItem::ItemIsSelectable,true);
w->setFlag(QGraphicsItem::ItemIsFocusable,true);
//////////////////////////////////////////////////////////////////

}


main.cpp


QGraphicsScene *myScene=new QGraphicsScene;
QGraphicsView *myView = new QGraphicsView(myScene);
myView->setRenderHint(QPainter::Antialiasing);
myView->setSceneRect(0, 0, 800, 800);
myView->setBackgroundBrush(Qt::gray);
QVBoxLayout* vlayout = new QVBoxLayout(mainClass.Interface.terraformTab);
vlayout->addWidget(myView);
GENBlock *a = new GENBlock(0, myScene);


Added after 28 minutes:

Just a further explanation of what I'd like to accomplish, so that perhaps you guys can give me an advice on making things simpler.
I need to create a very simple node-based interface, where the nodes are custom widgets (that obviously can be dragged around), each one with input and output ports. The container can be a simple QFrame.
The reason why I'm after QGraphics*.* stuff is because I need to draw the connection lines between those node ports, but I understood I can actually draw lines or other QPaint items also subclassing and using QFrame::PaintEvent. So at this point, would this be a simpler and effective solution for what I need to achieve? Any pitfall?
Thanks

anda_skoa
26th April 2014, 13:42
You are creating a proxy widget item "w" that is in no way connected to your item, i.e. you have two totally independent items.

What I think you want to do is setting your item as the parent of "w"


w->setParentItem(this);


"w" itself then probably doesn't even have to be movable or selectable, because its parent is.

Cheers,
_

papillon
26th April 2014, 14:01
That's right, it was not parented to anything, so I added the instruction but the guy it's still stuck there and can't be moved around.
Is that perhaps proxies need to have a custom mousemove event handler? Or you need to install and event filter of some kind?

anda_skoa
26th April 2014, 15:42
Hmm, could be that the widget is getting the events first and consumes them.

Have you tried making your item the child of the proxy?

Cheers,
_

papillon
26th April 2014, 17:00
Hi, thanks for helping. After some experimenting, I've explicitly set the window flag on the addWidget to Qt::Window like this:



QGraphicsProxyWidget *w = scene->addWidget(groupBox,Qt::Window);


This change added an invisible title bar to the widget, and now I can move it around. I've studied the window flags here: http://qt-project.org/doc/qt-4.8/qt.html#WindowType-enum
but still can't figure out why it shouldn't work in Qt::Widget mode.
Also, I don't know yet what implications using Qt::Window may add. Besides that, I can now build and add a custom widget to the proxy, and drag it around.
More questions to come for sure :)