Rechtsklick Menu

Fragen zu Tkinter.
Antworten
Fire Spike
User
Beiträge: 329
Registriert: Montag 13. Mai 2019, 16:05
Wohnort: Erde

Hallo ich habe 2 Fragen:
  • Ich habe ein Entry.
    Wie kann ich jetzt machen das wenn ich mit rechts auf das Entry klicke ein Menu erscheint?
  • Ich habe ein Fenster in dem ich 3 verschiedene Diagramme anzeigen will. Da die sehr gross sind würde ich gerne die so scrollen dass immer nur eins sichtbar ist. Wie kann ich das machen?
    Ich zeige die Diagramme so an:

    Code: Alles auswählen

    canvas = FigureCanvasTkAgg(fig, master=self)
    canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
Ich hoffe ihr könnt mir helfen :wink:
Danke im Voraus :)
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Bezueglich des Rechtsklicks musst du mal in der Dokumentation nach Event-Binding suchen, da wird das dann erklaert.
Fire Spike
User
Beiträge: 329
Registriert: Montag 13. Mai 2019, 16:05
Wohnort: Erde

OK. :

Code: Alles auswählen

self.bind("<Button-3>", blabla)
Und wie mache ich das Menu?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Indem du ein modales Fenster baust das du an der Stelle des Mauszeigers anzeigst. Und dann all die Sonderfaelle beachtest, wie zB was passiert wenn das Entry am Rande des Bildschirmes irgendwo ist, und das Menue irgendwo auftauchen wuerde, wo man es gar nicht mehr bedienen kann. Ein Start waere zB hier zu finden: https://stackoverflow.com/questions/120 ... ntext-menu
Fire Spike
User
Beiträge: 329
Registriert: Montag 13. Mai 2019, 16:05
Wohnort: Erde

Ich habe mal probiert das umzusetzen, aber ich scheitere an den Bindings, denn das vom root definiert auch das vom Menu.
Ich weiss nicht wieso das es nicht funktioniert.
Was mache ich falsch? :?:

So binde ich das Event:

Code: Alles auswählen

self.rklick = Rechtsklick(self)
binding = self.bind_all("<Button-1>", self.rklick.verstecken)
self.rklick.unbind(binding)
self.eingabe.bind("<Button-3>", self.rklick.popup)
So definiere ich das Rechtsklickmenu:

Code: Alles auswählen

class Rechtsklick():
    def __init__(self, master):
        self.master = master
        self.aMenu = tk.Menu(self.master, tearoff=0)
        self.aMenu.config(bg="white")
        self.aMenu.add_command(label="löschen", command=self.löschen)
        self.aMenu.add_command(label="Alles löschen", command=self.alles_löschen)

    def löschen(self):
        print("gelöscht")

    def alles_löschen(self):
        print("alles gelöscht")

    def popup(self, event):
        self.aMenu.post(event.x_root, event.y_root)
    
    def verstecken(self, event):
        self.aMenu.unpost()
    
    def unbind(self, binding):
        self.aMenu.unbind(binding)
Fire Spike
User
Beiträge: 329
Registriert: Montag 13. Mai 2019, 16:05
Wohnort: Erde

Könnt ihr mir bitte helfen?🙏🙏🙏
Wahrscheinlich habe ich genau eine Zeile zu wenig :oops:
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dann bau bitte ein komplett lauffaehiges Beispiel, oder poste deinen gesamten Code (der natuerlich auch laeuffaehig sein muss).
Fire Spike
User
Beiträge: 329
Registriert: Montag 13. Mai 2019, 16:05
Wohnort: Erde

Mein ganzer Code hat 473 Zeilen, willst du den wirklich, oder soll ich ein Beispiel machen?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das Internet ist gross, 473 Zeilen Code passen da noch gerade so rein. Der entscheidende Punkt ist, dass es *funktionieren* muss, ohne das man da irgendwie dran rumfummeln muss (mit Ausnahme des Rechts-Klicks natuerlich). Wenn das nicht so ohne weiteres moeglich ist (weil du ZB auf GPIO eines PI zugreifst), dann bau ein Beispiel.
Fire Spike
User
Beiträge: 329
Registriert: Montag 13. Mai 2019, 16:05
Wohnort: Erde

Ein Beispiel weil der original Code Exceldateien braucht.

Code: Alles auswählen

import tkinter as tk

class Rechtsklick():
    def __init__(root, master):
        root.master = master
        root.aMenu = tk.Menu(root.master, tearoff=0)
        root.aMenu.config(bg="white")
        root.aMenu.add_command(label="löschen", command=root.löschen)
        root.aMenu.add_command(label="Alles löschen", command=root.alles_löschen)

    def löschen(root):
        print("gelöscht")

    def alles_löschen(root):
        print("alles gelöscht")

    def popup(root, event):
        root.aMenu.post(event.x_root, event.y_root)
    
    def verstecken(root, event):
        root.aMenu.unpost()
    
    def unbind(root, binding):
        root.aMenu.unbind(binding)
        
