Я сделал простую «игру 9», которая отлично работает на чистом Python. Теперь я хочу сделать то же самое в окне Tkinter. Я пытаюсь обновить окно Tkinter с помощью нажатия клавиши - когда я нажимаю цифру (1-8), я устанавливаю в матрице разные числа и хочу обновить окно. К сожалению, я не знаю, как это сделать хорошо. Я использовал window.update () и window.destroy (), но это плохое решение. Не могли бы вы помочь, как обновить мое окно Tkinter без использования window.destroy ()? Я новичок в Tkinter, а также в Python :)

import random
import tkinter as tk
from time import sleep
import keyboard


x,px,py,px2,py2 = 0,0,0,0,0
matrix = [[0,0,0],[0,0,0],[0,0,0]]

# generate 9 unique numbers (0 to 8) and insert them into matrix 
z = random.sample(range(0,9),9)

matrix[0] = [(z[0]), (z[1]), (z[2])]
matrix[1] = [(z[3]), (z[4]), (z[5])]   
matrix[2] = [(z[6]), (z[7]), (z[8])]

def printmatrix():

    label1 = tk.Label(text = matrix[0])
    label1.grid(column = 1, row = 1)
    label2 = tk.Label(text = matrix[1])
    label2.grid(column = 1, row = 2)
    label3 = tk.Label(text = matrix[2])
    label3.grid(column = 1, row = 3)




# check win
def check_win():
    if matrix[0] == [1,2,3] and matrix[1] == [4,5,6] and matrix[2] == [7,8,0]:
        label4 = tk.Label(text = "you won !!!")
        label4.grid(column = 0, row = 6)
        window.update()
        sleep (5)
        exit ()


while __name__ == '__main__':
    window = tk.Tk()
    window.title("GAME 9")
    window.geometry("300x300")

    printmatrix()
    window.update()  


    check_win()

    # read key 1-8

    if keyboard.read_key() == "1":
        x = 1
    if keyboard.read_key() == "2":
        x = 2
    if keyboard.read_key() == "3":
        x = 3
    if keyboard.read_key() == "4":
        x = 4
    if keyboard.read_key() == "5":
        x = 5
    if keyboard.read_key() == "6":
        x = 6
    if keyboard.read_key() == "7":
        x = 7
    if keyboard.read_key() == "8":
        x = 8



# check position of "0"
    for pozx,j in enumerate(matrix):
        for pozy,l in enumerate(j):
            if l==0:
                px = int(pozx)
                py = int(pozy)


# check position of moved number
    for pozx2,j in enumerate(matrix):
        for pozy2,l in enumerate(j):
            if l==x:
                px2 = int(pozx2)
                py2 = int(pozy2)


# check if the moved number is on the right place  (if we can use it)
    if  (px == px2 or py == py2) and ((py+1 or py-1 == py2) or (px+1 or px-1 == px2)):
        if (px == 0 and px2 == 1) or (px == 1 and px2 == 2) or (px == 1 and px2 == 0) or (px == 2 and px2 == 1) or (py == 0 and py2 == 1) or (py == 1 and py2 == 2) or (py == 1 and py2 == 0) or (py == 2 and py2 == 1):


            matrix[px2][py2] = 0
            matrix[px][py] = x
            printmatrix()


        else:
            label5 = tk.Label(text = "wrong move, try again")
            label5.grid(column = 0, row = 5)
            window.update()
            sleep(2)
            printmatrix()


    else:
        label6 = tk.Label(text = "wrong move, try again")
        label6.grid(column = 0, row = 4)
        window.update()
        sleep(2)
        printmatrix()


    window.destroy()  
    window.mainloop()
-1
emax 22 Дек 2019 в 16:27
Не используйте методы модуля keyboard, а tkinter для привязки функции к нажатой клавише - root.bind("1", function_name) и внутри этой переменной набора функций. Вам нужно будет узнать, как работают все фреймворки графического интерфейса, и переписать их.
 – 
furas
22 Дек 2019 в 17:52
Создавать все метки в начале, а затем изменять только текст в метках. Не создавайте снова и снова ярлыки в одном и том же месте, потому что предыдущие ярлыки все еще находятся в окне и используют память.
 – 
furas
22 Дек 2019 в 17:55

1 ответ

Я не тестировал его до конца, но он использует методы, которые используются в большинстве графических интерфейсов.

Он связывает / назначает функции клавишам, поэтому запускается move(number) и номер хода.

Он создает метки при запуске, а затем меняет текст только в метках.

Ему не нужно update, потому что он обновляет его автоматически.

Кстати: как и в матрице, используемой в математике, я использую [row][column], что означает [y][x], а не [x][y]

import random
import tkinter as tk
import time

# generate 9 unique numbers (0 to 8) and insert them into matrix 
z = random.sample(range(0,9),9)

matrix = [
    [(z[0]), (z[1]), (z[2])],
    [(z[3]), (z[4]), (z[5])],
    [(z[6]), (z[7]), (z[8])],
]    
#print(matrix)

def update_labels():
    for row_matrix, row_labels in zip(matrix, labels):
        for item, label in zip(row_matrix, row_labels): 
            label["text"] = item


def move(number):
    #print(number)

    # find position of "0" and moved number
    for y, row in enumerate(matrix):
        for x, cell in enumerate(row):
            if cell == 0:
                zero_x = x
                zero_y = y
            elif cell == number:
                number_x = x
                number_y = y

    # check if the moved number is on the right place  (if we can use it)
    diff_x = abs(zero_x - number_x)
    diff_y = abs(zero_y - number_y)
    if (diff_x == 0 and diff_y == 1) or (diff_x == 1 and diff_y == 0):
            matrix[number_y][number_x] = 0
            matrix[zero_y][zero_x] = number
    else:
        message_label['text'] = "wrong move, try again"

    update_labels()
    check_win()

def check_win():
    if matrix == [[1,2,3], [4,5,6], [7,8,0]]:
        message_label['text'] = "you won !!!"
        time.sleep(5)
        exit()

if __name__ == '__main__':
    window = tk.Tk()
    window.title("GAME 9")
    window.geometry("300x300")

    # create labels
    labels = []
    for y in range(1, 4):
        row = []
        for x in range(1, 4): 
            label = tk.Label(window)
            label.grid(column=x, row=y)
            row.append(label)
        labels.append(row)

    # label for messages        
    message_label = tk.Label(window)
    message_label.grid(column=0, row=4, columnspan=5)

    # fill labels at start
    update_labels()

    # bind keys to function
    for i in range(1, 10):
        window.bind(str(i), lambda event, x=i:move(x))

    # start program and show window
    window.mainloop()
0
furas 22 Дек 2019 в 18:24
Спасибо за ответ, теперь кое-что мне стало понятнее. И я вижу, что ваш код находится на другом уровне (по сравнению с моим). Мне нужно многому научиться :)
 – 
emax
23 Дек 2019 в 18:44