Bonjour,

Je termine une petite application en python avec une interface en tkinter. Je suis dans la phase finition. J'aimerais ajouter une fonctionnalité intéressante: lorsque l'utilisateur passe le curseur de la souris sur certains elements, un popup apparait après x seconds contenant un message, popup qui disparaitrait au moindre mouvement de la souris.

Exemple:
Nom : Hover_Example.png
Affichages : 454
Taille : 4,8 Ko
Le screenshot a fait disparaitre le curseur, mais je pense que vous voyez ce que je veux dire.

Corrigez moi si je me trompe mais il n'y a rien de prévu en tkinter pour faire cela de base. En tout cas mes recherches n'ont rien données. J'ai envisagé deux possibilités:
  1. un toplevel
  2. un menu

J'ai finalement opté pour un Menu car ce widget peut être placé où l'on veut grâce à la method post(). Voici donc ce que j'ai fait pour le moment:
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
#!/usr/bin/env python
# -*- coding: utf-8 -
 
import Tkinter as tk
import ttk
import textwrap
 
class HoverInfo(tk.Menu):
    """
    """
    def __init__(self, master, text):
        # Options placed directly here for testing purpose
        options = {'activebackground': 'SystemHighlight',   # Default SystemHighlight
                   'background': 'SystemMenu',              # Default SystemMenu
                   'selectcolor': 'SystemMenuText',         # Default SystemMenuText
                   'tearoff': 0}                            # Default 1
        tk.Menu.__init__(self, master, **options)
        self.add_text(text)
        self._displayed = False
        master.bind('<Button-3>', self.display)
        master.bind('<ButtonRelease-3>', self.remove)
 
    def add_text(self, text):
        _text = '\n'.join(textwrap.wrap(text, width=40))    # Do not work
        self.add_command(label=_text)
 
    def display(self, event):
        if not self._displayed:
            self._displayed = True
            self.post(event.x_root, event.y_root)
 
    def remove(self, event):
        if self._displayed:
            self._displayed = False
            self.unpost()
 
class MyApp(tk.Frame):
    """
    """
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        label = tk.Label(self, text='Right click here', width=15, height=3)
        label.pack()
        hover = HoverInfo(label, "This is a message displayed when mouse's right button is kept pressed")
 
if __name__ == '__main__':
    root = tk.Tk()
    app = MyApp(root)
    app.pack()
    root.mainloop()
J'ai plusieurs questions/problèmes avec le code ci-dessus:

  • Il semblerait que bien qu'il existe un binding '<Enter>' pour appeler un callback lorque la souris passe sur l'élément, il n'y a pas d'équivalent lorsqu'on bouge la souris. (seulement '<Leave>' ce qui est génant si l'utilisateur laisse la souris sur l'élement pour remplir un Entry par exemple).
  • Ici j'utilise '<ButtonRelease-3>' pour faire disparaitre le Menu folttant. Le menu apparait si on clique droit dessus et disparait lorsqu'on relache le boutton. Compromis acceptable selon moi. Mais bien que cela fonctionne parfaitement sur Linux, python 2.7, même version de tkinter, sur win7 le menu reste affiché lorsque le boutton droit de la souris est relaché. Why?
  • Le menu généré est une sorte de "boutton". On peut le "sélectionner" et il devient alors bleu et disparait si on clique gauche dessus. J'aimerais enlever cela (ça ne le fait pas sur linux d'ailleurs).
  • Le contenu du popup peut être long (comme dans l'exemple ci-dessus). J'ai pensé à wrapper le texte avec une longeur définie (ici en utilisant textwrap). Mais visiblement on ne peut faire de saut à la ligne dans le text d'un menu...


Est-ce que l'un de vous aurais une idée de comment résoudre l'un des points ci-dessus? Je commence à regretter de ne mettre mis à quelque chose de plus haut niveau comme pyQT ou même wxPython...

Ciao ciao,

Julien