【问题标题】:Interactive game board with Tkinter Python - label updating使用 Tkinter Python 的交互式游戏板 - 标签更新
【发布时间】:2016-01-05 19:19:14
【问题描述】:

我对 Tkinter 完全陌生,所以如果我说错了什么,我深表歉意。我正在用 Python 实现游戏 15,我想用 Tkinter 使其可视化。请参阅以下 2x2 板:

4 3

如果你提示 x 用 3 交换,这些标签应该更新。到目前为止,我初始化了一个画布,并有两个代码 sn-ps,一个用于设置板:

def visualize():
    for i,row in enumerate(board):
        for j,column in enumerate(row):
            L = Label(root,text='   %s   '%board[i][j],bg='pink')
            if board[i][j] == d*d:
                L = tk.Label(root,text='        ')

对于移动功能:

def move():
    tile = int(raw_input('Which tile would you like to move: '))
    global board, blankx, blanky
    for i in range(d):
        for j in range(d):
            if(board[i][j] == tile):
                if(i - 1 == blanky or i + 1 == blanky or j - 1 == blankx or j + 1 == blankx):
                    board[i][j] = d * d
                    board[blanky][blankx] = tile
                    blanky = i
                    blankx = j
                    return True
    return False

关于如何将标签合并到我的画布中以及如何将移动作为画布上的有效事件合并的任何想法?非常感谢

