在使用tkinter的Python中,全局变量在函数间未被识别

0 投票
2 回答
39 浏览
提问于 2025-04-12 18:35

我对Python还很陌生,所以可能这是个简单的问题,我只是不太明白发生了什么。简单来说,我有一个下拉菜单,可以选择一个角色,然后显示对应的角色图片。第一次选择的时候一切都正常,但问题是我想在选择新图片后清除旧图片,却总是收到一个错误提示:“UnboundLocalError: 无法访问局部变量'imageAppear',因为它没有被赋值”。

这让我很困惑,因为我把'imageAppear'设置成了全局变量,所以我不明白为什么它会认为这是一个局部变量。

目前这段代码只是把新图片显示在旧图片的下面。

我把代码附在下面,任何帮助都非常感谢。

### MAIN WINDOW ###

# Using tkinter version 8.6
# Visit https://docs.python.org/3/library/tkinter.html for documentation
# Using pack as the LayoutManager, 

import tkinter as tk
import tkinter.ttk as ttk
from tkinter import *
from tkinter import filedialog
from PIL import Image, ImageTk
import pathlib
from pathlib import Path

def main():
    root = tk.Tk()
    root.geometry('1280x760')
    root.title("Slippi Stats")
    title = Label(root, text = "Slippi Stats", font = ('Helvetica 20 bold')).pack(pady = 20)
    
    # Create a File Explorer label
    global label_file_explorer
    label_file_explorer = Label(root, 
                                text = "File Explorer using Tkinter",
                                width = 100, height = 4)
    
    # Select Character
    characters = ["Mario", "Bowser", "Peach", "Yoshi", "Donkey Kong",
                  "Captain Falcon", "Fox", "Ness", "Ice Climbers",
                  "Kirby", "Samus", "Zelda", "Link", "Pikachu",
                  "Jigglypuff", "Dr. Mario", "Luigi", "Ganondorf",
                  "Falco", "Young Link", "Pichu", "Mewtwo",
                  "Mr. Game & Watch", "Marth", "Roy"]
    global selectedCharacter
    global label1
    label1 = Label(root, image = "")
    global imageAppear
    imageAppear = True
    selectedCharacter = tk.StringVar(master=root) #Always pass the 'master' keyword argument
    selectedCharacter.set("Mario")
    selectedCharacter.trace_add('write', characterImage)
    characterLabel = tk.Label(root, text="Select a character to train against")
    characterLabel.pack(pady=10)
    dropdown = tk.OptionMenu(root, selectedCharacter, *characters)
    dropdown.pack()
    
    button_explore = Button(root, 
                            text = "Browse Files",
                            command = browseFiles)
    label_file_explorer.pack(pady=10)
    button_explore.pack(pady=10)
    quitButton = tk.Button(text="Quit", command=root.destroy)
    quitButton.pack(pady = 100)
    root.mainloop()

def characterImage(*args):
    ##if imageAppear == True:
        ##clearImage()
    path = pathlib.Path(__file__).parent.resolve()
    path = path._str + "\\CharacterImages\\{}.jpg".format(selectedCharacter.get())
    # path = path.replace("\\\\","\\")
    path = Path(path)
    characterImage = Image.open(path)
    test = ImageTk.PhotoImage(characterImage)
    label1 = tk.Label(image=test)
    label1.image = test
    # Position image
    label1.pack()
    imageAppear = True

def clearImage():
    label1.config(image = "")

def browseFiles():
    filename = filedialog.askopenfilename(initialdir = "/",
                                          title = "Select a File",
                                          filetypes = (("Slippi Files",
                                                        "*.slp*"),
                                                       ("All files",
                                                        "*.*")))
    label_file_explorer.configure(text="File Opened: "+filename)
main()

关于imageAppear的检查部分被注释掉了,因为现在连一张图片都无法显示。

附注:我知道使用全局变量是不好的编程习惯,不用对我进行批评。

2 个回答

-1

也许你可以试着把这个应用程序改成面向对象的方式,这样你就可以用'self'来代替全局变量。也许你遇到的问题不是全局变量本身,而是这样会让代码看起来有点乱。

1

要更好地理解 global,可以看看这里的例子 这里

在Python中,使用global关键字的基本规则是:

  • 在函数内部创建的变量默认是局部变量。
  • 在函数外部定义的变量默认是全局变量。你不需要使用global关键字。
  • 我们使用global关键字来在函数内部读取和写入全局变量。
  • 在函数外使用global关键字没有任何效果。

这意味着在 main 函数内部设置 global imageAppear 是可以的,但在 characterImage 函数内部你必须再次使用 global,否则程序会认为这是一个只在 characterImage 函数内部的新变量:

def main():
    one()
    two()


def one():
    global one
    one = 1


def two():
    #global one  # whith this commented the code will fail with UnboundLocalError
    one += 1
    print(one)


if __name__ == '__main__':
    main()

至于 tkinter 项目,我非常喜欢面向对象编程(OOP),我觉得你绝对应该了解一下。你的代码在这方面很容易转换:把 def main() 改成 class Main,然后把代码放到 def __init__() 里。接着你可以简单地把全局变量声明为实例变量,前面加上 self.。如果你再把其他函数缩进一次,并且先传递参数 self,这样它们就能被分配到 Main 类中,你就可以用 self.imageAppear 来访问它们,比如说。

撰写回答