Reputation: 1917
In my Tkinter app I have a button that opens a Toplevel Window which dispays an event log. There are a few things I need the Toplevel Window to be able to do:
I have figured out #1. I am able to have the window open and display previous entries as well as update those entries while the window is open. My problem is with #2 and #3.
For #2 I am not sure how to disable the user's ability to move the window. I am assuming this may also disable the user's ability to close the window so I am not sure how to keep that functionality intact. Maybe a button with self.quit()
as it's command?
As for #3, I have no idea how to go about doing this. Maybe I suck as Googling but I can't seem to find out how to accomplish this.
This is the code I have at the moment, which is able to properly implement feature #1.
import tkinter as tk
class guiapp(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.master = master
self.value = 0.0
self.alive = True
self.list_for_toplevel = []
btn = tk.Button(self.master, text = "Click", command = self.TextWindow)
btn.pack()
def TextWindow(self):
self.textWindow = tk.Toplevel(self.master)
self.textFrame = tk.Frame(self.textWindow)
self.textFrame.pack()
self.textArea = tk.Text(self.textWindow, height = 10, width = 30)
self.textArea.pack(side = "left", fill = "y")
bar = tk.Scrollbar(self.textWindow)
bar.pack(side = "right", fill = "y")
bar.config(command = self.textArea.yview)
self.alive = True
self.timed_loop()
def timed_loop(self):
if self.alive == True and tk.Toplevel.winfo_exists(self.textWindow):
self.master.after(1000, self.timed_loop)
self.value += 1
self.list_for_toplevel.append(self.value)
self.textArea.delete(1.0, "end-1c")
for item in self.list_for_toplevel:
self.textArea.insert('end', "{}\n".format(item))
self.textArea.see('end')
else:
self.alive = False
if __name__ == "__main__":
root = tk.Tk()
root.geometry("800x480")
myapp = guiapp(root)
root.mainloop()
Upvotes: 0
Views: 5210
Reputation: 15226
We can remove the tool bar from the top of the toplevel
window and prevent the user from moving the window with self.textWindow.overrideredirect(True)
.
Then we can make sure that the toplevel
window is positioned in the top right corner by getting the root windows location and then setting the toplevel
window to the same location with self.master.winfo_x()
and self.master.winfo_y()
.
Last I would add a button that closes the window because we no longer have the tool bar for the toplevel
window.
UPDATE: I have added the ability for the toplevel
window to stay on top of the root window and to move around with the root window when root is dragged.
we can use bind()
to track when the root window is moved and then have a function that will update the toplevel
windows position to match the root windows.
We can also use self.textWindow.attributes("-topmost", True)
to tell tkinter to keep out toplevel
window on top of all other windows.
Take a look at the modified version of your code below. Let me know what you think or if you have any questions.
import tkinter as tk
class guiapp(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.master = master
self.textWindow = None
self.master.bind("<Configure>", self.move_me)
self.value = 0.0
self.list_for_toplevel = []
btn = tk.Button(self.master, text = "Click", command = self.TextWindow)
btn.pack()
def TextWindow(self):
x = self.master.winfo_x()
y = self.master.winfo_y()
self.textWindow = tk.Toplevel(self.master)
self.textFrame = tk.Frame(self.textWindow)
self.textWindow.overrideredirect(True)
self.textFrame.pack()
self.textWindow.attributes("-topmost", True)
self.textWindow.geometry('+{}+{}'.format(x+10, y+30))
self.close_toplevel = tk.Button(self.textWindow, text = "close", command = self.close_textWindow)
self.close_toplevel.pack()
self.textArea = tk.Text(self.textWindow, height = 10, width = 30)
self.textArea.pack(side = "left", fill = "y")
bar = tk.Scrollbar(self.textWindow)
bar.pack(side = "right", fill = "y")
bar.config(command = self.textArea.yview)
self.alive = True
self.timed_loop()
def close_textWindow(self):
self.textWindow.destroy()
self.textWindow = None
def move_me(self, event):
if self.textWindow != None:
x = self.master.winfo_x()
y = self.master.winfo_y()
self.textWindow.geometry('+{}+{}'.format(x+10, y+30))
def timed_loop(self):
if self.textWindow != None:
self.master.after(1000, self.timed_loop)
self.value += 1
self.list_for_toplevel.append(self.value)
self.textArea.delete(1.0, "end-1c")
for item in self.list_for_toplevel:
self.textArea.insert('end', "{}\n".format(item))
self.textArea.see('end')
if __name__ == "__main__":
root = tk.Tk()
root.geometry("800x480")
myapp = guiapp(root)
root.mainloop()
Upvotes: 2