Merely drawing lines is not enough - a modern, full-featured drawing application must offer boxes too. Phil has added the bitBlt function in version 0.7 of the pyKDE bindings - which means that the beautiful bug we had in the previous version has disappeared. If you want to see what it looked like, try to comment all the bitBlt function calls out...
#!/usr/bin/env python import sys from kdeui import * from qt import * PEN = 1 RECT = 2 class KPictureBox(QWidget): def __init__(self,*args): QWidget.__init__(self,parent,name) self.tool=PEN self.pm=QPixmap(320,300) def paintEvent(self, QPaintEvent): self.p = QPainter() self.p.begin(self) self.p.fillRect(self.rect(), QBrush(QColor(255,255,255))) self.p.drawRect(self.rect()) self.p.flush() self.p.end() def mouseMoveEvent(self, ev): self.p = QPainter() self.p.begin(self) # # I was getting a bit tired of the stream of errors that could # result from failure to draw, so I used an exception block here, # that isn't present in the c++ version. Of course, now that the # code is good, it shouldn't be necessary anymore... # try: if self.tool==PEN: self.p.drawLine(self.currentPos, ev.pos()) self.currentPos=QPoint(ev.pos()) elif self.tool==RECT: bitBlt(self, 0, 0, self.pm) self.p.drawRect(QRect(self.currentPos, ev.pos())) except: pass self.p.flush() self.p.end() def mousePressEvent(self, ev): self.p = QPainter() self.p.begin(self) try: if self.tool==PEN: self.p.drawPoint(ev.pos()) self.currentPos=QPoint(ev.pos()) elif self.tool==RECT: currentPos=QPoint(ev.pos()) bitBlt(self.pm,0,0,self) except: pass self.p.flush() self.p.end() def slotPen(instance): instance.tool=PEN def slotRect(instance): instance.tool=RECT class KMainWindow(KTMainWindow): def __init__(self): KTMainWindow.__init__(self) self.setGeometry(100,100,410,315) self.buttonPen=QPushButton("Pen", self) self.buttonPen.setGeometry(5,5,75,25) self.buttonPen.show() self.buttonRect=QPushButton("Rectangle", self) self.buttonRect.setGeometry(5,35,75,25) self.buttonRect.show() self.picture=KPictureBox(self,"picture") self.picture.setGeometry(85,5,320,300) self.connect(self.buttonPen,SIGNAL("clicked()"), self.picture.slotPen) self.connect(self.buttonRect, SIGNAL("clicked()"), self.picture.slotRect) app=KApplication(sys.argv, "KDraw - Python") window=KMainWindow() app.setMainWidget(window) window.show() app.exec_loop()
Two buttons are defined, one for the pen, and one for the rectangle. They are connected to slot functions in our Picturebox widgets, in an effort at modular code. Besides, it lets you see that signals and slots are not very class-concious and can cross class distinctions with ease.
This is one of the areas where version 0.7 is not entirely compatible with the previous versions: the convenient function connect has been removed, and now you need to qualify connect with some relevant descendant of QObject. (Or with QObject itself.)
In the mouse event functions, the chosen tool is detected, and if it is a pen, we draw a line, otherwise we draw a rectangle, using the bitBlt function and an off-screen pixmap. The use of pixmap buffers to store graphics has been discussed by Eirik Eng in Linux Journal 31, November 1996, pp. 32-43. Whenever the user presses the mousebutton the current state of the canvas is saved in a pixmap and a rectangle is drawn. With the next move, the copy is put back (without the rectangle) and a new, larger, rectangle is draw.