PyQt - clear widget for redraw

P

Peter

I want to draw some lines on a widget.
This works ok, but when I want to redraw, the old lines are still there.

How do I clear or refresh the widget, so I can draw a new set of lines?

Code snip below.

TIA

Peter


-------------------------
def paintLines(self, e):
p = QPainter(e)
mar = e.width()/100 # margin
vsp = 2 # vertical spacing
hrz = (e.width() - 2*mar)/100 # horizontal scalar
for i in range(100):
p.drawLine(mar,mar+vsp*i,hrz*(l1+1),mar+vsp*i)
-------------------------
 
D

Diez B. Roggisch

Peter said:
I want to draw some lines on a widget.
This works ok, but when I want to redraw, the old lines are still there.

How do I clear or refresh the widget, so I can draw a new set of lines?

Call erase on your widget. Or redraw a rectangle yourself.
 
P

Peter

Diez said:
Call erase on your widget. Or redraw a rectangle yourself.

Thanks, that works fine.
I just started using pyqt yesterday, and having trouble finding a reference
- most Qt stuff is written for c++.

Peter
 
J

Jim

Peter said:
Thanks, that works fine.
I just started using pyqt yesterday, and having trouble finding a
reference - most Qt stuff is written for c++.

Peter

Boudewijn Rempt's book _GUI Programming with Python: QT Edition_
might be helpful. It's available online at:

http://www.opendocspublishing.com/pyqt/

You can also post your questions at:
PyKDE mailing list (e-mail address removed)

sign up for the list at:
http://mats.imk.fraunhofer.de/mailman/listinfo/pykde

There's also a PyQt wiki at:
http://www.diotavelli.net/PyQtWiki
(it's fairly new and a little light on content, but there's already some
good stuff there).


Jim
 
D

Diez B. Roggisch

Peter said:
Thanks, that works fine.
I just started using pyqt yesterday, and having trouble finding a
reference - most Qt stuff is written for c++.

The neat thing on pyqt is that usually you can directly translate c++
examples to python. So there is no need to have a separate documentation
and other resources. The erase I looked up in the qt standard
documentation.
 
P

Peter

Diez said:
The neat thing on pyqt is that usually you can directly translate c++
examples to python. So there is no need to have a separate documentation
and other resources. The erase I looked up in the qt standard
documentation.

Thanks
(and thanks to Jim for his response, too)

What I'm drawing is a series of lines (like a horizontal bar chart) and it
is updated several times a second. The problem is that it goes too fast.
I tried the time.sleep() function, but then it doesn't draw properly. It
seems to draw only part of the chart each time, and flickers.

Is there some way to make the display smoother?

TIA

Peter
 
D

Diez B. Roggisch

What I'm drawing is a series of lines (like a horizontal bar chart) and it
is updated several times a second. The problem is that it goes too fast.
I tried the time.sleep() function, but then it doesn't draw properly. It
seems to draw only part of the chart each time, and flickers.

Usually there is no "to fast" in graphics - so I've got to admit I'm not
sure what you are talking about.

Where does the data to draw come from, and how fast is it actually coming? A
flickering sensation usually stems from the redrawing done so fast it
interfers with the vertical retrace.

Maybe it helps to put your sleep not in the drawing code, but between the
arrival of different data sets to draw, thus limiting the redraws to an
amount of lets say 10/s.

If you'd fill us in with some more details, the suggestions might be better.
And I think it would be worth asking these qustions on the PyKDE list Jim
has mentioned - I'm also there :)
 
P

Peter

Diez said:
Maybe it helps to put your sleep not in the drawing code, but between the
arrival of different data sets to draw, thus limiting the redraws to an
amount of lets say 10/s.

Yes - tried that, but gives incomplete draw / flicker.
If you'd fill us in with some more details, the suggestions might be
better. And I think it would be worth asking these qustions on the PyKDE
list Jim has mentioned - I'm also there :)

