I use tkinter and CTK:
I have created a page for login and I want to stop or use this page when the user is logged in, I want to show a new window and I want to resume the window when I want? How can I do that, I didn't know how to make it
I'll bite. Here's an example application that opens a second window when the user clicks a button on the main window, and disables interaction with the main window until the second window is closed.
Some configuration has been omitted for brevity, and I'm not using CTk here because I don't know how you've implemented it in your specific application - however, it should be easy enough to modify this example to work with CTk.
import tkinter as tk
from tkinter import ttk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.open_button = ttk.Button(
self,
text='Open 2nd Window',
command=self.modal
)
self.open_button.pack()
def modal(self):
self.window = tk.Toplevel(self) # create new window
# bind a handler for when the user closes this window
self.window.protocol('WM_DELETE_WINDOW', self.on_close)
# disable interaction with the main (root) window
self.attributes('-disabled', True)
self.close_button = ttk.Button(
self.window,
text='Close Modal',
command=self.on_close
)
self.close_button.pack()
def on_close(self):
# re-enable interaction the root window
self.attributes('-disabled', False)
# close the modal window
self.window.destroy()
if __name__ == '__main__':
app = App()
app.mailoop() # run the app
In the future:
Provide code that shows you made a good-faith effort to solve the problem on your own
Don't post the same question multiple times within hours - if you need to make changes, edit the original question
If you mean you want to open up another window to do something before going back to the original window, you should consider using message box. Here is a link that goes over the types of messageboxes: https://docs.python.org/3/library/tkinter.messagebox.html.
Related
I would like to disable the main window of my text adventure program while the character creation window is up. I am relatively new to this. When I try my code below, the main window stays interactable even though the secondary window (creator) is open. There is no error that the console puts out, it just doesn't work is all.
def characterCreator():
global creator
creator = Tk()
creator.title('Character Creator')
creator.geometry('300x400')
while creator.state=='normal':
root.state='disabled'
You should create your creator window as an instance of tkinter.Toplevel() rather than declaring a new instance of Tk() altogether, then you can use grab_set to prevent the user from interacting with the root window while the creator window is open.
import tkinter as tk
root = tk.Tk()
# usual root configs like title and geometry go here
creator = tk.Toplevel(root) # the Toplevel window is a child of the root window
# creator geometry and title and so on go here
creator.grab_set() # keep window on top
if __name__ == '__main__':
root.mainloop()
I am opening other windows from a single tkinter button as shown here:
https://www.pythontutorial.net/tkinter/tkinter-toplevel/
The code shown there is
import tkinter as tk
from tkinter import ttk
class Window(tk.Toplevel):
def __init__(self, parent):
super().__init__(parent)
self.geometry('300x100')
self.title('Toplevel Window')
ttk.Button(self,
text='Close',
command=self.destroy).pack(expand=True)
class App(tk.Tk):
def __init__(self):
super().__init__()
self.geometry('300x200')
self.title('Main Window')
# place a button on the root window
ttk.Button(self,
text='Open a window',
command=self.open_window).pack(expand=True)
def open_window(self):
window = Window(self)
window.grab_set()
if __name__ == "__main__":
app = App()
app.mainloop()
If I run this program, it is not possible to hit the "Open a window" button twice to get two Toplevel instances. I would like to get as many instances as I like to with only one button. Is this possible somehow?
Consider this line of code:
window.grab_set()
This is setting a grab on the first window that is created. That means that all events from both the keyboard and the mouse are funneled to the first window that is created. That means you can no longer click on the button in the root window until the grab has been removed. Note that if the window is destroyed, the grab is automatically removed.
Grabs are typically used when creating a modal dialog -- a dialog which requires user input before the program can continue. By doing a grab, you insure that the user can't interact with the main program until they've interacted with the dialog.
The solution is simple: remove the call to window.grab_set() if your goal is to be able to open multiple windows which can all be used at the same time.
Simply remove window.grab_set(). The grab_set() method routes all events for this application to this widget. Whatever events generated like button-click or keypress is directed to another window.
def open_window(self):
window = Window(self)
So I've given myself a little project and I'm trying to make a little tool to connect to the OKEX exchange. Now I'm currently working on the GUI and I've decided to use Tkinter. After lots of research and what-not, I've come up with the following, but now I've become a bit stuck.
I've got 2 classes, one for the main window and one for the login window. However, some of the functions of the main window rely on what happens after I've submitted the login details. Now I know that Toplevel is for creating additional windows in Tkinter, and you normally close these windows with .destroy() , and if I want to pick up on this event in the main window class then I need to use the Toplevel.protocol("WM_DELETE_WINDOW", function_name) call ...but this isn't working for me.
It works as expected if I close using the cross in the top right, but not if I close with my function that calls .destroy() , can anyone explain to me why this isn't working as intended? Perhaps I have missed something ?
I want to change the text in the first frame to "Logged In" after the user (me) enters in their details, but I need to login first and pass through a user object to contain those details.
Anyways, here's the code, please help me out!
The code in question is the myquit function in the LoginBox class , and the goToLogin function in the MainBox class :)
from tkinter import *
from tkinter.ttk import *
class LoginBox:
def __init__(self, master): # Master is the frame that is passed in.
# Create Frame
self.master = master
self.master.title('~ Please Login ~')
def login_function(self):
user = "xxx"
secret_key = "yyy"
print("User - API Key: " + user)
print("User - Secret Key: " + secret_key)
# Perhaps check the login ...
# if it's a success then quit the function
self.myquit()
def myquit(self):
self.master.destroy()
class MainBox:
def __init__(self, master):
# Set the root window
self.master = master
self.master.geometry("500x500")
self.master.title("OkBot v0.1")
self.master.resizable(False, False)
# Initialize the frames
self.uiFrame1 = Frame(self.master) # The Top Layer -- Login Text + Login Button
# uiFrame1 Initialize --Login Text + Login Button
self.ui1_button = Button(self.uiFrame1, text="Login", command=self.goToLogin).grid(row=0, column=3, sticky=E, padx=1)
# Create Topview for popup , pass in User Object to LoginBox
def goToLogin(self):
loginMaster = Toplevel(self.master)
loginMaster.protocol("WM_DELETE_WINDOW", self.checkLogin) # This is if they close via X
loginGUI = LoginBox(loginMaster)
def checkLogin(self):
print("This function was called -- The Protocol for destroyed windows works")
# Initialize the objects and start the program
mainWindow = Tk()
myProgram = MainBox(mainWindow)
mainWindow.mainloop()
It works as expected if I close using the cross in the top right, but not if I close with my function that calls .destroy() , can anyone explain to me why this isn't working as intended? Perhaps I have missed something ?
loginMaster.protocol("WM_DELETE_WINDOW", self.checkLogin) only tells tkinter what to do when the window manager destroys the window. When you call some function which calls destroy(), that doesn't involve the window manager and therefore your callback is not called.
If you want something to happen when the window is destroyed, you should bind to the <Destroy> event.
Below is part of my code. The problem I'm having is I want to insert a value to a Tkinter entry in my main window, but when I call the variable 'selected_db' I get the value of A. I want to get the value after the 'OK button' is clicked so I get the value of B
I'm not sure how should I do it or if this is even close to the right way to do it so I would really appreciate some help here.
Thanks in advance
Main_Window():
def browse_db(self):
my_dbs = Databases()
self.db_entry.insert(0,my_dbs.selected_db)
def __init__(self):
self.main_window = Tkinter.Toplevel()
self.db_entry = ttk.Entry(self.main_window, width=10)
self.db_entry.grid(row=1, column= 1)
Databases():
def __init__(self):
self.selected_db = A
self.db_window = Tkinter.Toplevel()
okButtom = ttk.Button(self.db_window, command=self.grab_db).grid(row=1, column=1)
def grab_db(self):
self.selected_db = B
It's hard to tell without a complete, working example, but I think what you are asking is how to make your main window wait for your popup to exit. In other words what we usually call a "modal window". To do that you need to pass the master window to the Toplevel call and add these commands at the end of the popup's __init__ method:
self.transient(master) # set to be on top of the main window
self.grab_set() # hijack all commands from the master (clicks on the main window are ignored)
master.wait_window(self) # pause anything on the main window until this one closes
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()