[pygtk] custom cairo widget
saeed
saeed.gnu at gmail.com
Sat Sep 5 22:42:05 WST 2009
That's cool...
I applied what Pietro wrote, and added pointer motion (dragging circle)
Also no need to get pointer and flag. event argument itself has these
data (event.x, event.y, event.button)
And 180 should be changed to 190 (symmetrization: 10 to 190, OR 20 to 180)
_______________________________________
''' Custom slider '''
import gtk, cairo
from math import pi
def draw_widget(context, x, y, w, h, color=(0.0, 0.0, 0.0), radius=5):
''' nakresli obdelnik s radiusy '''
cr = context
cr.set_source_rgb(0.3, 0.4, 0.2)
arc2bezier = 0.55228475
if radius > w - radius: radius = w / 2
elif radius > h - radius: radius = h / 2
c1 = arc2bezier * radius
c2 = arc2bezier * radius
cr.new_path()
cr.move_to( x + radius, y)
cr.rel_line_to(w - 2 * radius, 0.0)
cr.rel_curve_to(c1, 0.0, radius, c2, radius, radius)
cr.rel_line_to(0, h - 2 * radius)
cr.rel_curve_to(0.0, c2, c1 - radius, radius, -radius, radius)
cr.rel_line_to(-w + 2 * radius, 0)
cr.rel_curve_to(-c1, 0, -radius, -c2, -radius, -radius)
cr.rel_line_to(0, -h + 2 * radius)
cr.rel_curve_to(0.0, -c2, radius - c1, -radius, radius, -radius)
cr.close_path()
cr.stroke_preserve()
cr.set_source_rgb(color[0], color[1], color[2])
cr.fill()
class App:
def __init__(self):
self.wnd = gtk.Window()
self.wnd.set_border_width(5)
self.wnd.connect('destroy', lambda x: gtk.main_quit())
self.area = gtk.DrawingArea()
self.area.set_size_request(32, 200)
self.area.add_events(gtk.gdk.POINTER_MOTION_MASK |
gtk.gdk.BUTTON_PRESS_MASK)
self.area.connect('expose-event', self.expose)
self.area.connect('button-press-event', self.button_press)
self.area.connect('motion-notify-event', self.motion_notify)
self.wnd.add(self.area)
self.wnd.show_all()
self.old_y = 10
def expose(self, widget, event):
#print event.type
ctx = widget.window.cairo_create()
ctx.set_line_width(3)
draw_widget(ctx, 10, 10, 8, 180, radius=10)
ctx.set_source_rgb(0.5, 0.5, 0.5)
ctx.arc(14, self.old_y, 9, 0, 2 * pi)
ctx.stroke_preserve()
ctx.set_source_rgb(1.0, 0.0, 0.0)
ctx.fill()
def button_press(self, widget, event):
posx = event.x
posy = event.y
if event.button==1:
if posx > 5 and posx < 15:
if posy < 10: posy = 10
if posy > 190: posy = 190 ## 190, not 180 (because the
center of circle may be in slider)
self.old_y = posy
self.area.queue_draw()
def motion_notify(self, widget, event):
posy = event.y
if event.state & gtk.gdk.BUTTON1_MASK:
if posy < 10: posy = 10
if posy > 190: posy = 190 ## 190, not 180 (because the
center of circle may be in slider)
self.old_y = posy
self.area.queue_draw()
APP = App()
gtk.main()
______________________________
On 9/5/09, Pietro Battiston <toobaz at email.it> wrote:
> Il giorno sab, 05/09/2009 alle 12.22 +0200, M.B. ha scritto:
>> hi all,
>> im trying write my first custom widget.
>> its cairo slider. on my first look im happy :) but i know that code is
>> ugly. if this code running, Xorg is on 50% and python thread is on 49%
>> CPU !!!. ( using 'top' in console ).
>> Kick me to the right way with this code snipet pls.
>> where is error ? Why too much cpu power ?
>>
>> PS: sry for my english.
>
> Your mistake is that you continuously redraw, since "expose" calls
> "queue_redraw" which (almost immediately) calls (it's its job) "expose".
> This way, you have live animation, but you spend _all_ the time drawing.
> And indeed, notice you aren't using at all events for mouse, which
> however you did register (with self.area.add_events)!
>
> For this widget, you need _two_ handlers:
> - a handler for expose which _just draws_
> - a handler for pointer click and/or movement which updates self.old_y,
> and then calls queue_redraw
>
> bye
>
> Pietro
>
More information about the pygtk
mailing list