tkinter update main dialog widgets from function - python

I'm just getting started with tkinter, so the answer to this question may be rather obvious to those with more experience... My Python program defines a root window in the main code, which includes several label widgets:
for i in range(0,20):
line.append(ttk.Label(mainframe, text=""))
line[i].grid(column=1, row=i, sticky=W)
It also has a few menu items, one of which launches a graphical subprogram that operates in its own (pygame) window. I would like to modify the labels in the main window based on events in the subprogram, which I try using:
line[i].configure(text=s)
Problem is, these new label values don't show up until the subprogram completes and control returns to the main window. Is there a way around this?

Related

Is it bad practice to create a second tkinter Tk() after the first instance has been destroyed by closing the window?

I am learning about Tkinter and was wondering if it would cause errors if I did the following:
import tkinter as tk #import modules
from tkinter import ttk
parent=tk.Tk() #create first instance
card1="k spades"
card2="k diamonds"
comboform=ttk.Combobox(parent,textvariable='form',values=[card1,card2,"both","neither"])#create combobox input form
comboform.grid(row=0,column=0)#added to grid
parent.geometry("200x200")
parent.mainloop()#displays tkinter window
#window exited
parent=tk.Tk()#new instance created
label=tk.Label(parent,text="hi")#label produced
label.pack()#added to window
parent.mainloop()
If I click the exit cross is that the same as parent.destroy(); is that good practice? I know you're only supposed to run mainloop() once and have one Tk() instance but if it's destroyed is it going to cause problems? It's not like I'm creating a class the produces a Tk() instance, where there's a risk of multiple instances existing at once.
I am hoping to, eventually, have an application running in the IDLE and then have a tkinter window appear, presenting an input widget of some kind. After the user gives their input, the window would close and the user would continue in the main window. But could I then do it again, opening new windows (like the above code) on the provision that the instance of Tk() is destroyed each time?
If you've destroyed the root window and then create a new one, that's perfectly fine.
The problem with creating multiple instances of Tk is that most people don't understand what that actually does. Having multiple instances of Tk is fine as long as you realize that they operate in completely memory spaces and widgets and bindings in one can't interact with widgets and bindings in the other.
All of that being said, the best practice is to create a single root window at the start of the program, and it stays alive until the program exits. If you need additional windows, the best practice is to create instances of Toplevel.

Detect when a widget change from visible to invisible or the opposite [duplicate]

This question already has an answer here:
Event binding to detect a grid_remove (Tkinter)
(1 answer)
Closed 2 years ago.
Is it possible to be informed when we a widget which was visible become invisible .pack_forget() or an invisible widget become visible .pack() ?
Something Like button.bind("<Visible>", func_triggered_when_the_button_become_visible)
I want to hide and show entire frames and when I hide the widgets inside, I want their values to be reset.
I think <Map> is what your looking for, as per acw1668 suggestions. Here is an example to make you understand better:
from tkinter import *
from tkinter import messagebox
root = Tk()
def check(event): #function to be triggered only when the button is visible
messagebox.showinfo('Visible','Seeing this message only because button is visible')
b = Button(root,text='Im going to disappear') #making button but not packing it(invisible)
b1 = Button(root,text='Click me to make the button disappear',width=50,command=lambda: b.pack_forget()) #to hide the button(to make invisible)
b1.pack(padx=10)
b2 = Button(root,text='Click me to make the button appear',width=50,command=lambda: b.pack()) #to show the button(to make visible)
b2.pack(padx=10)
b.bind('<Map>',check) #every time button is visible, check() is triggered
root.mainloop()
Ive commented to understand this better, do let me know if any doubts.
A bit more on <Map> from the docs:
The Map and Unmap events are generated whenever the mapping state of a window changes.
Windows are created in the unmapped state. Top-level windows become mapped when they transition to the normal state, and are unmapped in the withdrawn and iconic states. Other windows become mapped when they are placed under control of a geometry manager (for example pack or grid).
A window is viewable only if it and all of its ancestors are mapped. Note that geometry managers typically do not map their children until they have been mapped themselves, and unmap all children when they become unmapped; hence in Tk Map and Unmap events indicate whether or not a window is viewable.

How do I navigate from one python gui program to another?

Here's an excerpt for a main menu using Python Tkinter
master = Tk()
lbl = Label(master, text = "Main Menu:")
lbl.grid(row=0,column=1)
def list():
import list
listb = Button(master, text = "Patient List", command=list, width=10)
listb.grid(row=1, column=1)
There's a button "Patient List" that when pressed, opens a window specified from a different python file.
My problem is that the Main Menu window suffers a bug where the window will collapse. The new window comes out fine, but after closing it, I can't use my Main Menu.
Also, on my other buttons. The Main Menu doesn't collapse, but let's say I have a button Add Patient and after clicking it, the Add Patient window appears. It's functional. And then I close it, either using the quit button I programmed in it, or the close button. The Main Menu won't open the Add Patient window again.
So how can I smoothly navigate from one python program to another? Without the main menu collapsing. While being able to open a window over and over again.
My Patient List program has a lot of customized gui programming in it. I think it's because I use a grid in my Main Menu, and it's not a grid in my Patient List. But it shouldn't be affecting the Main Menu because they're supposed to be separate programs.
When doing such program with TKinter I generally use Screen classes.
To your example it would be for example:
"MainScreen", "AddPatienScreen", ...
All are subclass of the Frame tkinter class.
My Tk app only display one screen and furnish function to destroy and replace one screen by another one.
I have not access to any code now, but I invite yourself to try this approach if you understand it. It lead to well separated code and had good results.
I may provide you a very short example if required.

How to expand window/frame when button or checkbox is clicked in tkinter?

I am using Tkinter for my python script. At current stage, gui looks ugly because of too many options/widgets in one screen. Not all of them are needed all the time and it can be divided into four parts. Hence my idea is to have them expand the frame (one frame for each part) with its options/widgets in the current window.
Is it possible in tkinter to expand the window/frame when a button or a checkbox is clicked?
ps - I have tried opening each part in new window but this makes gui unnecessarily complicated.
Thanks!
So, your gonna need to define what happens when the button is clicked-
def buttonClicked():
root.geometry("350x300")
where root is the window and then on the button you will need to write -
btn = tkinter.Button(text = "Button", command=buttonClicked)
btn.pack
Hope that answers your question!

How do I bind '<Return>' to focused (tabbed) button in tkinter?

I have multiple buttons in my tkinter 8.5 GUI (on Windows 7). I want whatever button is focused on (tabbed over) to be selected when the user hits Enter. I know I have to bind '<Return>', but I need the rest of the gaps filled in.
Thanks in advance!
Assuming you want this to be universal to all applications in the root window you could do something similar to this.
def clickButton():
widget = root.focus_get()
if widget != root:
widget.invoke()
root = Tkinter.Tk()
root.bind("<Return>", clickButton)
root.mainloop()
That will run any command associated with the currently tabbed selection. If you want to limit it to certain buttons you can do type-checking inside of the method. Widget will be whatever widget is currently in focus via the tabbed selection. Also beware of a user hitting enter on certain widgets that may not support the invoke method.

Categories