QGraphicsView: Widgets on the Canvas

Items or widgets? QGraphicsItem or QWidget? Which should I choose? Can you do everything with both? Mostly. You can write a games board widget, or a games board scene. An audio spectrum widget, or an audio spectrum item. Is QWidget faster? It can be, especially for simple widgets, and if you do everything right and have the time to spend. Will Graphics View save me time?

Maybe the task you're trying to solve is a perfect match for Graphics View, and as you go along implementing it, you implement zooming and scrolling and right there I'd like to double-click to open a line edit - pushbutton box but... how? Maybe you search the QGraphicsItem docs and can't find anything, so you create a QPushButton, and uh.. Where do I put it? Who is its parent? What do I do when the user scrolls the view? (Install event filters?)

void MyItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
QPushButton *button = new QPushButton("Hello!", event->widget());
button->move("#¤!¤ &am!#¤!"#¤%&/(/p;!¤#QRE // censored

Embedding a widget inside a QGraphicsScene... does stir your interest? Have you ever invested time and energy on creating the world's finest widget, and then wanted to use it with Graphics View? Or maybe your scene could use a combobox /right there/, but then you go... oh, I don't have any QGraphicsComboBoxItem. So what do you do?

  • Put the widget on one of the QGraphicsViews' viewports... somewhere.
    • It's /the/ widget, no emulation, no nothing.
    • Supports any widget, even custom widgets.
    • But: It's hard to keep track of the item's movement.
    • But: The item cannot be transformed. OTOH, it always looks right.
    • But: The item is always on top of the non-widget items (i.e., stacking order does not apply anymore).
    • But: With several views, the widget will have to pick one somehow.
  • Keep the actual widget outside the desktop, create an "emulator" item that draws by redirecting the painter, and sending paint events.
    • Supports any widget, even custom widgets.
    • You can have the same widget in many views.
    • You can transform the widget (but it won't necessarily look good).
    • But: You have to emulate all events, and the widget can only support the subset of what QGraphicsItem supports.
    • But: It's a horrible horrible hack, and I don't even know if it works at all ;-).
  • Write your own widget item, using QStyle to make it look like a real widget.
    • You have full control over the item, and can make it do what you want.
    • But: You have to write one item for each widget you want.
    • But: QStyle isn't exactly resolution-independent. Rotating something that uses cosmetic pens, for example?....
    • But: As fun as it may sound, you still have to implement all the logics inside the item yourself.

With either approach, what you want is to end up with something like this, graphics items and widgets dancing together as if nothing had happened:

QGraphicsWidgetItem in action

I myself and several other Trolls've spent some time researching this topic. It's not trivial; most solutions to embedding widgets into a scene end up with several serious drawbacks. That's also why Qt doesn't have any off-the-shelf solution to this.

  • Widgets cannot be scaled or rotated, but graphics items can.
  • Widgets can only appear once on the desktop, but several views can observe one graphicsitem.
  • Widgets express their geometries in pixels, graphics items use logical units. ( vs. double)
  • Widgets support tons of features that graphics items don't understand. Just look at QWidget's property docs.
  • Widgets understand layouts, graphics items don't.
  • 4000000 widgets don't work that well, but 4000000 items works perfectly.

So, fundamentally, the two are very different. But place some push button items on a scene, and pull up a view, and compare that to QPushButtons inside a QScrollArea, the two look the same, and feel the same. But they aren't the same. And that especially comes into play when you try to combine them.

I think the most reasonable thing to do is to either use the widget directly, or write your own custom control. To demonstrate the first approach, I've added a Graphics View experimental items section in Labs. You can take a look, download the example and see how it works. This approach doesn't support transformations, but... when was the last time you typed text comfortably into a line edit at a 22 degree angle?...

Btw, later on we'll be adding more experimental items to this page. If you have suggestions, please let us know.

Blog Topics: