2014-12-12 2 views
0

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

Он отлично работает, за исключением случаев, когда нажата кнопка до завершения вычислений, новые значения рассчитываются и выводятся перед возвратом к предыдущим значениям. В принципе, программа делает то, что я хочу, за исключением того, что она возвращается к первым вычислениям после нажатия кнопки и завершения вторых вычислений (все значения переменных возвращаются).

Общая схема задачи: 1. Корневые MainLoop 2. Значения введенному 3. Нажмите «Go» 4. Расчеты выводятся на экран (Monty Карло сим, кстати) 5. Нажмите кнопку, чтобы изменить входные значения 6. Новые вычисления, напечатанные на экране 7. Как только новые завершатся, вычисления для старых значений переменных возвращаются до завершения

Есть ли способ предотвратить возврат python к предыдущим значениям переменной? Я надеюсь, что есть способ вернуться к mainloop, чтобы вычисления на экране оставались верными. Благодаря!

Edit: Вот код (К сожалению, это немного долго, и это мой первый раз с Tkinter):

from tkinter import * 
from tkinter import ttk 
from random import * 
from statistics import * 
from math import * 

''' 
Prompt user for: number attacking with, number of defenders at each space 
Output: n approaching 100000 and error range approaching .3%, probabilities of next roll, probabilities of winning at each spot, average number of pieces lost & stddev,buttons for decreasing defender/attacker 

''' 

def reset(): 
    attacker_entry.delete(0,END) 
    for i in range(len(spaces_entry)): 
     spaces_entry[i].delete(0,END) 
    update_buttons() 

def update_buttons(*args): 
    buttons = [attacker_2,attacker_1,split_button,defender_1,defender_2] 
    try: 
     if int(attacker_entry.get()) > 1: 
      for button in buttons: 
       button['state'] = ['normal'] 
     elif int(attacker_entry.get()) == 1: 
      attacker_2['state'] = ['disabled'] 
      split_button['state'] = ['disabled'] 
     elif int(attacker_entry.get()) == 0: 
      for button in buttons: 
       button['state'] = ['disabled'] 
      return 
     if int(space1_entry.get()) > 1: 
      defender_2['state'] = ['normal'] 
     elif int(space1_entry.get()) == 1: 
      defender_2['state'] = ['disabled'] 
      split_button['state'] = ['disabled'] 
    except: 
     for button in buttons: 
      button['state'] = ['disabled'] 

def subtract(label,*args): 
    if label == "both": 
     label = "att def 1" 
    end = int(label[-1:]) 
    if "att" in label: 
     attacker_amount.set(int(attacker_entry.get()) - end) 
    if "def" in label: 
     space1.set(int(space1_entry.get()) - end) 
    if int(space1_entry.get()) == 0: 
     attacker_amount.set(int(attacker_entry.get()) - 1) 
     for i in range(len(spaces)): 
      try: 
       spaces[i].set(int(spaces_entry[i+1].get())) 
      except: 
       spaces[i].set("") 
       win_avgs[i].set("") 
       pieces_left[i].set("") 
       most_likely[i].set("")     
     space10.set("") 
    update_buttons() 
    go() 

def check_if_multiple(list1,list2): 
    if len(list1)>1 and len(list2)>1: 
     ret_val = 2 
    else: 
     ret_val = 1 
    return ret_val 

def set_rolls(total,limit): 
    list = [] 
    for i in range(total): 
     if len(list) < limit: 
      list.append(randrange(1,7)) 
    return list 

