在许多标签中多次更改图像的最佳方法是什么?

问题描述 投票:1回答:1

我需要一些关于如何处理这个项目的建议。很多年前我有一些编程经验,但过去几周才开始进入Python。

这个Python 3程序有一个tkinter屏幕,上面有150个图标。图标是标签小部件,根据从文本文件读入程序的设备状态,显示三个20x20 png图形中的一个。每个图标需要每天更改几次。

在这种情况下,任何关于哪种方法可行的建议,以显示这些图标都将受到赞赏。

我做了几次尝试。理想情况下,StringVar()/ textvariable类型的方法会很好(这对于更改标签中的文本很有用),但我找不到类似的图像方法。简单地将相同的标签一遍又一遍地推到屏幕上并不起作用,因为程序最终会崩溃“内存不足”。

编辑:我已经使用键/值对解决了这个问题,因此每个循环都不会创建新标签。该方法适用于单个实例,但是一旦我将它放入这个循环结构中,它就会崩溃,因为“TypeError:'str'对象不支持项目赋值”。我创建了这个简单的例程,它反映了我对更大项目的问题。我怎样才能让它发挥作用?

import tkinter as tk
import time

window = tk.Tk()
window.title("PiStatus")
window.geometry("500x500+0+0")

ct = 0
# You can use any small images for this, mine are 20x20 pixels.
pc_on_icon = tk.PhotoImage(file="1.png")
pc_active_icon = tk.PhotoImage(file="2.png")
pc_off_icon = tk.PhotoImage(file="0.png")

# This loop creates the base 15x10 grid of labels, each with a unique name.
for ypos in range(10):
    for xpos in range(15):
        label_name = "icon" + str(xpos) + "-" + str(ypos)
        label_name = tk.Label(window, image=pc_on_icon)
        label_name.grid(row=ypos, column=xpos)

while True:

# These statements cycle through the 3 images
    if ct == 0:
        turn = pc_off_icon
    elif ct == 1:
        turn = pc_on_icon
    else:
        turn = pc_active_icon

# This loop references each label giving it a different image each time around.
    for ypos in range(10):
        for xpos in range(15):
            label_name = "icon" + str(xpos) + "-" + str(ypos)
            label_name['image'] = turn  # This is where the error occurs.

    ct += 1

    if ct == 3:
        ct = 0

    window.update()

window.mainloop()
python tkinter
1个回答
-1
投票

我们可以创建一个自定义小部件来封装为一个特定设备显示多个状态图标的功能。我们称之为MultiStateIcon并从tk.Frame派生出来。

这个小部件将包含一个子tk.Label小部件的集合,每个可能的状态/图像一个。所有标签都将填充重叠,但只有一个(对应于当前状态)可见(其他标签可以使用pack_forget()隐藏)。

然后你只需要创建一个MultiStateIcons网格(或任何你想要的布局),只需改变文本文件所指示的状态即可。


为了演示,我已经定期(每10ms)将一个随机选择的设备的状态设置为随机选择的状态。

示例脚本:

import Tkinter as tk
import PIL.Image, PIL.ImageTk
from random import randrange


class MultiStateIcon(tk.Frame):
    def __init__(self, parent, images, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)

        self.images = images
        self.labels = []

        for image in images:
            l = tk.Label(self, image = image)
            l.pack()
            self.labels.append(l)

        self.set_state(0)

    def set_state(self, n):
        for i in range(len(self.labels)):
            if i == n:
                self.labels[i].pack()
            else:
                self.labels[i].pack_forget()

class TestApp(tk.Tk):
    def __init__(self, image_paths, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        self.title("Test")
        self.frame = tk.Frame(self)
        self.frame.pack()

        self.images = []
        for image_path in image_paths:
            img = PIL.ImageTk.PhotoImage(PIL.Image.open(image_path))
            self.images.append(img)

        self.icons = []
        for r in range(10):
            for c in range(15):
                icon_lbl = MultiStateIcon(self.frame, self.images)
                icon_lbl.grid(row=r, column=c)
                self.icons.append(icon_lbl)

        self.after(1000, self.change_random_icon)

    def change_random_icon(self):
        n = randrange(0, len(self.icons))
        state = randrange(0, len(self.images))
        self.icons[n].set_state(state)
        self.after(10, self.change_random_icon)

def run():
    app = TestApp(["multiicon_0.png", "multiicon_1.png", "multiicon_2.png"])    
    app.mainloop()

run()

我用过的图片:

应用程序的屏幕截图(一个在开头,另一个在一段时间后 - 内存使用似乎是稳定的):

© www.soinside.com 2019 - 2024. All rights reserved.