Python tkinter, how to disable background buttons from being clicked - python

When opening a new tkinter window, I only want the user to be able to click buttons on the new window. They should not be able to click on buttons from other windows that are part of the application. How would I accomplish this?
Here is a snip of my code:
def exportEFS(self):
self.exportGUI = Toplevel()
Button(self.exportGUI, text='Backup', command=self.backup).pack(padx=100,pady=5)
Button(self.exportGUI, text='Restore', command=self.restore).pack(padx=100,pady=5)
def backup(self):
self.backupWindow = Toplevel()
message = "Enter a name for your Backup."
Label(self.backupWindow, text=message).pack()
self.entry = Entry(self.backupWindow,text="enter your choice")
self.entry.pack(side=TOP,padx=10,pady=12)
self.button = Button(self.backupWindow, text="Backup",command=self.backupCallBack)
self.button.pack(side=BOTTOM,padx=10,pady=10)
In this snip, once the backupWindow is opened, the exportGUI remains open, but the user should not be able to click "Backup" or "Restore" while the backupWindow is opened.
Thanks!

You will want to call grab_set on the TopLevel window so that all keyboard and mouse events are sent to that.
def exportEFS(self):
self.exportGUI = Toplevel()
Button(self.exportGUI, text='Backup', command=self.backup).pack(padx=100,pady=5)
Button(self.exportGUI, text='Restore', command=self.restore).pack(padx=100,pady=5)
def backup(self):
self.backupWindow = Toplevel()
self.backupWindow.grab_set()
message = "Enter a name for your Backup."
Label(self.backupWindow, text=message).pack()
self.entry = Entry(self.backupWindow,text="enter your choice")
self.entry.pack(side=TOP,padx=10,pady=12)
self.button = Button(self.backupWindow, text="Backup",command=self.backupCallBack)
self.button.pack(side=BOTTOM,padx=10,pady=10)

What you can do is set the state to disabled. As so:
self.button.config(state="disabled")
And to enable it, you just use:
self.button.config(state="normal")
However, you must assign your buttons to variables first, like this:
self.backup=Button(self.exportGUI, text='Backup', command=self.backup)
self.backup.pack(padx=100,pady=5)
self.restore=Button(self.exportGUI, text='Restore', command=self.restore)
self.restore.pack(padx=100,pady=5)
so you would disable these using:
self.backup.config(state="disabled")
self.restore.config(state="disabled")
and re-enable using:
self.backup.config(state="normal")
self.restore.config(state="normal")
Please note however, that while the button is disabled, nothing can be changed to that button, both through the code, or through the user using it. So that means if you wanted to change the text of that button, you would have to change the state of the button to "normal" before changing it (if it already isn't in that state, which by default, all widgets are in that state when first created).
Cheers :)

Related

Only opening a Window only when it already is not open in Tkinter

I created a button in tkinter with its command being to create anew window. But I don't want it to create a new window every time I click the create a new window button. I want to tell the program to open the new window only if it is not already open. If somewhere in the background the window is already open and the user presses the create a new window button I want it to move that window on the first layer of the user's screen (bringing it upfront from all the other open windows).
Here is my code --
def main():
main_bg = "Gray"
main_fg = "White"
import tkinter as tk
employees = []
window = tk.Tk()
window.configure(bg=main_bg)
window.title("Business app")
window.geometry("1100x650")
def open_new_window():
random_window = tk.Toplevel(window)
random_window.configure(bg=main_bg)
random_window.geometry("600x600")
random_button = tk.Button(window, text="Do Something", font="Times 32", bg=main_bg, fg=main_fg, command=open_new_window)
random_button.pack()
window.mainloop()
if __name__ == "__main__":
main()
I have searched websites like Geeksforgeeks and this website but I could not find the solution I was looking for. Please help.
NOTE -- PLEASE DO NOT CLOSE THIS QUESTION AND POINT ME TOWARDS ANOTHER FORUM BECAUSE I HAVE CHECKED OTHERS IN THIS WEBSITE AS I MENTIONED ABOVE
Added grab_set() will prevent open new window again.
def open_new_window():
random_window = tk.Toplevel(window)
#random_window.configure(bg=main_bg)
random_window.geometry("600x600")
random_window.grab_set()
Result:
When you click Do Something will prevent open new window. Unless close the topelevel window and then open new window again
You can save a reference to the widget, and then check the reference to see if it's set. If it is set, you can then call winfo_exists to check whether the reference points to an existing window.
random_window = None
...
def open_new_window():
global random_window
if random_window and random_window.winfo_exists():
# the window exists, so do nothing
return
random_window = tk.Toplevel(window)
random_window.configure(bg=main_bg)
random_window.geometry("600x600")

Button will not change to active when listbox is selected?

I've made a function that creates a toplevel window with buttons and a listbox. I have an edit button to edit a selected item in said listbox, but I want this button disabled if nothing inside the listbox is selected.
def edit_page():
window3 = Toplevel()
frame3= Frame(window3)
frame3.pack(side=TOP)
color_list = Listbox(frame3)
color_list.grid(row=1,column=0)
edit_button = Button(frame3,text="Edit",command=fav_edit)
edit_button.grid(row=4,column=4)
if len(color_list.curselection()) > 0 :
edit_button.config(state=ACTIVE)
else:
edit_button.config(state=DISABLED)
The last thread was dead and it was filled with confusion, sorry.
It seems the if/else statement isn't working as intended. When I open this new window, the button is disabled, and when I click on the listbox, it stays disabled.
If I flip the ACTIVE and DISABLED states in the if/else, like:
if len(color_list.curselection()) > 0 :
edit_button.config(state=DISABLED)
else:
edit_button.config(state=ACTIVE)
The edit button is active, and will stay active even if the listbox is selected.
Is the window not updating? Do I need to try it another way? Any help is appreciated.
Edit: My listbox does include items/tuples inside of it even if it does not show it in this example of my project.
Used a mouse event to call to a function to check the length of the tuple.
def edit_page():
window3 = Toplevel()
frame3= Frame(window3)
frame3.pack(side=TOP)
color_list = Listbox(frame3)
color_list.grid(row=1,column=0)
edit_button = Button(frame3,text="Edit",command=fav_edit)
edit_button.grid(row=4,column=4)
color_list.bind("<Enter>",lambda *args: check_sel(edit_button,color_list.curselection()))
def check_sel(button,selection):
if len(selection) > 0:
button.config(state=ACTIVE)
else:
button.config(state=DISABLED)

