Tkinter - hide root window - python-3.x

I'm new to stack exchange and am inexperienced with python. I am using python3 and have used SourceFileLoader from importlib.machinery to run another script(which uses tkinter) from my main script. This initially caused an error covered in this question: tkinter.TclError: image "pyimage3" doesn't exist
The solution worked for me in resolving the error, and now the child script runs as intended, except that using the Toplevel() function now also causes the app to create an empty root window - Tk() which I want to hide. I have looked at a number questions' solutions that have not worked: How do I get rid of Python Tkinter root window?
Hide the root window when a Toplevel window is opened and make it reappear when the Toplevel is destroyed
Here is a sample of my code:
from tkinter import *
from PIL import ImageTk
from importlib.machinery import SourceFileLoader
root = Toplevel()
background = Tk()
...
def Puzzle5():
root.overrideredirect(1)
frame = Frame(root, width=320, height=160, borderwidth=2, relief=RAISED)
frame.pack_propagate(False)
frame.pack(side=TOP)
frame1 = Frame(root, width=500, height=150, borderwidth=2, relief=RAISED)
frame1.pack_propagate(False)
frame1.pack(side=BOTTOM)
image = ImageTk.PhotoImage(file="/home/pi/Media/arrowup.png")
image1 = ImageTk.PhotoImage(file="/home/pi/Media/arrowdown.png")
...
background.withdraw()('0x0+0+0')
root.geometry('644x450+150+50')
root.mainloop()
def close():
root.destroy()
background.destroy()
Puzzle5()

Widgets exist in a hierarchy. At the top of that hierarchy is the root window. For any tkinter widget to exist, there must first be a root window.
You can create the root window by creating an instance of Tk. If you do not, then the first time you create a window a root window will be created for you.
Now, consider this code:
root = Toplevel()
background = Tk()
Toplevel is not a root window. For it to exist, there must first be a root window. Since you did not create one, tkinter will create one for you. So, you get a root window, and then you get the instance of Toplevel.
Then you create another root window with the second line, resulting in three windows. Even when you hide background with background.withdraw(), you still have the original root window visible.
The simple solution is to reverse those two lines of code. Create the root window first, and the Toplevel second. Then you only have a single root window, and you can hide it if you wish. However, as the answer to How do I get rid of Python Tkinter root window? explains, an even better solution is to not use a Toplevel at all, but instead put your widgets in root.

Related

Adding a button to align with ttk notebook caused a geometry problem

