在使用tkinter的Python中,全局变量在函数间未被识别
我对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 个回答
也许你可以试着把这个应用程序改成面向对象的方式,这样你就可以用'self'来代替全局变量。也许你遇到的问题不是全局变量本身,而是这样会让代码看起来有点乱。
要更好地理解 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
来访问它们,比如说。