繁体   English   中英

如何使用“销毁”属性/功能修改此 class?

[英]How to modify this class with a "destroy" attribute/function?

您好,这是 github 上的一个模块,用于在 tkinter上播放视频。 我发现它满足了我的需求,但不幸的是它缺少“破坏”属性(例如 video.destroy())。 当我这样做时,它返回“AttributeError:'tkvideo2' object 没有属性'destroy'”。 我试着询问模块海报,但他似乎已经放弃了这个项目。 有人可以帮忙吗?

代码:

    try:
    import Tkinter as tk  # for Python2 (although it has already reached EOL)
except ImportError:
    import tkinter as tk  # for Python3
import threading
from time import perf_counter, sleep
import imageio
from PIL import Image, ImageTk

class tkvideo():
    """ 
        Main class of tkVideo. Handles loading and playing 
        the video inside the selected label.
        
        :keyword path: 
            Path of video file
        :keyword label: 
            Name of label that will house the player
        :param loop:
            If equal to 0, the video only plays once, 
            if not it plays in an infinite loop (default 0)
        :param size:
            Changes the video's dimensions (2-tuple, 
            default is 640x360) 
        :param hz:
            Sets the video's frame rate (float, 
            default 0 is unchecked) 
    
    """
    def __init__(self, path, label, loop = 0, size = (640,360), hz = 0):
        self.path = path
        self.label = label
        self.loop = loop
        self.size = size
        self.hz = hz

    def load(self, path, label, loop, hz):
        """
            Loads the video's frames recursively onto the selected label widget's image parameter.
            Loop parameter controls whether the function will run in an infinite loop
            or once.
        """
        frame_data = imageio.get_reader(path)

        if hz > 0:
            frame_duration = float(1 / hz)
        else:
            frame_duration = float(0)

        if loop == 1:
            while True:
                before = perf_counter()
                for image in frame_data.iter_data():
                    frame_image = ImageTk.PhotoImage(Image.fromarray(image).resize(self.size))
                    label.config(image=frame_image)
                    label.image = frame_image

                    diff = frame_duration + before
                    after = perf_counter()
                    diff = diff - after 
                    if diff > 0:
                        sleep(diff)
                    before = perf_counter()
        else:
            before = perf_counter()
            for image in frame_data.iter_data():
                    frame_image = ImageTk.PhotoImage(Image.fromarray(image).resize(self.size))
                    label.config(image=frame_image)
                    label.image = frame_image

                    diff = frame_duration + before
                    after = perf_counter()
                    diff = diff - after 
                    if diff > 0:
                        sleep(diff)
                    before = perf_counter()

    def play(self):
        """
            Creates and starts a thread as a daemon that plays the video by rapidly going through
            the video's frames.
        """
        thread = threading.Thread(target=self.load, args=(self.path, self.label, self.loop, self.hz))
        thread.daemon = 1
        thread.start()

编辑:

Traceback (most recent call last):
  File "lib\threading.py", line 973, in _bootstrap_inner
    self.run()
  File "lib\threading.py", line 910, in run
    self._target(*self._args, **self._kwargs)
  File "tkvideo2.py", line 60, in load
    label.config(image=frame_image)
  File "lib\tkinter\__init__.py", line 1646, in configure
    return self._configure('configure', cnf, kw)
  File "lib\tkinter\__init__.py", line 1636, in _configure
    self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
_tkinter.TclError: invalid command name ".!label2"

tkvideo不是真正的小部件,但 class 仅从视频中读取帧并将它们放入小部件Label中,您将其用作tkvideo()中的参数 - 所以您必须销毁此Label tkvideo

但首先你应该停止读取帧的线程。 tkvideo你可以使用变量self.running = True并且在销毁 label 之前你应该设置self.running = False并且线程应该在每个循环中检查这个值以停止循环和停止线程。

完整的工作示例

import tkinter as tk  # for Python3
import threading
from time import perf_counter, sleep
import imageio
from PIL import Image, ImageTk

class tkvideo():

    def __init__(self, path, label, loop=False, size=(640,360), hz=0):
        self.path = path
        self.label = label
        self.loop = loop
        self.size = size
        self.hz = hz
        self.running = True   # <-- variable to control loop 

    def load(self, path, label, loop, hz):
        """
            Loads the video's frames recursively onto the selected label widget's image parameter.
            Loop parameter controls whether the function will run in an infinite loop
            or once.
        """
        frame_data = imageio.get_reader(path)

        if hz > 0:
            frame_duration = float(1 / hz)
        else:
            frame_duration = float(0)

        if loop:
            while True:
                before = perf_counter()
                for image in frame_data.iter_data():
                    
                    frame_image = ImageTk.PhotoImage(Image.fromarray(image).resize(self.size))

                    if not self.running:   # <-- variable to control loop 
                        return             # exit function and stop thread
                    
                    label.config(image=frame_image)
                    label.image = frame_image

                    diff = frame_duration + before
                    after = perf_counter()
                    diff = diff - after 
                    if diff > 0:
                        sleep(diff)
                    before = perf_counter()
        else:
            before = perf_counter()
            for image in frame_data.iter_data():
                frame_image = ImageTk.PhotoImage(Image.fromarray(image).resize(self.size))
               
                if not self.running:   # <-- variable to control loop 
                    return             # exit function and stop thread

                label.config(image=frame_image)
                label.image = frame_image

                diff = frame_duration + before
                after = perf_counter()
                diff = diff - after 
                if diff > 0:
                    sleep(diff)
                before = perf_counter()

    def play(self):
        """
            Creates and starts a thread as a daemon that plays the video by rapidly going through
            the video's frames.
        """
        thread = threading.Thread(target=self.load, args=(self.path, self.label, self.loop, self.hz))
        thread.daemon = 1
        thread.start()

# --- main ---

import tkinter as tk
import time

def stop():
    video.running = False   # <-- variable to control loop 
    time.sleep(0.1)  # thread may need time to stop
    label.destroy()

root = tk.Tk()

label = tk.Label(root)
label.pack()

video = tkvideo('video.avi', label)
video.play()

button = tk.Button(root, text="STOP", command=stop)
button.pack()

root.mainloop()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM