[Interest] Object-based paint/update in Qt/PyQt4
Till Oliver Knoll
till.oliver.knoll at gmail.com
Tue Oct 23 18:03:30 CEST 2012
2012/10/23 Zsolt Ero <zsolt.ero at gmail.com>:
> In the original example file: graphicsview/collidingmice there is a special
> function def paint(self, painter, option, widget): what does the painting.
> There is no function calling the paint function, thus I'd think it's a
> special name called by QGraphicsView, but I don't understand what is a
> painter and what should a paint function implement.
Your question covers is quite broad and covers many (painting related)
topics, so let me answer by giving you a "general overview" about how
painting in Qt works, instead of answering every specific question you
I further strongly assume that the Python API is pretty much a 1:1
mapping to the corresponding Qt API, so I will explain it with the
One concept is that "every widget paints itself when asked to" (Qt is
traditionally a "widget based" API, so I'll start there):
* You derive from the base class QWidget and
* Implement the (protected) method paintEvent(QPaintEvent *):
Most widgets simply paint the entire surface they cover, but you can
optimise the painting if you only (re-)draw the area which is
specified in the argument QPaintEvent. For instance if your widget
shows a pixmap, you can only draw parts of that pixmap (typically the
part which was partly covered by another window, and has now been
uncovered, or when scrolling a widget: the part which has just become
But how do you paint?
Enter QPainter (http://qt-project.org/doc/qt-4.8/QPainter.html): the
painter class draws upon a "surface" which in most cases will be a
QWidget (you need to specify that "surface" (a "Paint Device" in Qt's
lingo) when creating a painter). It provides basic operations such
drawing a line, circle, rectangle, image, text etc. It is considered a
"stateful" API (like OpenGL), in the sense that when you set the
"brush colour", it will be used in successive paint operations - until
you change the colour again.
But when do you paint?
Most of the time you don't care! Or rather: the Qt Event Queue cares
for you! The Qt Event Queue will manage all the underlying window
manager "show, expose, resize, ..." window events and forward them to
the affected QWidgets - by "sending" a QPaintEvent (sic!) to them. The
net effect is that your protected paintEvent method will be called.
As a matter of fact you should never - ever - call that function
directly in your own code! The Qt Event queue knows better!
But what if I change the underlying data to be painted?
Off course you want to update and control the paint process: you want
to be able to say "I changed the coordinates of my polygon, please
repaint!" - But instead of calling your own paintEvent() method (see
above! Don't do that!) you tell the corresponding view (the QWidget
painting your polygon) to update itself - by calling the slot
Note that this is a slot, which is pretty convenient, as you could
connect it to a model's signal "changed" (so each time the model
changes, the view gets automatically notified to update itself).
What does update do? It does /not/ immediately repaint the widget!
Rather it tells the Qt Event Queue "Hey! When you think it is
convenient, please have that widget updated." And when the proper time
comes the Qt Event queue does exactly that (it is even so clever so
"compress" multiple update requests: the widget is only updated
/once/, even if you tell it 10 times to update shortly before).
So up to now you know:
* Where and when to paint (QWidget::paintEvent)
* How to paint (QPainter)
Off course managing a "scene" of objects, moving them around, doing
collision tests and much more is a common task for applications, so
implementing all that with traditional QWidgets would mean
"reinventing the wheel over and over again".
Managing A Scene
(http://qt-project.org/doc/qt-4.8/QGraphicsScene.html) and the
(http://qt-project.org/doc/qt-4.8/qgraphicsview.html)! A Graphics
Scene is a "container" for scene items
(http://qt-project.org/doc/qt-4.8/qgraphicsitem.html) such as
ellipses, polygons, text and images.
The View already implements many convenience functions: e.g. adding an
item will automatically re-trigger a repaint of the scene! Moving an
items (if it is made "movable") also works out of the box.
Now I understand your final goal is to make a polygon editable. To be
honest I don't quite know whether that is possible "out of the box": I
would start with either subclassing
http://qt-project.org/doc/qt-4.8/qgraphicspolygonitem.html, or one
you want to control the painting of the polygon yourself.
Note that painting and mouse handling is very similar to the QWidget
paint system above: so if you decided to subclass from Graphics Shape
Item and paint the polygon yourself (filled, dashed etc. depending on
the "state"), the you would overwrite the
(notice that unlike in the QWidget case you are already passed a
Or you could try to re-use the existing class Graphics Polygon Item
and have it updated by simply setting your new version of the Polygon
each time: http://qt-project.org/doc/qt-4.8/qgraphicspolygonitem.html#setPolygon
- that should re-trigger a repaint automatically. The way the polygon
would be drawn can be controlled with
And off course you would need to interact with the mouse events, but
don't worry: just as in the QWidget case you have access to them in
Graphics Items as well:
It should not be forgotten that Qt is now gearing towards "Qt Quick",
a "declarative approach" to define what and how things are painted.
But the above is perfectly fine and proven technology and my knowledge
about QML is /very/ limited (and if you'd ask me, I'd recommend using
the "procedural" approach with C++ and QWidgets/QGraphicsView - but
that depends whether you are more an XML/Java Script friend, then you
might prefer QML ;)), so I'll leave that up to others to explain ;)
Lastly, study a few "How-Tos" and tutorials and common concepts, such
More information about the Interest