0

画像操作に PIL を使用し、画像を表示するために Tkinter を使用して、イントロ CS コースで使用する画像操作クラスを作成しています。ユーザーが操作中に画像を見ることができるようにするために、別のスレッドでグラフィック操作を実行し、この質問に似たコードを使用します。これは機能しているように見えます (つまり、何もクラッシュしません) が、画像を表示できません。Tk は起動していますが、ウィンドウが表示されません。コードは次のようになります。

self.root = Tk.Toplevel()
self.frame = tk.Frame(self.root, width=self.image.size[0], height=self.image.size[1])
img = ImageTk.PhotoImage(self.image)
self.label = tk.Label(self.frame, image=img)
self.label.image = img
self.label.pack()
self.frame.pack()
tick()
self.root.mainloop()

このtick関数は、リンクされた質問のものと似ています。私の問題はTkinterの誤解によるものだと思いますが、本当にわかりません。

また、プログラムをうまく終了させることができないようです -これが実行されているdaemon=Trueを構築するときに設定したとしても、終了時にヒットする必要があります。これはちょっと見栄えが悪いので、偽のエラー メッセージで学生を悩ませたくありません。ThreadC-c

編集:ここにいくつかのコードがあります。

class Picture():

    ##
    # Constructor. Creates Picture either by passing in the path of an image file as param
    # or by passing in a tuple in the format of (x, y) to indicate the size of a blank image. 
    # Example 1: Picture("image.jpg") constructs Picture with image.jpg 
    # Example 2: Picture((500, 500)) constructs Picture with a blank image of size 500*500
    def __init__(self, param):
        # Check if parameter is the right type, because we can't
        # overload functions
        if isinstance(param, tuple) and len(param) == 2:
            self.image = Image.new('RGB', (param))
        elif isinstance(param, str):
            self.image = Image.open(param)
        else:
            raise TypeError('Parameter to Picture() should be a string or 2-tuple!')
        # Default values for pen
        self.pen_color = (0, 0, 0)
        self.pen_position = (0, 0)
        self.pen_width = 1.0
        self.pen_rotation = 0
        # Pixel data of the image
        self.pixel = self.image.load()
        # Draw object of the image
        self.draw = ImageDraw.Draw(self.image)
        # The main window, and associated widgets.
        self.root = None
        self.label = None
        self.frame = None
        # Threading support, so that we can show the image while
        # continuing to draw on it.
        self.request_queue = queue.Queue()
        self.result_queue = queue.Queue()
        self.thread = threading.Thread(target=self._thread_main)
        self.thread.start()

    def _thread_main(self):
        """
        Runs the main Tkinter loop, as well as setting up all the
        necessary GUI widgets and whatnot. By running Tkinter on
        a separate thread, we can keep the picture displaying
        even after the user's program is finished drawing on it.
        """
        def tick():
            """
            Called whenever Tk's main loop is idle. This lets us perform
            drawing operations on the right thread.
            """
            try:
                f, args, kwargs = self.request_queue.get_nowait()
            except queue.Empty:
                pass
            else:
                value = f(*args, **kwargs)
                self.result_queue.put(value)
            self.root.after_idle(tick)
        self.root = tk.Toplevel()
        self.frame = tk.Frame(self.root, width=self.image.size[0], height=self.image.size[1])
        img = ImageTk.PhotoImage(self.image)
        self.label = tk.Label(self.frame, image=img)
        # This line ensures that Python doesn't try to garbage collect
        # our photo, due to a bug in Tk.
        self.label.image = img
        self.label.pack()
        self.frame.pack()
        tick()
        self.root.mainloop()

    def _submit_operation(self, f, *args, **kwargs):
        """
        Submits an operation to the request queue. The arguments
        should consist of a function, any positional arguments
        to said function, and any keyword arguments to the function.
        If f returns a value, that value will be returned.

        Any function that does something with the picture (i.e.,
        saving it, drawing to it, reading from it, etc.) should
        be called only by submitting it to the queue.
        """
        self.request_queue.put((f, args, kwargs))
        return self.result_queue.get()

    ##
    # Display the picture.
    def display(self):
        def display_func():
            img = ImageTk.PhotoImage(self.image)
            self.label.configure(image=img)
            self.label.image = img
            self.label.pack()
            self.frame.pack()
        self._submit_operation(display_func)
4

0 に答える 0