Игра Python Minesweeper с графическим интерфейсом с использованием Tkinter Как правильно отображать кнопки?

1

Я создаю игру тральщика в python 2.7. При попытке создать графический интерфейс я столкнулся с несколькими проблемами. Я использовал библиотеку под названием easyGUI (здесь: http://easygui.sourceforge.net/) для некоторых базовых окон установки, но это не моя проблема. Проблема заключается в самом окне самого тральщика. Я не уверен, как поставить флаг, когда right- нажимает или запускает рекурсивную функцию location_reveal при щелчке левой кнопкой мыши на пробеле. Другая проблема заключается в том, как изменить текст на кнопке, чтобы указать, сколько пограничных мин есть, и где флаги каждый раз, когда пользователь принимает решение. Я столкнулся с огромной проблемой, потому что решил, что могу просто уничтожить окно и обновить его с помощью обновлений каждый раз, однако это тоже не сработало. Любая помощь будет принята с благодарностью.

from easygui import *
import random
import os
import Tkinter

def game_new():
    n = enterbox(msg='Enter your name.', title='Welcome new user!', strip=True)
    while n.strip() == "":
        n = enterbox(msg='Oops you forgot to enter a name!', title='Welcome new user!', strip=True)
    a = buttonbox(msg='Choose a game difficulty', title='Configuration', choices = ['Beginner','Intermediate','Expert','Custom'])
    if a[0] == 'B':
        return n, 9, 9, 10
    elif a[0] == 'I':
        return n, 16, 16, 40
    elif a[0] == 'E':
        return n, 30, 16, 99
    else:
        a,b,c = customconfigure()
        return n,a,b,c

def customconfigure():
    msg = "Minesweeper configuration:"
    title = "Settings"
    fieldNames = ["Width in mines (max 30):","Height in mines (max 20):","Mines:"]
    fieldValues = []  # we start with blanks for the values
    fieldValues = multenterbox(msg,title, fieldNames)
    while 1:
        if fieldValues == None: break
        errmsg = ""
        for i in range(len(fieldNames)):
            if fieldValues[i].strip() == "":
                errmsg += ('"%s" was left blank.\n\n' % fieldNames[i])
            elif not fieldValues[i].strip().isdigit:
                errmsg += ('"%s" must be an integer.\n\n' % fieldNames[i])
            elif i == 0 and not 3 <= int(fieldValues[i]) <= 30:
                errmsg += ('Width must be between 3 and 30 mines.\n\n')
            elif i == 1 and not 3 <= int(fieldValues[i]) <= 20:
                errmsg += ('Height must be between 3 and 20 mines.\n\n')
            elif i == 2 and not 1 <= int(fieldValues[i]) <= (int(fieldValues[0]) * int(fieldValues[1]) - 1):
                errmsg += ('Mines must be between 1 and ' + str(int(fieldValues[0]) * int(fieldValues[1]) - 1) + '\n\n')                
        if errmsg == "":
            break # no problems found
        fieldValues = multenterbox(errmsg, title, fieldNames, fieldValues)
    return int(fieldValues[0]),int(fieldValues[1]),int(fieldValues[2])

def inchk(s,m):
    if not s.isdigit:
        return False
    if 1 <= int(s) <= m:
        return True
    else:
        return False    

def move_get():
    user_x = raw_input("Enter the 'x' of the point you want to preform an action on: ")
    while not inchk(user_x,width):
        user_x = raw_input("Invalid selection. Enter a value for 'x': ")
    user_y = raw_input("Enter the 'y' of the point you want to preform an action on: ")
    while not inchk(user_y,height):
        user_y = raw_input("Invalid selection. Enter a value for 'y': ")
    return int(user_x), int(user_y)


def location_reveal(x,y):
    global field
    global showing    
    global symbol_mine
    if field[x][y] == symbol_mine:
        game_over()
    else:
        showing[x][y] = " " + str(field[x][y]) + " "
        if showing[x-1][y] == "     " and field[x-1][y] != symbol_mine:
            location_reveal(x-1,y)
        if showing[x+1][y] == "     " and field[x+1][y] != symbol_mine:
            location_reveal(x+1,y)        
        if showing[x][y+1] == "     " and field[x][y+1] != symbol_mine:
            location_reveal(x,y+1)
        if showing[x][y-1] == "     " and field[x][y-1] != symbol_mine:
            location_reveal(x,y-1)
    playing()

def location_chosen(s):
    global field
    global showing
    x = int(s[:s.index(":")]) + 1
    y = int(s[s.index(":")+1:]) + 1
    msg = "Choose an action to "
    choices = ["Reveal","Flag","Back"]
    reply = buttonbox(msg,choices=choices)
    field_hid.destroy
    if reply == "Back":
        playing()
    elif reply == "Flag":
        showing[x][y] = " F "
        playing()
    else:
        location_reveal(x,y)

def playing():
    global field
    global showing
    global width
    global height
    global symbol_mine
    win = False
    def k():
        field_hid.destroy()
    count_mine = 0
    count_flag = 0
    for x in field:
        count_mine += x.count(symbol_mine)
    for x in showing:
        count_flag += x.count(' F ')
    for x in range(1, width):
        for y in range(1, height):
            if field[x][y] == symbol_mine and showing[x][y] == ' F ':
                if count_mine == count_flag:
                    win = True                 
                else:
                    win = False
                    break               


    field_hid = Tkinter.Tk()    
    for x in range(width):
        for y in range(height):
            s = str(x) + ":" + str(y)
            t = showing[x+1][y+1]
            b = Tkinter.Button(field_hid, text = t, command = lambda s=s: location_chosen(s))
            #b.bind('<Button-1>', field_hid.destroy())
            b.pack()
            b.grid(row=x, column=y)
    Tkinter.mainloop()  

def main():
    global width
    global height
    global field
    global showing
    global symbol_mine
    user_name, width, height, mines = game_new()
    symbol_empty = ' '
    symbol_mine = 'M' 
    play = True

    #Creates field with empty spaces
    field = [[symbol_empty for h in range(width+2)] for w in range(height+2)]    #
    showing = [["     " for h in range(width+2)] for w in range(height+2)]

    # Randomly places mines on the field
    mines_placed = 0
    while mines_placed < mines:
        y = random.randint(1,width)#
        x = random.randint(1,height)#
        if field[x][y] == symbol_empty:
            field[x][y] = symbol_mine
            mines_placed += 1

    # Checks How many mines border each square
    for x in range(1,height+1):
        for y in range(1, width+1):
            if field[x][y] != symbol_mine:
                mines_touching = 0
                for x2 in range(x-1,x+2):
                    for y2 in range(y-1,y+2):
                        if field[x2][y2] == symbol_mine:
                            mines_touching += 1
                if mines_touching > 0:
                    field[x][y] = str(mines_touching)

    #Creates the playing field
    playing()

main()
Теги:
button
user-interface
tkinter
minesweeper

1 ответ

1
Лучший ответ

Вы можете изменить текст кнопкой с помощью кнопки configure кнопки (например: b1.configure(text="whatever")). Вам не нужно воссоздавать все окно с каждым обновлением. Просто создайте кнопки один раз и при необходимости измените текст или изображение.

Например, измените определение своей кнопки так:

b = Tkinter.Button(field_hid, text = t)
b.configure(command = lambda s=s, button=b: location_chosen(s,button))

Затем измените параметры location_chosen следующим образом:

def location_chosen(s,button):
    ...

Как только вы это сделаете, метод location_chosen будет передан в ссылку на кнопку, которая была нажата. Затем вы можете перенастроить эту кнопку, чтобы иметь любую метку или изображение, которые вы хотите, выполнив button.configure(...)

Конечно, другим способом является сохранение ссылок в массиве или словаре. Например, вы можете добавить:

self.button[s] = b

Таким образом, вы можете ссылаться на button[s], когда вам нужно обратиться к определенной кнопке с помощью x, y (например: self.button["1:2"].configure(...))

  • 0
    Спасибо за ответ. Я попытался использовать configure, однако все мои кнопки имеют одинаковое имя: field_hid = Tkinter.Tk () для x в диапазоне (ширина): для y в диапазоне (высота): s = str (x) + ":" + str ( y) t = отображение [x + 1] [y + 1] b = Tkinter.Button (field_hid, text = t, command = lambda s = s: location_chosen (s)) # b.bind ('<Button-1> ', field_hid.destroy ()) b.pack () b.grid (row = x, column = y) Tkinter.mainloop ()
  • 0
    @Nick Delbin: вы можете повторно использовать одну и ту же локальную переменную, но каждый виджет по-прежнему является отдельной сущностью. Вам просто нужно сохранить ссылку. Я рекомендую словарь, с двумя кортежами в качестве ключа. Например, self.button[(row,column)] = Tkinter.Button(...) . Однако, если у вас есть дизайн, он вам на самом деле не нужен, потому что вы можете просто передать ссылку на виджет в качестве параметра для обратного вызова (например: b = Tkinter.button(...); b.configure(command=lambda button=b: ...) )
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню