Tkinter не может рисовать в другое окно - PullRequest
0 голосов
/ 06 февраля 2020

Я хочу сделать что-то, что должно быть довольно простым, но я изо всех сил пытаюсь заставить это работать.

В основном у меня есть 2 Tkinter windows (canvas_tk и control_tk).

В canvas_tk Я хочу показать изображение и нарисовать круг поверх него.

В control_tk У меня есть запись для ввода радиуса круга, который будет нарисован.

В моем коде критическая строка находится в самом низу кода:

self.panel = tk.Label(canvas_tk, image=image)

Если я сделаю метку в control_tk или если я не укажу родителя, она на самом деле работает нормально и др aws круги в окне control_tk Однако я хочу, чтобы круги рисовались в окне canvas_tk

self.panel = tk.Label(image=image)              # Works
self.panel = tk.Label(control_tk, image=image)  # Works
self.panel = tk.Label(canvas_tk, image=image)    # Fails

Вот мой минимальный код:

import tkinter as tk
from PIL import Image, ImageTk, ImageDraw

control_tk = tk.Tk()
canvas_tk = tk.Tk()
control_tk.geometry("300x300")
canvas_tk.geometry("900x900")

class Drawing:
    def __init__(self):
        # Numerical entry with a variable traced with callback to "on_change" function
        self.radius_var = tk.IntVar()
        self.radius_var.trace_variable("w", self.on_change)
        tk.Entry(control_tk, textvariable=self.radius_var).grid()

        # Initialize image and panel
        self.image = Image.new('RGB', (1000, 1000))
        self.panel = None

        # mainloop for the two tkinter windows
        control_tk.mainloop()
        canvas_tk.mainloop()

    def on_change(self, *args):
        print("Value changed")   # to check that function is being called


        draw = ImageDraw.Draw(self.image)
        draw.ellipse((50-self.radius_var.get(), 50-self.radius_var.get(),
                      50+self.radius_var.get(), 50+self.radius_var.get()),
                     outline='blue', width=3)
        image = ImageTk.PhotoImage(self.image)

        if self.panel:  # update the image
            self.panel.configure(image=image)
            self.panel.image = image
        else:   # if it's the first time initialize the panel
            self.panel = tk.Label(canvas_tk, image=image)
            self.panel.image = image
            self.panel.grid(sticky="w")

Drawing()

И ошибка трассировки в основном жалуется на изображение не существует

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 508, in get
    return self._tk.getint(value)
_tkinter.TclError: expected integer but got ""

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
  File "C:/GIT/142-277-00_pyScuti2/test.py", line 29, in on_change
    draw.ellipse((50-self.radius_var.get(), 50-self.radius_var.get(),
  File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 510, in get
    return int(self._tk.getdouble(value))
_tkinter.TclError: expected floating-point number but got ""
Value changed
Value changed
Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
  File "C:/GIT/142-277-00_pyScuti2/test.py", line 38, in on_change
    self.panel = tk.Label(canvas_tk, image=image)
  File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 2766, in __init__
    Widget.__init__(self, master, 'label', cnf, kw)
  File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 2299, in __init__
    (widgetName, self._w) + extra + self._options(cnf))
_tkinter.TclError: image "pyimage1" doesn't exist

1 Ответ

2 голосов
/ 06 февраля 2020

Прежде всего, вы не должны использовать несколько Tk() экземпляров. Во-вторых, лучше не использовать trace() для отслеживания изменений ввода, используйте bind('<Return>', ...) для запуска рисования после ввода пользователем значения и нажмите клавишу Enter. Ниже приведен модифицированный код, основанный на вашем:

import tkinter as tk
from PIL import Image, ImageTk, ImageDraw

control_tk = tk.Tk()
control_tk.geometry("300x300+800+600")

canvas_tk = tk.Toplevel() # use Toplevel instead of Tk
canvas_tk.geometry("900x900+10+10")

class Drawing:
    def __init__(self):
        # Numerical entry with a variable traced with callback to "on_change" function
        self.radius_var = tk.IntVar()
        entry = tk.Entry(control_tk, textvariable=self.radius_var)
        entry.grid()
        # binding Enter key on entry to trigger the drawing
        entry.bind('<Return>', self.on_change)

        # Initialize image and panel
        self.image = Image.new('RGB', (1000, 1000))
        self.panel = None

        # mainloop for the main window
        control_tk.mainloop()

    def on_change(self, *args):
        try:
            radius = self.radius_var.get()
        except:
            print('Invalid number')
            return

        print("Value changed")   # to check that function is being called

        draw = ImageDraw.Draw(self.image)
        draw.ellipse((50-radius, 50-radius, 50+radius, 50+radius),
                     outline='blue', width=3)
        image = ImageTk.PhotoImage(self.image)

        if self.panel:
            self.panel.configure(image=image)
        else:
            self.panel = tk.Label(canvas_tk, image=image)
            self.panel.grid(sticky='w')
        self.panel.image = image

Drawing()
...