【问题讨论】:

    标签: python canvas tkinter visualization tkinter-canvas


    【解决方案1】:

    如果您不需要移动瓷砖的动画,那么您可以使用grid() 将标签放在行和列中 - 而不是使用Canvas - 并将文本从标签移动到标签。

    您甚至可以使用Button(而不是Label)和command= 为按钮分配功能。

    -

    如果您需要动画,则可以使用create_window()Label 添加到Canvasbind(event, function) 以将函数分配给事件调用的标签(如)。

    但您也可以使用place()Frame 中放置标签或按钮

    -

    并且您必须将所有标签/按钮保留在全局列表中才能访问它们。

    -

    编辑:简单且有效的示例(但不完整)

    import tkinter as tk
    
    # --- functions ---
    
    def move(x, y):
        global empty_x, empty_y, game_running   
    
        if game_running:        
            # check and move tile
            if (empty_x, empty_y) in [(x+1, y), (x-1, y), (x, y+1), (x, y-1)]:
    
                board[empty_y][empty_x] = board[y][x]
                board[y][x] = ' '
    
                buttons[empty_y][empty_x]['text'] = buttons[y][x]['text']
                buttons[y][x]['text'] = ' '
    
                empty_x = x
                empty_y = y
    
                if won():
                    # show label "Hurray"
                    label.lift()
                    game_running = False
    
        else:
            # start game again
    
            shuffle() # shuffle tiles
    
            game_running = True
    
            # hide label
            label.lower() # or frame.lift()
    
    
    def won():
    
        number = 0
    
        for y, row in enumerate(board):
            for x, char in enumerate(row, 1):
                number += 1
                if number == 9 and char == ' ':
                    #print('A |%s| %d' % (char, number))
                    return True
                elif char != str(number):
                    #print('B |%s| %d' % (char, number))
                    return False
    
        return True
    
    
    def shuffle():
        # TODO: shuffle tiles
    
        # it can't put tiles in random places
        # because it can create game without solution
    
        pass
    
    # --- data ---
    
    board = [
        ['1', '2', '3'],
        ['4', '5', '6'],
        ['7', '8', ' '],
    ]
    
    empty_x = len(board[0])-1
    empty_y = len(board)-1
    
    # --- main ---
    
    root = tk.Tk()
    
    # create label hidden behide frame
    
    label = tk.Label(root, text="Hurray!\n\n(click any button to play again)", bg="red")
    label.grid(row=0, column=0, ipadx=20, ipady=20)
    
    # create frame with buttons to fast show/hide label
    
    frame = tk.Frame(root)
    frame.grid(row=0, column=0) # the same (row,col) to hide label
    
    buttons = []
    
    for y, row in enumerate(board):
    
        buttons_row = []
    
        for x, char in enumerate(row):
    
            b = tk.Button(frame, text=char, width=10, height=5, command=lambda x=x,y=y:move(x,y))
            b.grid(row=y, column=x)
    
            buttons_row.append(b)
    
        buttons.append(buttons_row)
    
    # start game
    
    shuffle() # shuffle tiles
    game_running = True
    
    # start "the engine"
    
    root.mainloop()
    

    编辑:带有StringVar的新版本

    shuffle 中,我将图块放在随机位置,有时我会得到没有解决方案的游戏。

    有一些较小的修改 - “Hurray”现在是一个按钮并开始新游戏。

    import tkinter as tk
    import random
    
    # --- functions ---
    
    def move(x, y):
        global empty_x, empty_y, game_running   
    
        if game_running:        
            # check and move tile
            if (empty_x, empty_y) in [(x+1, y), (x-1, y), (x, y+1), (x, y-1)]:
    
                board[empty_y][empty_x].set( board[y][x].get() )
                board[y][x].set(' ')
    
                empty_x = x
                empty_y = y
    
                if won():
                    # show label "Hurray"
                    label.lift()
                    game_running = False
    
        else:
            # start game again
    
            shuffle() # shuffle tiles
    
    
    def won():
    
        number = 0
    
        for y, row in enumerate(board):
            for x, string_var in enumerate(row, 1):
                number += 1
                if number == 9 and string_var.get() == ' ':
                    #print('A |%s| %d' % (char, number))
                    return True
                elif string_var.get() != str(number):
                    #print('B |%s| %d' % (char, number))
                    return False
    
        return True
    
    
    def shuffle():
        global empty_x, empty_y, game_running
    
        # TODO: shuffle tiles
    
        # it can't put tiles in random places
        # because it can create game without solution
    
    
        # clear all tiles to recognize (in next step) empty tiles 
        for row in board:
            for element in row:
                element.set('')
    
        # put tiles in random places
        for number in range(1, 10):
            while True: 
                row = random.randint(0, 2)
                col = random.randint(0, 2)
                if board[row][col].get() == '':
                    board[row][col].set(str(number))
                    print('row/col/number:', row, col, number)
                    break
    
        # last number remove:
        print('empty row/col:', row, col)
        board[row][col].set(' ')
        empty_x = col
        empty_y = row
    
        # hide label
        label.lower() # or frame.lift()
    
        # start game
        game_running = True
    
    # --- main ---
    
    root = tk.Tk()
    
    # --- data ---
    
    # StringVar needs `root` - it has to be after tk.Tk()
    
    # empty board
    board = [   
    #    [tk.StringVar(value='1'), tk.StringVar(value='2'), tk.StringVar(value='3')],
        [tk.StringVar(), tk.StringVar(), tk.StringVar()],
        [tk.StringVar(), tk.StringVar(), tk.StringVar()],
        [tk.StringVar(), tk.StringVar(), tk.StringVar()],
    ]
    
    # create label hidden behide frame
    
    label = tk.Button(root, text="Hurray!\n\n(click here to play again)", command=shuffle)
    label.grid(row=0, column=0, ipadx=50, ipady=50)
    
    # create frame with buttons to fast show/hide label
    
    frame = tk.Frame(root)
    frame.grid(row=0, column=0) # the same (row,col) to hide label
    
    buttons = []
    
    for y, row in enumerate(board):
    
        buttons_row = []
    
        for x, string_var in enumerate(row):
    
            b = tk.Button(frame, textvariable=string_var, width=10, height=5, command=lambda x=x,y=y:move(x,y))
            b.grid(row=y, column=x)
    
            buttons_row.append(b)
    
        buttons.append(buttons_row)
    
    # start game
    
    shuffle() # shuffle tiles
    
    # start "the engine"
    
    root.mainloop()
    

    【讨论】:

    • 非常感谢,这真的很有用!我想知道你是否知道我怎么能把它放到一个'while won() == False:' 这样游戏就一直持续到游戏解决?它不像我尝试的那样简单,将这个 Tkinter sn-p 包含在循环中。
    • mainloop() 应该是 Tkinter 中唯一的(无限的)循环。我认为你不应该使用while won() == False:。最好在move() 使用if won(): print("Hurray!")
    • 我修改了代码以添加won()函数和"Hurray"标签。我使用Frame 轻松隐藏标签后面的所有按钮。它仍然需要shuffle() 函数。
    • 非常感谢,帮我省了很多麻烦。最后我用标签做到了,现在我正在尝试重置电路板。我认为 shuffle() 可能与我为 board[i][j] 设置值的 init 相同。但似乎在获胜后单击任意位置,棋盘保持不变,但值确实会回到初始棋盘值。我认为在改组后 mainloop() 将重新启动,并且将根据新的(初始)板值再次设置板。知道我哪里错了吗?
    • 如果您有 board 的新值,那么您必须使用它来更改按钮文本 - buttons[y][x]['text'] = board[y][x]
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-24
    • 1970-01-01
    相关资源
    最近更新 更多