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

KDraw 4


The main innovation in this example is the addition of filled boxes, and of drawing in white. If I hadn't already done so in the hello world examples, I would add button bars, menu's and perhaps a status bar too - but that's left as an exercise for the reader. (A statusbar that tells the user what tool he's using would be very handy, though.)


#!/usr/bin/env python
#
# Kdraw example
#

import sys
from kdeui import *
from qt import *

PEN = 1
RECT = 2
FRECT = 3
PENWIDTH=1

class KPictureBox(QWidget):

  def __init__(self,parent,name):
    QWidget.__init__(self,parent,name)
    self.tool=PEN
    self.fillColor=QColor(0,0,0)
    self.drawColor=QColor(0,0,0)
  
    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 and therefore closing the QPainter,
    # 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:
      self.p.setPen(QPen(self.drawColor,PENWIDTH)) # a small addition of my own
      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()))
      elif self.tool==FRECT:
        bitBlt(self, 0, 0, self.pm)
        self.p.fillRect(QRect(self.currentPos, ev.pos()), QBrush(self.fillColor))
        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=ev.pos()
        bitBlt(self.pm,0,0,self)
      elif self.tool==FRECT:
        currentpos=QPoint(ev.pos())
        bitBlt(self.pm, 0, 0, self)
    except:
      pass
    
    self.p.flush()
    self.p.end()
  
    if ev.button()==ButtonState.LeftButton:
      self.drawColor=QColor(0,0,0)
      self.fillColor=QColor(0,0,0)
    elif ev.button()==ButtonState.RightButton:
      self.drawColor=QColor(255,255,255)
      self.fillColor=QColor(255,255,255)
  
  def slotPen(instance):
    instance.tool=PEN
  
  def slotRect(instance):
    instance.tool=RECT
  
  def slotFrect(instance):
    instance.tool=FRECT
  
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.buttonFrect=QPushButton("Filled", self)
    self.buttonFrect.setGeometry(5,65,75,25)
    self.buttonFrect.show()

    self.picture=KPictureBox(self,"picture") #hmmm... I must pass 'self'
    self.picture.setGeometry(85,5,320,300)
  
    QObject.connect(self.buttonPen,SIGNAL("clicked()"), self.picture.slotPen)
    QObject.connect(self.buttonRect, SIGNAL("clicked()"), self.picture.slotRect)
    QObject.connect(self.buttonFrect, SIGNAL("clicked()"), self.picture.slotFrect)

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


Actually, little work is needed. An extra button, a state variable and some if statements. I've made one change to the original code, and that's the addition of self.p.setPen(QPen(self.drawColor,PENWIDTH)), which lets you draw in white. The original code only allowed white boxes. The Qt documentation really is a relief at times like these, as are the extremely well-commented KDE header files. Those are full of helpful texts, unlike some other header files I could mention.

Just to keep everyone on his toes - notice how I connect the slots and the signals in this example? It's different from the way I did it in the previous example.

That's all - I will continue working my way through Roberto Alsina's tutorial, which is quite good too, and perhaps do some of the examples Troll Tech offers us. But then it's time for a real application - perhaps a sketchpad for the children, or the NPC-tracker for my role-playing games. Or the linguistics app I have been busy with, or something to teach my children reading and writing. An application to show the structure of a website by links in a tree is nice to have, too.

A programmers life is good with Python and KDE.


Changes