Search code examples
pythonfunctiontkinterkeybind

Tkinter - How to bind a key press (not button) to call a function?


Suppose I have two functions which when called opens up a Frame:

Eg:

from tkinter import *
win = Tk()

class MyFrame(Frame):
    def __init__(self, master, **kwargs):
        Frame.__init__(self, master,
        bg='white' ,**kwargs)

def FuncOne():
    frameone = MyFrame(win)
    frameone.pack()

    lbl = Label(frameone, text="ABC", font='"Serif" 247' , width=win.winfo_screenwidth(), height=win.winfo_screenheight())
    lbl.pack(fill=BOTH, expand=True)


def FuncTwo():
    frametwo = MyFrame(win)
    frametwo.pack()

    lbl = Label(frametwo, text="ABC", font='"Serif" 200', width=win.winfo_screenwidth(), height=win.winfo_screenheight())
    lbl.pack()


win.mainloop()

How do I call FuncOne and FuncTwo which opens a separate frame each time by using a side arrow key and destroy the frame in FuncOne while calling FuncTwo and vice versa?


Solution

  • The following code provides 2 functions that will create a instance of your MyFrame class. In this function we will check if the list is empty with if actual_frame: returns False when its empty and create an instances of your class. On the bottom of this function wie store this instance in the list actual_frame. If you run now another time a function if actual_frame: returns True and it will destroy this instances, clear the list and build a new instance.

    from tkinter import *
    win = Tk()
    class MyFrame(Frame):
        def __init__(self, master, **kwargs):
            Frame.__init__(self, master,
            bg='red' ,**kwargs)
    actual_frame=[]
    def FuncOne(event):
        if actual_frame:
            actual_frame[0].destroy()
            actual_frame.clear()
            
        frameone = MyFrame(win)
        frameone.grid(column=0,row=0)
        lbl = Label(frameone, text="ABC", font='"Serif" 24' , width=10, height=15)
        lbl.pack(side=TOP,fill=BOTH, expand=True)
        
        actual_frame.append(frameone)
    
    def FuncTwo(event):
        if actual_frame:
            actual_frame[0].destroy()
            actual_frame.clear()
        
        frametwo = MyFrame(win)
        frametwo.grid(column=0,row=0)
        lbl = Label(frametwo, text="XYZ", font='"Serif" 20', width=10,height=15)
        lbl.pack(side=TOP, fill=BOTH, expand=True)
        
        actual_frame.append(frametwo)
    
    win.bind('<Left>', FuncOne)
    win.bind('<Right>', FuncTwo)
    
    win.mainloop()
    

    Update In this update I hade made another list in that we store all the functions you like to have. The keys we use here to cycle through the list with a little help oft itertools.cycle. We call in our new binded function the function that is next or once before in the function list.

    from tkinter import *
    from itertools import cycle
    
    win = Tk()
    class MyFrame(Frame):
        def __init__(self, master, **kwargs):
            Frame.__init__(self, master,
            bg='red' ,**kwargs)
    
    my_funcs=[]
    actual_frame=[]
    
    def FuncOne():
        if actual_frame:
            actual_frame[0].destroy()
            actual_frame.clear()
            
        frameone = MyFrame(win)
        frameone.grid(column=0,row=0)
        lbl = Label(frameone, text="ABC", font='"Serif" 24' , width=10, height=15)
        lbl.pack(side=TOP,fill=BOTH, expand=True)
        
        actual_frame.append(frameone)
    
    def FuncTwo():
        if actual_frame:
            actual_frame[0].destroy()
            actual_frame.clear()
        
        frametwo = MyFrame(win)
        frametwo.grid(column=0,row=0)
        lbl = Label(frametwo, text="XYZ", font='"Serif" 20', width=10,height=15)
        lbl.pack(side=TOP, fill=BOTH, expand=True)
        
        actual_frame.append(frametwo)
    
    def FuncThree():
        if actual_frame:
            actual_frame[0].destroy()
            actual_frame.clear()
        
        framethree = MyFrame(win)
        framethree.grid(column=0,row=0)
        lbl = Label(framethree, text="DEF", font='"Serif" 20', width=10,height=15)
        lbl.pack(side=TOP, fill=BOTH, expand=True)
        
        actual_frame.append(framethree)
        
    my_funcs.append(FuncOne)
    my_funcs.append(FuncTwo)
    my_funcs.append(FuncThree)
    
    cycle_of_funcs = cycle(my_funcs)
    
    def right_way(event):
        func = next(cycle_of_funcs)
        func()
    def left_way(event):
        leng = len(my_funcs)
        for function in range(leng-1):
            func = next(cycle_of_funcs)
        func()
    win.bind('<Left>', left_way)
    win.bind('<Right>', right_way)
    
    win.mainloop()
    

    I just want to leave a comment here that I think it isnt the best way of doing this, but still a possible way. Just to make sure on this answer is space for a OOP solutions [click]