I am making a program with tkinter and I'am using a PopUp window to allow for more functionality.
My PopUp window consists of a Notebook with different frames and a canvas under it that draws something according to which tab of the notebook is selected.
I have manage to create the functionality that I want, the only problem is that the drawing of the canvas is not shown when the PopUp window is created (it only shows the drawing when a tab is selected).
Is there a way to fix this issue?
Heres my code simplified where i manage to recreate the problem I have:
import tkinter as tk
import tkinter.ttk as ttk
class CustCanvas(tk.Canvas):
def __init__(self, root):
super().__init__(root, bg="lemon chiffon")
def draw_frame1(self):
print("Draws Frame 1")
self.delete("all")
W = self.winfo_width()
H = self.winfo_height()
r = min(W,H)*0.2
self.create_oval(W*0.5-r, H*0.5-r, W*0.5 r, H*0.5 r, fill="red")
def draw_frame2(self):
print("Draws Frame 2")
self.delete("all")
W = self.winfo_width()
H = self.winfo_height()
r = min(W,H)*0.2
self.create_oval(W*0.5-r, H*0.5-r, W*0.5 r, H*0.5 r, fill="green")
class PopUpwindow(tk.Toplevel):
def __init__(self, root, *args, **kargs):
super().__init__(root, *args, **kargs)
self.geometry("800x500")
self.master = root
self.notebook = ttk.Notebook(self)
self.notebook.bind("<<NotebookTabChanged>>", self.notebook_selected)
self.frame_n1 = tk.Frame(self.notebook)
self.frame_n2 = tk.Frame(self.notebook)
self.lbl1 = tk.Label(self.frame_n1, text="Label of frame 1")
self.lbl2 = tk.Label(self.frame_n2, text="Label of frame 2")
self.lbl1.pack()
self.lbl2.pack()
self.notebook.add(self.frame_n1, text=" Frame 1 ", sticky="nsew")
self.notebook.add(self.frame_n2, text=" Frame 2 ", sticky="nsew")
self.canvas = CustCanvas(self)
self.rowconfigure(0, weight=1)
self.rowconfigure(1, weight=1)
self.columnconfigure(0, weight=1)
self.notebook.grid(row=0, column=0, sticky="nsew")
self.canvas.grid(row=1, column=0, sticky="nsew")
def notebook_selected(self, event):
idx = self.notebook.index(self.notebook.select())
if idx == 0:
self.canvas.draw_frame1()
else:
self.canvas.draw_frame2()
class App:
def __init__(self, root):
self.root = root
but = tk.Button(root, text="Click me", command=self.open_window)
but.pack()
def open_window(self):
popUp = PopUpwindow(self.root)
popUp.mainloop()
root = tk.Tk()
app = App(root)
root.state("zoomed")
root.mainloop()
CodePudding user response:
The problem is the size of the window when first opened, you can check it with print(W, H,r)
in the draw_frame_1
function when first opened and after selecting the window, so the solution is to refresh the window with the command self.notebook.bind('<Configure>', self.notebook_selected)
with this line if the size of the windows have been changed the create_oval
also it adapts with it.
import tkinter as tk
import tkinter.ttk as ttk
class CustCanvas(tk.Canvas):
def __init__(self, _root):
super().__init__(_root, bg="lemon chiffon")
def draw_frame1(self):
print("Draws Frame 1")
self.delete("all")
W = self.winfo_width()
H = self.winfo_height()
r = min(W, H) * 0.2
self.create_oval(W * 0.5 - r, H * 0.5 - r, W * 0.5 r, H * 0.5 r, fill="red")
def draw_frame2(self):
print("Draws Frame 2")
self.delete("all")
W = self.winfo_width()
H = self.winfo_height()
r = min(W, H) * 0.2
self.create_oval(W * 0.5 - r, H * 0.5 - r, W * 0.5 r, H * 0.5 r, fill="green")
class PopUpwindow(tk.Toplevel):
def __init__(self, _root, *args, **kargs):
super().__init__(_root, *args, **kargs)
self.geometry("800x500")
self.master = _root
self.notebook = ttk.Notebook(self)
self.notebook.bind("<<NotebookTabChanged>>", self.notebook_selected)
self.notebook.bind('<Configure>', self.notebook_selected)
self.frame_n1 = tk.Frame(self.notebook)
self.frame_n2 = tk.Frame(self.notebook)
self.lbl1 = tk.Label(self.frame_n1, text="Label of frame 1")
self.lbl2 = tk.Label(self.frame_n2, text="Label of frame 2")
self.lbl1.pack()
self.lbl2.pack()
self.notebook.add(self.frame_n1, text=" Frame 1 ", sticky="nsew")
self.notebook.add(self.frame_n2, text=" Frame 2 ", sticky="nsew")
self.canvas = CustCanvas(self)
self.rowconfigure(0, weight=1)
self.rowconfigure(1, weight=1)
self.columnconfigure(0, weight=1)
self.notebook.grid(row=0, column=0, sticky="nsew")
self.canvas.grid(row=1, column=0, sticky="nsew")
def notebook_selected(self, event):
idx = self.notebook.index(self.notebook.select())
if idx == 0:
self.canvas.draw_frame1()
else:
self.canvas.draw_frame2()
class App:
def __init__(self, _root):
self._root = _root
but = tk.Button(_root, text="Click me", command=self.open_window)
but.pack()
def open_window(self):
popUp = PopUpwindow(self._root)
popUp.mainloop()
root = tk.Tk()
app = App(root)
root.state("zoomed")
root.mainloop()
CodePudding user response:
The problem is that when draw_frame1
is called, the canvas has size 1x1, you must wait that the canvas is mapped before drawing.
You can add to the end of PopUpwindow.__init__
this line of code:
self.canvas.bind('<Map>', lambda e: self.canvas.draw_frame1())