pythontkinterback-button

Tkinter back and forward buttons re: visited history


My app displays details for one person at a time based on a current_person_id and other information related to that person which is stored in a database. I wanted to change the details displayed based on the order in which different persons' details had been seen, so it would work like a browser's back/forward button.

I found instructions here, here, and here which suggested using two stacks, one for the back button and one for the forward button. I didn't understand these instructions so I compared them with each other and compiled a more succinct and better organized set of instructions.

It took several hours but I finally managed to get this to work in Tkinter. I will answer my question below.


Solution

  • The back stack and forward stack start out empty.

    On navigate to new page not using back/forward

    On click back

    On click forward


    In a class the global variables can be changed to instance variables.

    import tkinter as tk
    bck_stack = []
    fwd_stack = []
    current_person_id = 1
    
    def change_current_person(key):
        """ Append current_person_id to forward or backward stack before changing 
            it to its new value. The current_person_id is not in either stack.    
        """
        global fwd_stack, current_person_id
        if key == "changer":
            got = ent.get()
            if len(got) == 0:
                return
            fwd_stack = []
            bck_stack.append(current_person_id)
            current_person_id = got
            redraw(current_person_id)
            ent.delete(0, "end")
        elif key == "back":
            if len(bck_stack) == 0:
                pass            
            else:
                fwd_stack.append(current_person_id)
                current_person_id = bck_stack.pop()
                redraw(current_person_id)
        elif key == "forward":
            if len(fwd_stack) == 0:
                pass
            else:
                bck_stack.append(current_person_id)
                current_person_id = fwd_stack.pop()
                redraw(current_person_id)
    
    def redraw(current_person_id):
        current["text"] = current_person_id
        bck_history.delete("1.0", "end")
        bck_history.insert("1.0", bck_stack)
        fwd_history.delete("1.0", "end")
        fwd_history.insert("1.0", fwd_stack)
    
    if __name__ == "__main__":
    
        buttons = {}
    
        root = tk.Tk()
        root.geometry("+700+300")
        root.config(bg="black")
        lab_bck = tk.Label(
            root, text="Back Stack", anchor="w", bg="black", fg="white")
        bck_history = tk.Text(
            root, width=40, height=4, bg="steelblue", fg="white")
        bck_history.insert("1.0", "Back history displays here.")
    
        lab_fwd = tk.Label(
            root, text="Forward Stack", anchor="w", bg="black", fg="white")
        fwd_history = tk.Text(
           root, width=40, height=4, bg="steelblue", fg="white")
        fwd_history.insert("1.0", "Forward history displays here.")
    
        ent = tk.Entry(root, bg="steelblue", fg="white")
        for key in ("changer", "back", "forward"):
            buttons[key] = tk.Button(
            root, bg="teal", command=lambda key=key: change_current_person(key))        
    
        current = tk.Label(
            root, width=5, height=1, bg="blue", fg="white", 
            font=("arial black", 21), text=current_person_id)
    
        buttons["changer"]["text"] = "CHANGE CURRENT PERSON"
        buttons["back"]["text"] = "BACK"
        buttons["forward"]["text"] = "FORWARD"
    
        lab_bck.grid(column=0, row=0)
        bck_history.grid(column=0, row=1, columnspan=3)
        lab_fwd.grid(column=0, row=2)
        fwd_history.grid(column=0, row=3, columnspan=3)
        ent.grid(column=0, row=4)
        buttons["changer"].grid(column=1, row=4)
        current.grid(column=2, row=4)
        buttons["back"].grid(column=0, row=5)
        buttons["forward"].grid(column=1, row=5)
    
        ent.focus_set()
    
        root.mainloop()