tkinter - Going Back and Forth Between Frames Using Buttons - python

I need functions, preferably one function, that can go back and forth between pages when the next and back buttons are pressed. I imagine this could be done by assigning boolean variables to the back and next buttons (not sure if this can be done) to figure out if you're going foward or back down an ordered list of all the pages. The index of the currently raised frame will need to be known. The indexes could be used to figure out the next page and then it would be raised. If the current index is 0 or the last index (in this case 2) and you press back or next respectively, then you would go to a homepage class frame, in this case BlankPage.
import tkinter as tk
from tkinter import ttk
class Program(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.iconbitmap(self, default = "")
tk.Tk.wm_title(self, "")
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 (Add, BlankPage):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky = "nsew")
self.show_frame(Add)
def show_frame(self,cont):
frame = self.frames[cont]
frame.tkraise()
class Add(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
innerFrame = tk.Frame(self)
innerFrame.place(relx=.5, rely=.5, anchor="c", relwidth=1.0, relheight=1.0)
innerFrame.grid_rowconfigure(1, weight=1)
innerFrame.grid_columnconfigure(0, weight=1)
name = tk.Label(innerFrame, text = "User")
name.grid(row=0, sticky="NE")
pagename = tk.Label(innerFrame, text = "Label")
pagename.grid(row=0, sticky="N")
next = ttk.Button(innerFrame, text = "Next", command = self.changePage)
next.grid(row=2, sticky="E")
back = ttk.Button(innerFrame, text = "Back", command = self.changePage)
back.grid(row=2, sticky="W")
###########################################################################################################
self.pageThree = tk.Frame(innerFrame)
self.pageThree.grid(row=1)
self.pageThree.grid_rowconfigure(0, weight=1)
self.pageThree.grid_columnconfigure(0, weight=1)
pagename = tk.Label(self.pageThree, text = "Page 3")
pagename.grid(row=0, sticky="N")
###########################################################################################################
self.pageTwo = tk.Frame(innerFrame)
self.pageTwo.grid(row=1)
self.pageTwo.grid_rowconfigure(0, weight=1)
self.pageTwo.grid_columnconfigure(0, weight=1)
pagename = tk.Label(self.pageTwo, text = "Page 2")
pagename.grid(row=0, sticky="N")
###########################################################################################################
self.pageOne = tk.Frame(innerFrame)
self.pageOne.grid(row=1)
self.pageOne.grid_rowconfigure(0, weight=1)
self.pageOne.grid_columnconfigure(0, weight=1)
pagename = tk.Label(self.pageOne, text = "Page 1")
pagename.grid(row=0, sticky="N")
###########################################################################################################
def changePage(self,buttonBool):
pages = [self.pageOne,self.pageTwo,self.pageThree]
#find current raised page and set to variable 'current'
position = pages.index(current)
if (postion==0 and buttonBool==False) or (postion==len(pages)-1 and buttonBool==True):
show_frame(BlankPage)
elif buttonBool==True:
pages[position+1].tkraise()
else:
pages[position-1].tkraise()
class BlankPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
app = Program()
app.state('zoomed')
app.mainloop()
The changePage function is my attempt at this, how would I complete it?

You are very close to having it all working, after some looking myself I couldn't find any (not overly-complicated) way to figure out the top most Frame so it would probably be best to just keep a record of the current position:
def __init__(self, parent, controller):
...
self.position = 0 #the index of the pages list
And to get buttonBool to be passed to changePage you can something from here (Tlapička gives the best solution in my eyes since lambda expressions make the lines of code way too long)
def __init__(self, parent, controller):
...
# button commands don't have an event but sometimes you use these callbacks for both .bind and buttons
# so having event=None makes it work for both.
def go_next(event=None):
self.changePage(True)
next = ttk.Button(innerFrame, text = "Next", command = go_next)
next.grid(row=2, sticky="E")
def go_back(event=None):
self.changePage(False)
back = ttk.Button(innerFrame, text = "Back", command = go_back)
back.grid(row=2, sticky="W")
...
With these two (and implementing self.position into changePage) you can accomplish what you originally asked, everything below this is the code reviewer in me talking.
Although using a boolean would work, this strategy of dealing with extra arguments to callbacks lets you pass any argument into changePage so it would probably simplify the conditionals in changePage if it got the change in pages (so 1 or -1):
def go_next(event=None):
self.changePage(1)
next = ttk.Button(innerFrame, text = "Next", command = go_next)
next.grid(row=2, sticky="E")
def go_back(event=None):
self.changePage(-1)
back = ttk.Button(innerFrame, text = "Back", command = go_back)
back.grid(row=2, sticky="W")
#this is for the last suggestion
self.nextButton = next
self.backButton = back
...
then changePage could look like this although I'm not sure what would happen to self.position if you changed to an invalid page:
def changePage(self,change):
pages = [self.pageOne,self.pageTwo,self.pageThree]
new_position = self.position + change
if (new_postion < 0) or (new_postion <= len(pages)):
show_frame(BlankPage)
#not sure how you would handle the new position here
else:
pages[new_position].tkraise()
self.position = new_position
Even better, if you keep a reference to the next and back buttons you can config them to indicate that it is the end/beginning:
def changePage(self,change):
pages = [self.pageOne,self.pageTwo,self.pageThree]
new_position = self.position + change
if (0 <= new_postion < len(pages)):
pages[new_position].tkraise()
self.position = new_position
else:
show_frame(BlankPage)
if new_position+1 >= len(pages):
self.nextButton.config(text="End") #, state=tk.DISABLED)
else:
self.nextButton.config(text="Next") #, state=tk.NORMAL)
if new_position-1 < 0:
self.backButton.config(text="First") #, state=tk.DISABLED)
else:
self.backButton.config(text="Back") #, state=tk.NORMAL)
that way you would know when you reached the end even if there isn't indication from the contents. (or you could disable the buttons to prevent going past)

Related

Python Tkinter, problem with creating unique ListBox on new pages

In tkinter I have step up multiple pages, each page should have a unique Listbox that will be populated with unique information.
My problem is the 'listbox' shows the information from my initial page on the other pages. Even if I completely remove the List box from the other pages, the 'Listbox` from my first page still shows up.
This is basically the first time I have used classes with anything, so I am not sure why this isn't working. This is all basically copied form YouTube how to's, and I am trying to bend it to what I need.
class Uploader(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs) #sets up tk window stuff
container = tk.Frame(self)
container.grid(row = 0, column = 0)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (Gr7, Gr8, Gr9): #put new pages on this
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column = 0, sticky = "nsew")
self.show_frame(Gr7)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class Gr7(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self, parent)
lb = tk.Listbox(width=30, height=15)
lb.insert('end', *homelist)
lb.grid(row = 1, column = 0)
class Gr8(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self, parent)
lb1 = tk.Listbox(width=30, height=15)
lb1.insert('end', *homelist1)
lb1.grid(row = 1, column = 0)
class Gr9(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self, parent)
lb2 = tk.Listbox(width=30, height=15)
lb2.insert('end', *homelist2)
lb2.grid(row = 1, column = 0)
You are not specifying which widget should contain the listbox, so all of your listboxes are given the root window as its master. Because you are putting them all in the same row and column, you only see one listbox.
To fix this -- and as a good general rule of thumb -- you should always explicitly provide the master when creating widgets:
lb = tk.Listbox(self, width=30, height=15)

