[pygtk] Doc/tutorial on creating custom widgets
Mitko Haralanov
mitko at qlogic.com
Sat Apr 5 05:31:26 WST 2008
On Fri, 4 Apr 2008 13:02:47 -0700
Mitko Haralanov <mitko at qlogic.com> wrote:
> If I understand the mechanics correctly, what I will have to do is make
> a custom "clicked" handler that gets the coordinates of the mouse when
> a click occurs, if they are within the frame of the checkbutton, act on
> the checkbutton, otherwise call the "clicked" callback.
For those that might be interested, here is what I came up with that
works as I want it to (well, almost). I do have to manually tweak the
pointer coordinates since I can't correctly compute the coordinates of
the checkbox (self.chk.get_parent_window() returns None). Also, I wish
I could have the CheckButton be only the check box instead of the check
box and the space allocated to the label, but I guess it's better then
nothing.
#!/usr/bin/python
import pygtk
pygtk.require("2.0")
import gtk
import gobject
class Size:
def __init__ (self, x=0, y=0, w=0, h=0):
self.x = x
self.y = y
self.width = w
self.height = h
self.x_end = self.x + self.width
self.y_end = self.y + self.height
def __repr__ (self):
return "<Size x=%d, y=%d, width=%d, heigh=%d>"%(self.x, self.y, \
self.width, self.height)
def __str__ (self):
return self.__repr__ ()
class Button (gtk.Button):
def __init__ (self, label=None):
gtk.Button.__init__ (self)
self.label = label
self.callback = None
self.user_data = None
vbox = gtk.VBox ()
self.chk = gtk.CheckButton ("Select")
self.label = gtk.Label (self.label)
vbox.pack_start (self.label)
vbox.pack_start (self.chk, False)
self.add (vbox)
def widget_coords (self, widget):
allocation = widget.get_allocation ()
window = widget.get_parent_window ()
if not window:
# When 'widget' is self.chk, 'window' is
# None, so let's use the button
window = self.get_parent_window ()
x, y = window.get_root_origin ()
w, h = window.get_size ()
extents = window.get_frame_extents ()
coord = Size ()
coord.x = x + (extents.width-w)/2 + allocation.x
coord.y = y + (extents.height-h)-(extents.width-w)/2 + allocation.y
coord.width = allocation.width
coord.height = allocation.height
coord.x_end = coord.x + coord.width
coord.y_end = coord.y + coord.height
return coord
def do_realize (self):
gtk.Button.do_realize (self)
# try to get the coordinates of the checkbutton
self.chk_coord = self.widget_coords (self.chk)
self.add_events (gtk.gdk.BUTTON_PRESS_MASK | \
gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.POINTER_MOTION_HINT_MASK)
self.connect ("motion-notify-event", self.motion_notify_event)
def connect (self, signal, callback, *user_data):
if signal == "clicked":
self.callback = callback
self.user_data = user_data
gtk.Button.connect (self, signal, self.clicked_handler)
else:
gtk.Button.connect (self, signal, callback, *user_data)
return
def clicked_handler (self, button, *user_data):
if self.pointer_x >= self.chk_coord.x and \
self.pointer_x <= self.chk_coord.x_end and \
self.pointer_y >= self.chk_coord.y and \
self.pointer_y <= self.chk_coord.y_end:
self.chk.set_active (not self.chk.get_active ())
return False
else:
return self.callback (button, *self.user_data)
return
def motion_notify_event(self, widget, event):
# if this is a hint, then let's get all the necessary
# information, if not it's all we need.
if event.is_hint:
self.pointer_x, self.pointer_y, state = event.window.get_pointer()
else:
self.pointer_x = event.x
self.pointer_y = event.y
state = event.state
# Since I can't compute the coordinates of the checkbutton correctly
# I have to tweak the pointer coordinates
self.pointer_x += 5
self.pointer_y += 5
self.chk_coords = self.widget_coords (self.chk)
return False
def c (widget, *user_data):
print "c:", widget, user_data
if __name__ == "__main__":
gobject.type_register (Button)
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.set_border_width(10)
bcb = Button ("Checktext")
bcb.connect ("clicked", c)
window.add(bcb)
window.connect("delete-event", gtk.main_quit)
window.show_all()
gtk.main()
--
Mitko Haralanov
==========================================
Computer programmers do it byte by byte.
More information about the pygtk
mailing list