J'ai une interface graphique faite avec TKinter en Python. J'aimerais pouvoir afficher un message lorsque le curseur de ma souris passe, par exemple, au-dessus d'une étiquette ou d'un bouton. Le but est d'expliquer à l'utilisateur ce que fait ou représente le bouton/l'étiquette.
Existe-t-il un moyen d'afficher du texte lorsque vous survolez un objet tkinter en Python?
Vous devez définir une liaison sur le <Enter>
et <Leave>
événements.
Remarque: si vous choisissez de faire apparaître une fenêtre (c'est-à-dire une info-bulle), assurez-vous de ne pas la faire apparaître directement sous la souris. Ce qui se passera, c'est qu'il provoquera un événement de congé, car le curseur quitte l'étiquette et entre dans la fenêtre contextuelle. Ensuite, votre gestionnaire de congés fermera la fenêtre, votre curseur entrera dans l'étiquette, ce qui provoquera un événement enter, qui fera apparaître la fenêtre, ce qui provoquera un événement Leave, qui rejettera la fenêtre, ce qui provoquera un événement enter, ... ad infini.
Voici un exemple qui met simplement à jour une étiquette, semblable à une barre d'état utilisée par certaines applications.
import Tkinter as tk
class Example(tk.Frame):
def __init__(self, *args, **kwargs):
tk.Frame.__init__(self, *args, **kwargs)
self.l1 = tk.Label(self, text="Hover over me")
self.l2 = tk.Label(self, text="", width=40)
self.l1.pack(side="top")
self.l2.pack(side="top", fill="x")
self.l1.bind("<Enter>", self.on_enter)
self.l1.bind("<Leave>", self.on_leave)
def on_enter(self, event):
self.l2.configure(text="Hello world")
def on_leave(self, enter):
self.l2.configure(text="")
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(side="top", fill="both", expand="true")
root.mainloop()
Vous pouvez vous référer à ceci - HoverClass
C'est exactement ce dont vous avez besoin. Ni plus ni moins
from Tkinter import *
import re
class HoverInfo(Menu):
def __init__(self, parent, text, command=None):
self._com = command
Menu.__init__(self,parent, tearoff=0)
if not isinstance(text, str):
raise TypeError('Trying to initialise a Hover Menu with a non string type: ' + text.__class__.__name__)
toktext=re.split('\n', text)
for t in toktext:
self.add_command(label = t)
self._displayed=False
self.master.bind("<Enter>",self.Display )
self.master.bind("<Leave>",self.Remove )
def __del__(self):
self.master.unbind("<Enter>")
self.master.unbind("<Leave>")
def Display(self,event):
if not self._displayed:
self._displayed=True
self.post(event.x_root, event.y_root)
if self._com != None:
self.master.unbind_all("<Return>")
self.master.bind_all("<Return>", self.Click)
def Remove(self, event):
if self._displayed:
self._displayed=False
self.unpost()
if self._com != None:
self.unbind_all("<Return>")
def Click(self, event):
self._com()
Exemple d'application utilisant HoverInfo:
from Tkinter import *
from HoverInfo import HoverInfo
class MyApp(Frame):
def __init__(self, parent=None):
Frame.__init__(self, parent)
self.grid()
self.lbl = Label(self, text='testing')
self.lbl.grid()
self.hover = HoverInfo(self, 'while hovering press return \n for an exciting msg', self.HelloWorld)
def HelloWorld(self):
print('Hello World')
app = MyApp()
app.master.title('test')
app.mainloop()
Capture d'écran:
Je pense que cela répondrait à vos besoins.
Voici à quoi ressemble la sortie:
Tout d'abord, j'ai créé une classe nommée ToolTip
qui a les méthodes showtip
et hidetip
.
from tkinter import *
class ToolTip(object):
def __init__(self, widget):
self.widget = widget
self.tipwindow = None
self.id = None
self.x = self.y = 0
def showtip(self, text):
"Display text in tooltip window"
self.text = text
if self.tipwindow or not self.text:
return
x, y, cx, cy = self.widget.bbox("insert")
x = x + self.widget.winfo_rootx() + 57
y = y + cy + self.widget.winfo_rooty() +27
self.tipwindow = tw = Toplevel(self.widget)
tw.wm_overrideredirect(1)
tw.wm_geometry("+%d+%d" % (x, y))
label = Label(tw, text=self.text, justify=LEFT,
background="#ffffe0", relief=SOLID, borderwidth=1,
font=("tahoma", "8", "normal"))
label.pack(ipadx=1)
def hidetip(self):
tw = self.tipwindow
self.tipwindow = None
if tw:
tw.destroy()
def CreateToolTip(widget, text):
toolTip = ToolTip(widget)
def enter(event):
toolTip.showtip(text)
def leave(event):
toolTip.hidetip()
widget.bind('<Enter>', enter)
widget.bind('<Leave>', leave)
Le widget est l'endroit où vous souhaitez ajouter le conseil. Par exemple, si vous souhaitez obtenir une astuce lorsque vous survolez un bouton, une entrée ou une étiquette, l'instance de celle-ci doit être fournie au moment de l'appel.
Note rapide : le code ci-dessus utilise from tkinter import *
Qui n'est pas suggéré par certains programmeurs là-bas, et ils ont des points valides. Vous voudrez peut-être apporter les modifications nécessaires dans ce cas.
Pour déplacer le conseil à l'emplacement souhaité, vous pouvez modifier x
et y
dans le code. La fonction CreateToolTip()
permet de créer facilement cette astuce. Passez simplement le widget et la chaîne que vous souhaitez afficher dans la boîte à astuces à cette fonction, et vous êtes prêt à partir.
Voici comment vous appelez la partie ci-dessus:
button = Button(root, text = 'click mem')
button.pack()
CreateToolTip(button, text = 'Hello World\n'
'This is how tip looks like.'
'Best part is, it\'s not a menu.\n'
'Purely tipbox.')
N'oubliez pas d'importer le module si vous enregistrez le plan précédent dans différents fichiers python, et n'enregistrez pas le fichier sous CreateToolTip
ou ToolTip
pour éviter confusion.
J'ai une solution très hacky mais elle a certains avantages par rapport aux réponses actuelles, donc j'ai pensé que je la partagerais.
lab=Label(root,text="hover me")
lab.bind("<Enter>",popup)
def do_popup(event):
# display the popup menu
root.after(1000, self.check)
popup = Menu(root, tearoff=0)
popup.add_command(label="Next")
popup.tk_popup(event.x_root, event.y_root, 0)
def check(event=None):
x, y = root.winfo_pointerxy()
widget = root.winfo_containing(x, y)
if widget is None:
root.after(100, root.check)
else:
leave()
def leave():
popup.delete(0, END)
Le seul vrai problème avec cela est qu'il laisse derrière lui une petite boîte qui éloigne le focus de la fenêtre principale Si quelqu'un sait comment résoudre ces problèmes, faites le moi savoir
La meilleure façon que j'ai trouvée pour créer une fenêtre d'aide contextuelle est d'utiliser le tix.Balloon
. Je l'ai modifié ci-dessous pour le rendre plus joli et montrer un exemple (notez l'utilisation de tix.Tk
):
import tkinter as tk
import tkinter.tix as tix
class Balloon(tix.Balloon):
# A modified tix popup balloon (to change the default delay, bg and wraplength)
init_after = 1250 # Milliseconds
wraplength = 300 # Pixels
def __init__(self, master):
bg = root.cget("bg")
# Call the parent
super().__init__(master, initwait=self.init_after)
# Change background colour
for i in self.subwidgets_all():
i.config(bg=bg)
# Modify the balloon label
self.message.config(wraplength=self.wraplength)
root = tix.Tk()
l = tk.Label(root, text="\n".join(["text"] * 5))
l.pack()
b = Balloon(root.winfo_toplevel())
b.bind_widget(l, balloonmsg="Some random text")
root.mainloop()
ANCIENNE RÉPONSE:
Voici un exemple utilisant <enter>
et <leave>
comme @bryanoakley l'a suggéré avec un niveau supérieur (avec overridedirect
défini sur true). Utilisez le hover_timer
classe pour une utilisation facile. Cela nécessite le widget et le texte d'aide (avec un argument de délai facultatif - 0,5 s par défaut) et peut être facilement appelé simplement en lançant la classe puis en l'annulant.
import threading, time
from tkinter import *
class hover_window (Toplevel):
def __init__ (self, coords, text):
super ().__init__ ()
self.geometry ("+%d+%d" % (coords [0], coords [1]))
self.config (bg = "white")
Label (self, text = text, bg = "white", relief = "ridge", borderwidth = 3, wraplength = 400, justify = "left").grid ()
self.overrideredirect (True)
self.update ()
self.bind ("<Enter>", lambda event: self.destroy ())
class hover_timer:
def __init__ (self, widget, text, delay = 2):
self.wind, self.cancel_var, self.widget, self.text, self.active, self.delay = None, False, widget, text, False, delay
threading.Thread (target = self.start_timer).start ()
def start_timer (self):
self.active = True
time.sleep (self.delay)
if not self.cancel_var: self.wind = hover_window ((self.widget.winfo_rootx (), self.widget.winfo_rooty () + self.widget.winfo_height () + 20), self.text)
self.active = False
def delayed_stop (self):
while self.active: time.sleep (0.05)
if self.wind:
self.wind.destroy ()
self.wind = None
def cancel (self):
self.cancel_var = True
if not self.wind: threading.Thread (target = self.delayed_stop).start ()
else:
self.wind.destroy ()
self.wind = None
def start_help (event):
# Create a new help timer
global h
h = hover_timer (l, "This is some additional information.", 0.5)
def end_help (event):
# If therre is one, end the help timer
if h: h.cancel ()
if __name__ == "__main__":
# Create the tkinter window
root = Tk ()
root.title ("Hover example")
# Help class not created yet
h = None
# Padding round label
Frame (root, width = 50).grid (row = 1, column = 0)
Frame (root, height = 50).grid (row = 0, column = 1)
Frame (root, width = 50).grid (row = 1, column = 2)
Frame (root, height = 50).grid (row = 2, column = 1)
# Setup the label
l = Label (root, text = "Hover over me for information.", font = ("sans", 32))
l.grid (row = 1, column = 1)
l.bind ("<Enter>", start_help)
l.bind ("<Leave>", end_help)
# Tkinter mainloop
root.mainloop ()