带mainloop的可更新tkinter画布

时间:2019-05-14 22:51:29

标签: python multithreading python-2.7 tkinter tkinter-canvas

我希望能够使自己成为Tkinter中用于项目的图形化api 使用 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方法阻止了画布上的任何进一步操作,我需要一种可更新屏幕的解决方案。

我尝试通过mainloopupdate方法使用线程,但是它将立即退出窗口。

感谢您的帮助,祝您生活愉快

1 个答案:

答案 0 :(得分:1)

您可能需要阅读一些有关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