如何使用 OOP 概念在 Tkinter 中添加背景图像?

How to add background image in Tkinter using OOP concept?

我是面向对象 python 编程的新手。目前我正在使用 Python 3. 我想创建一个有多个页面的应用程序。我可以在页面之间导航,但发现很难在后台添加图像。

请注意,我不想知道如何在 tkinter 中设置背景图片,因为我已经可以根据以下代码做到这一点。

bg = PhotoImage(file="images\bg.png")
label_bgImage = Label(master, image=bg)
label_bgImage.place(x=0, y=0)

我想知道如何在将每个 window 定义为 class 时向页面添加背景图像。我把插入背景图片的代码放在了class ABCApp__init__()方法中。当我尝试将用于添加背景图像的代码插入现有代码时,它停止显示标签和按钮,现在只显示 window.

以下代码是我尝试添加图像作为背景。

import tkinter  as tk
from tkinter import ttk
from tkinter import *

class ABCApp(tk.Tk):

    def __init__(self,*args,**kwargs):

        tk.Tk.__init__(self,*args,**kwargs)

        self.geometry("1500x750")

        main_frame = tk.Frame(self)
        main_frame.pack(side = 'top',fill = 'both',expand ='True')

        main_frame.grid_rowconfigure(0,weight=1)
        main_frame.grid_columnconfigure(0,weight=1)

        bg = PhotoImage(file="images\bg.png")
        label_bgImage = Label(self, image=bg)
        label_bgImage.place(x=0, y=0)

        self.frames = {}

        for F in (HomePage,PageOne,PageTwo):
            frame = F(main_frame, self)
            self.frames[F] = frame
            frame.grid(row=0,column=0,sticky='nsew')

        self.show_frame(HomePage)

    def show_frame(self,container):

        frame = self.frames[container]
        frame.tkraise()


class HomePage(tk.Frame):

    def __init__(self,parent,controller):

        tk.Frame.__init__(self,parent)

        label = ttk.Label(self,text='Home Page',font =("Helvetica",20))
        label.pack(padx=10,pady=10)

        button1 = ttk.Button(self,text = "Page 1",command = lambda: controller.show_frame(PageOne))
        button1.pack()

        button6 = ttk.Button(self, text="Page 2", command=lambda: controller.show_frame(PageTwo))
        button6.pack()

class PageOne(tk.Frame):

    def __init__(self,parent,controller):
        tk.Frame.__init__(self, parent)

        label1 = ttk.Label(self, text='Page 1', font=("Helvetica", 20))
        label1.pack(padx=10, pady=10)

        button2 = ttk.Button(self, text="Back", command=lambda: controller.show_frame(HomePage))
        button2.pack()

        button5 = ttk.Button(self, text="Page 2", command=lambda: controller.show_frame(PageTwo))
        button5.pack()

class PageTwo(tk.Frame):

    def __init__(self,parent,controller):
        tk.Frame.__init__(self, parent)

        label2 = ttk.Label(self, text='Page 2', font=("Helvetica", 20))
        label2.pack(padx=10, pady=10)

        button3 = ttk.Button(self, text="Back", command=lambda: controller.show_frame(HomePage))
        button3.pack()

        button4 = ttk.Button(self, text="Page 1", command=lambda: controller.show_frame(PageOne))
        button4.pack()

app = ABCApp()
app.mainloop()

我希望将相同或不同的图像显示为每个页面的背景。不管怎样我都很满意

由于背景图像在所有 Page classes 上都是相同的,因此一种面向对象的方法是定义一个 base class 上面有背景图片,然后从中导出所有具体的 Page classes 而不是普通的 tk.Frame。之后,每个 subclass 都需要调用其基础 class' __init__() 方法,然后再添加它独有的任何小部件。在下面的代码中,这个新基 class 就是名为 BasePage.

的基

为避免为每个 BasePage 子 class 实例加载图像文件的单独副本,它只完成一次并保存为 ABCApp [=39= 的属性](这是传递给每个 BasePage subclass 的构造函数的 controller 参数)。因为每个页面 class 在显示时会完全覆盖所有其他页面,所以每个页面都需要创建自己的 Label 并在其上放置背景图片。

下面显示了我的意思。 (注意我使代码比你问题中的更PEP 8 - Style Guide for Python Code兼容)。

import tkinter as tk
from tkinter.constants import *
from tkinter import ttk


class ABCApp(tk.Tk):
    BKGR_IMAGE_PATH = '8-ball.png'

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.geometry("1500x750")

        main_frame = tk.Frame(self)
        main_frame.pack(side='top', fill='both', expand='True')

        main_frame.grid_rowconfigure(0, weight=1)
        main_frame.grid_columnconfigure(0, weight=1)

        self.bkgr_image = tk.PhotoImage(file=self.BKGR_IMAGE_PATH)

        self.frames = {}
        for F in (HomePage, PageOne, PageTwo):
            frame = F(main_frame, self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky='nsew')

        self.show_frame(HomePage)

    def show_frame(self,container):
        frame = self.frames[container]
        frame.tkraise()


class BasePage(tk.Frame):

    def __init__(self, parent, controller):
        super().__init__(parent)

        label_bkgr = tk.Label(self, image=controller.bkgr_image)
        label_bkgr.place(relx=0.5, rely=0.5, anchor=CENTER)  # Center label w/image.


class HomePage(BasePage):

    def __init__(self, parent, controller):
        super().__init__(parent, controller)

        label = ttk.Label(self, text='Home Page', font =("Helvetica",20))
        label.pack(padx=10, pady=10)

        button1 = ttk.Button(self, text="Page 1",
                             command=lambda: controller.show_frame(PageOne))
        button1.pack()

        button6 = ttk.Button(self, text="Page 2",
                             command=lambda: controller.show_frame(PageTwo))
        button6.pack()


class PageOne(BasePage):

    def __init__(self,parent,controller):
        super().__init__(parent, controller)

        label1 = ttk.Label(self, text='Page 1', font=("Helvetica", 20))
        label1.pack(padx=10, pady=10)

        button2 = ttk.Button(self, text="Back",
                             command=lambda: controller.show_frame(HomePage))
        button2.pack()

        button5 = ttk.Button(self, text="Page 2",
                             command=lambda: controller.show_frame(PageTwo))
        button5.pack()


class PageTwo(BasePage):

    def __init__(self, parent, controller):
        super().__init__(parent, controller)

        label2 = ttk.Label(self, text='Page 2', font=("Helvetica", 20))
        label2.pack(padx=10, pady=10)

        button3 = ttk.Button(self, text="Back",
                             command=lambda: controller.show_frame(HomePage))
        button3.pack()

        button4 = ttk.Button(self, text="Page 1",
                             command=lambda: controller.show_frame(PageOne))
        button4.pack()


app = ABCApp()
app.mainloop()

另请注意,如果您希望每个 Page class 具有不同的背景图片,您可以做一些不同的事情 - 即每个页面 负责加载自己的图像。为此,对 BasePage 构造函数的调用需要传递要使用的图像文件的名称(作为 super().__init__() 语句中的附加参数)。