【问题标题】:App/Homepage displaying as blank window while using class structures with tkinter in Python 3.7在 Python 3.7 中使用带有 tkinter 的类结构时,应用程序/主页显示为空白窗口
【发布时间】:2019-09-14 08:44:53
【问题描述】:

我是 python/编程的新手(2-3 周的经验),我正在尝试使用 tkinter 为我最初作为我的第一个项目的 cmd 线游戏编写的战舰游戏制作一个 GUI 应用程序。我希望这个 GUI 有几个不同的屏幕/框架,引导用户在单人游戏或两个玩家模式下设置和玩游戏。

问题:我能够在一个窗口中以程序方式生成一个主页,其中我想要放置作为标签的背景图像,但是当我尝试将相同的代码实现到类结构中以开始制作多个屏幕时,脚本会运行,但我得到的只是一个完全空白的窗口。

大部分类结构代码或多或少直接来自教程,我也看到它在这种情况下在论坛上流传。但是,我在上面发现的大多数问题似乎都在处理错误,而我的代码运行时,它并没有做我想要的。我仍在学习 OOP 和类结构,所以我认为我遗漏了一些简单的东西。

我尝试单独声明 self.frames 字典的键:值,而不是使用 for 循环。

我已经分别尝试使用 .pack、.grid 和 .place 来放置容器和主页/双人框架。

我尝试将我想要作为背景放置的图像存储在类变量而不是实例变量中。 (另一个关于 tkinter 多帧的问题表明在某些情况下可能是一个问题)

from tkinter import *
from PIL import Image, ImageTk

class Battleship(Tk):

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

        self.geometry("1920x1080")

        container = Frame(self)
        container.pack(side="top", fill="both")
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}

        for F in (Homepage, Twoplayer):
            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky = "nsew")

        self.show_frame(Homepage)

    def show_frame(self, page_name):
        """Show given frame"""
        frame=self.frames[page_name]
        frame.tkraise()


class Homepage(Frame):
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        # Add battleship photo to background
        mainBG = ImageTk.PhotoImage(Image.open("CSEdit.jpg"))
        BGlabel = Label(parent, image=mainBG)
        BGlabel.grid()


class Twoplayer(Frame):
    # This code not relevant to problem, can't even get Homepage to work

root = Battleship()
root.mainloop()

当我不使用类结构时,这可以在窗口中为主页创建我想要的屏幕:

from tkinter import *
from PIL import Image, ImageTk

root=Tk()
root.geometry("1920x1080")
container=Frame(root)
container.pack(side="top", fill= "both")

mainBG = ImageTk.PhotoImage(Image.open("CSEdit.jpg"))
BGlabel = Label(container, image=mainBG)
BGlabel.pack()

root.mainloop()

但是,尝试在类结构中以类似方式创建该屏幕只会产生一个空白窗口。

【问题讨论】:

  • PhotoImage 在函数中创建并分配给局部变量时,有一个错误会从内存中删除它。您必须将 PhotoImage 分配给类变量 - self.mainBG。请参阅页面上的“注意”:effbot.org/tkinterbook/photoimage.htm
  • 对我而言,您应该使用self,而不是Label(self, ...) 中的parent - 使用self,您将Label 放入Homepage(Frame)。使用parent,您将标签放入container,它可能是不可见的——即。隐藏在Homepage(Frame) 下。在旧版本中,你只有 containterLabel (container<-Label) 在课堂上你有 container<-Homepage<-Label 所以标签需要不同的父级 - Homepage 而不是 container

标签: python-3.x class user-interface tkinter


【解决方案1】:

你有一个错误和一个bug问题。

  1. 您将Label 放入parent,这意味着container,但您必须将其放入Homepage - 这意味着self

    BGlabel = Label(self, image=self.mainBG)
    
  2. 当您在函数中创建 PhotoImage 并将其分配给局部变量时,有一个错误会从内存中删除它。您必须分配给全局或类变量 - 即。 self.main.BG

    self.mainBG = ImageTk.PhotoImage(Image.open("CSEdit.jpg"))
    BGlabel = Label(self, image=self.mainBG)
    

工作代码:

from tkinter import *
from PIL import Image, ImageTk

class Battleship(Tk):

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

        self.geometry("1920x1080")

        container = Frame(self)
        container.pack(side="top", fill="both")
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}

        for F in (Homepage, Twoplayer):
            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky = "nsew")

        self.show_frame(Homepage)

    def show_frame(self, page_name):
        """Show given frame"""
        frame=self.frames[page_name]
        frame.tkraise()


class Homepage(Frame):
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        # Add battleship photo to background
        self.mainBG = ImageTk.PhotoImage(Image.open("CSEdit.jpg"))
        BGlabel = Label(self, image=self.mainBG)
        BGlabel.grid()


class Twoplayer(Frame):
    # This code not relevant to problem, can't even get Homepage to work
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        pass

root = Battleship()
root.mainloop()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-25
    • 1970-01-01
    • 1970-01-01
    • 2020-06-06
    相关资源
    最近更新 更多