Object-based paint/update in Qt/PyQt4
-
I'd like to tag items by drawing polygons over an image in Python using PyQt4. I was able to implement the image viewer with QGraphicsScene but I don't understand the concept behind painting/updating objects.
What I'd like to do is a Polygon class, what supports adding and editing. What confuses me is the QGraphicsScene.addItem and the different paint or update methods. What I'd like to implement is to
- draw a polygon as lines while not complete
- draw it as a filled polygon once complete
The algorithm part is OK, what I don't understand is that how do I implement the paint or update functions.
Here is my confusion
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.
On the other hand in numerous online tutorials I find def paintEvent(self, event): functions, what seems to follow a totally different concept compared to the graphicsview / paint.
Maybe to explain it better: for me the way OpenGL does the scene-update is clear, where you always clean everything and re-draw elements one by one. There you just take care of what items do you want to draw and draw the appropriate ones. There is no update method, because you are drawing always the most up-to-date state. This Qt GUI way is new to me. Can you tell me what happens with an item after I've added it to the scene? How do I edit something what has been added to the scene, where is the always updating 'loop'?
Here is my source in the smallest possible form, it creates the first polygon and starts printing it's points. I've arrived so far that the paint method is called once (why only once?) and there is this error NotImplementedError: QGraphicsItem.boundingRect() is abstract and must be overridden. (just copy any jpg file as big.jpg)
@from future import division
import sys
from PyQt4 import QtCore, QtGuiclass Polygon( QtGui.QGraphicsItem ):
def __init__(self): super(Polygon, self).__init__() self.points = [] self.closed = False def addpoint( self, point ): self.points.append( point ) print self.points def paint(self, painter, option, widget): print "paint"
class MainWidget(QtGui.QWidget):
poly_drawing = False def __init__(self): super(MainWidget, self).__init__() self.initUI() def initUI(self): self.scene = QtGui.QGraphicsScene() self.img = QtGui.QPixmap( 'big.jpg' ) self.view = QtGui.QGraphicsView( self.scene ) self.view.setRenderHint(QtGui.QPainter.Antialiasing) self.view.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.view.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.pixmap_item = QtGui.QGraphicsPixmapItem( self.img, None, self.scene) self.pixmap_item.mousePressEvent = self.pixelSelect self.mypoly = Polygon() layout = QtGui.QVBoxLayout() layout.addWidget( self.view ) self.setLayout( layout ) self.resize( 900, 600 ) self.show() def resizeEvent(self, event): w_scale = ( self.view.width() ) / self.img.width() h_scale = ( self.view.height() ) / self.img.height() self.scale = min( w_scale, h_scale) self.view.resetMatrix() self.view.scale( self.scale, self.scale ) def pixelSelect(self, event): if not self.poly_drawing: self.poly_drawing = True self.mypoly = Polygon() self.scene.addItem( self.mypoly ) point = event.pos() self.mypoly.addpoint( point )
def main():
app = QtGui.QApplication(sys.argv) ex = MainWidget() sys.exit(app.exec_())
if name == 'main':
main()@