【问题标题】:Sudoku GUI in Python with Tkinter - StringVar not updating带有 Tkinter 的 Python 中的数独 GUI - StringVar 未更新
【发布时间】:2020-04-18 23:44:46
【问题描述】:

我最近成功编写了一个递归代码,它使用回溯来解决一个简单的数独难题。我想创建它,以便我实时解决难题,即数字实时变化,并希望使用 tkinter 模块来做到这一点。我创建了一个 9*9 的板,每个数字都作为一个特定的标签,并将标签的文本存储在 StringVar() 中,这样我就可以不断更新它。所有的 StringVar 都存储在一个 9*9 数组(称为 textvars)中,因此它们对应于我想要解决的原始数独板,因此我可以使用行号和列号来更新文本。以下是这部分的代码:

def main():
    textvars = []
    t1 = []
    board = [[3, 0, 6, 5, 0, 8, 4, 0, 0],
             [5, 2, 0, 0, 0, 0, 0, 0, 0],
             [0, 8, 7, 0, 0, 0, 0, 3, 1],
             [0, 0, 3, 0, 1, 0, 0, 8, 0],
             [9, 0, 0, 8, 6, 3, 0, 0, 5],
             [0, 5, 0, 0, 9, 0, 6, 0, 0],
             [1, 3, 0, 0, 0, 0, 2, 5, 0],
             [0, 0, 0, 0, 0, 0, 0, 7, 4],
             [0, 0, 5, 2, 0, 6, 3, 0, 0]]

    for i in range(9):
        t1 = []
        for j in range(9):
            txt = StringVar()
            if board[i][j]==0:
                txt.set('')
            else:
                txt.set(str(board[i][j]))
            Label(root,height = 2, width = 4, textvariable = txt, relief = "solid").grid(row = i, column = j)
            t1.append(txt)
        textvars.append(t1)

    solve_board(board, textvars)

这些文本变量和板被传递给使用回溯的 solve_board() 函数,当更新板时,它使用 .set() 函数更新文本,如下所示:

def solve_board(board,textvars):

        for rowno in range(9):

            for colno in range(9):

                if board[rowno][colno] == 0:
                    for i in range(1,10):

                        if (is_valid(board,rowno,colno,i)):
                            board[rowno][colno]=i
                            textvars[rowno][colno].set(str(i))
                            solve_board(board,textvars)
                            board[rowno][colno]=0
                            textvars[rowno][colno].set('')
                    return False

        print (np.matrix(board))

所有与 gui 或 tkinter 无关的位都可以完美地工作,尽管它们是匆忙输入的,导致代码不是最优的。

运行此代码时,tkinter 窗口上显示的板是未解决的板,而正在打印的板已完全解决。

我希望你能帮助我弄清楚为什么这段代码不起作用,我附上了其余的代码、一个 is_valid 函数和一个主要的函数,以供进一步参考。谢谢。

def is_valid(b,r,c,n): #check if number insertion is valid
    if n in b[r]: #if in row
        return False
    for x in range(0,9):
        if n == b[x][c]: #check for column
            return False
    sr = r - r%3
    sc = c - c%3
    for x in range(sr,sr+3):
        for y in range(sc,sc+3):
            if b[x][y]==n:
                return False
    return True

if __name__ == "__main__":
    root = Tk()
    root.title("Sudoku")

    main()
    root.mainloop()

编辑:

代码:

board[rowno][colno]=0
textvars[rowno][colno].set('')

这用于反映回溯过程,即如果做出的选择不正确,程序会返回上次做出选择的时间,并通过将其设置为 0 来重置选择。将文本设置为 '' 是只是为了反映重置使我的程序在 tkinter 窗口中。

【问题讨论】:

  • 我也尝试将所有标签存储在另一个数组中,输出相同。
  • 我认为你需要把t1 = []放在for j in range(9)之前。
  • 哦,是的,我的错!我忘了说 - 它解决了顶行从输出中消失但标签仍然没有在 tkinter 窗口中更新的问题,并且在我打印的电路板解决时显示的电路板仍未解决!
  • 我认为这是因为您在内部 if 块的末尾调用了 textvars[rowno][colno].set('')。尝试删除该行。
  • 最好更新StringVar末尾的solve_board()

标签: python user-interface tkinter tk sudoku


【解决方案1】:

我认为您需要在solve_board() 函数的末尾返回True。如果 solve_board() 在 if 块中返回 True 也立即返回。

由于solve_board()运行时mainloop()不会被执行,所以如果想在求解过程中看到更新,需要在设置StringVar后调用root.update()

def solve_board(board, textvars):
    for rowno in range(9):
        for colno in range(9):
            if board[rowno][colno] == 0:
                for i in range(1, 10):
                    if is_valid(board, rowno, colno, i):
                        board[rowno][colno] = i
                        textvars[rowno][colno].set(str(i))
                        root.update()
                        if solve_board(board, textvars):
                            return True
                        board[rowno][colno] = 0
                        textvars[rowno][colno].set('')
                        root.update()
                return False
    print(np.matrix(board))
    return True

【讨论】:

  • 效果很好!我认为缺少的更新弄乱了我的代码,非常感谢!
猜你喜欢
  • 2012-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多