【问题标题】:An error while trying to change the list and show the result in python尝试更改列表并在 python 中显示结果时出错
【发布时间】:2021-11-23 19:59:30
【问题描述】:

我试图用这种方式在 python 中使用 tkinter 制作 XO 游戏,这是我的代码:

def button_function(name: tkinter.Button, n: str):
    global row, column
    info = name.grid_info()
    row1 = info.get('row')
    column1 = info.get('column')
    name.grid_remove()
    button = Button(root, text=n, font="decorative 9 bold", height=3, width=6, bg="white", state=DISABLED)
    button.grid(row=row1, column=column1)
    my_list = [cell1, cell2, cell3, cell4, cell5, cell6, cell7, cell8, cell9]
    for x in my_list:
        if x.grid_info():
            info = x.grid_info()
            row = info.get('row')
            column = info.get('column')
            x.grid_remove()
            if n == "X":
                my_list[my_list.index(x)] = Button(root, height=3, width=6, bg="gray",
                                                   command=lambda: button_function(x, "O"))
                my_list[my_list.index(x)].grid(row=row, column=column)
            elif n == "O":
                my_list[my_list.index(x)] = Button(root, height=3, width=6, bg="gray",
                                                   command=lambda: button_function(x, "X"))
                my_list[my_list.index(x)].grid(row=row, column=column)
            else:
                pass
    info.clear()


def xo():
    global cell1, cell2, cell3, cell4, cell5, cell6, cell7, cell8, cell9
    cell1 = Button(root, height=3, width=6, bg="gray", command=lambda: button_function(cell1, "X"))
    cell2 = Button(root, height=3, width=6, bg="gray", command=lambda: button_function(cell2, "X"))
    cell3 = Button(root, height=3, width=6, bg="gray", command=lambda: button_function(cell3, "X"))
    cell4 = Button(root, height=3, width=6, bg="gray", command=lambda: button_function(cell4, "X"))
    cell5 = Button(root, height=3, width=6, bg="gray", command=lambda: button_function(cell5, "X"))
    cell6 = Button(root, height=3, width=6, bg="gray", command=lambda: button_function(cell6, "X"))
    cell7 = Button(root, height=3, width=6, bg="gray", command=lambda: button_function(cell7, "X"))
    cell8 = Button(root, height=3, width=6, bg="gray", command=lambda: button_function(cell8, "X"))
    cell9 = Button(root, height=3, width=6, bg="gray", command=lambda: button_function(cell9, "X"))
    cell1.grid(row=2, column=1)
    cell2.grid(row=2, column=3)
    cell3.grid(row=2, column=5)
    cell4.grid(row=4, column=1)
    cell5.grid(row=4, column=3)
    cell6.grid(row=4, column=5)
    cell7.grid(row=6, column=1)
    cell8.grid(row=6, column=3)
    cell9.grid(row=6, column=5)

在第一个函数中,我试图在不更改单元格名称的情况下更改列表的内容,但我发现不能简单地通过向其添加值并将其网格化来完成,因为它将是本地的变量不属于列表。

x = Button(root, height=3, width=6, bg="gray", command=lambda: button_function(x, "O"))

所以我在上面尝试了这种方式,但我得到了这个错误

    traceback (most recent call last):
  File "C:\Users\HP\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 1892, in __call__
    return self.func(*args)
  File "D:\Python projects\python\Better XO.py", line 42, in <lambda>
    cell8 = Button(root, height=3, width=6, bg="gray", command=lambda: button_function(cell8, "X"))
  File "D:\Python projects\python\Better XO.py", line 23, in button_function
    my_list[my_list.index(x)].grid(row=row, column=column)
ValueError: <tkinter.Button object .!button9> is not in list

那么有没有其他方法可以正确地做到这一点,谢谢

【问题讨论】:

  • 请完整错误码
  • 如果您发布完整的回溯,我们可以更轻松地查看错误所在..
  • @CoolCloud 正如你所说,我提供了所有的引用
  • @tdelaney 正如你所说,我提供了所有引用
  • @Matiiss 正如你所说,我提供了所有引用

标签: python list function tkinter valueerror


【解决方案1】:

你有一个ValueError

不在列表中

