在python

时间:2016-09-04 12:34:34

标签: python tkinter singleton

编写以下代码以在Python中使用Tkinter显示棋盘:

import tkinter as tk

class Gui(tk.Tk):
    _instance = None

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super().__new__(cls, *args, **kwargs)
            cls._instance.__initialized = False
        return cls._instance

def __init__(self):
    if self.__initialized:
        return
    self.__initialized = True
    super().__init__()

class Color(object):
    white =(0xff,0xff,0xff)
    black =(0x00,0x00,0x00)

class Tile(tk.PhotoImage):
    @staticmethod
    def putTile(image, color, width, height, coordinates):
        pix = "#%02x%02x%02x" % color
        coor = (coordinates[0]*width, coordinates[1]*height)
        line = "{" + " ".join([pix]*width) + "}"
        image.put(" ".join([line]*height),coor)

class Grid(tk.PhotoImage):
    def __init__(self,grid):
        super().__init__(width=10*len(grid), height=10*len(grid[0]))
        for x in range(len(grid)):
            for y in range(len(grid[x])):
                Tile.putTile(self,Color.white if grid[x][y]==1 else
                             Color.black,10,10,(x,y))

class ChessBoard(Grid):
    chessboard = 4 * ([4 * [0,1]] + [4 * [1,0]])
    def __init__(self):
        super().__init__(self.chessboard)

所以Gui()实现为单例模式。另外tk.Tk.__init__()只被调用一次,另外我每次调用Gui()时都会看到一个窗口。

我希望以下内容显示一个带棋盘的窗口:
案例1:

label = tk.Label(Gui(), image=ChessBoard())
label.pack()
Gui().mainloop()

这会创建一个没有错误或警告的空窗口。 print语句显示确实调用了方法tilePut

只有当我在程序中添加额外的Gui()语句时,如下所示,每个语句都完美无缺,并且会打印棋盘。

案例2:

Gui()
label = tk.Label(Gui(), image=ChessBoard())
label.pack()
Gui().mainloop()

所以我想image.put来电需要Gui()才能存在。虽然如果我尝试以下代码:

案例3:

board = ChessBoard()
label = tk.Label(Gui(), image=board)
label.pack()
Gui().mainloop()

我很快就会调用image.put。考虑到我在案例1中没有得到同样的错误,我很惊讶案例1不起作用。任何人都可以解释原因吗?

1 个答案:

答案 0 :(得分:2)

您的问题的答案可归结为两个因素:

  1. 在创建图像之前必须存在根窗口
  2. 您必须保留对图像的引用,否则tkinter将会破坏 垃圾收集时的图像数据。
  3. 使用此代码的正确方法是首先创建Gui的实例,然后创建Chessboard并保存变量中返回的内容。然后,您可以在其余代码中使用这些引用。

    这是实现这一目标的常用方法:

    root = Gui()
    chessboard = ChessBoard()
    label = tk.Label(root, image=chessboard)
    label.pack()
    root.mainloop()
    

    由于您将Gui定义为单身,因此以下内容也适用。但是,我认为使用单例会增加复杂性并使代码不那么清晰,因为看起来您正在创建三个Gui实例:

    Gui()
    chessboard = ChessBoard()
    label = tk.Label(Gui(), image=chessboard)
    label.pack()
    Gui().mainloop()