2011-06-06 4 views
1

Je crée un jeu de dragueur de mines en python 2.7. J'ai rencontré plusieurs problèmes en essayant de créer l'interface graphique. J'ai utilisé une bibliothèque appelée easyGUI (trouvée ici: http://easygui.sourceforge.net/) pour certaines des fenêtres de configuration de base, mais ce n'est pas mon problème. Le problème est avec la fenêtre de dragueur de mines lui-même. Je ne suis pas sûr de savoir comment mettre un drapeau lorsque vous cliquez avec le bouton droit de la souris ou que vous exécutez ma fonction récursive 'location_reveal' lorsque vous cliquez sur un espace. L'autre problème est de savoir comment modifier le texte sur le bouton pour indiquer le nombre de mines en bordure et où les indicateurs sont chaque fois que l'utilisateur prend une décision. Je me suis heurté à un énorme problème parce que je pensais que je pouvais simplement détruire la fenêtre et la recréer avec les mises à jour à chaque fois, mais cela ne fonctionnait pas non plus. Toute aide serait grandement appréciée.Python Démineur jeu avec GUI en utilisant Tkinter Comment afficher sur les boutons correctement?

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

Répondre

1

Vous pouvez modifier le texte sur un bouton avec la méthode configure du bouton (par exemple: b1.configure(text="whatever")). Vous n'avez pas besoin de recréer toute la fenêtre à chaque mise à jour. Il suffit de créer les boutons une fois et de changer le texte ou l'image au besoin.

Par exemple, changer votre définition de bouton pour ressembler à ceci:

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

Ensuite, modifiez les paramètres de location_chosen être comme ceci:

def location_chosen(s,button): 
    ... 

Une fois que vous faites cela, la méthode location_chosen sera passé dans une référence au bouton sur lequel vous avez cliqué. Vous pouvez ensuite reconfigurer ce bouton pour avoir n'importe quelle étiquette ou image que vous voulez en faisant button.configure(...)

Bien sûr, une autre façon est de stocker les références dans un tableau ou un dictionnaire. Par exemple, vous pouvez ajouter:

self.button[s] = b 

De cette façon, vous pouvez référencer button[s] lorsque vous avez besoin de se référer à un bouton spécifique par x, y (par exemple: self.button["1:2"].configure(...))

+0

Merci pour la réponse. J'essayé d'utiliser configure, mais tous mes boutons ont le même nom: field_hid = Tkinter.Tk() pour x dans la plage (largeur): pour y dans la plage (hauteur): s = str (x) + " : "+ str (y) t = montrant [x + 1] [y + 1] b = Tkinter.Button (champ_hid, texte = t, commande = lambda s = s: location_chosen (s)) #b. bind ('', field_hid.destroy()) b.pack() b.grid (ligne = x, colonne = y) Tkinter.mainloop() –

+0

@Nick Delbin: vous pouvez réutiliser la même variable locale, mais chaque widget est toujours une entité distincte. Vous avez juste besoin de sauvegarder une référence. Je recommande un dictionnaire, avec un deux-tuple comme une clé. Par exemple, 'self.button [(ligne, colonne)] = Tkinter.Button (...)'. Cependant, avec le design que vous avez, vous n'en avez pas vraiment besoin car vous pouvez simplement passer la référence au widget en tant que paramètre du callback (par exemple: 'b = Tkinter.button (...); b.configure (commande = lambda button = b: ...) ') –

+0

Je ne suis pas sûr de ce que vous entendez par là, y a-t-il un moyen d'être plus spécifique? Je comprends en utilisant configure, mais comment détermine-t-il le bouton sur lequel je souhaite changer le texte? –

Questions connexes