def go(*args): 
    update_buttons() 
    try: 
     attacker_total = int(attacker_entry.get()) 
    except: 
     return 

    defender_pieces_list = [] 
    for entry in spaces_entry: 
     try: 
      new_val = int(entry.get()) 
      if new_val == 0: 
       None 
      else: 
       defender_pieces_list.append(new_val) 
     except: 
      None 

    defender_total_spaces = len(defender_pieces_list) 
    attacker_total_original = attacker_total 

    total_trials = 10000 
    defender_losses = 0 
    attacker_losses = 0 
    first_round_defender_total_wins = 0 
    first_round_attacker_total_wins = 0 
    first_round_split_total = 0 

    space1_succ,space2_succ,space3_succ,space4_succ,space5_succ,space6_succ,space7_succ,space8_succ,space9_succ,space10_succ = [],[],[],[],[],[],[],[],[],[] 
    space1_all,space2_all,space3_all,space4_all,space5_all,space6_all,space7_all,space8_all,space9_all,space10_all = [],[],[],[],[],[],[],[],[],[] 

    succ_list = [space1_succ,space2_succ,space3_succ,space4_succ,space5_succ,space6_succ,space7_succ,space8_succ,space9_succ,space10_succ] 
    all_list = [space1_all,space2_all,space3_all,space4_all,space5_all,space6_all,space7_all,space8_all,space9_all,space10_all] 

    for trial in range(total_trials): 
     if trial%20 == 0: 
      for i in range(0,defender_total_spaces): 
       try: 
        win_avgs[i].set(round(((len(succ_list[i]))/trial)*100,1)) 
        pieces_left[i].set(str(round(mean(all_list[i]),2))) 
        most_likely[i].set(mode(all_list[i])) 
        root.update() 
       except: 
        None 
     attacker_total = attacker_total_original 
     first_round = True 
     for i in range(defender_total_spaces): 
      defender_total = defender_pieces_list[i] 
      while defender_total>0 and attacker_total > 0: 
       defender_win = False 
       attacker_win = False 

       defender_rolls_list = set_rolls(defender_total,2) 
       attacker_rolls_list = set_rolls(attacker_total,3) 
       if len(attacker_rolls_list) == 1: 
        defender_rolls_list = [randrange(1,7)] 

       for j in range(check_if_multiple(defender_rolls_list,attacker_rolls_list)): 
        if max(defender_rolls_list)>=max(attacker_rolls_list): 
         attacker_total += -1 
         defender_win = True 
        else: 
         defender_total += -1 
         attacker_win = True 
        attacker_rolls_list.remove(max(attacker_rolls_list)) 
        defender_rolls_list.remove(max(defender_rolls_list))  

       if first_round == True: 
        if defender_win == True and attacker_win == True: 
         first_round_split_total += 1 
        elif attacker_win == True: 
         first_round_attacker_total_wins += 1 
        elif defender_win == True: 
         first_round_defender_total_wins += 1 

       first_round = False 

      if defender_total == 0: 
       succ_list[i].append(attacker_total) 
       all_list[i].append(attacker_total) 
       if attacker_total == 1: 
        attacker_total == -1 

      if attacker_total == 0: 
       all_list[i].append(attacker_total) 

      attacker_total += -1 
    for i in range(0,defender_total_spaces): 
     try: 
      win_avgs[i].set(round(((len(succ_list[i]))/trial)*100,1)) 
      pieces_left[i].set(str(round(mean(all_list[i]),2))+"("+str(round(stdev(all_list[i]),1))+")") 
      most_likely[i].set(mode(all_list[i])) 
     except: 
      None 

height = 450 
width = 600 
shape = str(width) + "x" + str(height) 

root = Tk() 
root.title("Risk Probability Calculator") 
root.geometry(shape) 

content = ttk.Frame(root) 
content.grid(column=0, row=0, sticky=(N, W, E, S)) 
content.columnconfigure(0, weight=1) 
content.rowconfigure(0, weight=1) 

title = ttk.Label(content, text="Risk Probability Calculator", relief="ridge", background="gray",font=("TkHeadingFont",20),anchor="center") 
title.grid(column=1, row=1, columnspan=8, padx=3, pady=4,sticky=(N,W,E,S)) 

reset_button = ttk.Button(content, text="Reset", command=reset) 
reset_button.grid(column=1, row=2,padx=3, pady=4, sticky=(N, W, E, S)) 
go_button = ttk.Button(content, text="Go", command=go) 
go_button.grid(column=2, row=2,padx=3, pady=4, sticky=(N, W, E, S)) 

ttk.Label(content, text="Attacking with:").grid(column=1, row=3,padx=3, pady=4, sticky=(NW)) 
ttk.Label(content, text="Defending with:").grid(column=1, row=4,padx=3, pady=4, sticky=(NW)) 
for i in range(5,15): 
    text = "Space " + str(i-4) + ":" 
    ttk.Label(content, text=text).grid(column=1,padx=3, pady=4, row=i, sticky=(N,E,S)) 

attacker_amount = StringVar() 
attacker_entry = ttk.Entry(content, textvariable=attacker_amount, width=4) 
attacker_entry.grid(column=2, row=3,padx=3, pady=4, sticky=(N, W, S)) 