I have found out a method to get a button to align with ttk.Notebook.
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
notebook = ttk.Notebook(root)
ttk.Button(notebook).pack()
notebook.pack(fill='both', expand=1)
label = ttk.Label(notebook, text='Text', font='Arial 50')
notebook.add(label, text='Tab')
root.mainloop()
However, this caused a problem that the geometry manager only displays the button. I have to maximise the window in order to see all the contents.
In my another bigger gui, this is just a little bit of the window. I can’t see the content inside the notebook even I maximise the window.
So, how can I get it working? Thanks for any ideas!
This is due to the fact that you're calling pack on a button inside the notebook. The button is empty so it has a size of zero, and calling pack on the button causes the notebook to shrink to the size of the button.
You shouldn't ever call pack or grid on widgets that are direct children of a notebook, they should only ever be added with the add method of the notebook.
It's not clear where you want the button, but it shouldn't be a child of the notebook. If you make it a child of the root window (eg: ttk.Button(root), you can add it to the root window with pack to get it to be either above, below, or to one of the sides of the notebook.

How to close a particular window without closing the whole app in Tkinter?

I'm creating a Tic-Tac-Toe program using tkinter, in which I would like to take the name of the user using entry and the next name to be given in a separate window, but before that I would like to automatically close the previous window.
I used a common variable called root (mainloop also) for displaying all the windows. Once I destroy the root, the whole program stops. Should I name a separate variable with tk.Tk() to proceed and use it in other windows? I just can't understand.
Can anyone help me...
Yes, destroying the root will close the entire app.
If you want to close windows while keeping the app running, you can use a tk.Toplevel to pop a window open, and be able to close it while continuing other operations.
maybe like this:
import tkinter as tk
def popup():
p = tk.Toplevel(root)
p.title('popup')
tk.Label(p, text='I will self destroy in 3 seconds').pack()
p.after(3000, p.destroy)
root = tk.Tk()
btn = tk.Button(root, text='pop a new window', command=popup)
btn.pack()
root.mainloop()

Weird white Stripe appearing next to tkinter scrollbar

So while 'designing' my tkinter application i noticed this white stripe appearing next to the scrollbar there:
It is not disappearing when the scrollbar gets to an active state but it is definetly part of the Scrollbar itself because there is nothing under it in my programm which has a white background.
It seems to appear no matter if I use grid or pack. In this case I use grid - here the little extract of my code:
class App(Tk):
def __init__(self):
#other stuff
self.hvf=hvFrame(self,sticky=EW,showfocus=S,bg='white',padx=5,pady=5)
self.hvf.grid(row=1,column=0,columnspan=2,sticky=NSEW,pady=5,padx=(0,5))
sb=Scrollbar(self,orient=VERTICAL,command=self.hvf.yview,bd=0,highlightthickness=0)
sb.grid(row=1,column=2,sticky=NSEW,pady=5)
self.hvf.config(yscrollcommand=sb.set)
If you ned more, then here you go. (Should not be executable for you because you do not have the extras file but you should still be able to understand it.)
EDIT:
A little reproduceable example:
from tkinter import Tk,Frame,Scrollbar,VERTICAL,NS
root = Tk()
frame = Frame(root,height=300,width=500)
frame.grid(row=0,column=0,padx=(0,5),pady=5)
sb = Scrollbar(root,orient=VERTICAL)
sb.grid(row=0,column=1,sticky=NS,pady=5)
root.mainloop()
After testing a few things like changing the windows theme or changing the root and frame background to black the while line still comes up. I cannot be 100% sure but I believe this is due to fact that tkinter on Windows pulls the scrollbar design from Windows itself and it is simply part of that design. It may be a design choice to give the scroll bar some visual depth. That said you cannot do anything to change the design of the scrollbar within a Windows environment so you as stuck with this unless you write a custom scrollbar.
Example code:
import tkinter as tk
root = tk.Tk()
root['bg'] = 'black'
frame = tk.Frame(root, height=300, width=500, background='black')
frame.grid(row=0, column=0)
sb = tk.Scrollbar(root, orient=tk.VERTICAL)
sb.grid(row=0, column=1, sticky=tk.NS)
root.mainloop()
Results from overlay of white and black backgrounds:
Below is the code I use for a custom scrollbar (but did not write myself). You can find the post where I got the code here.

Hide tk window when using filedialog

I'm trying to use filedialog.asksavefilename to get a save file path. I am running this code in the IDLE shell and it's a text based interface. This is the function to get the save path:
def getPath():
root=tk.Tk()
root.lift()
root.attributes('-topmost',True)
root.after_idle(root.attributes,'-topmost',False)
path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=(("Text Documents", "*.txt"),))
root.destroy()
The dialog opened behind other windows, so I used this to make the dialog appear at the front. This works, but there is still an empty window behind it which I don't want. I've tried using root.withdraw() but this just hides everything. I'd like to have only the file dialog open without the empty tk window. Any ideas as to how to do this?
I've found a way to achieve the desired effect:
def getPath():
root=tk.Tk()
root.overrideredirect(True)
root.attributes("-alpha", 0)
path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=(("Text Documents", "*.txt"),))
root.destroy()
I've removed all of the unnecessary lift and topmost parts - they didn't help. I used root.overrideredirect(True) to remove the title bar and root.attributes("-alpha", 0) to make the window 100% transparent, so you can't see it. The only drawback is that the file dialog window flashes when it opens, but that's not too much of a problem.
from tkinter import Tk
from tkinter.filedialog import asksaveasfilename
def get_path():
root = Tk()
root.withdraw()
path = asksaveasfilename()
root.destroy()
return(path)
print(get_path()) # to verify expected result
Is this the behavior you're looking for? Hope this helps.

Closing a tkinter Entry Widget without killing the program

I am currently stepping through the tkinter tutorial at python-course.eu. Is it possible to close an entry widget without killing the program? What I am trying to do is incorporate the tkinter entry box into a pygame program such that the program asks for the players name via an entry box and then closes once the text has been entered. The game should then continue. Is this possible?
What I would like to do is:
-create a pygame surface
-open a tkinter entry widget on top of that surface
-get the users name
-close the tkinter widget
-write text using pygame onto the surface that incorporates the user's name
What is stumping me is the fact that the tkinter examples on python-course.eu all end with a mainloop() statement while I would like pygame to have an event loop so that I can expand the program. I anticipate that the widget creation would occur prior to dropping into the event loop. This is where I am stuck :-(
rather than trying to mix two GUI libraries in the same window, if a prompt is acceptable you could use:
import tkinter as tk
from tkinter import simpledialog
root = tk.Tk() # needed to prevent extra window being created by dialog
root.withdraw() # hide window as not needed
username = simpledialog.askstring('Username', 'Enter username:')
root.destroy()

Resources