【问题标题】:How to make each button display a different image on click using tkinter (python)如何使用tkinter(python)使每个按钮在单击时显示不同的图像
【发布时间】:2018-07-10 13:43:17
【问题描述】:

我正在创建一个带有“.grid”按钮的 GUI。我想让每个按钮在按下时显示不同的图像。因此,当我单击按钮 1 时,它会在按钮底部显示 "image1"。当我点击按钮 2 时,它会弹出 "image2" 等等。

通过一些研究,我能够使按钮运行一个通过以下方法接收参数的函数。但是,我似乎无法让按钮显示图像。相反,当我按下任何按钮时,它只会在按钮下方留出一个空白区域。

免责声明: - 我不希望有很多图片,只有一张图片,它会根据我按下的按钮而改变。

代码如下:

from tkinter import *

def funct(numimg):
    image = PhotoImage(file="image"+str(numimg)+".png")   
    label = Label(image=image)
    label.grid(row = row_no+1, column = 0, columnspan = num_of_cols)

def make_funct(number):
    return (lambda: funct(number))

root= Tk()
row_no = -1
buttons = []
num_of_cols = 3
root.resizable(0, 0)
numfiles = 6

for x in range(0, numfiles):
    if(x % num_of_cols is 0):
        row_no+=1

    buttons.append(Button(root, text = "Button "+str(x), bg = '#4098D3', width = 30,height = 13,command = make_funct(x)))
    buttons[x].grid(row = row_no, column = x % num_of_cols)

root.mainloop()

所以我的问题是,如何让每个单独的按钮在按下时显示不同的图像?这个程序在这里只是留下一个空白区域来替换图像,并且图片未显示。

【问题讨论】:

  • 您必须明确保留对 Tkinter 图像的引用,否则它们将被垃圾收集 - 仅具有显示图像的小部件不算作引用。将image 设为全局变量将是您代码中最简单的解决方案。此外,您说您一次只想要一张图像,但实际上您创建了无限数量的标签来保存它们,所有标签都堆积在同一个网格单元中。在启动期间创建一个标签,然后根据需要重新配置其图像属性。
  • 哇。这实际上马上就奏效了。我将图像设置为全局变量,现在它似乎按我的预期工作。我了解标签将如何堆叠在同一个网格单元中,但是当它在函数(函数)内部时,我将如何“重新配置”它们?对不起,如果这是一个明显的问题——我是 tkinter 中 gui 的新手。谢谢!

标签: python tkinter


【解决方案1】:

您发布的代码存在两个主要问题。

第一个与本题基本相同:Why does Tkinter image not show up if created in a function?。您应该保留对PhotoImage 对象的引用,否则它将被垃圾收集并且不会显示。

第二个是在每次单击按钮时创建一个新的Label。你应该只创建一个Label 并使用label.config() 方法更改图像。

我会(不将您的 GUI 包装在一个类中,这可能是一个更好的解决方案)在初始化时加载所有图像,将它们作为标签的属性保存在列表中,并且仅在单击按钮时更改图像。

我还删除了您的 make_funct 函数并将其替换为 lambda,这是在回调时将变量传递给函数的最常用方法。

from tkinter import *

def funct(numimg):
    label.config(image=label.images[numimg])

root= Tk()
row_no = -1
buttons = []
num_of_cols = 3
root.resizable(0, 0)
numfiles = 3

for x in range(0, numfiles):
    if(x % num_of_cols is 0):
        row_no+=1

    buttons.append(Button(root, text = "Button "+str(x), bg = '#4098D3', width = 30,height = 13, command = lambda n=x: funct(n)))
    buttons[x].grid(row = row_no, column = x % num_of_cols)

label = Label(root)
label.grid(row = row_no+1, column = 0, columnspan = num_of_cols)

label.images=[]

for x in range(0, numfiles):
    label.images.append(PhotoImage(file="image"+str(x)+".png"))

root.mainloop()

【讨论】:

  • 感谢您的回答。我已将其标记为正确,因为它按预期工作。但是,我有一个问题:我尝试了带有和不带有“n=x”部分的 lambda 函数。但是,它似乎不起作用。使用 lambda 时如何需要 n=x? (您的回答有效,我只是想知道为什么)再次感谢您
  • 当您执行lambda x: funct(x) 时,您将变量 x 绑定为参数,而不是当时x。因为变量x 在整个循环中都在变化,所以在评估lambda 函数时x 始终具有最后一个值。你可以通过给你的参数一个默认值来规避这个问题,它确实绑定了当前值。你可以使用lambda x=x: funct(x),但为了清楚起见,我更喜欢给参数起一个不同的名称,所以我使用lambda n=x: funct(n)。在 google 上搜索 python lambda for loop 会为您提供更多关于此的问题以及很好的答案。
猜你喜欢
  • 1970-01-01
  • 2018-04-17
  • 2016-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多