Popupmenu in GUI integrieren

Fragen zu Tkinter.
Antworten
stefanxfg
User
Beiträge: 85
Registriert: Sonntag 2. April 2017, 14:11

Ich möchte ein Popup- oder Kontextmenu per Rechtsklick in die GUI integrieren. Dazu habe ich folgende PopupGUI erstellt.

Code: Alles auswählen

# -*- coding: utf-8 -*-

try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk

#import DynTkInter as tk # for GuiDesigner


#============= imports call Code ===================
import testcode

# Toplevel definition ===============================

class PopupMenuFrame(tk.Toplevel):

    def __init__(self,master,**kwargs):
        tk.Toplevel.__init__(self,master,**kwargs)
        self.myclass = 'PopupMenuFrame'
        self.call_code = 'testcode.PopupMenuCode'
        self.geometry('116x50+379+272')
        self.minsize(116, 1)
        self.maxsize(1444, 882)
        # widget definitions ===================================
        self.menu = PopupMenu(self,name='#0_menu')
        self['menu'] = self.menu
        # call Code ===================================
        testcode.PopupMenuCode(self)

class PopupMenu(tk.Menu):

    def __init__(self,master,**kwargs):
        tk.Menu.__init__(self,master,**kwargs)
        self.myclass = 'PopupMenu'
        self.call_code = 'testcode.PopupCode'
        # widget definitions ===================================
        self.dyntk_name = 'Undo'
        self.add_command(label='command')
        self.dyntk_name = 'Redo'
        self.add_command(label='command')
        # indexes for entryconfig later
        self.Undo_index = 1
        self.Redo_index = 2
        # call Code ===================================
        testcode.PopupCode(self)

if __name__ == '__main__':
    #PopupMenuFrame(tk.Tk()).master.mainloop('guidesigner/Guidesigner.py') # for GuiDesigner
    PopupMenuFrame(tk.Tk()).mainloop()

Dazu habe folgende Codezeilen als testcode.PopupCode erstellt.

Code: Alles auswählen

class PopupMenuCode:
     
    def __init__(self,container):
        self.container = container

        subscribe('BIND_SEND',self.do_popup)
        
    def do_popup(self,event):
        self.container.tk_popup(event.x_root, event.y_root,0)
        
class PopupCode:
     
    def __init__(self,container):
        self.container = container
Nun muss man doch eigentlich nur noch einen Bind-Befehl etablieren, welcher in der richtigen GUI einen Sendebefehl zum PopupCode sendet.

Code: Alles auswählen

        self.container.bind_all("<Button-3>",publish('BIND_SEND'))
Aber was mach ich falsch?
stefanxfg
User
Beiträge: 85
Registriert: Sonntag 2. April 2017, 14:11

Also wenn ich es als neues Toplevel anlege, wird es nun beim Programmstart ausgeführt. Demnach ohne Sender/EMpfänger.

self.container.bind("<Button-3>",AppPopup.PopupMenuFrame(self.container))

Aber noch nicht wie gewünscht.
stefanxfg
User
Beiträge: 85
Registriert: Sonntag 2. April 2017, 14:11

Ich habe nun die Ansteuerung des Popups über eine Methode gesteuert.

Code: Alles auswählen

        self.container.Inputnotebook.bind_all("<Button-3>",self.s_open)

    def s_open(self,container):
        print('Popup1')

        self.SettingProgr = AppPopup.PopupMenuFrame(self.container)
Aber die Methode zum Popup, an welchem Ort es erscheinen soll wird noch nicht verwendet. Vielleicht muss diese Information nicht im Popup selbst stehen, sondern in der MainGUI.
stefanxfg
User
Beiträge: 85
Registriert: Sonntag 2. April 2017, 14:11

So nun habe ich die Eventmethode zum Aufruf mithinzugenommen und bekomme mein Kontextmenü.

Code: Alles auswählen

        self.container.Inputnotebook.bind_all("<Button-3>",self.s_open)

    def s_open(self,event):
        print('Popup1')

        self.SettingProgr = AppPopup.PopupMenuFrame(self.container)
        self.SettingProgr.menu.tk_popup(event.x_root, event.y_root)
Jedoch wird auch das Toplevel mit angezeigt. Vielleicht kann man das auch minmieren?
stefanxfg
User
Beiträge: 85
Registriert: Sonntag 2. April 2017, 14:11

Ja das verbergen des Toplevel-Windows führt zum Ziel. Meine nächste Etappe ist das Popup-Menü von mehreren Klassen anzusteuern. Kann man die Ansteuerung auch auf eine globale Funktion machen?

Ich meine es so:

Code: Alles auswählen

def context_input_open(event,Zaehler):
    print('Popup1')
        
    Zaehler = Zaehler + 1
    if Zaehler<=1:        
        SettingProgr = AppPopup.PopupMenuFrame(self.container)
        SettingProgr.wm_state('iconic')
        SettingProgr.menu.tk_popup(event.x_root, event.y_root)
    else:
        SettingProgr.destroy()
        subscribe('TOPLEVEL_DESTROYER',None)

        SettingProgr = AppPopup.PopupMenuFrame(self.container)
        SettingProgr.wm_state('iconic')
        SettingProgr.menu.tk_popup(event.x_root, event.y_root)
        
class General_Input:
     
    def __init__(self,container):
        self.container = container
        subscribe('FILL_GENERAL_INPUT',self.eingabe)
        
        self.Zaehlerr = DEFAULT_ZAEHLER
        self.container.companynamelabel.bind("<Button-3>",context_input_open(self.Zaehlerr))



Ich benötige noch die Übergabe der Variable, damit ein Check ausgeführt werden kann, ob das Menü bereits angezeigt wird. Aber das geht irgendwie nicht.
stefanxfg
User
Beiträge: 85
Registriert: Sonntag 2. April 2017, 14:11

Ich habe es nochmal anders probiert, damit das Popup global angesteuert werden kann. Die GUI ist nun nicht ein Toplevel. Ist das okay?

Ansteuerung nun so:

Code: Alles auswählen

        Zaehlerr = DEFAULT_ZAEHLER
        self.container.companynamelabel.bind("<Button-3>",lambda event, arg=Zaehlerr: context_input_open_global(event,arg))
Die Zähler-Variable wird verwendet, um zu prüfen, ob es schon mehrfach vorliegt.

Die globale Funktion dann so:

Code: Alles auswählen

def context_input_open_global(event, Zaehler):
    print('Popup1 global')
        
    Zaehler = Zaehler + 1
    print(Zaehler)
    if Zaehler<=1:        
        SettingProgr = AppPopup_Test.PopupMenuFrame()
        SettingProgr.wm_state('iconic')
        SettingProgr.menu.tk_popup(event.x_root, event.y_root)
    else:
        SettingProgr.destroy()
        subscribe('TOPLEVEL_DESTROYER',None)

        SettingProgr = AppPopup_Test.PopupMenuFrame()
        SettingProgr.wm_state('iconic')
        SettingProgr.menu.tk_popup(event.x_root, event.y_root)
Problem ist aber das die Variable Zaehler nichtgespeichert wird, sondern jedesmal übergeben wird und dann immer gleich. Vielleicht sollte man das in eine globale Variable zurückgeben?
stefanxfg
User
Beiträge: 85
Registriert: Sonntag 2. April 2017, 14:11

Aha. Das war wohl quatsch. Man kann die Funktion nicht global machen, da nach verlassen der Funktion auch die Existens der angelegten Objekte verloren geht. Daher bleibe ich bei meiner vorherigen Lösung und man muss eben das BIND in der Inittialisierung und den Event in einer klasse bringen. Es ist dann eben so, dass man in jeder Klasse dieselben Befehle stehen hat.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

stefanxfg hat geschrieben:Ich möchte ein Popup- oder Kontextmenu per Rechtsklick in die GUI integrieren.
Rechtsklick auf welchem Widget? Auf freiem Platz im Top Window oder auch auf allen Widgets darin? Ist da überhaupt ein freier Platz. oder ist alles mit Frames belegt und sind die Frames teilweise leer oder auch alles gefüllt?

Willst Du jetzt auf allen Widgets den Rechtsklick implementieren? Oder wäre es nicht besser das Menü zu verwenden oder einen Menübutton oder Button?
stefanxfg
User
Beiträge: 85
Registriert: Sonntag 2. April 2017, 14:11

Ich würde im Eingabebereich allen Widgets das Kontextmenü verpassen. Es muss sicher nicht überall definiert werden, da sich Container auch überlagern.
Im Output möchte ich ein anderes Popup setzen. Das ist trivial.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

stefanxfg hat geschrieben:Ich würde im Eingabebereich allen Widgets das Kontextmenü verpassen. Es muss sicher nicht überall definiert werden, da sich Container auch überlagern.
Im Output möchte ich ein anderes Popup setzen. Das ist trivial.
Ich weiß jetzt nicht, wo das Problem mit dem Popup sein sollte. Da habe ich etwas von einem Zähler gesehen, wofür soll denn der gut sein?

Wenn das Popup nicht mehrfach aufgemacht werden soll, dann mache doch einfach ein Objekt dafür. Dieses kann sich ja merken, ob das Popup auf ist oder nicht.
stefanxfg
User
Beiträge: 85
Registriert: Sonntag 2. April 2017, 14:11

Ich hatte ja geschrieben, dass ich das Popup lokal gesetzt hatte und damit im angeklickten Feld aktiviert habe. Dann hatte ich versucht, die Aktivierung global zu setzen, damit nur noch der entsprechende Bind-Befehl lokal gesetzt zu werden braucht.

Ich hatte nur nicht geschafft, das das aufgerufene Fenster selbst gemekrt hat, ob es bereits offen war.
Antworten