Apr-09-2020, 06:13 PM
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!!
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()