Какой лучший способ изменить изображение несколько раз во многих ярлыках? - PullRequest
1 голос
/ 10 апреля 2019

Мне нужен совет о том, как подойти к этому проекту. У меня есть некоторый опыт программирования много лет назад, но я начал изучать Python только в последние несколько недель.

Эта программа на Python 3 имеет экран tkinter с 150 значками. Значки представляют собой виджеты меток, которые отображают одну из трех графических изображений 20x20 png в зависимости от состояний устройства, которые считываются в программу из текстовых файлов. Каждую иконку нужно менять несколько раз в день.

Любая рекомендация о том, какой метод будет работать, для отображения этих значков, в этой ситуации будет принята.

У меня было несколько попыток. В идеале, подход типа StringVar () / textvariable был бы хорош (который отлично подходит для изменения текста в метке), но я не могу найти аналогичный подход для изображений. Простое нажатие одной и той же метки на экран снова и снова не работает, так как программа в конечном итоге вылетает «из памяти».

Edit: Я подошел к этой проблеме, используя пары ключ / значение, чтобы каждый цикл не создавал новую метку. Метод работает на одном экземпляре, но как только я помещаю его в эту циклическую структуру, он вылетает с " 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()

1 Ответ

0 голосов
/ 10 апреля 2019

Мы можем создать собственный виджет, который будет включать в себя функцию отображения нескольких значков состояния для одного конкретного устройства.Давайте назовем его MultiStateIcon и выведем из tk.Frame.

. Этот виджет будет содержать коллекцию дочерних tk.Label виджетов, по одному на каждое возможное состояние / изображение.Все метки будут перекрываться, однако будет видна только одна (соответствующая текущему состоянию) (остальные можно скрыть с помощью pack_forget()).

Тогда вам просто нужно создать сетку из MultiStateIcon s (или любой другой макет по вашему желанию) и просто измените их состояние, как показывает текстовый файл.


Для демонстрации я сделал приложение периодически (каждые 10 мс), устанавливающее состояние одного случайно выбранногоустройство в произвольно выбранном состоянии.

Пример сценария:

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()

Изображения, которые я использовал:

Снимки экрана приложения (один в начале, другой через некоторое время - использование памяти кажется стабильным):

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...