How to create and display multiple widgets using a loop (Tkinter)

I am creating a program with two frames in one window. The first has input fields, the second will create a graph.
I found a way to create input fields dynamically from a list and get their values accordingly, but I can't get them to show on the window. When I run the program it shows an empty window.
What should I do to get the label and input widgets to show on the first frame (InputPage)? I tried changing 'parent' to 'self' but it made no difference. I don't really understand the structure of widgets in multiple frame applications.
Here is my code:
from tkinter import *
namesInput = ["first", "second", "third", "fourth", "fifth"]
entryInput = {}
labelInput = {}
root = Tk()
class ZorgplanGrafiek(Tk):
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
container = 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 (InputPage, GraphPage):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(InputPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class InputPage(Frame):
def __init__(self, parent, controller):
Frame.__init__(self,parent)
label = Label(self, text="Zorgplan input")
label.pack(pady=10,padx=10)
i = 0
for name in namesInput:
e = Entry(self)
entryInput[name] = e
lb = Label(self, text=name)
labelInput[name] = lb
i += 1
#def print_all_entries():
# for name in namesInput:
# print( entryInput[name].get())
class GraphPage(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
label = Label(self, text="The graph will show here")
label.pack(pady=10,padx=10)
button = Button(self, text="Back to Home",
command=lambda: controller.show_frame(InputPage))
button.pack()
app = ZorgplanGrafiek()
app.mainloop()
Firstly delete root = Tk() at the top of your code you are creating 2 windows. Secondly, your loop to create the entry and label widgets is not correct therefore they are not displayed on the frame, so that is your answer for why they wont show.
Try this:
class InputPage(Frame):
def __init__(self, parent, controller):
Frame.__init__(self,parent)
label = Label(self, text="Zorgplan input")
label.grid(row=0, column=0, sticky ='n', columnspan =2)
# i brought your variable in the class for example sake
namesInput = ["First:", "second:", "Third:", "Fourth:", "Fifth:"]
self.entryWidgets = [] # we want to call this in another function so we assign it as self.variableName
labelWidgets = []
#LOOP TO CREATE WIDGETS
for i in range(0, len(namesInput)):
labelWidgets.append(Label(self, text = namesInput[i]))
self.entryWidgets.append(Entry(self))
labelWidgets[-1].grid(row= i+1, column =0, sticky='e')
self.entryWidgets[-1].grid(row= i+1, column = 1, sticky='w')
submit = Button(self, text = "Submit", command = self.getEntries)
submit.grid(row = 6, column =0, columnspan =2)
def getEntries(self):
results = []
for x in self.entryWidgets: # i.e for each widget in entryWidget list
results.append(x.get())
print(results)
Code explanation:
We are iteratively creating widgets to the number of elements within namesInput list. Each time we create a widget we add it to their respective list. E.g for entry widgets we created a list called entryWidgets. We append them to a list so that we can reference them individually later on when we want to do something with them.
Furthermore, i changed pack() to grid(). The grid method is much cleaner and gives us more control over the layout of our window in my opinion.
Note - If you're struggling to understand how i 'grided' the widgets in the way i did, i just drew up a quick sketch of the widgets with co-ordinates representing their row and column and then from there its fairly easy to see how to manipulate the grid settings in the for loop.
Screenshot:

Double-lambda Python

Is it feasible to execute multiple statements in a lambda? The app_data dictionary in my controller has a property "listbox" that stores a selected listbox value. A button on SelectPage has a lambda command that changes frames to NextPage.
Can the frame switch and app_data set statements both occur in a double-lambda? If so, what might this look like? Or do these operations have to occur separately (i.e. in a button click event)?
Update #1:
Issue isolated to lambda expression since just putting a constant (i.e. 1) in like .set(1) does not save either.
Update #2:
Using a lambda with doStuff(controller) solves the problem somewhat, but the listbox reference throws an error:
value = self.listbox.get(self.listbox.curselection())
AttributeError: 'SelectPage' object has no attribute 'listbox'
button:
button1 = ttk.Button(self, text='Next Page',
command=lambda:self.doStuff(controller))
doStuff():
def doStuff(self,controller):
controller.show_frame(NextPage)
controller.app_data["listbox"].set(1)
value = self.listbox.get(self.listbox.curselection())
print(value)
print("do Stuff successful")
Full Code:
from tkinter import *
from tkinter import ttk
class MyApp(Tk):
# Controller class
def __init__(self):
Tk.__init__(self)
# App data in controller
self.app_data = {"listbox": StringVar(),
"entry": StringVar(),
}
container = ttk.Frame(self)
container.pack(side="top", fill="both", expand = True)
self.frames = {}
for F in (SelectPage, NextPage):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky = NSEW)
self.show_frame(SelectPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
def get_page(self,classname):
for page in self.frames.values():
if str(page.__class__.__name__) == classname:
return page
return None
class SelectPage(ttk.Frame):
def __init__(self, parent, controller):
self.controller = controller
ttk.Frame.__init__(self, parent)
ttk.Label(self, text='Select Page').grid(padx=(20,20), pady=(20,20))
listbox = Listbox(self,exportselection=0)
listbox.grid()
for item in [0,1,2,3,4,5]:
listbox.insert(END, item)
print (item)
entry1 = ttk.Entry(self, textvariable=self.controller.app_data["entry"], width=8)
entry1.grid()
button1 = ttk.Button(self, text='Next Page',
command=lambda:self.doStuff(controller)) # something like this lambda concept
button1.grid()
def doStuff(self,controller):
controller.show_frame(NextPage)
controller.app_data["listbox"].set(1)
value = self.listbox.get(self.listbox.curselection())
print(value)
print("do Stuff successful")
class NextPage(ttk.Frame):
def __init__(self, parent, controller):
self.controller = controller
ttk.Frame.__init__(self, parent)
ttk.Label(self, text='Next Page').grid(padx=(20,20), pady=(20,20))
button1 = ttk.Button(self, text='Select Page',
command=lambda: controller.show_frame(SelectPage))
button1.grid()
button2 = ttk.Button(self, text='press to print', command=self.print_it)
button2.grid()
def print_it(self):
value = self.controller.app_data["listbox"].get()
print ('The value stored in StartPage some_entry = ' + str(value))
value = self.controller.app_data["entry"].get()
print ('The value stored in StartPage some_entry = ' + str(value))
app = MyApp()
app.title('Multi-Page Test App')
app.mainloop()
Your original lambda didn't work because show_frame(...) returns None, which short-circuits the and so the remaining expression doesn't execute. Just change it to an or. Since the event caller doesn't care what you return, you could also create a two item tuple for the two subexpressions. There are other problems, such as self.listbox doesn't exist, which I fixed, but others remain.
As a pedantic aside, lambda only accepts an expression, which is a subset of a statement.
self.listbox = listbox
button1 = ttk.Button(self, text='Next Page',
command=lambda: controller.show_frame(NextPage) or self.controller
.app_data["listbox"]
.set(self.listbox.get(self.listbox.curselection()))) # something like this lam
Is it feasible to execute multiple statements in a lambda?
No. In general, you should avoid using lambda at all, and when you must use it you need to keep it as brief as possible. If you need to call more than a single function, create a new function that calls the other functions.
Also, if you're passing in an argument that is just an attribute of the object, you don't need lambda at all. I think the following code is much easier to read, much easier to understand, much easier to write, and thus much easier to maintain:
button1 = ttk.Button(self, text='Next Page',command=self.doStuff)
...
def doStuff(self):
self.controller.show_frame(NextPage)
self.controller.app_data["listbox"].set(1)

tkinter - How to get frames and widgets to fill window?

The two frames in my program, ViewSubjects and AddSubjects both contain frames and widgets that are not stretching to fill the screen. Why are they doing this and how would I go about fixing it?
ViewSubjects Frame
AddSubjects Frame
Here is my code:
import tkinter as tk
from tkinter import ttk
import tkinter.scrolledtext as tks
class Program(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.iconbitmap(self, default = "")
tk.Tk.wm_title(self, "")
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 (SubjectHome, ViewSubject, AddSubject):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky = "nsew")
self.show_frame(SubjectHome)
def show_frame(self,cont):
frame = self.frames[cont]
frame.tkraise()
class SubjectHome(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
ttk.Style().configure("TButton", padding=6, relief="flat", background="#ccc")
name = tk.Label(self, text = "User: FirstName + LastName")
name.pack(anchor="ne")
pagename = tk.Label(self, text = "Subject Menu")
pagename.pack(anchor="n")
self.innerFrame = tk.Frame(self, bg="red")
self.innerFrame.place(relx=.5, rely=.5, anchor="c")
view = ttk.Button(self.innerFrame, text = "View Subjects", command = lambda: controller.show_frame(ViewSubject))
view.grid(row=0, sticky="W"+"E")
add = ttk.Button(self.innerFrame, text = "Add Subjects", command = lambda: controller.show_frame(AddSubject))
add.grid(row=1, sticky="W"+"E")
class ViewSubject(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
innerFrame = tk.Frame(self)
innerFrame.place(relx=.5, rely=.5, anchor="c")
firstFrame = tk.Frame(innerFrame)
firstFrame.grid(row=0, sticky="WE")
secondFrame = tk.Frame(innerFrame)
secondFrame.grid(row=1, sticky="WE")
self.text = tks.ScrolledText(firstFrame)
self.text.grid(rowspan=3, columnspan=3 ,sticky="E")
scrollbar = tk.Scrollbar(secondFrame, orient="vertical")
lb = tk.Listbox(secondFrame, yscrollcommand=scrollbar.set)
scrollbar.config(command=lb.yview)
scrollbar.pack(side="right", fill="y")
lb.pack(side="left",fill="both", expand=True)
for x in range(15):
lb.insert("end", x)
back = ttk.Button(innerFrame, text = "Back", command = lambda: controller.show_frame(SubjectHome))
back.grid(row=2, sticky="W")
next = ttk.Button(innerFrame, text = "Next")
next.grid(row=2, sticky="E")
class AddSubject(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
name = tk.Label(self, text = "User: FirstName + LastName")
name.pack(anchor="ne")
pagename = tk.Label(self, text = "Add Subjects")
pagename.pack(anchor="n")
self.innerFrame = tk.Frame(self)
self.innerFrame.place(relx=.5, rely=.5, anchor="c")
canvas = tk.Canvas(self.innerFrame)
self.firstFrame = tk.Frame(canvas)
self.firstFrame.pack(anchor="n")
info = tk.Label(self.innerFrame, text = "Information...\n Information....")
info.pack()
for x in range(5):
pagename = tk.Label(self.firstFrame, text = "Unit Name")
pagename.grid(row=0, column=x)
self.text = tks.ScrolledText(self.firstFrame, width=50)
self.text.grid(row=1, column=x ,sticky="E")
scrollbar = tk.Scrollbar(self.innerFrame, orient="horizontal", command=canvas.xview)
canvas.configure(xscrollcommand=scrollbar.set)
scrollbar.pack(side="bottom", fill="x")
canvas.pack(side="left", fill="both", expand=True)
back = ttk.Button(self.innerFrame, text = "Back", command = lambda: controller.show_frame(SubjectHome))
back.pack(anchor="sw")
next = ttk.Button(self.innerFrame, text = "Next")
next.pack(anchor="se")
app = Program()
app.state('zoomed')
app.mainloop()
Most of your problems boil down to three common mistakes:
First, you are using place, and place by default doesn't make windows grow or shrink. It assumes you created widgets to be the exact size you want them to be. You need to explicitly tell tkinter how you want it to handle extra space.
In your case you probably want to set the relative width and relative height of the inner frames to 1.0 (ie: 100% of the width and height of the containing window) with the relwidth and relheight options. This will force the inner frame to always be exactly as tall and wide as its parent.
self.innerFrame.place(..., relwidth=1.0, relheight=1.0)
Second, you are using grid within the inner frames, but you are failing to give any rows or columns a weight. The weight tells tkinter how to allocate extra space. By default, extra space goes unused. Since you want your widgets to fill the extra space, you need to give at least one row and one column a positive weight.
Third, you're trying to solve too many problems at once. My advice is to remove all of the widgets except one frame. Get it to fill, grow and shrink the way you want. Then, add its immediate children and do likewise. Then, add any grandchildren, and continue on, one group of widgets at a time, until you're satisfied with that frame. Only then should you move on and fix another frame.
protip: give each frame a unique color during development. This makes it easy to see which frames are growing or shrinking, and which ones are not.

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

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

Categories