首页 > 解决方案 > Tkinter:对全局变量所做的更改不会保留

问题描述

每当我按下创建的按钮之一时,运行的过程最初确实会更改全局变量的值,但一旦过程完成执行,它们会出于某种原因恢复。这是代码:

from tkinter import *

transformEnabled,selectionEnabled,paintEnabled = False,False,False

root = Tk()

def hide(tool,toolkit):
    for i in toolkit:
        i.grid_forget()
    tool=False
def toolkitFunctions(tool1,tool2,tool3,toolkit1,toolkit2,toolkit3):
    print(tool1)
    if tool1 == False:
        print("Before other tools set to false: ",str(tool1))
        if tool2:
            hide(tool2,toolkit2)
        if tool3:
            hide(tool3,toolkit3)
        for i in range(0,len(toolkit1)):
            toolkit1[i].grid(row=i+4,column=0)
        tool1=True
        print("After other tools set: ",str(tool1))
    else:
        print("If tool1 already true: ",str(tool1))
        hide(tool1,toolkit1)

#Transform Buttons
transformNames = ["Scale Image","Rotate Image","Move Image","Flip Image","Sharpen/Soften Image","Brightness/Constrast"]
transformButtons = [Button(root,text=transformNames[i],width=20) for i in range(0,len(transformNames))]
#SelectionButtons
selectionNames = ["Regular Shape Selection","Free hand Tool","Colour Picker"]
selectionButtons = [Button(root,text=selectionNames[i],width=20) for i in range(0,len(selectionNames))]
#Paint Buttons
paintNames = ["Paintbrush","Airbrush","Pencil","Eraser","Fill","Smudge","Dodge and Burn"]
paintButtons = [Button(root,text=paintNames[i],width=20) for i in range(0,len(paintNames))]

def transformFunctions():
    toolkitFunctions(transformEnabled,selectionEnabled,paintEnabled,transformButtons,selectionButtons,paintButtons)
def selectionFunctions():
    toolkitFunctions(selectionEnabled,transformEnabled,paintEnabled,selectionButtons,transformButtons,paintButtons)
def paintFunctions():
    toolkitFunctions(paintEnabled,transformEnabled,selectionEnabled,paintButtons,transformButtons,selectionButtons)

transform = Button(root,text="Transform Tools",width=20,command=transformFunctions).grid(row=3,column=0)
selection = Button(root,text="Selection Tools",width=20,command=selectionFunctions).grid(row=2,column=0)
paint = Button(root,text="Paint tools",width=20,command=paintFunctions).grid(row=1,column=0)

root.mainloop()

有什么可以纠正的吗?

标签: pythontkinterglobal-variables

解决方案


您将值从全局变量发送transformEnabled到函数,但对于 string/int/float/boolean Python 不会保留对原始变量的引用,而是将值复制到新变量。

您可以global transformEnabled在函数中使用并直接更改transformEnabled = True以将值分配给全局变量。但是对于这个简单的方法来说,你的复杂代码太复杂了。

在您的代码中,最好将值保存在全局字典中并发送字符串"transform", "selection""paint"并使用它们来访问此全局字典中的数据。

这是代码的巨大变化,但你需要它。最终,您可以尝试使用类来创建为一种功能保留按钮和值的小部件。您还可以使用Frame对按钮进行分组并显示/隐藏此框架。


我更改了代码中的其他内容 - 基于PEP 8 -- Python 代码样式指南

import tkinter as tk

# --- functions --- (lower_case_names)

def hide(toolkit):
    for item in toolkit:
        item.grid_forget()

def show(toolkit):
    for i, item in enumerate(toolkit):
        item.grid(row=i+4, column=0) # maybe len(settings) instead of `4` so it will be works when you add more data in dictionary.

def on_click(name):

    print('--- before ---')
    for key, value in settings.items():
        print('{} enabled: {}'.format(key, value['enabled']))

    print('--- changes ---')
    if not settings[name]['enabled']:
        # hide other buttons
        for key, value in settings.items():
            print("Check:", key, key != name, value['enabled'])
            if key != name and value['enabled']:
                hide(value['buttons'])
                value['enabled'] = False

        # show buttons for `name`
        print("Show:", name)
        show(settings[name]['buttons'])
        settings[name]['enabled'] = True
    else:
        # hide buttons for `name`
        print("Hide:", name)
        hide(settings[name]['buttons'])
        settings[name]['enabled'] = False

