Python tkinter增长调用堆栈?

时间:2014-12-12 03:00:10

标签: python tkinter

所以我正在制作一个程序,它调用一个函数来进行一些计算,并且有按钮可以按下来改变输入并重新计算。

效果很好,除非在计算完成之前按下按钮,否则会计算并输出新值,然后再返回到先前的值。基本上,程序执行我想要的操作,除了按下按钮并完成第二次计算后返回第一次计算(所有变量值都返回)。

问题的一般示意图: 1.根主循环 2.输入的值 3.按' Go' 4.打印到屏幕上的计算(顺便说一下Monty Carlo sim) 5.按按钮更改输入值 6.打印到屏幕上的新计算 7.一旦新的变量完成,旧变量值的计算将返回完成

有没有办法阻止python返回到之前的变量值?我希望有一种方法可以返回主循环,以便屏幕上的计算保持正确。谢谢!

编辑: 这是代码(抱歉它有点长,这是我第一次使用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()

1 个答案:

答案 0 :(得分:0)

简短的回答是,这是因为你致电root.update()。这不仅会重绘屏幕,还会处理任何待处理的事件。一个好的经验法则是“从不打电话给update”这个确切的原因。您很少必须,但通常有更好的方法来组织您的代码。如果你在一个只需要几毫秒的函数中执行它,你有时可以使用它,但看起来你的函数计算了很多东西。如果用户按下某个键或单击按钮然后调用update,则tkinter将尝试在继续之前处理该事件。

我建议先删除电话,看看会发生什么。如果屏幕似乎冻结(考虑到您尝试运行多少代码,可能会冻结),您可以尝试将其替换为root.update_idletasks()。这不会处理任何点击或按钮事件,只会处理某类事件,例如“重新绘制屏幕”。