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+ Discussion :

Widget de type "palette"


Sujet :

GTK+

  1. #1
    Membre averti
    Inscrit en
    Janvier 2007
    Messages
    329
    Détails du profil
    Informations forums :
    Inscription : Janvier 2007
    Messages : 329
    Points : 366
    Points
    366
    Par défaut Widget de type "palette"
    Salut à tous,

    Je cherche à faire un widget qui affiche une palette d'outils, comme dans Gimp ou dans l'éditeur Glade par exemple (=> une sorte de GtkTable, mais qui adapte automatiquement le nombre de ses lignes/colones quant on le redimensionne).

    Savez-vous comment je pourrais faire ça simplement ? Si vous avez des exemples (en pygtk de préférence), je suis preneur.

    Merci d'avance

  2. #2
    Rédacteur

    Avatar de gege2061
    Femme Profil pro
    Administrateur de base de données
    Inscrit en
    Juin 2004
    Messages
    5 840
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Juin 2004
    Messages : 5 840
    Points : 11 625
    Points
    11 625
    Par défaut
    Bonjour,

    Ce sont des widgets fait maison.

    Par exemple pour gimp, il s'agit de GtkVWrapBox

  3. #3
    Membre averti
    Inscrit en
    Janvier 2007
    Messages
    329
    Détails du profil
    Informations forums :
    Inscription : Janvier 2007
    Messages : 329
    Points : 366
    Points
    366
    Par défaut
    Merci pour l'info.

    J'ai pas compris grand chose au code de la GtkVWrapBox, donc j'ai essayé de reprogrammer ex nihilo.
    Il reste deux trucs qui ne marchent pas : l'évenement (expose-event) qui détecte le redimensionnement, et le truc qui calcule la taille des boutons d'outils (attribut "allocation"). En fait, le prog ne me donne pas la bonne taille du bouton, du coup la grille prend plus de place qu'estimé, donc la fenêtre s'agrandit automatiquement et ça fait une boucle sans fin...

    Y'a moyen de connaitre la taille des boutons de manière fiable ?

  4. #4
    Membre averti
    Inscrit en
    Janvier 2007
    Messages
    329
    Détails du profil
    Informations forums :
    Inscription : Janvier 2007
    Messages : 329
    Points : 366
    Points
    366
    Par défaut
    Bon, j'ai fini par pondre un truc qui marche pas trop mal. Le widget prend pour argument une fonction qui détermine la largeur du parent. Dans l'exemple, c'est la taille de la fenêtre, et dans mon projet, ce sera la position d'un "HPaned".

    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
     
    # -*- coding:utf-8 -*-
     
    import pygtk
    pygtk.require('2.0')
    import gtk
     
    #------------------------------------------------------------------------------
     
    class Palette(gtk.ScrolledWindow):
        """Palette toolbar with automatic lines/columns adaptation."""
     
        def __init__(self, get_width_func):
            gtk.ScrolledWindow.__init__(self)
            self.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
            self.set_shadow_type(gtk.SHADOW_NONE)
            self.table = gtk.Table()
            self.table.set_homogeneous(True)
            self.add_with_viewport(self.table)
            self.tools = []
            self.get_width = get_width_func
            self.show_all()
            return
     
        def add_tool(self, tool):
            """Add a tool to the palette."""
            self.tools.append(tool)
            tool.show_all()
            return
     
        def remove_tool(self, tool):
            """Remove the specified tool."""
            tool.destroy()
            self.tools.remove(tool)
            return
     
        def display_update(self, widget=None, data=None):
            """Callback to execute when the size of the widget is changed."""
            # Get tools size and remove them
            w = 1
            for t in self.table.get_children():
                alloc = t.get_allocation()
                if alloc.width > w:
                    w = alloc.width
                self.table.remove(t)
            # Compute grid size
            col = int(self.get_width() / w) - 1
            if col < 1:
                col = 1
            row = int(len(self.tools) / col) + 1
            if row*col < len(self.tools):
                row += 1
            # Attach tools to the grid
            self.table.resize(row, col)
            for i in range(len(self.tools)):
                r = int(i / col)
                c = i - r*col
                self.table.attach(self.tools[i], c, c+1, r, r+1, xoptions=gtk.FILL, yoptions=gtk.FILL)
            self.show_all()
            return False
     
    #------------------------------------------------------------------------------
     
    if __name__ == "__main__":
        win = gtk.Window()
        win.connect('destroy', lambda w: gtk.main_quit())
        win.set_default_size(150, 150)
        p = Palette(lambda : win.get_size()[0])
        for i in range(25):
            img = gtk.Image()
            img.set_from_stock(gtk.STOCK_HOME, gtk.ICON_SIZE_MENU)
            b = gtk.Button()
            b.add(img)
            p.add_tool(b)
        win.add(p)
        win.show_all()
        gtk.main()
    Y'a un espace réservé à droite pour la barre de défilement verticale. Ça fait un gros trou quand elle n'est pas affichée, mais j'ai pas trouvé comment détecter si elle est là ou pas.

    Pour l'instant, ça me convient bien

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    151
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 151
    Points : 83
    Points
    83
    Par défaut
    Salut,

    Je cherche le même type de conteneur. J'ai essayé ton code, mais je n'arrive pas à le faire fonctionner.
    Il me semble qu'il manque quelques éléments ; comme la connexion du callback à l'événement size-allocate. Malgré cela, la ligne self.table.remove(t) du callback entraine une boucle sans fin. Avais-tu eu ce problème ?

    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
     
    # -*- coding:utf-8 -*-
     
    import pygtk
    pygtk.require('2.0')
    import gtk
     
    #------------------------------------------------------------------------------
     
    class Palette(gtk.ScrolledWindow):
        """Palette toolbar with automatic lines/columns adaptation."""
     
        def __init__(self):
            gtk.ScrolledWindow.__init__(self)
            self.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
            self.set_shadow_type(gtk.SHADOW_NONE)
     
            self.table = gtk.Table()
            self.table.set_homogeneous(False)
            self.add_with_viewport(self.table)
     
            self.connect("size-allocate", self.update_organization)
            self.tools = []
            self.show_all()
     
        def add_tool(self, tool):
            """Add a tool to the palette."""
            self.tools.append(tool)
            tool.show_all()
     
        def remove_tool(self, tool):
            """Remove the specified tool."""
            tool.destroy()
            self.tools.remove(tool)
     
        def update_organization(self, widget=None, allocation=None):
    		"""Callback to execute when the size of the widget is changed."""
     
    		width = 1
     
    		# Get the widthest widget and remove all widgets from the table
    		for t in self.tools:
    			if t.allocation.width > width:
    				width = t.allocation.width
    			self.table.remove(t)
     
    		#*Get the number of columns and rows
    		cols = int(allocation.width / width)
     
    		if cols < 1:
    			cols = 1
    		rows = int(len(self.tools) / cols) + 1
     
    		if rows*cols < len(self.tools):
    			rows += 1
     
    		#*Re-organize the table
    		self.table.resize(rows, cols)
     
    		i = 0
    		for r in range(rows):
    			for c in range(cols):
    				if i <= len(self.tools) - 1:
    					print c, c+1, r, r+1
    					self.table.attach(self.tools[i], c, c+1, r, r+1, xoptions=gtk.FILL, yoptions=gtk.FILL, xpadding=5, ypadding=5)
    					i += 1
    		self.show_all()
    		print "Done"	
     
     
    #------------------------------------------------------------------------------
     
    if __name__ == "__main__":
        win = gtk.Window()
        win.connect('destroy', lambda w: gtk.main_quit())
        win.set_size_request(150, 150)
     
        p = Palette()
        for i in range(25):
            b = gtk.Button(stock=gtk.STOCK_SAVE)
            b.show()
            p.add_tool(b)
        win.add(p)
     
        win.show_all()
        gtk.main()
    Merci d'avance.

  6. #6
    Membre averti
    Inscrit en
    Janvier 2007
    Messages
    329
    Détails du profil
    Informations forums :
    Inscription : Janvier 2007
    Messages : 329
    Points : 366
    Points
    366
    Par défaut
    Salut,

    Effectivement, mon code étant vite fait - mal fait, il est possible qu'il reste quelques erreurs...

    Je regarde ça en détail demain et je te tiens au courant

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    151
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 151
    Points : 83
    Points
    83
    Par défaut
    Merci de passer du temps dessus.

    J'attends avec impatience

  8. #8
    Membre averti
    Inscrit en
    Janvier 2007
    Messages
    329
    Détails du profil
    Informations forums :
    Inscription : Janvier 2007
    Messages : 329
    Points : 366
    Points
    366
    Par défaut
    Me revoilà ! Désolé de n'avoir pas pu répondre plus tôt...

    Ce code devrait marcher un peu mieux :
    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
     
    # -*- coding:utf-8 -*-
     
    import pygtk
    pygtk.require('2.0')
    import gtk
    import gobject
     
    #------------------------------------------------------------------------------
     
    class Palette(gtk.Fixed):
        """Palette toolbar with automatic lines/columns adaptation."""
     
        def __init__(self, parent=None):
            gtk.Fixed.__init__(self)
            self.set_size_request(50, -1)
            if parent == None:
                parent = self
            ###self.set_redraw_on_allocate(False)
            ###parent.connect('size-allocate', self.display_update)
            parent.connect('expose-event', self.display_update)
            self.tools = []
            self.show_all()
            gobject.timeout_add(10, self.display_update)
            return
     
        def add_tool(self, tool):
            """Add a tool to the palette."""
            self.tools.append(tool)
            self.put(tool, 0, 0)
            tool.show_all()
            return
     
        def remove_tool(self, tool):
            """Remove the specified tool."""
            self.tools.remove(tool)
            tool.destroy()
            return
     
        def display_update(self, widget=None, data=None):
            """Callback to execute when the size of the widget is changed."""
            # Get tools max size
            w = max([1] + map(lambda t: t.get_allocation().width, self.tools))
            h = max([1] + map(lambda t: t.get_allocation().height, self.tools))
            print w, h, self.get_allocation().width, self.get_allocation().height, len(self.tools)
            # Compute grid size
            col = int(self.get_allocation().width / w)
            if col < 1:
                col = 1
            row = int(len(self.tools) / col) + 1
            if row*col < len(self.tools):
                row += 1
            # Attach tools to the grid
            for i in range(len(self.tools)):
                r = int(i / col)
                c = i - r*col
                self.move(self.tools[i], c*w, r*h)
            return False
     
    #------------------------------------------------------------------------------
     
    if __name__ == "__main__":
        win = gtk.Window()
        win.connect('destroy', gtk.main_quit)
        win.set_default_size(150, 250)
        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        sw.set_shadow_type(gtk.SHADOW_NONE)
        win.add(sw)
        p = Palette(win)
        for i in range(25):
            img = gtk.Image()
            img.set_from_stock(gtk.STOCK_HOME, gtk.ICON_SIZE_MENU)
            b = gtk.Button()
            b.add(img)
            p.add_tool(b)
        sw.add_with_viewport(p)
        win.show_all()
        gtk.main()
    J'avais eu quelques problèmes au niveau de la détection du redimensionnement ; normalement l'évènement 'size-allocate' est le plus adapté mais il me fait des boucles sans fin. J'ai du mettre aussi une mini-tempo de 10ms pour forcer le rafraichissement au début.

    Si tu as des questions, n'hésites pas

  9. #9
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    151
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 151
    Points : 83
    Points
    83
    Par défaut
    Merci beaucoup pour ce code

    Ça marche plutôt bien sauf que j'ai une boucle sans fin.
    En utilisant ce code seul, pas de soucis, mais dès que je l'inclus dans mon projet.. boucle sans fin.

    J'ajoute la palette dans une vbox comprise dans un notebook, la palette n'a pas de parent. Elle comprend des éléments qui héritent de EventBox.

    Si t'as une petite idée, je sèche moi..

  10. #10
    Membre averti
    Inscrit en
    Janvier 2007
    Messages
    329
    Détails du profil
    Informations forums :
    Inscription : Janvier 2007
    Messages : 329
    Points : 366
    Points
    366
    Par défaut
    Oui, ça fait souvent des trucs bizarres quand on l'inclue dans un projet plus grand, mais tu peux jouer sur deux paramètres :
    • Le widget à surveiller ; il est passé en argument quand on crée la Palette :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      # ici, on  surveille la fenêtre principale "win"
      p = Palette(win)
      Si pas d'argument, c'est la palette qu'on surveille.
    • L'évènement lui-même :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      # prendre un des deux :
      parent.connect('size-allocate', self.display_update)
      parent.connect('expose-event', self.display_update)
      Y'a peut-être d'autres évènements possibles, suivant le widget (par exemple 'check-resize' pour un gtk.Container)


    En bidouillant, y'a moyen d'arriver à quelque chose qui marche...

    -

  11. #11
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    151
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 151
    Points : 83
    Points
    83
    Par défaut
    Ayé, j'ai trouvé, le fait d'inclure la Palette dans une ScrolledWindow enlève la boucle sans fin

    Tout marche nickel, merci pour ton aide

  12. #12
    Membre averti
    Inscrit en
    Janvier 2007
    Messages
    329
    Détails du profil
    Informations forums :
    Inscription : Janvier 2007
    Messages : 329
    Points : 366
    Points
    366
    Par défaut
    OK super

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

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