# --- main --- (lower_case_names)

settings = {
    'transform': {
        'enabled': False,
        'names': ["Scale Image", "Rotate Image", "Move Image", "Flip Image", "Sharpen/Soften Image", "Brightness/Constrast"],
        'buttons': [],
    },
    'selection': {
        'enabled': False,
        'names': ["Regular Shape Selection", "Free hand Tool", "Colour Picker"],
        'buttons': [],
    }, 
    'paint': {
        'enabled': False,
        'names': ["Paintbrush", "Airbrush", "Pencil", "Eraser", "Fill", "Smudge", "Dodge and Burn"],
        'buttons': [],
    },
}    

root = tk.Tk()

settings['transform']['buttons'] = [tk.Button(root, text=item, width=20) for item in settings['transform']['names']]

# Selection Buttons
settings['selection']['buttons'] = [tk.Button(root, text=item, width=20) for item in settings['selection']['names']]

# Paint Buttons
settings['paint']['buttons'] = [tk.Button(root, text=item, width=20) for item in settings['paint']['names']]

transform = tk.Button(root, text="Transform Tools", width=20, command=lambda:on_click('transform'))
transform.grid(row=3, column=0)

selection = tk.Button(root, text="Selection Tools", width=20, command=lambda:on_click('selection'))
selection.grid(row=2, column=0)

paint = tk.Button(root, text="Paint Tools", width=20, command=lambda:on_click('paint'))
paint.grid(row=1, column=0)

root.mainloop()

编辑:相同的代码,但按钮是用循环创建的。我改用len(settings)删除4按钮 - 这样我可以在Help不更改其他代码的情况下将菜单添加到字典中。

import tkinter as tk

# --- functions --- (lower_case_names)

def hide(toolkit):
    for item in toolkit:
        item.grid_forget()

def show(toolkit):
    for i, item in enumerate(toolkit):
        item.grid(row=i+len(settings), column=0)

def on_click(name):

    print('--- before ---')
    for key, value in settings.items():
        print('{} enabled: {}'.format(key, value['enabled']))

    print('--- changes ---')
    if not settings[name]['enabled']:
        # hide other buttons
        for key, value in settings.items():
            print("Check:", key, key != name, value['enabled'])
            if key != name and value['enabled']:
                hide(value['buttons'])
                value['enabled'] = False

        # show buttons for `name`
        print("Show:", name)
        show(settings[name]['buttons'])
        settings[name]['enabled'] = True
    else:
        # hide buttons for `name`
        print("Hide:", name)
        hide(settings[name]['buttons'])
        settings[name]['enabled'] = False

# --- main --- (lower_case_names)

settings = {
    'transform': {
        'title': "Transform Tools",
        'enabled': False,
        'names': ["Scale Image", "Rotate Image", "Move Image", "Flip Image", "Sharpen/Soften Image", "Brightness/Constrast"],
        'buttons': [],
    },
    'selection': {
        'title': "Selection Tools",
        'enabled': False,
        'names': ["Regular Shape Selection", "Free hand Tool", "Colour Picker"],
        'buttons': [],
    }, 
    'paint': {
        'title': "Paint Tools",
        'enabled': False,
        'names': ["Paintbrush", "Airbrush", "Pencil", "Eraser", "Fill", "Smudge", "Dodge and Burn"],
        'buttons': [],
    },
    'help': {
        'title': "Help",
        'enabled': False,
        'names': ["Help ...", "Home Page", "About"],
        'buttons': [],
    },
}    

root = tk.Tk()

for i, name in enumerate(['paint', 'selection', 'transform', 'help']): # it could be `enumerate(settings.keys())` but sometimes it may not keep order.
    settings[name]['buttons'] = [tk.Button(root, text=item, width=20) for item in settings[name]['names']]
    button = tk.Button(root, text=settings[name]['title'], width=20, command=lambda arg=name:on_click(arg))
    button.grid(row=i, column=0)

root.mainloop()

推荐阅读