chuong nguyen vien <[email protected]>:
> Hello,
>
> I have just played with pygtk a couple of day and everything seems ok but the
> drawing system. I dont know how it works basically and got confused, very
> confused !
>
> I read somewhere on the internet it say that i have to follow a pattern to
> make it work, and the key to that pattern is : we need to implement the
> drawing code within the expose event handler. Why ?
>
> I tried to make some drawing code outside the expose event handler, and didnt
> write a expose event handler at all. It didnt work. It just appear a window
> without anything, or my drawing stuff didnt display.
>
> So basically, how the expose event and drawing in GTK work or relate to each
> other ?
>
> Thanks
>
> Chuong
Here's the canvas-management class I wrote for the GPSD test client. You
may be able to use it as a model. Note how (a) all the actual drawing
is done in the expose event, (b) redrawing is implemented with the
queue_draw() method, (c) the canvas's actual size allocation
is picked up for later use in the on_size_allocate event.
class SkyView(gtk.DrawingArea):
"Satellite skyview, encapsulates pygtk's draw-on-expose behavior."
# See <http://faq.pygtk.org/index.py?req=show&file=faq18.008.htp>
HORIZON_PAD = 20 # How much whitespace to leave around horizon
SAT_RADIUS = 5 # Diameter of satellite circle
GPS_PRNMAX = 32 # above this number are SBAS satellites
def __init__(self):
gtk.DrawingArea.__init__(self)
self.set_size_request(400, 400)
self.gc = None # initialized in realize-event handler
self.width = 0 # updated in size-allocate handler
self.height = 0 # updated in size-allocate handler
self.connect('size-allocate', self.on_size_allocate)
self.connect('expose-event', self.on_expose_event)
self.connect('realize', self.on_realize)
self.pangolayout = self.create_pango_layout("")
self.satellites = []
def on_realize(self, widget):
self.gc = widget.window.new_gc()
self.gc.set_line_attributes(1, gtk.gdk.LINE_SOLID,
gtk.gdk.CAP_ROUND, gtk.gdk.JOIN_ROUND)
def on_size_allocate(self, widget, allocation):
self.width = allocation.width
self.height = allocation.height
self.diameter = min(self.width, self.height) - SkyView.HORIZON_PAD
def set_color(self, spec):
"Set foreground color for drawing."
self.gc.set_rgb_fg_color(gtk.gdk.color_parse(spec))
def draw_circle(self, widget, x, y, diam, filled=False):
"Draw a circle centered on the specified midpoint."
widget.window.draw_arc(self.gc, filled,
x - diam / 2, y - diam / 2,
diam, diam, 0, 360 * 64)
def draw_square(self, widget, x, y, diam, filled=False):
"Draw a square centered on the specified midpoint."
widget.window.draw_rectangle(self.gc, filled,
x - diam / 2, y - diam / 2,
diam, diam)
def draw_string(self, widget, x, y, letter):
"Draw a letter on the skyview."
self.pangolayout.set_text(letter)
# FIXME: When the layout object can report its size, use it
self.window.draw_layout(self.gc, x-5, y-10, self.pangolayout)
def pol2cart(self, az, el):
"Polar to Cartesian coordinates within the horizon circle."
az *= (math.pi/180) # Degrees to radians
# Exact spherical projection would be like this:
# el = sin((90.0 - el) * DEG_2_RAD);
el = ((90.0 - el) / 90.0);
xout = int((self.width / 2) + math.sin(az) * el * (self.diameter / 2))
yout = int((self.height / 2) - math.cos(az) * el * (self.diameter / 2))
return (xout, yout)
def on_expose_event(self, widget, event):
self.set_color("white")
widget.window.draw_rectangle(self.gc, True, 0,0, self.width,self.height)
# The zenith marker
self.set_color("gray")
self.draw_circle(widget, self.width / 2, self.height / 2, 6)
# The circle corresponding to 45 degrees elevation.
# There are two ways we could plot this. Projecting the sphere
# on the display plane, the circle would have a diameter of
# sin(45) ~ 0.7. But the naive linear mapping, just splitting
# the horizon diameter in half, seems to work better visually.
self.draw_circle(widget, self.width / 2, self.height / 2,
int(self.diameter * 0.5))
self.set_color("black")
# The horizon circle
self.draw_circle(widget, self.width / 2, self.height / 2,
self.diameter)
# The compass-point letters
(x, y) = self.pol2cart(0, 0)
self.draw_string(widget, x, y+10, "N")
(x, y) = self.pol2cart(90, 0)
self.draw_string(widget, x-10, y, "E")
(x, y) = self.pol2cart(180, 0)
self.draw_string(widget, x, y-10, "S")
(x, y) = self.pol2cart(270, 0)
self.draw_string(widget, x+10, y, "W")
# The satellites
for sat in self.satellites:
(x, y) = self.pol2cart(sat.azimuth, sat.elevation)
if sat.ss < 10:
self.set_color("Black")
elif sat.ss < 30:
self.set_color("Red")
elif sat.ss < 35:
self.set_color("Yellow");
elif sat.ss < 40:
self.set_color("Green3");
else:
self.set_color("Green1");
if sat.PRN > SkyView.GPS_PRNMAX:
self.draw_square(widget,
x-SkyView.SAT_RADIUS, y-SkyView.SAT_RADIUS,
2 * SkyView.SAT_RADIUS + 1, sat.used);
else:
self.draw_circle(widget,
x-SkyView.SAT_RADIUS, y-SkyView.SAT_RADIUS,
2 * SkyView.SAT_RADIUS + 1, sat.used);
self.set_color("Black")
self.draw_string(widget, x, y+10, str(sat.PRN))
def redraw(self, satellites):
"Redraw the skyview."
self.satellites = satellites
self.queue_draw()
--
<a href="http://www.catb.org/~esr/">Eric S. Raymond</a>
_______________________________________________
pygtk mailing list [email protected]
http://www.daa.com.au/mailman/listinfo/pygtk
Read the PyGTK FAQ: http://faq.pygtk.org/