spaces = [] 
spaces_entry = [] 
for i in range(1, 11): 
    globals()['space'+str(i)] = StringVar() 
    spaces.append(globals()['space'+str(i)]) 

    globals()['space'+str(i)+'_entry'] = ttk.Entry(content, textvariable=spaces[i-1], width=4) 
    globals()['space'+str(i)+'_entry'].grid(column=2, row=(i+4),padx=3, pady=4, sticky=(N, W, S)) 
    spaces_entry.append(globals()['space'+str(i)+'_entry']) 

attacker_2 = Button(content, text="Attacker -2",command=lambda: subtract("att 2")) 
attacker_2.grid(column=4, row=2,padx=3, pady=4, sticky=(N,W,E,S)) 
attacker_1 = Button(content, text="Attacker -1",command=lambda: subtract("att 1")) 
attacker_1.grid(column=5, row=2,padx=3, pady=4, sticky=(N,W,E,S)) 
split_button = Button(content, text="Split",command=lambda: subtract("both")) 
split_button.grid(column=6, row=2,padx=3, pady=4, sticky=(N,W,E,S)) 
defender_1 = Button(content, text="Defender -1",command=lambda: subtract("def 1")) 
defender_1.grid(column=7, row=2,padx=3, pady=4, sticky=(N,W,E,S)) 
defender_2 = Button(content, text="Defender -2",command=lambda: subtract("def 2")) 
defender_2.grid(column=8, row=2,padx=3, pady=4, sticky=(N,W,E,S)) 

ttk.Separator(content,orient="vertical").grid(column=3,row=2,rowspan=15,padx=3, pady=4,sticky=(N,W,E,S)) 

results_frame = ttk.Labelframe(content, text='Results:') 
results_frame.grid(column=4, row=3, columnspan=5, rowspan=12,padx=3, pady=4, sticky=(N,W,E,S)) 

pane = ttk.Panedwindow(results_frame, orient='horizontal') 
pane.grid(column=1,row=1,columnspan=5,padx=3,sticky=(N,W,E,S)) 

pane1 = ttk.Labelframe(pane) 
pane.add(pane1) 
Label(pane1,text="% Win").grid(column=1,row=1,sticky=(N,W,E)) 

win_avgs = [] 
for i in range(1,11): 
    globals()['win_avg'+str(i)] = StringVar() 
    win_avgs.append(globals()['win_avg'+str(i)]) 
    Label(pane1,textvariable=win_avgs[i-1]).grid(column=1,row=i+1,padx=4, pady=4,sticky=(N,W,S)) 

pane2 = ttk.Labelframe(pane) 
pane.add(pane2) 
Label(pane2,text="Pieces Left").grid(column=1,row=1,sticky=(N,W,E)) 

pieces_left = [] 
for i in range(1,11): 
    globals()['pieces_left'+str(i)] = StringVar() 
    pieces_left.append(globals()['pieces_left'+str(i)]) 
    Label(pane2,textvariable=pieces_left[i-1]).grid(column=1,row=i+1,padx=4, pady=4,sticky=(N,W,S)) 

pane3 = ttk.Labelframe(pane) 
pane.add(pane3) 
Label(pane3,text="Most likely # of Pieces Left").grid(column=1,row=1,sticky=(N,W,E)) 

most_likely = [] 
for i in range(1,11): 
    globals()['most_likely'+str(i)] = StringVar() 
    most_likely.append(globals()['most_likely'+str(i)]) 
    Label(pane3,textvariable=most_likely[i-1]).grid(column=1,row=i+1,padx=4, pady=4,sticky=(N,W,S)) 

root.mainloop() 
+2

не могли бы вы разместить соответствующий код? – chris

ответ

0

Короткий ответ, что это потому, что вы называете root.update(). Это не только перерисовывает экран, но обрабатывает любые ожидающие события события. Хорошее эмпирическое правило «никогда не вызывать update» именно по этой причине. Редко вы просто должны, но обычно есть лучший способ организовать свой код. Вы можете иногда уйти от него, если вы делаете это в функции, которая занимает всего несколько мс, но похоже, что ваша функция вычисляет много вещей. Если пользователь нажимает клавишу или нажимает кнопку, а затем вы вызываете update, tkinter попытается обработать это событие, прежде чем продолжить.

Я бы порекомендовал сначала просто удалить звонок и посмотреть, что произойдет. Если экран, кажется, замерзает (что может, учитывая, сколько кода вы пытаетесь запустить), вы можете попробовать заменить его root.update_idletasks(). Это не будет обрабатывать какие-либо события на клике или кнопке, а только определенный класс событий, например «перерисовка экрана».

Смежные вопросы