[Main Page] [kdraw #1] [kdraw #2] [kdraw #3] [kdraw #4]

KDraw 2


All of a sudden, the application begins to live. In this version, you can already draw wriggly and scratchy lines, in short, hours of fun for the younger elements of the family.


#!/usr/bin/env python

import sys
from kdeui import KApplication, KTMainWindow
from qt import QWidget, QPainter, QBrush, QPoint, QPaintEvent, white

class KPictureBox(QWidget):
  currentPos=None
  
  def __init__(self,parent,name):
    QWidget.__init__(self,parent,name)
    
  def paintEvent(self, QPaintEvent):
    self.p = QPainter()
    self.p.begin(self)
    self.p.fillRect(self.rect(), QBrush(white))
    self.p.drawRect(self.rect())
    self.p.flush()
    self.p.end()
    
  def mouseMoveEvent(self, ev):
    self.p = QPainter()
    self.p.begin(self)
    self.p.drawLine(self.currentPos, ev.pos())
    self.currentPos=QPoint(ev.pos())
    self.p.flush()
    self.p.end()
  
  def mousePressEvent(self, ev):
    self.p = QPainter()
    self.p.begin(self)
    self.p.drawPoint(ev.pos())
    self.currentPos=QPoint(ev.pos())
    self.p.flush()
    self.p.end()
  
class KMainWindow(KTMainWindow):
  def __init__(self):
    KTMainWindow.__init__(self)
    self.picture=KPictureBox(self,"picture")
    self.picture.setGeometry(50,10,400,400)

app=KApplication(sys.argv, "KDraw - Python")
window=KMainWindow()
window.setGeometry(100,100,500,500)
app.setMainWidget(window)
window.show()
app.exec_loop()

So, what is working the magic here? By subclassing a simple QWidget, we can chip in on a couple of important events. That widget, our KPictureBox, is used as the main widget of the MainWindow class, much like the buttons in the hello world examples.

The first is the paintEvent. It delivers a reference to self, aptly named self, and a reference to the calling event, also appropriately termed QPaintEvent. We don't do anything with the QPaintEvent, so let's forget about that.

The paintEvent is fired whenever the widget is asked to redraw itself, for instance when it has been partially covered by another window, or when Fvwm2 moves the window. (Though curiously enough not when the KDE window manager KWM moves the window.)

We use the paintEvent to draw a large, white canvas on our window. In order to get the QPainter to really draw on our window we have to reference it with our instance, self. The drawing procedure is adequately described in the Qt documentation, so I won't waste any bytes on it.

The other two events we catch, are mouseMoveEvent and mousePressEvent. The last comes first, in the order of things. We use that event to determine the start position of the cursor, and we place a dot at that position. We'll have to refer a lot to those mouse events, so ev seems long enough a name. A member of that ev event is the position of the mouse: ev.pos.

Up to version 0.7 of the KDE bindings it was enough to say: self.currentPos=ev.pos(). From version 0.8 onwards the way the bindings work is slightly different: in version 0.7 a reference to a C++ object returned by a C++ function was not so much a reference as well as a whole new copy of that object. Obviously, this was not what was wanted, but it served its purpose in the drawing program, where we wanted a new QPoint object to store the new coordinates. Now we have to create our new coordinate point explicitly: self.currentPos=QPoint(ev.pos()), otherwise we'd be drawing from startpoint to startpoint, i.e. draw a dot!

The mouseMoveEvent draws a line acccording to the movement of the mouse - and update our reference to the cursorposition. Really quite straightforward.


Changes