More details:
the idea is to provide a graphics demo of sort algorithms for my 13 year old
son. A number of lines of differring lengths are shown on the screen, and
you can watch as these are sorted, step by step. So you can see the
difference between bubble sort, ripple sort, etc.
Code copied below.
Improving the smoothness of the display is the main thing I'm after.
Also, how can I write the counters to the form? It uses the LCD widget now,
but there must be another way.

TIA

Peter

-- sort1.py ---
#!/usr/bin/python
#
# demo of sort algorithms, using PyQt

import sys, random, time
from qt import *

from frmtest import frmTest

class dlgForm(frmTest):

def __init__(self, parent=None):
frmTest.__init__(self, parent)
self.connect(self.cmdQuit, SIGNAL("clicked()"),self,
SLOT("close()"))
self.connect(self.cmd2, SIGNAL("clicked()"), self.reshuffle)
self.connect(self.cmdSort, SIGNAL("clicked()"), self.sort1)
self.connect(self.cmdBubble, SIGNAL("clicked()"), self.bubble)
self.connect(self.cmdRipple, SIGNAL("clicked()"), self.ripple)
self.connect(self.cmdShell, SIGNAL("clicked()"), self.shells)
self.refresh()

def reshuffle(self):
global cComp, cSwap, b1, b2, r1, r2
cComp, cSwap, b1, b2 = [0,0,0,len(l1)]
random.shuffle(l1)
self.refresh()

def sort1(self):
global cComp, cSwap, b1, b2, r1, r2
cComp, cSwap, b1, b2 = [0,0,0,len(l1)]
l1.sort()
self.refresh()

def bubble(self): # simple bubble sort
global cComp, cSwap, b1, b2, r1, r2
cComp, cSwap, b1, b2 = [0,0,0,len(l1)]
b1 = 0
b2 = len(l1)
for i in range(len(l1)):
b2 = len(l1) - i
for j in range(b2-1):
cComp = cComp + 1
r1 = j
r2 = j+1
if l1[r1] > l1[r2]:
cSwap = cSwap + 1
l1[r1], l1[r2] = [l1[r2], l1[r1]]
self.refresh()
time.sleep(0.02)

def ripple(self):
global cComp, cSwap, b1, b2, r1, r2
cComp, cSwap, b1, b2 = [0,0,0,len(l1)]
bDone =1
while bDone:
bDone = 0
for j in range(b1,b2-1):
cComp = cComp + 1
r1 = j
r2 = j + 1
if l1[r1] > l1[r2]:
cSwap = cSwap + 1
bDone = 1
l1[r1], l1[r2] = [l1[r2], l1[r1]]
self.refresh()
time.sleep(0.01)
b2 = b2 - 1
for j in range(b2,b1,-1):
cComp = cComp + 1
r1 = j - 1
r2 = j
if l1[r1] > l1[r2]:
cSwap = cSwap + 1
bDone = 1
l1[r1], l1[r2] = [l1[r2], l1[r1]]
self.refresh()
time.sleep(0.01)
b1 = b1 + 1
self.refresh()

def shells(self):
global cComp, cSwap, b1, b2, r1, r2
cComp, cSwap, b1, b2 = [0,0, 0, len(l1)]
bDone = 1
span = 64
while bDone:
bDone = 0
for i in range(b1,b2-span):
r1 = i
r2 = i + span
cComp = cComp + 1
if l1[r1] > l1[r2]:
cSwap = cSwap + 1
bDone = 1
l1[r1], l1[r2] = [l1[r2], l1[r1]]
self.refresh()
time.sleep(0.01)

if not bDone: # if no changes that sweep, exit
break
bDone = 0
if span > 1:
span = int(span/2)

for i in range(b2-1,b1+span,-1):
r1 = i - span
r2 = i
cComp = cComp + 1
if l1[r1] > l1[r2]:
cSwap = cSwap + 1
bDone = 1
l1[r1], l1[r2] = [l1[r2], l1[r1]]
self.refresh()
time.sleep(0.01)
if span > 1:
span = int(span/2)
self.refresh()

