Обновляемый холст tkinter с mainloop - PullRequest
1 голос
/ 15 мая 2019

Я хочу быть в состоянии сделать себя графическим API в Tkinter для проекта используя Python 2.7

import Tkinter as tk
# import tkinter as tk    # if you are using python 3


class Graphics(tk.Tk):

    def __init__(self, width=60, height=60, pixel_width=10):
        #super().__init__()
        tk.Tk.__init__(self)
        self.width, self.height = width, height
        self.pixel_width = pixel_width
        # self.geometry(f'{self.width*self.pixel_width}x{self.height*self.pixel_width}')
        self.geometry('600x600')
        self.my_canvas = tk.Canvas(
            self, 
            width = self.width * self.pixel_width, 
            height = self.height * self.pixel_width,
        )

        self.pixels = [[None for x in range(self.width)] for y in range(self.height)]
        self.fill_area((0, 0), (self.width, self.height), 'white')

        self.fill_point((30, 30),'red')
        self.fill_area((10, 10), (15, 20), 'yellow')


        self.my_canvas.pack()
        self.run()

    def fill_point(self, point, color):
        pixel = self.pixels[point[0]][point[1]]
        if pixel is None:
            cx0 = self.pixel_width * point[0]
            cy0 = self.pixel_width * point[1]
            cx1 = self.pixel_width * (point[0] + 1)
            cy1 = self.pixel_width * (point[1] + 1)
            self.pixels[point[0]][point[1]] = self.my_canvas.create_rectangle(cx0, cy0, cx1, cy1, fill=color)   # outline=''
        else:
            self.my_canvas.itemconfig(pixel, fill=color)

    def fill_area(self, pointA, pointB, color):
        for x in range(pointA[0], pointB[0]):
            for y in range(pointA[1], pointB[1]):
                self.fill_point((x, y), color)

    def run(self):
        self.mainloop()


g = Graphics()
g.fill_point((9,9),'blue')

Как я понял, метод mainloop блокирует любые дальнейшие действия на холсте, и мне нужно решение для обновляемого экрана.

Я пытался использовать потоки с методами mainloop и update, но он просто немедленно выходил бы из окна.

Спасибо за помощь и хорошего дня

1 Ответ

1 голос
/ 15 мая 2019

Возможно, вам нужно немного прочитать о канве tkinter и его огромных возможностях: в отличие от pygame или других графических полотен, ему не нужно обновляться с заданной частотой; К элементам холста можно обращаться индивидуально, а их атрибуты задавать точно.

Я переработал ваш код для отображения холста, сделанного из «масштабированных пикселей»: здесь ширина 60 x 60 пикселей, каждый пиксель увеличен в 10 раз.
2D список self.pixels содержит элементы холста; обновления напрямую изменяют атрибуты этих элементов.

Вы можете удалить черные линии вокруг каждого пикселя, установив для их атрибута outline пустую строку (см. Комментарий в коде).

import Tkinter as tk
# import tkinter as tk    # if you are using python 3


class Graphics(tk.Tk):

    def __init__(self, width=60, height=60, pixel_width=10):
        super().__init__(self)
        self.width, self.height = width, height
        self.pixel_width = pixel_width
        # self.geometry(f'{self.width*self.pixel_width}x{self.height*self.pixel_width}')
        self.geometry('600x600')
        self.my_canvas = tk.Canvas(
            self, 
            width = self.width * self.pixel_width, 
            height = self.height * self.pixel_width,
        )

        self.pixels = [[None for x in range(self.width)] for y in range(self.height)]
        self.fill_area((0, 0), (self.width, self.height), 'white')

        self.fill_point((30, 30),'red')
        self.fill_area((10, 10), (15, 20), 'yellow')


        self.my_canvas.pack()
        self.run()

    def fill_point(self, point, color):
        pixel = self.pixels[point[0]][point[1]]
        if pixel is None:
            cx0 = self.pixel_width * point[0]
            cy0 = self.pixel_width * point[1]
            cx1 = self.pixel_width * (point[0] + 1)
            cy1 = self.pixel_width * (point[1] + 1)
            self.pixels[point[0]][point[1]] = self.my_canvas.create_rectangle(cx0, cy0, cx1, cy1, fill=color)   # outline=''
        else:
            self.my_canvas.itemconfig(pixel, fill=color)

    def fill_area(self, pointA, pointB, color):
        for x in range(pointA[0], pointB[0]):
            for y in range(pointA[1], pointB[1]):
                self.fill_point((x, y), color)

    def run(self):
        self.mainloop()


g = Graphics()

enter image description here

...