Radio Button and Checkbox don't update variable value

I have a GUI that uses a class that calls a function that provides a popup window.
The popup box has a button that gets a directory from the user using askdirectory() from tkinter.filedialog, a pair of radio buttons(RadioG, RadioY), and checkbox(state_checkbox) that I want to update the two different variables(driveletter and statevalue) . I've set the drive letter to "G:" and that value is held correctly, but doesn't update if I select the "Y:" Radio button. I have the IntVar.set(1), but that checkbox does not populate as checked and checking/unchecking it keeps the value at 1 and does not update it to 0 when unchecked.
Any advice on what I'm missing to keep my values from updating is appreciated.
relevant section of code below:
class preferences(Preferences):
def save_preferences(self):
# Used to reset the folder location desired by the user
self.prefdialog = tk.Tk()
self.prefdialog.title('Set Preferences')
self.driveletter = tk.StringVar()
self.driveletter.set("G:")
self.statevalue = tk.IntVar()
self.statevalue.set(1)
self.fpath = '\\Desktop'
self.RadioG = tk.Radiobutton(self.prefdialog, text="G:", variable=self.driveletter,
value="G:", command=lambda: print(self.driveletter.get()))
self.RadioG.grid(row=3,column=0,sticky=tk.W,pady=4)
self.RadioY = tk.Radiobutton(self.prefdialog, text="Y:", variable=self.driveletter,
value="Y:", command=lambda: print(self.driveletter.get()))
self.RadioY.grid(row=3,column=1,sticky=tk.W,pady=4)
self.state_checkbox = tk.Checkbutton(
self.prefdialog, text="Check to use state folders",
variable=self.statevalue, command=lambda: print(self.statevalue.get()))
self.state_checkbox.grid(row=4,column=0,sticky=tk.W,pady=4)
self.prefdialog.mainloop()
For posterity: Looks like my issue was using Tk() twice. Per Bryan since I'm trying to create a popup window, I should be calling Toplevel(), not a second instance of Tk(). I also definitely called mainloop() twice, once for my main window and once for this popup window.

tkinter messagebox without buttons

In my program I just need to notify user to not press a physical button om a system with no keyboad or mouse,
want to popup a Wait message that disapears when the system is again ready
There are two reasons you don't want a message box here.
First, the whole point of a message box is that it's a modal dialog with some standardized buttons, and you don't want those buttons.
Second, the whole point of a modal dialog is that it's modal—it runs its own event loop, and doesn't return until the dialog is dismissed. This means (unless you're using background threads) your app can't do anything while displaying it.
The first problem is easy to solve. tkMessageBox is just a simple wrapper around tkCommonDialog.Dialog. It's worth looking at the source to see just how simple it is to construct a dialog box that does what you want. But tkSimpleDialog.Dialog is even simpler than tkCommonDialog (hence the name). For example:
class WaitDialog(tkSimpleDialog.Dialog):
def __init__(self, parent, title, message):
self.message = message
Dialog.__init__(self, parent, title=title, message=message)
def body(self, master):
Label(self, text=self.message).pack()
def buttonbox(self):
pass
def wait(message):
WaitDialog(root, title='Wait', message=message)
That's all it takes to create a modal dialog with no buttons. Dialog Windows and the source to tkSimpleDialog have more details.
The second problem is even easier to solve: If you don't want a modal dialog, then all you want is a plain old Toplevel. You may want it to be transient, so it stays on top of the master, hides with it, doesn't show up on the taskbar, etc., and you may want to configure all kinds of other things. But basically, it's this simple:
def wait(message):
win = Toplevel(root)
win.transient()
win.title('Wait')
Label(win, text=message).pack()
return win
Now you can call wait() and continue to run:
def wait_a_sec():
win = wait('Just one second...')
root.after(1000, win.destroy)
root = Tk()
button = Button(root, text='do something', command=wait_a_sec)
root.mainloop()

Close a tkinter window after a period of time

I have a piece of Python code that is supposed to open a new window for a period of time and then close the window. The window is triggered by clicking a button. Here is the basics of what I have.
def restore(self):
self.restore = Toplevel()
message = "Select an available Backup to Restore to."
Label(self.restore, text=message).pack()
# We then create and entry widget, pack it and then
# create two more button widgets as children to the frame.
os.chdir('.')
for name in os.listdir("."):
if os.path.isdir(name):
self.button = Button(self.restore, text=name,command=self.restoreCallBack)
self.button.pack(side=BOTTOM,padx=10)
def restoreCallBack(self):
self.restoreCB = Toplevel()
message = "Please wait while the database is restored..."
Label(self.restoreCB, text=message, padx=100, pady=20).pack()
time.sleep(5)
self.restore.destroy()
self.restoreCB.destroy()
I need the restoreCallBack window to be displayed for 5 seconds, then the windows to close. Thanks!
Have a look at the after method. e.g.:
widget.after(5000,callback)
You shouldn't use sleep in (the main thread of) a GUI -- The entire thing will just freeze.

Categories

Resources