[Tkinter] Program with Multiple Windows - how to use Class: - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: GUI (https://python-forum.io/forum-10.html) +--- Thread: [Tkinter] Program with Multiple Windows - how to use Class: (/thread-25730.html) |
Program with Multiple Windows - how to use Class: - Riddle - Apr-09-2020 Hi everyone, This is my first post on this forum. I have been trying to learn Tkinter and find answers via web searches, but it only got me so far. I am writing code to create multiple windows, and then have them interact with each other. Here, to stay simple, I created a program that has a list of values, a main menu window, a window where you can change the values, a window that lets you select the values to display, and a window where you display them. I also played around with scrollbars and progress bars. My main question is the following: - To take this to the next level, I would like to move to object-oriented approach. I read online that the best way to do this is to create a class for each window. However, I am not quite sure where to start. Since each window has to display my values, and the windows interact with each other, would I have to insert every variable I am using as an argument for each window? If so, where do I define the variables? Do I make a "main()" function that defines the variables, then have each class use them as argument? Where do I put the ".mainloop()" command then? And I have another couple of smaller questions about my code: - On Lines 98 and 123, I was not able to automatically create Buttons and CheckButtons that would work for each i, and I then had to individually create the first few by hand. How do I do it all at once (it would be painful to have to create 50 of them by hand)? - I was able to make the Scrollbar work in the "Change Values" window even if I scroll while the mouse is anywhere on the screen, but for the "Select Values" window, I need to be on the side on top of the scrollbar itself to work. What is the best way to make it so that, if I am in particular window, scrolling with the mouse anywhere on the window will make it scroll? Here is the code. Thank you so much for the help!! # Basic Tkinter project with multiple windows interacting with each other from tkinter import * from tkinter import ttk import tkinter as tk root = Tk() # The number of values to store n = 50 # A list 'values' to contain the 'n' values and set them equal to 1 values = [IntVar() for _ in range(n)] for i in range(n): values[i].set(1) # A list 'selectValues' to keep track of which values are selected selectValues = [IntVar() for _ in range(n)] for i in range(n): selectValues[i].set(0) # Two variables to be used later label = [0 for _ in range(n)] progress = [0 for _ in range(n)] # Show windowToShow and hide other windows def showWindow(windowToShow): for W in (change, select, display): W.iconify() windowToShow.deiconify() return() # To put a vertical scrollbar when windows are too long def onFrameConfigure(canvas): '''Reset the scroll region to encompass the inner frame''' canvas.configure(scrollregion=canvas.bbox("all")) # These allow to scroll with the mouse wheel def _on_mousewheel(canvas, event): canvas.yview_scroll(int(-1*(event.delta/120)), "units") # Increase value by 1 def increase(num): values[int(num)].set(values[int(num)].get() + 1) progress[int(num)]["value"] = values[int(num)].get() # Update selected values def updateSelection(num): if selectValues[int(num)].get() == 1: label[int(num)].grid() progress[int(num)]["value"] = values[int(num)].get() progress[int(num)].grid() else: label[int(num)].grid_remove() progress[int(num)].grid_remove() # Create Main Menu mainmenu = ttk.Frame(root, width=200, height=200, padding="100 100 100 100") mainmenu.grid(column=0, row=0, sticky=(N, W, E, S)) # Create windows needed for game change = tk.Toplevel(root) change.geometry("600x600") select = tk.Toplevel(root) select.geometry("1250x700") display = tk.Toplevel(root) display.geometry("1250x700") # Hide all windows to start the game change.iconify() select.iconify() display.iconify() # Widgets for the Main Menu changeButton = ttk.Button(mainmenu, text="Change Values", command= lambda: showWindow(change)) changeButton.grid(column=1, row=1) selectButton = ttk.Button(mainmenu, text="Select Values", command= lambda: showWindow(select)) selectButton.grid(column=1, row=11) displayButton = ttk.Button(mainmenu, text="Display Values", command= lambda: showWindow(display)) displayButton.grid(column=1, row=21) # Add padding to all widgets in the Main Menu for child in mainmenu.winfo_children(): child.grid_configure(padx=5, pady=5) # Put a canvas in the Change Values window to be able to use a scrollbar changeCanvas = tk.Canvas(change) changeFrame = tk.Frame(changeCanvas) vsb = tk.Scrollbar(change, orient="vertical", command=changeCanvas.yview) changeCanvas.configure(yscrollcommand=vsb.set) vsb.pack(side="right", fill="y") changeCanvas.pack(side="left", fill="both", expand=True) changeCanvas.create_window((4,4), window=changeFrame, anchor="nw") changeFrame.bind("<Configure>", lambda event, canvas=changeCanvas: onFrameConfigure(canvas)) changeCanvas.bind_all("<MouseWheel>", lambda event, canvas=changeCanvas: _on_mousewheel(canvas, event)) # Widgets for the Change Values window ttk.Button(changeFrame, text="Return to Main Menu", command=change.iconify).grid(column=0,row=0,columnspan=1000) for i in range(n): ttk.Label(changeFrame, textvariable=values[i]).grid(column=10, row=10+i) # ttk.Button(changeFrame, text="increase by 1", command = lambda: increase(i)).grid(column=20, row=10+i) ttk.Button(changeFrame, text="increase by 1", command = lambda: increase(0)).grid(column=20, row=10) ttk.Button(changeFrame, text="increase by 1", command = lambda: increase(1)).grid(column=20, row=11) ttk.Button(changeFrame, text="increase by 1", command = lambda: increase(2)).grid(column=20, row=12) ttk.Button(changeFrame, text="increase by 1", command = lambda: increase(3)).grid(column=20, row=13) ttk.Button(changeFrame, text="increase by 1", command = lambda: increase(4)).grid(column=20, row=14) # Add padding to all widgets in the Change Values window for child in changeFrame.winfo_children(): child.grid_configure(padx=5, pady=5) # Put a canvas in the Select Values window to be able to use a scrollbar selectCanvas = tk.Canvas(select) selectFrame = tk.Frame(selectCanvas) vsb = tk.Scrollbar(select, orient="vertical", command=selectCanvas.yview) selectCanvas.configure(yscrollcommand=vsb.set) vsb.pack(side="right", fill="y") selectCanvas.pack(side="left", fill="both", expand=True) selectCanvas.create_window((4,4), window=selectFrame, anchor="nw") selectFrame.bind("<Configure>", lambda event, canvas=selectCanvas: onFrameConfigure(selectCanvas)) # Widgets for the Select Values window ttk.Button(selectFrame, text="Return to Main Menu", command=select.iconify).grid(column=0, row=0, columnspan=1000) for i in range(n): ttk.Label(selectFrame, textvariable=values[i]).grid(column=10, row=10+i) # ttk.Checkbutton(selectFrame, text="Select", variable=selectValues[i], command=lambda: updateSelection(i)).grid(column=20, row=10+i) ttk.Checkbutton(selectFrame, text="Select", variable=selectValues[0], command=lambda: updateSelection(0)).grid(column=20, row=10) ttk.Checkbutton(selectFrame, text="Select", variable=selectValues[1], command=lambda: updateSelection(1)).grid(column=20, row=11) ttk.Checkbutton(selectFrame, text="Select", variable=selectValues[2], command=lambda: updateSelection(2)).grid(column=20, row=12) ttk.Checkbutton(selectFrame, text="Select", variable=selectValues[3], command=lambda: updateSelection(3)).grid(column=20, row=13) ttk.Checkbutton(selectFrame, text="Select", variable=selectValues[4], command=lambda: updateSelection(4)).grid(column=20, row=14) # Add padding to all widgets in the Select Values window for child in selectFrame.winfo_children(): child.grid_configure(padx=5, pady=5) # Widgets for the Display window ttk.Button(display, text="Return to Main Menu", command=display.iconify).grid(column=0, row=0, columnspan=1000) for i in range(n): label[i] = ttk.Label(display, textvariable=values[i]) label[i].grid(column=10, row=10+i) progress[i] = ttk.Progressbar(display, orient=HORIZONTAL, length=100, mode='determinate') progress[i].grid(column=20, row=10+i) progress[i]["value"] = values[i].get() progress[i]["maximum"] = 10 label[i].grid_remove() progress[i].grid_remove() # Main Loop root.mainloop() RE: Program with Multiple Windows - how to use Class: - Riddle - Apr-09-2020 Edit: I was able to fix the problem for Lines 98 and 123 by adding an "i=i" after the "lambda". |