def main():
    root = tk.Tk()
    root.config(bg="white")
    rklick = Rechtsklick(root)
    binding = root.bind_all("<Button-1>", rklick.verstecken)
    rklick.unbind(binding)
    
    tk.Label(root, text="Name", fg="darkblue", bg="white", font=('arial', 15)).grid(row=0, column=0, sticky="w")
    root.name_eingabe = tk.Entry(root, bg="white", width=30, font=('arial', 13))
    root.name_eingabe.grid(row=1, column=0, sticky="w")
    root.name_eingabe.bind("<Button-3>", rklick.popup)
    
    tk.Label(root, text="Vorname", fg="darkblue", bg="white", font=('arial', 15)).grid(row=2, column=0, sticky="w")
    root.first_name_eingabe = tk.Entry(root, bg="white", width=30, font=('arial', 13))
    root.first_name_eingabe.grid(row=3, column=0, sticky="w")
    root.first_name_eingabe.bind("<Button-3>", rklick.popup)
    root.mainloop()
    
if __name__ == "__main__":
    main()
Es sind in Wirklichkeit viel mehr Eingabefelder darum das bind_all.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Neben dem vergurkten root, das stattdessen ein self sein sollte, liegt das Problem in deinem rklick.unbind - damit entfernst du augenscheinlich das Binding fuer den Menueeintrag. So funktiontiert es fuer mich:

Code: Alles auswählen

import tkinter as tk

class Rechtsklick():
    def __init__(self, master):
        self.master = master
        self.aMenu = tk.Menu(master, tearoff=0)
        self.aMenu.config(bg="white")
        self.aMenu.add_command(label="löschen", command=self.löschen)
        self.aMenu.add_command(label="Alles löschen", command=self.alles_löschen)

    def löschen(self):
        print("gelöscht")

    def alles_löschen(self):
        print("alles gelöscht")

    def popup(self, event):
        self.aMenu.post(self.master.winfo_pointerx(), self.master.winfo_pointery())

    def verstecken(self, event):
        self.aMenu.unpost()

    def unbind(self, binding):
        self.aMenu.unbind(binding)


def main():
    root = tk.Tk()
    root.config(bg="white")
    rklick = Rechtsklick(root)
    #binding = root.bind_all("<Button-1>", rklick.verstecken)
    #rklick.unbind(binding)

    tk.Label(root, text="Name", fg="darkblue", bg="white", font=('arial', 15)).grid(row=0, column=0, sticky="w")
    root.name_eingabe = tk.Entry(root, bg="white", width=30, font=('arial', 13))
    root.name_eingabe.grid(row=1, column=0, sticky="w")
    root.name_eingabe.bind("<Button-3>", rklick.popup)

    tk.Label(root, text="Vorname", fg="darkblue", bg="white", font=('arial', 15)).grid(row=2, column=0, sticky="w")
    root.name_eingabe = tk.Entry(root, bg="white", width=30, font=('arial', 13))
    root.name_eingabe.grid(row=3, column=0, sticky="w")
    root.name_eingabe.bind("<Button-3>", rklick.popup)
    root.mainloop()

if __name__ == "__main__":
    main()
Fire Spike
User
Beiträge: 329
Registriert: Montag 13. Mai 2019, 16:05
Wohnort: Erde

so muss ich ja bei jedem Objekt

Code: Alles auswählen

bind("<Button-1>", self.rklick.verstecken)
hinzufügen und wie gesagt: das sind sehr viele :shock:
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich glaube eher das unbiding ist das Problem. Aber wenn es auf die eine Art geht, und auf die andere nicht - was willst du sonst machen?
Sirius3
User
Beiträge: 18260
Registriert: Sonntag 21. Oktober 2012, 17:20

@Fire Spike: wenn man etwas an sehr vielen Stellen im Code gleichartig ändern muß, dann ist das ein Zeichen dafür, dass man besser eine Funktion schreibt.
Fire Spike
User
Beiträge: 329
Registriert: Montag 13. Mai 2019, 16:05
Wohnort: Erde

wie würdest den du Entrys, Text, Button und Label mit einer Funktion diese Binding hinzufügen?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ohne irgendwas anderes zu machen geht es nicht. Du kannst zB eine Liste der Kontext-Objekte verwalten, und dann fuer die dann die Bindung in einem Rutsch (aber eben mit einzelnen calls) anlegen. Oder du kannst versuchen, nur auf dem toplevel-Objekt (also dem Fenster) ein Rechtsklick zu binden. Wenn der durchgeht, weil kein anderes Objekt davor ihn konsumiert (was eigentlich so sei sollte AFAIK), dann kannst du probieren, das passende Kind zum Rechtsklick anhand der Koordinaten zu finden, und damit dann weiter arbeiten.
Sirius3
User
Beiträge: 18260
Registriert: Sonntag 21. Oktober 2012, 17:20

Wie sieht denn Dein Code jetzt aus?
Antworten