def refresh(self):
self.LCDcount.display('%3d' % cComp) # update counters
self.LCDswap.display('%3d' % cSwap)
self.frame4.erase() # clear any old lines
p = QPainter(self.frame4)
mar = self.frame4.width()/100 # margin
vsp = 2 # vertical spacing
hrz = (self.frame4.width()-2*mar)/100 # horizontal scalar
p.setPen(QColor("black"))
for i in range(100):
p.drawLine(mar,mar+vsp*i,hrz*(l1+1),mar+vsp*i)
p.setPen(QColor("blue"))
p.drawLine(mar,mar+vsp*b1-1,hrz*100,mar+vsp*b1-1)
p.drawLine(mar,mar+vsp*b2-1,hrz*100,mar+vsp*b2-1)
p.setPen(QColor("red"))
p.drawLine(mar,mar+vsp*r1+1,hrz*100,mar+vsp*r1+1)
p.drawLine(mar,mar+vsp*r2+1,hrz*100,mar+vsp*r2+1)

if __name__ == '__main__':
l1 = range(100) # numbers 0 to 99
b1 = 0 # blue line 1
b2 = 100 # blue line 2
r1 = 1 # red line 1
r2 = 1 # red line 2
cComp = 0 # count of compares
cSwap = 0 # count of swaps
app = QApplication(sys.argv)
QObject.connect(app, SIGNAL('lastWindowClosed()'),
app, SLOT('quit()'))
win = dlgForm()
app.setMainWidget(win)
win.show()
app.exec_loop()
-------------------------------------------------------


-------- frmtest.py --------------------------
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'frmtest.ui'
#
# Created: Sun Aug 1 15:55:11 2004
# by: The PyQt User Interface Compiler (pyuic) 3.8
#
# WARNING! All changes made in this file will be lost!

from qt import *

class frmTest(QMainWindow):
def __init__(self,parent = None,name = None,fl = 0):
QMainWindow.__init__(self,parent,name,fl)
self.statusBar()

if not name:
self.setName("frmTest")

self.setCentralWidget(QWidget(self,"qt_central_widget"))

self.frame4 = QFrame(self.centralWidget(),"frame4")
self.frame4.setGeometry(QRect(40,109,441,210))
self.frame4.setMinimumSize(QSize(440,210))
self.frame4.setFrameShape(QFrame.StyledPanel)
self.frame4.setFrameShadow(QFrame.Raised)
self.frame4.setMargin(1)

self.cmd2 = QPushButton(self.centralWidget(),"cmd2")
self.cmd2.setGeometry(QRect(210,330,100,50))

self.cmdSort = QPushButton(self.centralWidget(),"cmdSort")
self.cmdSort.setGeometry(QRect(350,330,100,50))

self.cmdQuit = QPushButton(self.centralWidget(),"cmdQuit")
self.cmdQuit.setGeometry(QRect(70,330,100,50))

self.txtHello = QLabel(self.centralWidget(),"txtHello")
self.txtHello.setGeometry(QRect(50,20,450,76))
txtHello_font = QFont(self.txtHello.font())
txtHello_font.setPointSize(48)
self.txtHello.setFont(txtHello_font)
self.txtHello.setAlignment(QLabel.AlignCenter)

self.cmdBubble = QPushButton(self.centralWidget(),"cmdBubble")
self.cmdBubble.setGeometry(QRect(500,109,80,40))

self.cmdRipple = QPushButton(self.centralWidget(),"cmdRipple")
self.cmdRipple.setGeometry(QRect(500,160,80,40))

self.cmdShell = QPushButton(self.centralWidget(),"cmdShell")
self.cmdShell.setGeometry(QRect(500,210,80,40))

self.txtCopyright = QLabel(self.centralWidget(),"txtCopyright")
self.txtCopyright.setGeometry(QRect(40,380,400,21))

self.LCDswap = QLCDNumber(self.centralWidget(),"LCDswap")
self.LCDswap.setGeometry(QRect(490,370,91,31))
self.LCDswap.setSegmentStyle(QLCDNumber.Flat)

