PyGTK FAQ Custom widget

Материал из Wiki.crossplatform.ru

(Различия между версиями)
Перейти к: навигация, поиск
(исправил название категории)
(Удалено по требованию автора...)
 
Строка 1: Строка 1:
-
Have you ever looked at an application and wondered, how a particular gui item was created?
 
-
Probably every wannabe programmer has. Then you were looking at a list of widgets provided by your favourite gui library. But you couldn't find it. Toolkits usually provide only the most common widgets like buttons, text widgets, sliders etc. No toolkit can provide all possible widgets.
 
-
There are actually two kinds of toolkits. Spartan toolkits and heavy weight toolkits.
 
-
The FLTK toolkit is a kind of a spartan toolkit. It provides only the very basic widgets and assumes, that the programemer will create the more complicated ones himself. wxWidgets is a heavy weight one.
 
-
It has lots of widgets. Yet it does not provide the more specialized widgets. For example a speed meter widget, a widget that measures the capacity of a CD to be burned (found e.g. in nero). Toolkits also don't have usually charts.
 
-
Programmers must create such widgets by themselves. They do it by using the drawing tools provided by the toolkit.
 
-
There are two possibilities. A programmer can modify or enhance an existing widget.
 
-
Or he can create a custom widget from scratch.
 
-
== Burning widget ==
 
-
This is an example of a widget, that we create from scratch. This widget can be found in various media burning applications, like Nero Burning ROM.
 
-
<source lang="python">
 
-
#!/usr/bin/python
 
-
# ZetCode PyGTK tutorial
 
-
#
 
-
# This example creates a burning
 
-
# custom widget
 
-
#
 
-
# author: jan bodnar
 
-
# website: zetcode.com
 
-
# last edited: February 2009
 
-
 
-
import gtk
 
-
import cairo
 
-
 
-
class Burning(gtk.DrawingArea):
 
-
 
-
    def __init__(self, parent):
 
-
        self.par = parent
 
-
        super(Burning, self).__init__()
 
-
 
-
        self.num = ( "75", "150", "225", "300",
 
-
            "375", "450", "525", "600", "675" )
 
-
 
-
        self.set_size_request(-1, 30)
 
-
        self.connect("expose-event", self.expose)
 
-
   
 
-
 
-
    def expose(self, widget, event):
 
-
        cr = widget.window.cairo_create()
 
-
        cr.set_line_width(0.8)
 
-
 
