如何使用 OOP 确保所有元素都显示在 Tkinter Canvas 上

How to make sure all elements show on the Tkinter Canvas using OOP

我对 python 还很陌生,正试图掌握它的 类 和功能。我之前写了一段代码,为了让它干净,我试图把它放在 类 中,但它的一些元素不再显示了。

代码应该显示一个白色圆角矩形,上面有文本和一个按钮,效果很好,但是当我添加分类时,按钮和文本不显示。

这可能只是一些很小的东西,但正如我所说,我正在努力学习 - 如何让它像使用 OOP 之前一样显示?我究竟做错了什么?感谢您的帮助!

我的代码如下。

    root = Tk()
root.configure(bg="steel blue")
canvas = Canvas(root, highlightthickness=0)
canvas.config(width=350, height=250,
             bg="steel blue", )  # canvas.config(width = root.winfo_screenwidth(), height = root.winfo_screenheight() )
canvas.pack()


class User_Identification(object):
    def User_Id(self):
        canvas.delete("all")  # root.configure(bg = "white")   #canvas.config(bg = "white")
        canvas.config(width=505, height=505,
                      bg="steel blue")  # canvas.config(width = root.winfo_screenwidth(), height = root.winfo_screenheight() )
        box = canvas.create_rectangle(40, 20, 500, 500, fill="white", width=4)
        canvas.create_text(255, 65, text="Who are you?", font=("comic sans", 30))
        box2 = canvas.create_rectangle(50, 30, 450, 100, width=2)
        canvas.move(box2, 9, 5)
        canvas.place(relx=0.5, rely=0.5, anchor=CENTER)

        User_button = Button(root, text="User", anchor=CENTER, command=Per_Form)
        User_button.configure(width=45, height=6, bg="white", fg="black", border=10)  # height
        User_button = canvas.create_window(60, 150, anchor=NW, window=User_button)

        Driver_button = Button(root, text="Driver", anchor=CENTER, command=Per_Form)
        Driver_button.configure(width=45, height=6, bg="white", fg="black", border=10)  # height
        Driver_button = canvas.create_window(60, 300, anchor=NW, window=Driver_button)


class Rectangle:

   def round_rectangle(x1, y1, x2, y2, radius=25, **kwargs):  # Making of the round rectangle

       points = [x1 + radius, y1,
                 x1 + radius, y1,
                 x2 - radius, y1,
                 x2 - radius, y1,
                 x2, y1,
                 x2, y1 + radius,
                 x2, y1 + radius,
                 x2, y2 - radius,
                 x2, y2 - radius,
                 x2, y2,
                 x2 - radius, y2,
                 x2 - radius, y2,
                 x1 + radius, y2,
                 x1 + radius, y2,
                 x1, y2,
                 x1, y2 - radius,
                 x1, y2 - radius,
                 x1, y1 + radius,
                 x1, y1 + radius,
                 x1, y1]

       return canvas.create_polygon(points, **kwargs, smooth=True)

   my_rectangle = round_rectangle(10, 60, 330, 250, radius=23, outline="black", fill="white", width=4)

   def __init__(self, Next_button):
        self.Next_button = Next_button
        Next_button = Button(root, text="Next", anchor=CENTER, command=User_Identification)
        Next_button.configure(width=10, bg="black", fg="blue", border=10)
        canvas.create_window(500, 500, anchor=NW, window=Next_button)

   def text(text):
        text = canvas.create_text(170, 100, text="Hey there, welcome to DeliverToday! \nWe bring your needs right at your doorstep ~ \nhave a great journey ahead!")


canvas.place(relx=0.5, rely=0.5, anchor=CENTER)

我认为您正在尝试执行类似于以下脚本的操作。我说明了一堆不同的概念,其中一些对于您的需求来说是不必要的。阅读文档并学习计算机科学,以便您可以理解它们。

config.py

from dataclasses import dataclass, asdict

#to make things more complicated and force you to get better
#create a dataclass of default properties
@dataclass
class Button_dc:
    bg:    str = "white"
    fg:    str = "gray20"
    font:  str = 'Calibri 14 bold'
    border:int = 10
    
#make a dict instance of the dataclass    
DefaultButton = asdict(Button_dc())

#make a slightly different instance
UserRoleButton = asdict(Button_dc(font='Calibri 24 bold'))

shapes.py

#add more static methods that return complex shape points
class Shapes:
    @staticmethod
    def RoundRectangle(x1, y1, x2, y2, radius=25):  # Making of the round rectangle
        return [x1 + radius, y1,
                x1 + radius, y1,
                x2 - radius, y1,
                x2 - radius, y1,
                x2, y1,
                x2, y1 + radius,
                x2, y1 + radius,
                x2, y2 - radius,
                x2, y2 - radius,
                x2, y2,
                x2 - radius, y2,
                x2 - radius, y2,
                x1 + radius, y2,
                x1 + radius, y2,
                x1, y2,
                x1, y2 - radius,
                x1, y2 - radius,
                x1, y1 + radius,
                x1, y1 + radius,
                x1, y1]

main.py

import tkinter as tk
import config as cfg
from shapes import Shapes
from enum import Enum


#entirely over-engineered for it's purpose
class Role(Enum):
    User = 1
    Driver = 2


class App(tk.Tk):
    #width, height and title are constants of your app so, write them as such
    WIDTH  = 660
    HEIGHT = 400
    TITLE  = "DeliveryToday ~ We bring your needs right to your doorstep"

    def __init__(self):
        tk.Tk.__init__(self)
        self.configure(bg="steel blue")

        self.canvas = tk.Canvas(self, bg="steel blue", highlightthickness=0)
        self.canvas.pack(side='top', fill='both', expand=True)
        
        rect = Shapes.RoundRectangle(20, 20, 640, 320, radius=60)
        self.canvas.create_polygon(rect, outline="black", fill="white", width=4, smooth=True)

        #simple manual text centering, also...
        #making an entire function to store text is ridiculous
        text = f'{"Hey there, welcome to DeliverToday!":^{48}}\n{"We bring your needs right to your doorstep.":^{40}}\n{"Have a great journey ahead!":^{46}}'
        self.canvas.create_text(40, 100, anchor='nw', font='Helvetica 20 bold', text=text)
        
        #using **kwargs makes lines a lot shorter. prepare your data, then use it
        self.next_btn = tk.Button(self, text="next", command=self.user_id, **cfg.DefaultButton)
        self.canvas.create_window(500, 340, anchor='nw', window=self.next_btn)
        
    def user_id(self):
        self.canvas.delete("all")
        #put user id code here
        self.canvas.create_rectangle(40, 20, 620, 380, fill="white", width=4)
        self.canvas.create_text(255, 65, text="Choose your role?", font="comicsans 30")
        
        #using a lambda in this way we can pass arguments to other methods
        self.user_btn = tk.Button(self, text="User", command=lambda: self.user_form(Role.User), **cfg.UserRoleButton)
        self.canvas.create_window(60, 280, anchor='nw', window=self.user_btn)
        
        self.driver_btn = tk.Button(self, text="Driver", command=lambda: self.user_form(Role.Driver), **cfg.UserRoleButton)
        self.canvas.create_window(180, 280, anchor='nw', window=self.driver_btn)
        
    def user_form(self, type):
        if type is Role.User:
            print("this is a user")
        elif type is Role.Driver:
            print("this is a driver")
        

#use proper PEP8 to initialize your program
if __name__ == "__main__":
    app = App()
    app.geometry(f'{App.WIDTH}x{App.HEIGHT}')
    app.resizable(width=False, height=False)
    app.title(App.TITLE)
    app.mainloop()