self.LCDcount = QLCDNumber(self.centralWidget(),"LCDcount")
self.LCDcount.setGeometry(QRect(490,329,91,31))
self.LCDcount.setMode(QLCDNumber.Dec)
self.LCDcount.setSegmentStyle(QLCDNumber.Flat)

self.languageChange()

self.resize(QSize(603,438).expandedTo(self.minimumSizeHint()))
self.clearWState(Qt.WState_Polished)

def languageChange(self):
self.setCaption(self.__tr("test form"))
self.cmd2.setText(self.__tr("Reshuffle"))
self.cmdSort.setText(self.__tr("Sort"))
self.cmdQuit.setText(self.__tr("Quit"))
self.txtHello.setText(self.__tr("Sort Demo"))
self.cmdBubble.setText(self.__tr("Bubble"))
self.cmdRipple.setText(self.__tr("Ripple"))
self.cmdShell.setText(self.__tr("Shell"))
self.txtCopyright.setText(self.__tr("Copyright 2004 GPL Peter"))

def __tr(self,s,c = None):
return qApp.translate("frmTest",s,c)
---------------------------------------------------------
 
P

Phil Thompson

Yes - tried that, but gives incomplete draw / flicker.

There are lots of standard graphics techniques for eliminating flicker when
drawing that you can exploit with PyQt. Double buffering for example - draw
to a QPixmap and then blit it to the QWidget.

Phil
 
K

Ken Godee

Peter said:
Yes - tried that, but gives incomplete draw / flicker.

More details:
the idea is to provide a graphics demo of sort algorithms for my 13 year old
son. A number of lines of differring lengths are shown on the screen, and
you can watch as these are sorted, step by step. So you can see the
difference between bubble sort, ripple sort, etc.
Code copied below.
Improving the smoothness of the display is the main thing I'm after.


def refresh(self):
self.LCDcount.display('%3d' % cComp) # update counters
self.LCDswap.display('%3d' % cSwap)
self.frame4.erase() # clear any old lines
p = QPainter(self.frame4)
mar = self.frame4.width()/100 # margin
vsp = 2 # vertical spacing
hrz = (self.frame4.width()-2*mar)/100 # horizontal scalar
p.setPen(QColor("black"))
for i in range(100):
p.drawLine(mar,mar+vsp*i,hrz*(l1+1),mar+vsp*i)
p.setPen(QColor("blue"))
p.drawLine(mar,mar+vsp*b1-1,hrz*100,mar+vsp*b1-1)
p.drawLine(mar,mar+vsp*b2-1,hrz*100,mar+vsp*b2-1)
p.setPen(QColor("red"))
p.drawLine(mar,mar+vsp*r1+1,hrz*100,mar+vsp*r1+1)
p.drawLine(mar,mar+vsp*r2+1,hrz*100,mar+vsp*r2+1)


To me it would seem the problems lies in the refresh routine,
you're erasing and then redrawing, a viewed object, this will
cause it to flicker around, even worse if using sizers.
There's probally a better way to do this, but when I've
been faced with this type of problem here's what I would try
and maybe it will help you or give you a different way to
look at it.

I'd create a clone of frame4, maybe frame5, only viewing
one at a time.

In my refresh routine I'd create some type of loop
and alternate them using .hide() .show() and only
do my drawing/erasing on the hidden object.

I think anyway you do it, you should only draw/erase
on a hidden object, you could also have frame4 and 5
be the same, but in the routine that calls refresh, .hide()
4, .show() 5, refresh then redraws 4, and on returning from
refresh, .hide() 5, .show()4. Anyway I thing you get the idea.

Just something I'd try.
 
P

Peter

Phil said:
There are lots of standard graphics techniques for eliminating flicker
when drawing that you can exploit with PyQt. Double buffering for example
- draw to a QPixmap and then blit it to the QWidget.

ok - I don't know what QPixmap or blit are, but it gives me some clues to
use in google. :)

Thanks for your help

Peter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top