2011-06-06 64 views
1

我正在python 2.7中创建一个扫雷游戏。尝试创建GUI时遇到了几个问题。我已经在一些基本的设置窗口中使用了一个名为easyGUI的库(在这里找到:http://easygui.sourceforge.net/),但那不是我的问题。问题在于实际的扫雷窗口本身。我不确定如何在右键单击时放置一个标志,或者在左键单击空间时运行递归“location_reveal”功能。另一个问题是如何改变按钮上的文本以表示有多少边界地雷,以及每次用户做出决定时标志的位置。我遇到了一个巨大的问题,因为我想我可以摧毁窗口并每次使用更新重新创建它,但是这也不起作用。任何帮助将不胜感激。 (:b1.configure(text="whatever")如)用GUI使用Tkinter的Python扫雷游戏如何正确显示按钮?

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() 

回答

1

您可以用按钮的configure方法更改按钮上的文本。每次更新都不需要重新创建整个窗口。只需创建一次按钮并根据需要更改文本或图像。

例如,改变你的按钮定义是这样的:

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 

这样,当你需要用X来指代特定的按钮,你可以参考button[s],Y(如:self.button["1:2"].configure(...)

+0

感谢您的答复。我尝试使用配置,但是我所有的按钮都具有相同的名称: 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。绑定( '',field_hid.destroy()) b.pack() b.grid(行= X,柱= Y) Tkinter.mainloop() – 2011-06-06 23:46:14

+0

@Nick Delbin:则可以重复使用相同的本地变量,但每个小部件仍然是一个单独的实体。你只需要保存一个参考。我推荐一本字典,用一个二元组作为关键字。例如,'self.button [(row,column)] = Tkinter.Button(...)'。尽管如此,通过设计,您并不需要它,因为您可以将引用传递给该回调的参数(例如:'b = Tkinter.button(...); b.configure(command = lambda按钮= b:...)') – 2011-06-07 03:08:29

+0

我不确定你是什么意思,有什么办法可以更具体吗?我明白使用配置,但它如何确定哪个按钮我想改变文本? – 2011-06-07 15:33:19