Home > front end >  Why does the drawing of my canvas dont appear when popUp window is created?
Why does the drawing of my canvas dont appear when popUp window is created?

Time:01-31

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())
  •  Tags:  
  • Related