I have a Tkinter window in the file gui.py. Upon the press of the Spacebar, I want to open another Tkinter window which is used to obtain an input from the user via the file imageinput.py.
So, I wrote the code to execute the run function of imageinput.py
def keyPressed(event, data):
if event.keysym == "space": image_run()
When I run this, I get the following error:
What is the best way to open such another Tkinter window this way?
Without knowing more of your code, you would create a new "top level" widget and use that widget like you used the original root top level window ( root = tkinter.Tk()) as the parent of whatever widget hierarchy you create. So...
def image_run(parent, *args, **kwargs):
top = tkinter.Toplevel(parent)
top.transient(parent)
canvas = tkinter.Canvas(top, ...)
:
:
Hope that helps!
Related
I have created a class "Node" which creates a binary tree. (I know i can use binarytree module but its a project given to me in DSA subject.)
class Node:
def __init__(self, data) -> None:
#initialisation
def addNode(self, data):
# Code to add data.
def traverse(self):
#traverses the tree and returns a dict
def view(
self,
length=500,
width=1000,
yDist=50,
xDistScale=0.25,
title='Tree View',
):
# shows the tree in a tkinter window as in the screenshot attached
tree = self.traverse()
root = tk.Tk()
self.root=root
root.geometry(str(width)+'x'+str(length))
root.title(title)
# ........ some code which places the nodes on the window using the place() method
root.mainloop()
Now, I import the code in an another file, create an instance of the class add some nodes and call the view() method it works fine but the code after the view() methd does not run till I close the tkinter window.
How can I make the code after view() run without the window being closed?
Its ok if the window is not able to update.
Code where I import and use the node class :
t1 = Node(15)
t1.addNode(12)
t1.addNode(27)
t1.addNode(7)
t1.addNode(14)
t1.addNode(20)
t1.addNode(88)
t1.addNode(23)
t1.view()
# The code here does not run until I close the window.
Output of the above code :
Link to image
I tried googling and also viewed following stackoverflow posts:
Calling a tkinter application from a different class in python,
A code needs to be continued...(Python with Tkinter)
How would I continue to run code after importing a Tkinter file?
Few other websites and guides...
But nothing was helpful.
Please help/guide me.
I am new to StackOverflow and Python.
Thanks in Advance :)
Method 1: Don't update window
You could replace the root.mainloop() with root.update(). This will stop showing any changes to the window. The window will only and always close if the program stops running.
Method 2: using threading
You could useimport threading to run t1.view() in another thread: threading.Thread(target=t1.view).start(). This may result in a Tcl_AsyncDelete error.
Is there any way to put a toplevel window in front of the main window?
Here's the code:
from tkinter import *
root = Tk()
root.geometry('1280x720')
def create_new_window():
root2 = Toplevel()
root2.geometry('500x500')
create_new_window()
mainloop()
Here, I want the root2 window to always stay in front of the root window.
I tried using root2.attributes('-topmost' , 1), but the problem is that this line puts the window on top of all the other programs as well.
What I want is that the toplevel window should only be in front of the main window, and it should never go back when I click on the main window.
Is there any way to achieve this in tkinter?
It would be great if anyone could help me out.
What you want, i think, is a transient window, you nedd to do:
root2.wm_transient(root)
From the manual:
wm transient window ?master?
If master is specified, then the window manager is informed that window is a transient window (e.g. pull-down menu) working on behalf of master (where master is the path name for a top-level window). If master is specified as an empty string then window is marked as not being a transient window any more. Otherwise the command returns the path name of window's current master, or an empty string if window isn't currently a transient window. A transient window will mirror state changes in the master and inherit the state of the master when initially mapped. It is an error to attempt to make a window a transient of itself.
So you could do something like this, but it seems buggy for me.
What I have done is to bind the FocusOut event to the toplevel that was created, so every time it looses the focus it triggers the event stackingorder to put the windos in the right order. You may need to expire this code for several events of your choice, but to get you the idea..
Here is the code:
import tkinter as tk
def add_toplevel(idx, toplevel):
if idx == 'end':
idx = len(toplevels)
toplevels.insert(idx,toplevel)
def create_new_window():
root2 = tk.Toplevel()
root2.geometry('500x500')
add_toplevel('end',root2)
root2.bind('<FocusOut>', stackingorder)
def stackingorder(event):
for toplevel in toplevels:
toplevel.lift()
toplevel.update_idletasks()
toplevels = [] #stacking order by index
root = tk.Tk()
create_new_window()
root.mainloop()
You are maybe also intrested in this:
https://stackoverflow.com/a/10391659/13629335
I'm trying to have a "Downloading..." pop-up window show up as another function is running, and then when that function is done to close that pop-up window.
Thanks
import tkinter as t
from tkinter import ttk
root = t.Tk()
t.Label(root, text='Downloading...').pack()
pb = ttk.Progressbar(root, length=200, mode='indeterminate')
pb.pack()
pb.start()
root.update()
This code will immediately display this window:
Also, this won't stop execution... If you write more code below, python will continue executing your program; but there is a caveat - you have to call root.update() from time to time while you're doing something else, to allow tkinter to update the window, otherwise your window will seem frozen and the window manager will mark the window as "not responding".
Create a Tk() window and put a progress bar inside it.
You can find out how to create a popup window by searching StackOverflow for [tkinter] pop-up window. When you have done that, here is a generic 'downloading' wrapper function.
def downloading(parent, function, args, kwargs):
popup = <code or function call to create popup using parent)
ret = function(*args, **kwargs)
popup.destroy()
return ret
args is a tuple or list of positional arguments. kwargs is a key-value dict of keyword names and arguments.
I am using python3 on a mac and run scripts with the IDLE which comes automatically with the python3 installation.
I am trying to make an alert to the user and found the command
tkinter.messagebox.showinfo("title","some text")
So I i tried a minimal script to check if I can get along with that command
import tkinter
tkinter.messagebox.showinfo("test" , "blabla")
The window is displayed correctly but it doesn't respond when I click on the "OK" button.
Addtionally there is a second empty window which appears when I start the script.
What is the explanation for this or at least how can I fix that?
tkinter isn't designed to work this way. Every tkinter requires a root window. If you don't explicitly create one (and you didn't), one will be created for you. That's what the blank window is.
Also, a tkinter GUI can't function properly unless it has a running event loop. This is necessary because some functions, such as responding to buttons and redrawing the window, only happens in response to events. If the event loop isn't running, events can't be processed.
Bottom line: the dialogs aren't designed to be used outside of the context of a proper tkinter app.
Wrapper for standalone use
The following code can be used to display one of the dialogs in standalone mode. It works by creating and hiding a root window, displaying the dialog, and then destroying the root window.
import tkinter as tk
from tkinter import messagebox
def show_dialog(func, *args, **kwargs):
# create root window, then hide it
root = tk.Tk()
root.withdraw()
# create a mutable variable for storing the result
result = []
# local function to call the dialog after the
# event loop starts
def show_dialog():
# show the dialog; this will block until the
# dialog is dismissed by the user
result.append(func(*args, **kwargs))
# destroy the root window when the dialog is dismissed
# note: this will cause the event loop (mainloop) to end
root.destroy()
# run the function after the event loop is initialized
root.after_idle(show_dialog)
# start the event loop, then kill the tcl interpreter
# once the root window has been destroyed
root.mainloop()
root.quit()
# pop the result and return
return result.pop()
To use it, pass the dialog you want as the first option, followed by dialog-specific options.
For example:
result = show_dialog(messagebox.askokcancel, "title", "Are you sure?")
if result:
print("you answered OK")
else:
print("you cancelled")
I work with Python 3.5 and TKinter.
I defined a label and file dialog that updates this label.
A button is responsible to launch this dialog.
self.sel_folder_val = the label that will be updated.
The code:
self.sel_folder_val['text']=filedialog.askdirectory()
After pressing the button in order to launch this dialog, the button stays pressed. Any dialog that a button is responsible to open cause the button to stay low (pressed) after closing this dialog.
I have tried this also with no help...:
self.select_folder_btn.config(relief=RAISED)
Code example:
self.select_folder_btn = Button(self.top)
self.select_folder_btn.place(relx=0.07, rely=0.57, height=34, width=187)
self.select_folder_btn.configure(activebackground="#d9d9d9")
self.select_folder_btn.configure(activeforeground="#000000")
self.select_folder_btn.configure(background="#d9d9d9")
self.select_folder_btn.configure(disabledforeground="#a3a3a3")
self.select_folder_btn.configure(font=self.font3)
self.select_folder_btn.configure(foreground="#000000")
self.select_folder_btn.configure(highlightbackground="#d9d9d9")
self.select_folder_btn.configure(highlightcolor="black")
self.select_folder_btn.configure(pady="0")
self.select_folder_btn.configure(text='''Select destination folder''')
self.select_folder_btn.bind('<Button-1>',self.update_folder_value)
def update_folder_value(self,event):
self.sel_folder_val['text']=filedialog.askdirectory()
return
After executing update_folder_value() function, self.select_folder_btn stays down.
I used the command:
self.select_folder_btn.configure(command=self.update_folder_value)
Instead of bind:
self.select_folder_btn.bind('<Button-1>',self.update_folder_value)
It solved my problem.
Thanks
First for future reference this is a minimal working example:
from Tkinter import *
import tkFileDialog as filedialog
class app:
def __init__(self):
self.top = Tk()
self.select_folder_btn = Button(self.top)
self.select_folder_btn.place(relx=0.07, rely=0.57, height=34, width=187)
self.select_folder_btn.configure(activebackground="#d9d9d9")
self.select_folder_btn.configure(activeforeground="#000000")
self.select_folder_btn.configure(background="#d9d9d9")
self.select_folder_btn.configure(disabledforeground="#a3a3a3")
#self.select_folder_btn.configure(font=self.font3)
self.select_folder_btn.configure(foreground="#000000")
self.select_folder_btn.configure(highlightbackground="#d9d9d9")
self.select_folder_btn.configure(highlightcolor="black")
self.select_folder_btn.configure(pady="0")
self.select_folder_btn.configure(text='''Select destination folder''')
self.select_folder_btn.configure(command=self.update_folder_value)
self.sel_folder_val = {}
self.top.mainloop()
def update_folder_value(self):
self.sel_folder_val['text']=filedialog.askdirectory()
self.top.update_idletasks()
app()
and even that's not minimal. Second your problem is hard to find since this isn't minimal- you're doing something really weird - binding the button to a click. You're overriding the built-in binding, and apparently it still affects the state of the button on press, but not going back. What you wanted is:
self.select_folder_btn.configure(command=self.update_folder_value)
instead of your:
self.select_folder_btn.bind('<Button-1>',self.update_folder_value)
You could also define that in the Button command. What you did is bypassed the button mechanism, so apparently only half of it is executed, and the relief is not raised. Note you have to remove the event parameter your method accepts.