为什么在创建 popUp window 时我的 canvas 的图没有出现?

Why does the drawing of my canvas dont appear when popUp window is created?

我正在用 tkinter 制作一个程序,我正在使用 PopUp window 来实现更多功能。

我的 PopUp window 由一个具有不同框架的笔记本和一个 canvas 下面的 canvas 组成,根据选择笔记本的哪个选项卡绘制一些东西。

我已经设法创建了我想要的功能,唯一的问题是创建 PopUp window 时未显示 canvas 的绘图(它仅在创建时显示绘图选择了一个选项卡)。

有办法解决这个问题吗?

这里是我的代码简化版,我设法重现了我遇到的问题:

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()

问题是当draw_frame1被调用时,canvas的大小是1x1,你必须等待canvas被映射后才能绘制。

您可以在PopUpwindow.__init__这行代码的末尾添加:

self.canvas.bind('<Map>', lambda e: self.canvas.draw_frame1())

问题是window第一次打开时的大小,可以在第一次打开draw_frame_1功能里用print(W, H,r)查看,选择[=18=后] ],因此解决方案是使用命令 self.notebook.bind('<Configure>', self.notebook_selected) 刷新 window,如果 windows 的大小已更改,create_oval 也会随之调整。

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()