因为你做my_list[my_list.index(x)] = Button(时按钮被替换了

您可以通过传递按钮在网格中的位置并仅使用configure 函数更改按钮属性来简化button_function

示例

def button_function(button, x, y):
    global count
    if button["text"]=="":
        button.configure(font="decorative 9 bold", bg="white", state=DISABLED)
        if count % 2 == 0:
            button.configure(text= "X")
            my_list[x][y] = "X"
        else:
            button.configure(text= "O")
            my_list[x][y] = "O"
        count +=1

        if count > 4 and is_winner(my_list[x][y]):
            messagebox.showinfo("Winner",'Player "{}" win'.format(my_list[x][y]))


def xo():

    cell1 = Button(root, height=3, width=6, bg="gray", command=lambda: button_function(cell1, 0, 0))
    ...

您还可以添加一个功能,在点击五次后检查获胜者

代码

import tkinter
from tkinter import Button, DISABLED, messagebox


root = tkinter.Tk()
count = 0
my_list  = [["", "", ""],
            ["", "", ""],
            ["", "", ""]]


def is_winner(mark):
    if (my_list[0][0]==my_list[1][0]==my_list[2][0]==mark or
        my_list[0][1]==my_list[1][1]==my_list[2][1]==mark or
        my_list[0][2]==my_list[1][2]==my_list[2][2]==mark or
        my_list[0][0]==my_list[0][1]==my_list[0][2]==mark or
        my_list[1][0]==my_list[1][1]==my_list[1][2]==mark or
        my_list[2][0]==my_list[2][1]==my_list[2][2]==mark or        
        my_list[0][0]==my_list[1][1]==my_list[2][2]==mark or
        my_list[0][2]==my_list[1][1]==my_list[2][0]==mark):
        return True

def button_function(button, x, y):
    global count
    if button["text"]=="":
        button.configure(font="decorative 9 bold", bg="white", state=DISABLED)
        if count % 2 == 0:
            button.configure(text= "X")
            my_list[x][y] = "X"
        else:
            button.configure(text= "O")
            my_list[x][y] = "O"
        count +=1

        if count > 4 and is_winner(my_list[x][y]):
            messagebox.showinfo("Winner",'Player "{}" win'.format(my_list[x][y]))


def xo():
        
    cell1 = Button(root, height=3, width=6, bg="gray", command=lambda: button_function(cell1, 0, 0))
    cell2 = Button(root, height=3, width=6, bg="gray", command=lambda: button_function(cell2, 0, 1))
    cell3 = Button(root, height=3, width=6, bg="gray", command=lambda: button_function(cell3, 0, 2))
    cell4 = Button(root, height=3, width=6, bg="gray", command=lambda: button_function(cell4, 1, 0))
    cell5 = Button(root, height=3, width=6, bg="gray", command=lambda: button_function(cell5, 1, 1))
    cell6 = Button(root, height=3, width=6, bg="gray", command=lambda: button_function(cell6, 1, 2))
    cell7 = Button(root, height=3, width=6, bg="gray", command=lambda: button_function(cell7, 2, 0))
    cell8 = Button(root, height=3, width=6, bg="gray", command=lambda: button_function(cell8, 2, 1))
    cell9 = Button(root, height=3, width=6, bg="gray", command=lambda: button_function(cell9, 2, 2))
    cell1.grid(row=2, column=1)
    cell2.grid(row=2, column=3)
    cell3.grid(row=2, column=5)
    cell4.grid(row=4, column=1)
    cell5.grid(row=4, column=3)
    cell6.grid(row=4, column=5)
    cell7.grid(row=6, column=1)
    cell8.grid(row=6, column=3)
    cell9.grid(row=6, column=5)
    
xo()

【讨论】:

    【解决方案2】:

    虽然 Kenly 已经提供了您收到错误的原因:

    你有一个ValueError

    不在列表中

    因为你做my_list[my_list.index(x)] = Button(时按钮被替换了

    我认为你可以将代码简化很多,例如:(我还添加了对获胜状态的检查)

    import tkinter
    from tkinter import messagebox
    
    root = tkinter.Tk()
    even_turn = 0 # who's turn it is: 0: first player's turn | 1: second player's turn
    
    # an efficient way to check if a player won the game:
    # each counter has two lists, one for each player, that represent the amount of that player's symbol in a specific row/column/diagonal
    # a player has won if one of their counters are 3. and we only need to check they updated counters on each turn
    row_counter = [[0,0,0],[0,0,0]] 
    col_counter = [[0,0,0],[0,0,0]]
    dia_counter = [[0,0],[0,0]]
    # a table for the cells in the grid
    cells = [[],[],[]]
    
    def win(even):
        tkinter.messagebox.showinfo('GAME', 'Player {} win!'.format('O' if even else 'X'))
        root.destroy()
    
    def get_move_func(y: int, x: int):
        def func():
            global cells, even_turn
            # checking if cell is empty
            if(cells[y][x].cget('text') == ''):
                cells[y][x].config(text = ('O' if even_turn else 'X'))
                # updating counter
                row_counter[even_turn][y] += 1 # updating row counter
                col_counter[even_turn][x] += 1 # updating column counter
                if(x == y): # if on (left-up -> right-down) diagonal
                    dia_counter[even_turn][0] += 1
                    if(dia_counter[even_turn][0] == 3):
                        # won with diagonal
                        win(even_turn)
                        return
                if(y == 2 - x): # if on (left-down -> right-up) diagonal
                    dia_counter[even_turn][1] += 1
                    if(dia_counter[even_turn][1] == 3):
                       # won with diagonal
                       win(even_turn)
                       return 
                if(row_counter[even_turn][y] == 3 or col_counter[even_turn][x] == 3):
                    # won with row / column
                    win(even_turn)
                even_turn = 1 - even_turn
        return func
    
    def xo():
        global cells
        # some settings:
        cell_height = 3
        cell_width = 6
        cell_bg = "gray"
        curr_index = 0 # for insertion of cells into the "cells" table
        # setting the grid:
        for y in range(3):
            for x in range(3):
                cell = tkinter.Button(root, text='', font="decorative 9 bold", height=cell_height, width=cell_width, bg=cell_bg, command=get_move_func(y,x))
                cell.grid(row=y,column=x)
                cells[y].append(cell)
                curr_index += 1
    
    # calling the main function:
    xo()
    # starting the main loop:
    root.mainloop()
    

    此实现修复了原始代码中的以下不准确之处:

    • 重复代码看起来很糟糕并可能导致错误(例如,单元格声明只是重复的相同代码,但略有不同。我们有一个循环来解决这类问题)。重复代码也意味着如果你想改变它,你必须改变它的每一次出现。
    • 不必要的删除和插入对象。如果您只是要更改有关它们的一件事,则没有理由删除和插入按钮。只需使用 .config() 编辑它们
    • 转弯处理:您可以跟踪当前转弯并在命令中实施,而不是每次转弯都更改所有 Buttons 命令。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-21
      • 1970-01-01
      • 2021-09-10
      • 1970-01-01
      • 2021-03-22
      • 1970-01-01
      • 2018-06-19
      • 2017-10-30
      相关资源
      最近更新 更多