-
        cr.select_font_face("Courier",
 
-
            cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
 
-
        cr.set_font_size(11)
 
-
 
-
        width = self.allocation.width
 
-
   
 
-
        self.cur_width = self.par.get_cur_value()
 
-
 
-
        step = round(width / 10.0)
 
-
 
-
        till = (width / 750.0) * self.cur_width
 
-
        full = (width / 750.0) * 700
 
-
 
-
        if (self.cur_width >= 700):
 
-
           
 
-
            cr.set_source_rgb(1.0, 1.0, 0.72)
 
-
            cr.rectangle(0, 0, full, 30)
 
-
            cr.clip()
 
-
            cr.paint()
 
-
            cr.reset_clip()
 
-
           
 
-
            cr.set_source_rgb(1.0, 0.68, 0.68)
 
-
            cr.rectangle(full, 0, till-full, 30)
 
-
            cr.clip()
 
-
            cr.paint()
 
-
            cr.reset_clip()
 
-
 
-
        else:   
 
-
            cr.set_source_rgb(1.0, 1.0, 0.72)
 
-
            cr.rectangle(0, 0, till, 30)
 
-
            cr.clip()
 
-
            cr.paint()
 
-
            cr.reset_clip()
 
-
     
 
-
 
-
        cr.set_source_rgb(0.35, 0.31, 0.24)
 
-
       
 
-
        for i in range(1, len(self.num) + 1):
 
-
            cr.move_to(i*step, 0)
 
-
            cr.line_to(i*step, 5)
 
-
            cr.stroke()
 
-
           
 
-
            (x, y, width, height, dx, dy) = cr.text_extents(self.num[i-1])
 
-
            cr.move_to(i*step-width/2, 15)
 
-
            cr.text_path(self.num[i-1])
 
-
            cr.stroke()
 
-
     
 
-
class PyApp(gtk.Window):
 
-
    def __init__(self):
 
-
        super(PyApp, self).__init__()
 
-
       
 
-
        self.set_title("Burning")
 
-
        self.set_size_request(350, 200)       
 
-
        self.set_position(gtk.WIN_POS_CENTER)
 
-
        self.connect("destroy", gtk.main_quit)
 
-
 
-
        self.cur_value = 0
 
-
     
 
-
        vbox = gtk.VBox(False, 2)
 
-
       
 
-
        scale = gtk.HScale()
 
-
        scale.set_range(0, 750)
 
-
        scale.set_digits(0)
 
-
        scale.set_size_request(160, 35)
 
-
        scale.set_value(self.cur_value)
 
-
        scale.connect("value-changed", self.on_changed)
 
-
               
 
-
        fix = gtk.Fixed()
 
-
        fix.put(scale, 50, 50)
 
-
       
 
-
        vbox.pack_start(fix)
 
-
       
 
-
        self.burning = Burning(self)
 
-
        vbox.pack_start(self.burning, False, False, 0)
 
-
 
-
        self.add(vbox)
 
-
        self.show_all()
 
-
       
 
-
       
 
-
    def on_changed(self, widget):
 
-
        self.cur_value = widget.get_value()
 
-
        self.burning.queue_draw()
 
-
   
 
-
   
 
-
    def get_cur_value(self):
 
-
        return self.cur_value
 
-
   
 
-
 
-
PyApp()
 
-
gtk.main()
 
-
</source>
 
-
 
-
We put a <b>DrawingArea</b> on the bottom of the window and draw the entire widget manually. All the important code resides in the <b>expose()</b> method of the Burning class. This widget shows graphically the total capacity of a medium and the free space available to us. The widget is controlled by a scale widget. The minimum value of our custom widget is 0, the maximum is 750. If we reach value 700, we began drawing in red colour. This normally indicates overburning. 
 
-
 
-
<source lang="python">
 
-
self.num = ( "75", "150", "225", "300",
 
-
    "375", "450", "525", "600", "675" )
 
-
</source>
 
-
 
-
These numbers are shown on the burning widget. They show the capacity of the medium.
 
-
 
-
<source lang="python">
 
-
self.cur_width = self.par.get_cur_value()
 
-
</source>
 
-
 
-
These two lines get the current number from the scale widget. We get the parent widget and from the parent widget, we get the current value.
 
-
 
-
<source lang="python">
 
-
till = (width / 750.0) * self.cur_width
 
-
full = (width / 750.0) * 700
 
-
</source>
 
-
 
-
The till parameter determines the total size to be drawn. This value comes from the slider widget.  It is a proportion of the whole area. The full parameter determines the point, where we begin to draw in red color.
 
-
 
-
<source lang="python">
 
-
cr.set_source_rgb(1.0, 1.0, 0.72)
 
-
cr.rectangle(0, 0, till, 30)
 
-
cr.clip()
 
-
cr.paint()
 
-
cr.reset_clip()
 
-
 
-
</source>
 
-
 
-
This code here, draws a yellow rectangle up to point, where the medium is full.
 
-
 
-
<source lang="python">
 
-
(x, y, width, height, dx, dy) = cr.text_extents(self.num[i-1])
 
-
cr.move_to(i*step-width/2, 15)
 
-
cr.text_path(self.num[i-1])
 
-
cr.stroke()
 
-
</source>
 
-
 
-
This code here draws the numbers on the burning widget. We calculate the
 
-
<b>TextExtents</b> to position the text correctly.
 
-
 
-
<source lang="python">
 
-
def on_changed(self, widget):
 
-
    self.cur_value = widget.get_value()
 
-
    self.burning.queue_draw()
 
-
</source>
 
-
 
-
We get the value from the scale widget, store it in the <b>cur_value</b> variable for later use. We redraw the burning widget.
 
-
 
-
[[image: pygtk_faq_burning.png | center]]
 
-
 
-
In this chapter, we created a custom widget in PyGTK.
 
-
 
-
[[Категория:Python]]
 
-
[[Категория:GTK+]]
 

Текущая версия на 11:26, 7 апреля 2009