2015-11-20 298 views
2

我想加載應該在其自己的線程中運行的Tkinter UI。創建UI實例後,當嘗試訪問該屬性時出現此錯誤:line 18, in do_move: self.game_ui.setTile(4, 0, 0) AttributeError: 'Play' object has no attribute 'game_ui'無法訪問類屬性

我不確定是否弄亂了線程或其他內容,但我也注意到self.game_ui.drawBoard(..)並未實際更新UI。

import GUI 
import game 


class Play: 
    def __init__(self): 
     print ('Init') 
     self.game_core = game.Board() 
     print(self.game_core.tiles) 
     self.game_ui = GUI.getNewBoardWindow(self.keylistener) 
     self.game_ui.drawBoard(self.game_core.tiles) 

    def keylistener(self, event): 
     self.do_move((event.keycode-38) % 4) 

    def do_move(self, key): 
     print(key) 
     self.game_ui.setTile(4, 0, 0) 


def main(): 
    Play() 


main() 

凡GUI是這樣的:

from tkinter import * 
from threading import Thread 


class GUI(Frame, Thread): 
    cellColors = {0: "#CCC0B3", 2: "#eee4da", 4: "#ede0c8", 8: "#f2b179", 16: "#f59563", 32: "#f67c5f", 64: "#f65e3b", 128: "#edcf72", 256: "#edcc61", 512: "#edc850", 1024: "#edc53f", 2048: "#edc22e", 4096: "#3c3a32"} 
    boardSize = 4 

    def __init__(self, parent): 
     Frame.__init__(self, parent, bg="#BBADA0") 
     Thread.__init__(self) 
     self.parent = parent 
     self.cells = [] 
     self.initUI(150) 
     self.pack() 
     self.start() 
     self.parent.mainloop() 

    def initUI(self, cellSize): 
     for row in range(self.boardSize-1, -1, -1): 
      self.cells.append([]) 
      for column in range(self.boardSize): 
       cell = Frame(self, width=cellSize, height=cellSize) 
       cell.grid(row=row, column=column, padx=4, pady=4) 
       cell.pack_propagate(0) 

       tile = Label(cell, bg="#CCC0B3", font=("Helvetica", 35, "bold")) 
       tile.pack(fill=BOTH, expand=1) 
       self.cells[-1].append(tile) 

    def setTile(self, value, x, y): 
     print(value) 
     self.cells[y][x].config({ 
      "bg": GUI.cellColors[min(4096, value)], 
      "fg": ("#776E65" if value < 8 else "#f9f6f2"), 
      "text": str(value) if value else ''}) 

    def drawBoard(self, board): 
     for col in range(len(board)): 
      for row in range(len(board)): 
       self.setTile(board[col][row], col, row) 


def getNewBoardWindow(listener=None): 
    root = Tk() 
    root.title("2048") 
    if listener: 
     root.bind("<Key>", listener) 

    app = GUI(root) 
    root.mainloop() 
    #mainThread = Thread(target=root.mainloop) 
    #mainThread.start() 
    return app 

回答

1

你開始在getNewBoardWindow()主循環root.mainloop(),這反過來將返回app將在Play被assinged到self.game_ui。由於getNewBoardWindow()在GUI運行時不能返回,因此self.game_ui不能存在。

您可以通過app一起返回root解決這個問題:

def getNewBoardWindow(listener=None): 
    root = Tk() 
    root.title("2048") 
    if listener: 
     root.bind("<Key>", listener) 
    app = GUI(root) 
    return app, root 

Play

class Play: 
    def __init__(self): 
     print ('Init') 
     self.game_core = game.Board() 
     print(self.game_core.tiles) 
     self.game_ui, self.root = GUI.getNewBoardWindow(self.keylistener) 
     self.game_ui.drawBoard(self.game_core.tiles) 
     self.root.mainloop() 

我會建議重新設計你的程序,以便root.mainloop()是在結束主程序,不在__init__()內。

+0

所以我要調用start'root.mainloop()''中Play',分配後? – tsorn

+0

是的,我添加了一個建議,你可以做到這一點。 –