How to start the execution of a function (and/or) class only when a button is clicked in Tkinter

165 views Asked by At

I am new to Python and am writing a code to automate certain measurement equipment. I am going to mention only a small part of my code to keep it concise.

The first class VSWR is used to select different frames. Since I need to change frames and go back and forth in them, I made a class VSWR. This class calls Start Page , which has a button "Path Loss". After clicking this button, the user needs to enter certain parameters, and in this case "Start and Stop Frequencies". Clicking the OK button will show what the user has entered and then asks the user to confirm it. After confirming a text window opens in a new frame(which is the RunModuleTests class). I will write all my remaining automation code in this class. But for now I want the power supply to turn on(for now I am using insert command message to show that my power supply is turned on) after 4 secs after I hit the confirm button. But what is happening is the RunModuleTests class executes as soon as I run the whole code and by the time I reach to my text window after entering the parameters, power supply will already be turned on.

What I think is happening is that as soon as I hit run on my whole code, the mainloop starts the execution of all the frames. (Please correct me if I am wrong here), whereas I want my frames(or classes and their functions) to execute only when those classes are called by clicking the button and not when I hit Run for the whole code. Is there any work around to this ?? Please let me know if someone needs me to elaborate my question or need more details of the issue I am facing here. Thanks

import Tkinter as tk
from Tkinter import DoubleVar, IntVar, StringVar
import ttk
from numpy import arange

LARGE_FONT= ("Verdana", 12)

class VSWR(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        tk.Tk.wm_title(self, "VSWR")
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)
        self.frames = {}
        for F in (StartPage, PathLoss, RunModuleTests):   
            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row = 0, column = 0, sticky = "nsew")
        self.show_frame(StartPage)

    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()

class StartPage(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="This is the start page", font=LARGE_FONT)
        label.pack(pady=10,padx=10)
        button3 = ttk.Button(self, text="Path Loss",
                            command=lambda: controller.show_frame(PathLoss))
        button3.pack()

class PathLoss(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        labelPathLoss = ttk.Label(self, text = 'Path Loss Measurement:', font=LARGE_FONT)
        labelPathLoss.pack(pady=10,padx=10)

        global X, Y
        X = 20
        Y = 100

        #Define Variables with Type
        self.startFreq = DoubleVar()
        self.stopFreq = DoubleVar()
        self.freqInc = IntVar()


        labelenterStartFreq = ttk.Label(self, text = 'Enter the Start Frequency (in MHz):')
        labelenterStartFreq.place(x = X, y = Y+20)
        labelenterStopFreq = ttk.Label(self, text = 'Enter the Stop Frequency (in MHz):')
        labelenterStopFreq.place(x = X, y = Y+40)
        entryStartFreq = ttk.Entry(self, textvariable = self.startFreq)
        entryStartFreq.place(x = X+240, y = Y+20)
        entryStopFreq = ttk.Entry(self, textvariable = self.stopFreq)
        entryStopFreq.place(x = X+240, y = Y+40)


        buttonOK = ttk.Button(self, text = 'OK', command = lambda: self.getValues(X,Y, controller))
        buttonOK.place(x = X+240, y = Y+270)

    def getValues(self,X,Y, controller):
        getStartFreq = self.startFreq.get()
        getStopFreq = self.stopFreq.get()


        ttk.Label(self, text = 'You entered the following values:').place(x = X+580, y = Y)
        ttk.Label(self, text = 'Start Frequency : %5.2f' %getStartFreq).place(x = X+580, y = Y+20)
        ttk.Label(self, text = 'Stop Frequency : %5.2f' %getStopFreq).place(x = X+580, y = Y+40)

        buttonConfirmPL = ttk.Button(self, text = 'Confirm', command = lambda: controller.show_frame(RunModuleTests))
        buttonConfirmPL.place(x = X+580, y = Y+300)

class RunModuleTests(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)        
        self.rootText = tk.Text(self) 
        self.rootText.place(x = 200, y = 100)
        self.rootText.tkraise()

        opening = '\nProceeding to measure TRX path loss for FWD/REV....\n'
        self.rootText.insert("insert", opening )

        self.rootText.after(4000, self.temp)

    def temp(self):
        self.rootText.insert("insert", '\nTurning Power supply ON...\n')

app = VSWR()
app.geometry('1000x600+150+100')
app.mainloop()
1

There are 1 answers

0
Bryan Oakley On

The reason the power supply turn-on message appears immediately is this: At the very start of your program you create an instance of StartPage, PathLoss and RunModuleTests. In the __init__ method of RunModuleTests you're calling self.rootText.after(4000, self.temp), and self.temp writes that message. Thus, four seconds after your program starts, that message appears.

There are many solutions, but to do it properly involves a lot of rewriting. The structure of your code makes a simple solution difficult. The most common things you can try is to either a) not create an instance of RunModuleTests until you actually need it, or b) move the call to after into some other function, and then call that function only after you make that frame visible.

Personally I would do the latter -- you need to decouple the creation of the frame from the functions that can be done when the frame is visible. That means you'll need to add some extra logic to show_frame, or replace the call to show_frame with something else.