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

Tkinter Python Discussion :

Hover Info - info Popup [Python 2.X]


Sujet :

Tkinter Python

  1. #1
    Membre éprouvé

    Homme Profil pro
    Ingénieur
    Inscrit en
    Août 2010
    Messages
    654
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2010
    Messages : 654
    Points : 1 150
    Points
    1 150
    Par défaut Hover Info - info Popup
    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 : 372
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

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut,

    C'est un widget qui existe dans Pmw qui s'appelle Balloon.
    Mais, vous avez aussi ceux de idlelib dans Lib\idlelib\ToolTip.py qui sont raisonnablement exploitables/adaptables.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Membre éprouvé

    Homme Profil pro
    Ingénieur
    Inscrit en
    Août 2010
    Messages
    654
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2010
    Messages : 654
    Points : 1 150
    Points
    1 150
    Par défaut
    Salut,

    Merci Wiztricks. Pmw semble intéressant, mais je n'ai pas encore pris le temps de regarder en détail ce que propose le module. Par contre j'ai regardé ToolTip et effectivement c'est pile-poil ce que je cherchais à faire. Très bien vu.

    Je n'ai pas eu beaucoup à adapter la BaseClass pour mon cas. Je ne souhaite pas faire quelque chose de très générique, donc j'ai simplifié et renommé quelques petites choses. Je reposte le même exemple que précédemment mais avec une nouvelle classe HoverInfo basée sur celle de ToolTip au cas où quelqu'un souhaiterais faire de même:
    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
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    """
     
    """
    import Tkinter as tk
    import ttk
    import textwrap
     
    class HoverInfo():
        """Allow to display an info window near a Tkinter widget. Based on
        ToolTipBase object from evandrix (idlelib)
        
        Parameters
        ----------
            master : Tkinter widget
            text : str
                Text to display in the info window.
            width : int
                Max width of the info window in character length. Default 40.
            duration : int
                Time in ms to wait before seing the info window to popup.
        """
        def __init__(self, master, text='', width=40, duration=1500):
            self.master = master
            if not isinstance(text, str):
                raise ValueError('"text" parameter must be a string')
            if not isinstance(duration, int):
                raise ValueError('"duration" parameter must be an integer')
            if not isinstance(width, int):
                raise ValueError('"width" parameter must be an integer')
            self.text_info = text
            self.width = width
            self.duration = duration
            self.infowindow = None
            self.id = None
            self.x = self.y = 0
            self._id1 = self.master.bind('<Enter>', self.enter)
            self._id2 = self.master.bind('<Leave>', self.leave)
            self._id3 = self.master.bind('<ButtonPress>', self.leave)
     
        def enter(self, event=None):
            self.schedule()
     
        def leave(self, event=None):
            self.unschedule()
            self.hideinfo()
     
        def schedule(self):
            self.unschedule()
            self.id = self.master.after(self.duration, self.showinfo)
     
        def unschedule(self):
            id = self.id
            self.id = None
            if id:
                self.master.after_cancel(id)
     
        def showinfo(self):
            if self.infowindow:
                return
            # Place the infowindow outside the master
            x = self.master.winfo_rootx() + 20
            y = self.master.winfo_rooty() + self.master.winfo_height() + 1
            self.infowindow = tw = tk.Toplevel(self.master)
            tw.wm_overrideredirect(1)
            tw.wm_geometry('+%d+%d' % (x, y))
            # Wrap text_info to avoid too large infowindow
            _text = '\n'.join(textwrap.wrap(self.text_info, width=self.width))
            label = tk.Label(self.infowindow, text=_text, justify='left',
                             background="#E6E6FA", borderwidth=0.5)
            label.pack()
     
        def hideinfo(self):
            tw = self.infowindow
            self.infowindow = None
            if tw:
                tw.destroy()
     
    class MyApp(tk.Frame):
        """
        """
        def __init__(self, parent, *args, **kwargs):
            tk.Frame.__init__(self, parent, *args, **kwargs)
            label = tk.Label(self, text='Hover me!', width=15, height=3)
            label.pack()
            hover = HoverInfo(label, "This is a message displayed when \
            mouse's cursor is let more than 1.5s over this widget")
     
    if __name__ == '__main__':
        root = tk.Tk()
        app = MyApp(root)
        app.pack()
        root.mainloop()
    J'ai conservé textwrap car l'option wraplength du Label ne me satisfait pas, mais pour limiter les dépendances c'est une bonne option.

    Merci beaucoup.

    Ju

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

Discussions similaires

  1. envoie info sur popup via un lien..
    Par flo456 dans le forum Général JavaScript
    Réponses: 7
    Dernier message: 17/01/2006, 11h13

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