PDA

View Full Version : QGraphicsProxyWidget does not behave as child of QGraphicsWidget



pinkieiknip
21st May 2011, 19:57
Basically, what I'm trying to do, is incorporating a lot of custom drawing (and also editing the drawing, such as resizing, moving) by using a QGraphicsScene and QGraphicsWidget together with existing widgets, such as QComboBox and possibly some more 'simple' input widgets, such as LineEdit.

At this point, my experiment of subclassing a QGraphicsWidget which holds one QComboBox has failed: the QComboBox draws itself, is accessible, responds to mouse events, but fails to move when the custom QGraphicsWidget moves.


compositeGraphicsItem::compositeGraphicsItem(QGrap hicsWidget *parent) :
QGraphicsWidget(parent)
{

}


QRectF compositeGraphicsItem::boundingRect() const
{
qreal penWidth = 1;
return QRectF(-10 - penWidth / 2, -10 - penWidth / 2,
50 + penWidth, 50 + penWidth);
}

void compositeGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
painter->setRenderHint(QPainter::Antialiasing);
painter->drawRoundedRect(-10, -10, 50, 50, 5, 5);
}


MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QGraphicsScene * gs = new QGraphicsScene(QRect(0,0,20,20));
ui->graphicsView->setScene(gs);
compositeGraphicsItem *c = new compositeGraphicsItem();
gs->addItem(c);
QGraphicsProxyWidget *proxy = gs->addWidget(new QComboBox());
proxy->setParent(c);
//c->setVisible(false); // when uncommented, this line should also hide the proxy, but it does not
proxy->moveBy(10,10); // this works, moves the proxy
c->moveBy(20,20); // this does not work as i intend it to, it moves the graphicsWidget, but not the proxy which should be a child and therefore be moved too
}

I tried to re-implement the moveBy function, but I noticed that the foreach loop did not get executed, which means that the proxy is not registered as a child:

void compositeGraphicsItem::moveBy(qreal dx, qreal dy){
QGraphicsWidget::moveBy(dx,dy);
foreach(QGraphicsItem * c, childItems()){
c->moveBy(dx,dy);
}
}

I do understand that a proxy-widget is somewhat hackish, but I'd like to know how I would be able to make something useful of it, since I'd like to be scaling and perhaps even animating the scene.

Any tips on how to solve this problem? I might be just looking at this completely wrong; there is so much to Qt that I haven't seen yet.

Context:
The application I want to be able to create with this is a viewer/manipulator for UML-based class diagrams like for example MS Visio is able to do. I'm trying to use a QAbstractItemModel together with a nicely structured hierarchy, so that I can always navigate it using a QTreeView.

Partial Solution:

void compositeGraphicsItem::moveBy(qreal dx, qreal dy){
QGraphicsWidget::moveBy(dx,dy);
foreach(QGraphicsProxyWidget* proxy, findChildren<QGraphicsProxyWidget*>()){
proxy->moveBy(dx,dy);
}
}
}
This at least makes the proxy move along with the composite widget. I don't know how elegant this solution is when using many elements though.

Furthermore, it also doesn't solve the visibility issue.

Added after 14 minutes:

This solves the visibility issue I had.


void compositeGraphicsItem::showEvent(QShowEvent *event){
QGraphicsWidget::showEvent(event);
foreach(QGraphicsProxyWidget* proxy, findChildren<QGraphicsProxyWidget*>()){
proxy->setVisible(true);
}
}
void compositeGraphicsItem::hideEvent(QHideEvent *event){
QGraphicsWidget::hideEvent(event);
foreach(QGraphicsProxyWidget* proxy, findChildren<QGraphicsProxyWidget*>()){
proxy->setVisible(false);
}
}

CAUTION: I realize why this is unwanted behaviour in the default case! For example, if the proxy is hidden, the actual widget is also hidden. This means that there would be some strange behaviour when this widget is also used in another location!

Added after 55 minutes:

When working with just the above solution, the default flags for ItemIsMovable allow moving of the QGraphicsWidget, but not the proxies inside; i.e. they won't move along again....

Solution:

void compositeGraphicsItem::moveEvent(QGraphicsSceneMov eEvent *event){
foreach(QGraphicsProxyWidget* proxy, findChildren<QGraphicsProxyWidget*>()){
QPointF p = event->newPos()-event->oldPos();
proxy->moveBy(p.x(), p.y());
}
}

I'll keep adding all modifications I needed to work around all the issues I come by.

Added after 19 minutes:

Another update: if you are following this line of thought, and want to be able to create compositie graphicwidgets, it is necessary to have a pointer to *some* QGraphicsScene object, or it isn't really possible to create a proxy, AFAIK. So, just pass that scene along in the constructor, use it there and just add itself to the scene. For your convenience.