IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

GTK+ avec Python Discussion :

[TreeView]comment créer son propre CellRenderer ?


Sujet :

GTK+ avec Python

  1. #1
    Membre émérite
    Homme Profil pro
    heu...
    Inscrit en
    Octobre 2007
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : heu...

    Informations forums :
    Inscription : Octobre 2007
    Messages : 648
    Par défaut [TreeView]comment créer son propre CellRenderer ?
    Salut,

    Voilà, il se trouve que j'aimerais sous-classer gtk.CellRendererPixbuf, de façon à ce que, si l'on clique dessus, une liste d'entrées (à la facon d'un CellRendererCombo) apparaisse, et que ces entrée soit affichée sous forme d'images (pixbuf donc).

    Je me suis dis qu'en premier lieu, savoir créer une ComboBox personalisée pour n'afficher que des images (alors que les données stockées dans le model sont des noms d'images), serait un premier pas. C'est chose faite.
    Custom_ComboBox.zip(ignorez la class TreeView)

    Maintenant, le plus dur, c'est que je ne sais pas vraiment comment procéder pour parvenir au résultat voulu... Le sauriez-vous ?

    Je vais continuer à chercher de mon côté, mais si vous savez comment faire, vous me feriez gagner un temps précieux

  2. #2
    Membre émérite
    Homme Profil pro
    heu...
    Inscrit en
    Octobre 2007
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : heu...

    Informations forums :
    Inscription : Octobre 2007
    Messages : 648
    Par défaut
    He bien j'ai fini par y arriver .

    Voici la documentation que j'ai trouvé (merci le cache de google ):
    13.41. How do I show a GtkImage (even animations) in a treeview? (subclassing GtkCellRenderer)

    Here is a cellrenderer that allows to put a gtk.Image in your TreeStore :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    class CellRendererImage(gtk.GenericCellRenderer):
     
       __gproperties__ = {
          "image": (gobject.TYPE_OBJECT, "Image",
          "Image", gobject.PARAM_READWRITE),
       }
     
       def __init__(self):
          self.__gobject_init__()
          self.image = None
     
       def do_set_property(self, pspec, value):
          setattr(self, pspec.name, value)
     
       def do_get_property(self, pspec):
          return getattr(self, pspec.name)
     
       def func(self, model, path, iter, (image, tree)):
          if model.get_value(iter, 0) == image:
             self.redraw = 1
             cell_area = tree.get_cell_area(path, tree.get_column(0))
             tree.queue_draw_area(cell_area.x, cell_area.y, cell_area.width, \
     
                cell_area.height)
     
       def animation_timeout(self, tree, image):
          if image.get_storage_type() == gtk.IMAGE_ANIMATION:
             self.redraw = 0
             image.get_data('iter').advance()
             model = tree.get_model()
             model.foreach(self.func, (image, tree))
             if self.redraw:
                gobject.timeout_add(image.get_data('iter').get_delay_time(), \
                   self.animation_timeout, tree, image)
             else:
                image.set_data('iter', None)
     
       def on_render(self, window, widget, background_area,cell_area, \
          expose_area, flags):
          if not self.image:
             return
          pix_rect = gtk.gdk.Rectangle()
          pix_rect.x, pix_rect.y, pix_rect.width, pix_rect.height = \
             self.on_get_size(widget, cell_area)
     
          pix_rect.x += cell_area.x
          pix_rect.y += cell_area.y
          pix_rect.width  -= 2 * self.get_property("xpad")
          pix_rect.height -= 2 * self.get_property("ypad")
     
          draw_rect = cell_area.intersect(pix_rect)
          draw_rect = expose_area.intersect(draw_rect)
     
          if self.image.get_storage_type() == gtk.IMAGE_ANIMATION:
     
             if not self.image.get_data('iter'):
                animation = self.image.get_animation()
                self.image.set_data('iter', animation.get_iter())
                gobject.timeout_add(self.image.get_data('iter').get_delay_time(), \
                   self.animation_timeout, widget, self.image)
     
             pix = self.image.get_data('iter').get_pixbuf()
          elif self.image.get_storage_type() == gtk.IMAGE_PIXBUF:
             pix = self.image.get_pixbuf()
          else:
             return
          window.draw_pixbuf(widget.style.black_gc, pix, \
             draw_rect.x-pix_rect.x, draw_rect.y-pix_rect.y, draw_rect.x, \
             draw_rect.y+2, draw_rect.width, draw_rect.height, \
             gtk.gdk.RGB_DITHER_NONE, 0, 0)
     
       def on_get_size(self, widget, cell_area):
          if not self.image:
             return 0, 0, 0, 0
          if self.image.get_storage_type() == gtk.IMAGE_ANIMATION:
             animation = self.image.get_animation()
             pix = animation.get_iter().get_pixbuf()
          elif self.image.get_storage_type() == gtk.IMAGE_PIXBUF:
             pix = self.image.get_pixbuf()
          else:
             return 0, 0, 0, 0
          pixbuf_width  = pix.get_width()
          pixbuf_height = pix.get_height()
          calc_width  = self.get_property("xpad") * 2 + pixbuf_width
          calc_height = self.get_property("ypad") * 2 + pixbuf_height
          x_offset = 0
          y_offset = 0
          if cell_area and pixbuf_width > 0 and pixbuf_height > 0:
             x_offset = self.get_property("xalign") * (cell_area.width - \
                calc_width -  self.get_property("xpad"))
             y_offset = self.get_property("yalign") * (cell_area.height - \
                calc_height -  self.get_property("ypad"))
          return x_offset, y_offset, calc_width, calc_height
    Don't forget to register this class with:
    gobject.type_register(CellRendererImage)
    Then use it as another cellrenderer:
    col = gtk.TreeViewColumn()
    cell = CellRendererImage()
    col.pack_start(cell, False)
    col.add_attribute(cell, 'image', 0)
    Edit this entry / Log info / Last changed on Wed May 4 07:36:11 2005 by Nikos Kouremenos (kourem@gmail.com)


    13.45. How do I create a custom gtk.CellRenderer?

    In order to render custom objects in TreeViews you have to subclass the gtk.GenericCellRenderer class and register it.
    The following example shows a CellRenderer for a custom object.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    class CellRendererCustom(gtk.GenericCellRenderer):
            __gproperties__ = {
                    "custom": (gobject.TYPE_OBJECT, "Custom",
                    "Custom", gobject.PARAM_READWRITE),
            }
     
            def __init__(self):
                    self.__gobject_init__()
                    self.custom = None
     
            def do_set_property(self, pspec, value):
                    setattr(self, pspec.name, value)
     
            def do_get_property(self, pspec):
                    return getattr(self, pspec.name)
     
            def on_render(self, window, widget, background_area, cell_area, expose_area, flags):
                    self.custom.draw(window, widget, cell_area.x, cell_area.y)
     
            def on_get_size(self, widget, cell_area=None):
                    return (0, 0, self.custom.get_width(), self.custom.get_height())
     
     gobject.type_register(CellRendererCustom)
    Note that in order to use the custom object in e. g. a ListStore you'll have to subclass it from gobject.GObject and register it properly.
    Notice however that in more recent pygtk versions it is possible to subclass a predefined CellRenderer type instead of starting from scratch from GenericCellRenderer; in this case you just have to overwrite methods of the form do_*: for instance the following creates a CellRenderer for text which cells twice as big as normal:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class CellRendererBig(gtk.CellRendererText):
     
         def __init__(self):
             gtk.CellRendererText.__init__(self)
     
         def do_get_size(self, widget, cell_area):
             # We start from the standard dimension...
             size_tuple = gtk.CellRendererText.do_get_size(self, widget, cell_area)
             size = [item * 2 for item in size_tuple]
             return tuple(size)      
     
     gobject.type_register(CellRendererBig)
    Jiri Bajer: draw() method in on_render is deprecated - use self.widget.window.draw_rectangle() instead. See [www.mail-archive.com] for details.
    Edit this entry / Log info / Last changed on Sun Aug 16 12:52:07 2009 by Jiri Bajer (sarimak@seznam.cz)


    13.55. How do I enable editing of CellRendererProgress?

    CellRendererProgress has no 'editable' property and doesn't emit 'edited' signal - this renderer can only display the value, not edit. You have two options how to edit the value displayed:
    1) easy: share a model column between CellRendererProgress and CellRendererSpin

    this method has a disadvantage of having two columns with the same value displayed

    2) harder: subclass CellRendererProgress and add the editing capability to it

    see FAQ 13.45 for hints on subclassing a CellRenderer and FAQ 6.1 for subclassing a GObject

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    class CellRendererProgressEditable(gtk.CellRendererProgress):
     
    	__gproperties__ = { 'editable': ( gobject.TYPE_BOOLEAN, 'editable', 'is editable?', False, gobject.PARAM_READWRITE ) }
     
    	__gsignals__ = { 'edited': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_FLOAT )),
    			 'editing-done': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_STRING,)) }
     
    	__gtype_name__ = 'CellRendererProgressEditable'
     
    	def __init__(self):
    		gtk.CellRendererProgress.__init__(self)
    		self.set_property('mode', gtk.CELL_RENDERER_MODE_EDITABLE)
     
    	def do_get_property(self, pspec):
    		return getattr(self, pspec.name)
     
    	def do_set_property(self, pspec, value):
    		setattr(self, pspec.name, value)
     
    	def do_start_editing(self, event, treeview, path, background_area, cell_area, flags):
    		if not self.get_property('editable'):
    			return
    		adjustment = gtk.Adjustment(value=self.get_property('value'), lower=0, upper=100, step_incr=1, page_incr=10)
    		spin = gtk.SpinButton(adjustment)
    		spin.connect('editing-done', self.editing_done, path)
    		spin.connect('key-press-event', self.key_press_event, path)
    		spin.show()
    		spin.grab_focus()
    		return spin
     
    	def editing_done(self, spin, path):
    		self.emit('edited', path, spin.get_property('value'))
     
    	def key_press_event(self, spin, event, path):
    		if event.type == gtk.gdk.KEY_PRESS:
    			if gtk.gdk.keyval_name(event.keyval) == 'Up':
    				spin.spin(gtk.SPIN_STEP_FORWARD)
    				return True
    			if gtk.gdk.keyval_name(event.keyval) == 'Down':
    				spin.spin(gtk.SPIN_STEP_BACKWARD)
    				return True
    'editable' property and 'edited' signal work in the same fashion as for CellRendererText and others
    'start-editing' signal is internal and occurs after user doubleclicks on a cell (or presses space/enter). We have to create and display a gtk.Editable and wait for user to edit the value. By default the TreeView would 'eat' signals for Up and Down arrows - we have to catch them and handle on our own (and notify the parent we have already handled the signals - see return True).

    'editing-done' signal is internal and occurs after user finishes editing in our SpinButton. All we have to do is emit the standard 'edited' signal and let the end user to handle it.
    Et voici mon code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    import pygtk,os; pygtk.require('2.0')
    import gtk, gobject
     
    ICONS=dict([(name,gtk.image_new_from_file(name)) for name in os.listdir('./') if name[-4:]=='.ico'])
     
    class Window(gtk.Window):
        def __init__(s):
            gtk.Window.__init__(s)
            s.set_title('Basic TreeView Example')
            s.set_size_request(200,200)
            s.connect('delete_event', s.quit)
            s.ts = ListStore()
            s.tv = TreeView(s.ts)
            s.add(s.tv)
            s.show_all()
        def quit(s,w,e,data=None):
            gtk.main_quit()
        def main(s):
            gtk.main()
     
    class ListStore(gtk.ListStore):
        def __init__(s):
            gtk.ListStore.__init__(s,str)
            for x in range(4):
                s.append([ICONS.keys()[0]])
     
    class TreeView(gtk.TreeView):
        def __init__(s,model):
            gtk.TreeView.__init__(s,model)
            s.model         = model
            s.columns = [gtk.TreeViewColumn('Icons')]
            s.cells   = [CellRendererPixCombo()]
            for idx,col in enumerate(s.columns) :
                s.append_column(col)
                col.pack_start(s.cells[idx],True)
            s.columns[0].set_cell_data_func(s.cells[0], s.data_pixbuf_func)
            s.cells[0].set_property('editable', True)
            s.cells[0].connect('edited', s.on_edited)
            s.columns[0].set_sort_column_id(0)
        def data_pixbuf_func(s,col,cell,model,iter,data=None):
            icon_name = model.get_value(iter,0)
            if icon_name is not None:
                pb = ICONS[icon_name].get_pixbuf()
                cell.set_property('pixbuf', pb)
        def on_edited(s, cell, path, new_text, *data):
            print 'edited',new_text, type(new_text)
            model,iter=s.get_selection().get_selected()
            model.set_value(iter,0, new_text)
     
    class CellRendererPixCombo(gtk.CellRendererPixbuf):
        __gproperties__ = {'editable':(gobject.TYPE_BOOLEAN, 'editable', 'is editable?', True, gobject.PARAM_READWRITE)}
        __gsignals__    = {'edited': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_STRING)),\
                           'editing-done': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_STRING,)) }
        __gtype_name__  = 'CellRendererPixCombo'
        def __init__(s):
            gtk.CellRendererPixbuf.__init__(s)
            print s.get_property('mode'), 'changed to',
            s.set_property('mode',gtk.CELL_RENDERER_MODE_EDITABLE)
            print s.get_property('mode')
        def do_get_property(s,pspec):
            return getattr(s, pspec.name)
        def do_set_property(s,pspec,v):
            setattr(s,pspec.name,v)
        def do_start_editing(s, evt, treeview, path, background_area, cell_area, flags):
            print 'start editing', s.get_property('editable')
            if not s.get_property('editable'): return
            combo = ComboBox()
            combo.connect('editing-done',s.editing_done, path)
            combo.show()
            combo.grab_focus()
            return combo
        def editing_done(s, combo, path):
            s.emit('edited', path, combo.get_active_text())
    gobject.type_register(CellRendererPixCombo)
     
    class ComboBox(gtk.ComboBox):
        def __init__(s):
            s.model = s._listStore()
            gtk.ComboBox.__init__(s,s.model)
            s.cell  = gtk.CellRendererPixbuf()
            s.pack_start(s.cell,False)
            s.set_cell_data_func(s.cell, s.data_func)
            #s.connect('changed',s.on_changed)
        def data_func(s, celllayout, cell, model, iter, data=None):
            pb = ICONS[model.get_value(iter,0)].get_pixbuf()
            cell.set_property('pixbuf',pb)
        def on_changed(s, cb, *data):
            print s.get_active_text()#s.model[s.get_active()]
        def _listStore(s):
            lst = gtk.ListStore(str)
            for name in sorted(ICONS.keys()):
                lst.append([name])
            return lst
     
     
    if __name__=='__main__':
        app=Window()
        app.main()
    NB : pour utiliser un widget en tant qu'"éditeur" il faut que ce dernier implemente l'interface gtk.CellEditable, cec est signalé dans les docs des références, ex
    Citation Envoyé par PyGTK references
    Implemented Interfaces

    gtk.ComboBox implements gtk.Buildable atk.ImplementorIFace gtk.CellEditable gtk.CellLayout

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 14
    Dernier message: 15/01/2014, 15h37
  2. Comment créer son propre Widget Gtkmm?
    Par Greensource dans le forum GTK+ avec C & C++
    Réponses: 2
    Dernier message: 08/04/2009, 11h41
  3. Comment créer son propre logo ?
    Par jojo_ol76 dans le forum Imagerie
    Réponses: 7
    Dernier message: 15/01/2008, 15h03
  4. Comment créer son propre iterator ?
    Par kidpaddle2 dans le forum C++
    Réponses: 9
    Dernier message: 02/04/2007, 22h02
  5. Comment créer son propre logiciel de gestion ?
    Par Sayanne dans le forum Autres Logiciels
    Réponses: 8
    Dernier message: 11/04/2006, 18h03

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo