Search code examples
pythontkintertkinter-button

a software built to calculate Mento Carlo reliability


I set four RadioButtons for users to choose the type of distribution, then use a global variable s_val to record the type of distribution. However, no matter which button users choose, s_val always equals to 0. I wonder what causes this problem.

Here is my code:

`import tkinter as tk
import tkinter.messagebox as messagebox
from numpy import*

#设计交互页面
#s_val强度分布种类
#r_val应力分布种类
para1_1 = 0
para1_2 = 0
para2_1 = 0
para2_2 = 0



class basedesk:
    def __init__(self, master):
        self.root = master
        self.root.config()
        self.root.title('可靠性计算')
        self.root.geometry('400x300')
        initface1(self.root)


class initface1:
    def get_val1(self):
        global s_val
        s_val = self.s_value.get()
    def __init__(self, master):
        self.master = master
        #基准界面initface1
        self.initface1 = tk.Frame(self.master, )
        self.initface1.pack()
        reminder = tk.Label(self.initface1, text='please choose the distribution type of strength', width=50, height=10)
        reminder.pack()
        #获取应力分布的按键设计
        self.s_value = tk.IntVar()
        self.radio()
        tk.Button(self.initface1, text='确定', command=self.change).pack()

    def radio(self):
        radio_bt1=tk.Radiobutton(self.initface1, text='normal distribution', variable=self.s_value, value=1,
                       command=self.get_val1())
        radio_bt2=tk.Radiobutton(self.initface1, text='lg normal distribution', variable=self.s_value, value=2,
                       command=self.get_val1())
        radio_bt3=tk.Radiobutton(self.initface1, text='exponential distribution', variable=self.s_value, value=3,
                       command=self.get_val1())
        radio_bt4=tk.Radiobutton(self.initface1, text='weibull distribution', variable=self.s_value, value=4,
                       command=self.get_val1())
        radio_bt1.pack()
        radio_bt2.pack()
        radio_bt3.pack()
        radio_bt4.pack()

    def change(self, ):
        self.initface1.destroy()
        face1(self.master)




class face1:
    def __init__(self, master):
        self.master = master
        self.face1 = tk.Frame(self.master, )
        self.face1.pack()
        global s_val
        print(s_val)
        if s_val==1|s_val==2:
            tk.Label(self.face1, text='please fill two parameters of this distribution', width=50, height=10).pack()
            tk.Label(self.face1, text='mean').pack()
            self.parameter1 = tk.Entry(self.face1, relief='groove', width=20)
            self.parameter1.pack()
            tk.Label(self.face1, text='standard deviation').pack()
            self.parameter2 = tk.Entry(self.face1, relief='groove', width=20)
            self.parameter2.pack()
        else:
            tk.Label(self.face1, text='please fill the parameter of this distribution', width=50, height=10).pack()
            self.parameter1 = tk.Entry(self.face1, relief='groove', width=20)
            self.parameter1.pack()

        tk.Label(self.face1, text='caution: only numbers are allowed').pack()
        tk.Button(self.face1, text='yes', command=self.com).pack()

    def com(self):
        global para1_1
        global para1_2
        global s_val
        if s_val == 1 | s_val == 2:
            if self.parameter1.get().isdigit()&self.parameter2.get().isdigit():
                para1_1 = float(self.parameter1.get())
                para1_2 = float(self.parameter2.get())
                self.change()
            else:
                messagebox.showwarning('warning', 'not numbers')
        else:
            if self.parameter1.get().isdigit():
                para1_1 = self.parameter1.get()
                para1_2 = 0
                self.change()
            else:
                messagebox.showwarning('warning', 'not numbers')

    def change(self,):
        self.face1.destroy()
        initface2(self.master)


class initface2:
    def __init__(self, master):
        self.master = master
        #第二个确认分布界面
        self.initface2 = tk.Frame(self.master, )
        self.initface2.pack()
        reminder = tk.Label(self.initface2, text='please choose the distribution type of r', width=50, height=10)
        reminder.pack()
        #获取应力分布的按键设计
        self.r_value = tk.IntVar()
        radio_bt1 = tk.Radiobutton(self.initface2, text='normal distribution', variable=self.r_value, value=1,
                                   command=self.get_val2())
        radio_bt2 = tk.Radiobutton(self.initface2, text='lg normal distribution', variable=self.r_value, value=2,
                                   command=self.get_val2())
        radio_bt3 = tk.Radiobutton(self.initface2, text='exponential distribution', variable=self.r_value, value=3,
                                   command=self.get_val2())
        radio_bt4 = tk.Radiobutton(self.initface2, text='weibull distribution', variable=self.r_value, value=4,
                                   command=self.get_val2())
        radio_bt1.pack()
        radio_bt2.pack()
        radio_bt3.pack()
        radio_bt4.pack()
        btn = tk.Button(self.initface2, text='yes', command=self.change)
        btn.pack()

    def change(self, ):
        self.initface2.destroy()
        face2(self.master)

    def get_val2(self):
        global r_val
        r_val = int(self.r_value.get())


class face2:
    def __init__(self, master):
        self.master = master
        self.face2 = tk.Frame(self.master, )
        self.face2.pack()
        global r_val
        if r_val == 1 | r_val == 2:
            tk.Label(self.face2, text='please fill two parameters of this distribution', width=50, height=10).pack()
            tk.Label(self.face2, text='mean').pack()
            self.parameter3 = tk.Entry(self.face2, relief='groove', width=20)
            self.parameter3.pack()
            tk.Label(self.face2, text='standard deviation').pack()
            self.parameter4 = tk.Entry(self.face2, relief='groove', width=20)
            self.parameter4.pack()
        else:
            tk.Label(self.face2, text='please fill the parameter of this distribution', width=50, height=10).pack()
            self.parameter3 = tk.Entry(self.face2, relief='groove', width=20)
            self.parameter3.pack()
        tk.Label(self.face2, text='caution: only numbers are allowed').pack()
        tk.Button(self.face2, text='yes', command=self.com).pack()

    def com(self):
        global para2_2
        global para2_1
        global r_val
        if r_val == 1 | r_val == 2:
            if self.parameter3.get().isdigit() & self.parameter4.get().isdigit():
                para2_1 = float(self.parameter3.get())
                para2_2 = float(self.parameter4.get())
            else:
                messagebox.showwarning('warning', 'not numbers')

        else:
            if self.parameter3.get().isdigit():
                para2_1 = float(self.parameter3.get())
                para2_2 = 0
            else:
                messagebox.showwarning('warning', 'not numbers')
        self.cal_res(s_val, r_val, para1_1, para1_2, para2_1, para2_2)

    def cal_res(self,type1, type2, p1, p2, p3, p4):
        if type1==1:
            x1 = random.normal(p1, p2, size=(1000, 1))
        elif type1==2:
            x1 = random.lognormal(p1, p2, size=(1000, 1)), 2
        elif type1==3:
            x1 = random.weibull(p1, size=(1000, 1)), 2
        else:
            x1 = random.exponential(float(p1), size=(1000, 1)), 2
        if type2==1:
            x2 = random.normal(p3, p4, size=(1000, 1)), 2
        elif type1==2:
            x2 = random.lognormal(p3, p4, size=(1000, 1)), 2
        elif type1==3:
            x2 = random.weibull(p3, size=(1000, 1)), 2
        else:
            x2 = random.exponential(p3, size=(1000, 1)), 2
        times = 0
        n1 = 0
        while times<1000:
            if x1[times] > x2[times]:
                n1 = n1+1
            times = times+1
        result = n1/1000
        messagebox.showinfo('result', 'the result is'+str(result))


if __name__ == '__main__':
    root = tk.Tk()
    basedesk(root)
    root.mainloop()

I tried to change the type of s_val, from global variabale to class varibale. Yet it did't work.


Solution

  • It's somewhat hard to follow your original code, so here's a reformulation that does (or at least should do) the same thing with a (somewhat) nicer UI:

    enter image description here

    The main idea in the refactoring here is to move things into reusable functions, and store state in Tk variables up until the last moment.

    This could be made nicer still by e.g. wrapping each distribution into a class, but this is a start...

    import tkinter as tk
    import tkinter.messagebox as messagebox
    import numpy as np
    
    distribution_types = {
        "normal": "normal distribution",
        "lgnormal": "lg normal distribution",
        "expo": "exponential distribution",
        "weibull": "Weibull distribution",
    }
    
    
    def make_dist_groupbox(master, variable, command=None):
        groupbox = tk.LabelFrame(master, text="Distribution type")
        for dist, text in distribution_types.items():
            tk.Radiobutton(groupbox, text=text, variable=variable, value=dist, command=command).pack(anchor=tk.W)
        return groupbox
    
    
    def make_var_groupbox(root, dist_var, par1_var, par2_var):
        var_groupbox = tk.LabelFrame(root, text="Strength")
    
        def update_var_boxes():
            dist = dist_var.get()
            if dist in ("normal", "lgnormal"):
                p1_label["text"] = "mean"
                p2_label["text"] = "std"
                p2_entry["state"] = "normal"
            else:
                p1_label["text"] = "scale"
                p2_label["text"] = ""
                p2_entry["state"] = "disabled"
    
        make_dist_groupbox(var_groupbox, dist_var, command=update_var_boxes).pack()
        p1_label = tk.Label(var_groupbox, text="parameter 1")
        p1_entry = tk.Entry(var_groupbox, textvariable=par1_var)
        p2_label = tk.Label(var_groupbox, text="parameter 2")
        p2_entry = tk.Entry(var_groupbox, textvariable=par2_var)
        p1_label.pack()
        p1_entry.pack()
        p2_label.pack()
        p2_entry.pack()
        update_var_boxes()
    
        return var_groupbox
    
    
    def generate_dist(type, p1, p2, n=1000):
        size = (n,)
        if type == "normal":
            return np.random.normal(p1, p2, size=size)
        if type == "lgnormal":
            return (np.random.lognormal(p1, p2, size=size),)
        elif type == "weibull":
            return np.random.weibull(p1, size=size)
        elif type == "expo":
            return np.random.exponential(float(p1), size=size)
    
    
    def generate(s_dist_var, s_par1_var, s_par2_var, r_dist_var, r_par1_var, r_par2_var):
        n = 1000
        try:
            s_dist = s_dist_var.get()
            s_par1 = s_par1_var.get()
            s_par2 = s_par2_var.get()
            r_dist = r_dist_var.get()
            r_par1 = r_par1_var.get()
            r_par2 = r_par2_var.get()
        except Exception as e:
            messagebox.showerror("error", f"Invalid input: {e}")
            return
        x1 = generate_dist(s_dist, s_par1, s_par2, n=n)
        x2 = generate_dist(r_dist, r_par1, r_par2, n=n)
        times = np.sum(x1 > x2)
        messagebox.showinfo(
            "result",
            f"Parameters:\n{s_dist}({s_par1}, {s_par2}), {r_dist}({r_par1}, {r_par2})\n\n" f"Result: {times / n}",
        )
    
    
    def main():
        root = tk.Tk()
        s_dist_var = tk.StringVar(value="normal")
        s_par1_var = tk.DoubleVar()
        s_par2_var = tk.DoubleVar()
        r_dist_var = tk.StringVar(value="normal")
        r_par1_var = tk.DoubleVar()
        r_par2_var = tk.DoubleVar()
    
        make_var_groupbox(root, s_dist_var, s_par1_var, s_par2_var).pack(side=tk.LEFT, anchor=tk.N)
        make_var_groupbox(root, r_dist_var, r_par1_var, r_par2_var).pack(side=tk.RIGHT, anchor=tk.N)
    
        action_button = tk.Button(
            root,
            text="Generate",
            command=lambda: generate(s_dist_var, s_par1_var, s_par2_var, r_dist_var, r_par1_var, r_par2_var),
        )
        action_button.pack(side=tk.BOTTOM, anchor=tk.S, fill=tk.X)
    
        root.mainloop()
    
    
    if __name__ == "__main__":
        main()