Tkinter / Python: Frames aren't lifting - python

Hi I was wondering why my DisplayPage wasn't lifting when the ok button was pressed in MainPage. I've cut off most of my code (to keep it more to the point of the error, so its a bit segmented but basically I'm creating 2 frames (MainPage and DisplayPage) and want to basically let the user input data into MainPage and then press the next button to show/output the input data in DisplayPage.
Here's a section of the code that's creating the unexpected result.
from Tkinter import *
import Tkinter as tk
import os
class page(tk.Frame):
def __init__(self, *args, **kwargs):
tk.Frame.__init__(self, *args, **kwargs)
def show(self):
self.lift()
class DisplayPage(page):
def __init__(self, *args, **kwargs):
page.__init__(self, *args, **kwargs)
# deleted - however will upload if needed more information about my code
class MainPage(tk.Frame):
def __init__(self, *args, **kwargs):
tk.Frame.__init__(self, *args, **kwargs)
p1 = DisplayPage(self)
# create all of the main containers
frame_A = Frame(self, width=930, height=780)
frame_B = Frame(self, width=465, height=280)
frame_C = Frame(self, width=465, height=280)
frame_D = Frame(self, width=465, height=140)
frame_E = Frame(self, width=465, height=70)
# layout all of the main containers
frame_A.grid(row=0, column=0, columnspan=2, rowspan=3)
frame_B.grid(row=0, column=3)
frame_C.grid(row=1, column=3)
frame_D.grid(row=2, column=3)
frame_E.grid(row=3, column=3)
# next ok button
content4= Frame(frame_E)
ok = tk.Button(content4, text="Locate", font =('Roboto Thin', 30), command= p1.lift)
ok.pack()
# layout all widgets
content1.grid(column=0, row=0)
content2.grid(column=3, row=1)
content3.grid(column=3, row=2)
content4.grid(column=3, row=3)
namelbl.grid(column=3, row=1)
name.grid(column=3, row=6)
namelbl2.grid(column=3, row=5)
name2.grid(column=3, row=8)
namelbl3.grid(column=3, row=7)
name3.grid(column=3, row=10)
one.grid(column=3, row=2)
two.grid(column=3, row=3)
three.grid(column=3, row=4)
ok.grid(column=3, row=11)
namelbl4.grid(column=3, row=9)
p1.show()
if __name__ == "__main__":
root = tk.Tk()
main = MainPage(root)
main.pack(side="top", fill="both", expand=True)
root.wm_title('MobilePark Simulator')
root.wm_geometry("1300x830")
root.mainloop()

You must create a toplevel window. I have modified your code, but only put the most necessary into it. You can place widgets in a toplevel window, too (see the label).
import Tkinter as tk
import os
class MainPage(tk.Frame):
def __init__(self, *args, **kwargs):
tk.Frame.__init__(self, *args, **kwargs)
self.p1flag=0 # EDIT1
self.p1=tk.Toplevel(self)
self.p1.title("Hello")
self.p1label=tk.Label(self.p1,text="FYI "*20)
self.p1label.pack()
# create all of the main containers
frame_A = tk.Frame(self, width=930, height=780)
frame_B = tk.Frame(self, width=465, height=280)
frame_C = tk.Frame(self, width=465, height=280)
frame_D = tk.Frame(self, width=465, height=140)
frame_E = tk.Frame(self, width=465, height=70)
frame_A.grid(row=0, column=0, columnspan=2, rowspan=3)
frame_B.grid(row=0, column=3)
frame_C.grid(row=1, column=3)
frame_D.grid(row=2, column=3)
frame_E.grid(row=3, column=3)
content4= tk.Frame(frame_E)
self.ok = tk.Button(content4, text="Locate", font =('Roboto Thin', 30), command= self.show_p1) # EDIT2
self.ok.pack()
# layout all widgets
content4.grid(column=3, row=3)
def show_p1(self): # EDIT3
if not self.p1flag%2:
self.p1.lift()
else:
self.p1.lower()
self.p1flag+=1
if __name__ == "__main__":
root = tk.Tk()
main = MainPage(root)
main.pack(side="top", fill="both", expand=True)
root.wm_title('MobilePark Simulator')
root.wm_geometry("1200x900")
root.mainloop()

Related

Tkinter: "NameError: name 'event' is not defined error" when passing argument in button command

I'm trying to pass the event argument in my button command function to create a toplevel, but I'm getting this error:
NameError: name 'event' is not defined
This is my code
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
frame = tk.Frame(root)
frame.pack(fill='x')
self.button = tk.Button(frame, text='M', font='Verdana 13 bold', command= lambda: self.toplevel(event))
self.button.pack(side='right', anchor='e', padx=10, pady=10)
def toplevel(self, event):
self.toplevel = tk.Toplevel()
self.toplevel.overrideredirect(True)
self.toplevel.geometry(f"100x130+{event.x}+{event.y}")
button = tk.Button(self.toplevel, text="Quit")
button.pack(padx=5, pady=5, anchor='w')
if __name__ == "__main__":
root = tk.Tk()
root.title('Title')
MainApplication(root).pack(side="top", fill="both", expand=True)
root.mainloop()
What am I doing wrong?
Button press is not considered an event. An event is binding a function to a mouse, or keyboard action. In this example I get the cursor position upon left click, relative to the top left corner of the screen. The event is bound to the root widget.
import tkinter as tk
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
frame = tk.Frame(root)
frame.pack(fill='x')
self.button = tk.Button(frame, text='M', font='Verdana 13 bold', command= lambda: self.toplevel(x, y))
self.button.pack(side='right', anchor='e', padx=10, pady=10)
def toplevel(self, x, y):
self.toplevel = tk.Toplevel()
self.toplevel.overrideredirect(True)
self.toplevel.geometry(f"100x130+{x}+{y}")
button = tk.Button(self.toplevel, text="Quit")
button.pack(padx=5, pady=5, anchor='w')
def get_event(event):
global x, y
x = event.x_root
y = event.y_root
if __name__ == "__main__":
root = tk.Tk()
root.title('Title')
MainApplication(root).pack(side="top", fill="both", expand=True)
root.bind('<Button-1>', get_event)
root.mainloop()

Using Tkinter filedialog within a frame and accessing the output globally

I am building my first GUI using tkinter and have come up against some problems. To make the code more modular, I am using an object-oriented approach, as seen in the code below. The basic idea is that I have defined classes for the DataFrame, MetaFrame and SaveFrame, which are all instantiated within the OptionsFrame, which then is instantiated within the MainWindow.
import tkinter as tk
from tkinter import ttk
class DataFrame(ttk.Frame):
def __init__(self, main, *args, **kwargs):
super().__init__(main, *args, **kwargs)
# data frame elements
self.data_label = ttk.Label(self, text="Add Data:")
self.labelled_tweets_label = ttk.Label(self, text="Labelled-Tweets: ")
self.labelled_tweets_button = ttk.Button(self, text="Browse")
self.places_label = ttk.Label(self, text="Places: ")
self.places_button = ttk.Button(self, text="Browse")
self.plots_label = ttk.Label(self, text="Plots Path: ")
self.plots_button = ttk.Button(self, text="Browse")
self.submit_button = ttk.Button(self, text="Submit")
# data frame layout
self.data_label.grid(row=0, column=0, columnspan=2, pady=10)
self.labelled_tweets_label.grid(row=1, column=0)
self.labelled_tweets_button.grid(row=1, column=1)
self.places_label.grid(row=2, column=0)
self.places_button.grid(row=2, column=1)
self.plots_label.grid(row=3, column=0)
self.plots_button.grid(row=3, column=1)
self.submit_button.grid(row=4, column=0, columnspan=2, pady=10)
class MetaFrame(ttk.Frame):
...
class SaveFrame(ttk.Frame):
...
class OptionsFrame(ttk.Frame):
def __init__(self, main, *args, **kwargs):
super().__init__(main, *args, **kwargs)
# options frame components
self.data_frame = DataFrame(self)
self.horiz1 = ttk.Separator(self, orient="horizontal")
self.meta_frame = MetaFrame(self)
self.horiz2 = ttk.Separator(self, orient="horizontal")
self.save_frame = SaveFrame(self)
# options frame layout
self.data_frame.grid(row=0, column=0)
self.horiz1.grid(row=1, column=0, sticky="ew", pady=30)
self.meta_frame.grid(row=2, column=0)
self.horiz2.grid(row=3, column=0, sticky="ew", pady=30)
self.save_frame.grid(row=4, column=0, sticky="s")
class MainWindow(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.geometry("800x600")
self.resizable(False, False)
# configuration
self.columnconfigure(index=0, weight=1)
self.columnconfigure(index=1, weight=2)
# main frames
self.options_frame = OptionsFrame(self, width=400, height=600, borderwidth=1)
self.vert = ttk.Separator(self, orient="vertical")
# main layout
self.options_frame.grid(row=0, column=0)
self.vert.grid(row=0, column=1, sticky="ns")
def main():
root = MainWindow()
root.mainloop()
The layout can be seen in the following image.
This is the basic layout I want within the OptionsFrame. My confusion lies with creating filedialog methods for the three file browsing buttons within the DataFrame. I understand how to use the filedialog class to return the path to a given file, but then this value is restricted to be in the scope of the DataFrame.
I have a back-end that is already developed which requires these file paths, so ideally I would like to access them from the main() function. How is this possible?
Thanks

Changing a Variablestring in a Class in Python

I have a small piece of code, which was working fine, until I decided to create a class and put things into that class. Now my problem is, I cannot change stringvariable anymore.
Here is my code:
import tkinter as tk
import tkinter.ttk as ttk
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.parent = parent
frame1 = ttk.LabelFrame(root, text="PANEL A", borderwidth=5)
frame1.grid(row=0, column=0, padx=5, pady=5)
frame2 = ttk.LabelFrame(frame1, text="PANEL B", width = 500, height = 1000)
frame2.grid(row=0, column=0, padx=5, pady=5, sticky='NSWE')
strVarMeasurement = tk.StringVar()
frame3 = ttk.LabelFrame(frame2, text="PANEL C")
frame3.grid(row=0, column=0, padx=5, pady=5)
lbl_01 = ttk.Label(frame3, width=20, anchor = tk.E, text="Measurement: ").grid(row=0, column=0)
e_01 = ttk.Entry (frame3, width=8, textvariable=strVarMeasurement).grid(row=0, column=1)
def setString():
strVarMeasurement.set(1234)
if __name__ == "__main__":
root = tk.Tk()
MainApplication(root)
MainApplication.setString()
root.mainloop()
This is the error I get:
NameError: name 'strVarMeasurement' is not defined
How can I change that string of the class?
Isn't that variable created during MainApplication(root)?
Do you think it is better to define such a string inside or outside the class?
Add self and and Object, this may fix this error.
import tkinter as tk
import tkinter.ttk as ttk
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.parent = parent
frame1 = ttk.LabelFrame(root, text="PANEL A", borderwidth=5)
frame1.grid(row=0, column=0, padx=5, pady=5)
frame2 = ttk.LabelFrame(frame1, text="PANEL B", width = 500, height = 1000)
frame2.grid(row=0, column=0, padx=5, pady=5, sticky='NSWE')
self.strVarMeasurement = tk.StringVar()
frame3 = ttk.LabelFrame(frame2, text="PANEL C")
frame3.grid(row=0, column=0, padx=5, pady=5)
lbl_01 = ttk.Label(frame3, width=20, anchor = tk.E, text="Measurement: ").grid(row=0, column=0)
e_01 = ttk.Entry (frame3, width=8, textvariable= self.strVarMeasurement).grid(row=0, column=1)
def setString(self):
self.strVarMeasurement.set(1234)
if __name__ == "__main__":
root = tk.Tk()
app = MainApplication(root)
app.setString()
root.mainloop()

How to insert a separator Frame between two other Frames

I'm trying to separate two frames with a third one, which should look like a vertical line. Using pack manager it always shows up on the very left or right, no matter how I shuffle the order of packing and/or side as 'left' or 'right'. When I use grid it doesn't show at all. Below is my code:
EDIT:
I added Import/Export Section definition, so the code is complete working example.
class ImportSection(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.lbl_import = tk.Label(self, text='IMPORT', width=20)
self.lbl_import.grid()
class ExportSection(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.lbl_export = tk.Label(self, text='EXPORT', width=20)
self.lbl_export.grid()
class Main(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.import_section = ImportSection(self)
self.export_section = ExportSection(self)
self.sep = tk.Frame(width=2, bd=1, relief='sunken')
# I tried to shuffle the order and experimented with left/right with no luck.
# the line is always on the very right or left
# self.import_section.pack(side='left', padx=5, pady=5, anchor='n')
# self.export_section.pack(side='left', padx=5, pady=5, anchor='n')
# self.sep.pack(side='left', fill='y', padx=5, pady=5)
# another attempt with grid, but the line does not show at all
self.import_section.grid(row=0, column=0, padx=5, pady=5, sticky='n')
self.sep.grid( row=0, column=1, padx=5, pady=5, sticky='ns')
self.export_section.grid(row=0, column=2, padx=5, pady=5, sticky='n')
if __name__ == '__main__':
root = tk.Tk()
app = Main(root)
# app.pack(side='top', fill='both', expand=True) - I used this version with pack
app.grid()
root.mainloop()
You can maybe use ttk.Separator:
import tkinter as tk
from tkinter import ttk
class Main(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.import_section = tk.Frame(self)
tk.Canvas(self.import_section, width=200, height=400, bg='cyan').grid(column=0, row=0)
self.export_section = tk.Frame(self)
tk.Canvas(self.export_section, width=200, height=400, bg='lightgreen').grid(column=0, row=0)
self.sep = ttk.Separator(self, orient=tk.VERTICAL)
self.import_section.grid(row=0, column=0, padx=5, pady=5, sticky='n')
self.sep.grid( row=0, column=1, padx=5, pady=5, sticky='ns')
self.export_section.grid(row=0, column=2, padx=5, pady=5, sticky='n')
if __name__ == '__main__':
root = tk.Tk()
app = Main(root)
app.grid()
root.mainloop()
The problem is that the frame you are trying to use as separator is not in the same frame as the ImportSection and ExportSection because you don't specify its parent. When you don't specify a parent, tkinter will make the widget a child of the root window. This is also the reason why you can't pack app into the root window: self.sep is already put into root with grid.
Change
self.sep = tk.Frame(width=2, bd=1, relief='sunken')
to
self.sep = tk.Frame(self, width=2, bd=1, relief='sunken')

Tkinter custom frame not working

I'm trying to create a custom frame in tkinter, Python v2.7. I have done this just fine once (a frame with a scrollbar), but my second attempt isn't working. I compare it to the Frame that does work, and I can't understand what I have done differently.
What I want is a frame that has a little separator line underneath it, so I'm creating a "normal" frame, a thin frame to use as a separator under it, and a bigFrame to hold it.
Everything I create in the class works, except the frame itself. Hopefully my comments explain what is and isn't showing.
from Tkinter import *
class FunFrame(Frame):
def __init__(self, master, lbl, **kwargs):
self.bigFrame = Frame(master)
Frame.__init__(self, self.bigFrame, width=280, height=200, bg="red", **kwargs)
self.grid(row=0, column=0, pady=3) #this is in bigFrame, and doesn't display
#however the padding is still respected
self.separator = Frame(self.bigFrame, height=2, bd=1, width=280, relief = SUNKEN)
self.separator.grid(row=1, column=0) #this is in bigFrame, and displays
self.l = Label(self, text=lbl) #this is in self and doesn't display
self.l.grid(row=0, column=0)
def grid(self, **kwargs):
self.bigFrame.grid(**kwargs)
if __name__ == "__main__":
root=Tk()
Frame1=FunFrame(root, "hello")
Frame2=FunFrame(root, "world")
Frame1.grid(row=0, column=0)
Frame2.grid(row=1, column=0)
root.mainloop()
If you call self.grid in __init__, it calls your own grid, not Tkinter's version.
Try following (renamed grid to grid_):
from Tkinter import *
class FunFrame(Frame):
def __init__(self, master, lbl, **kwargs):
self.bigFrame = Frame(master)
Frame.__init__(self, self.bigFrame, width=280, height=200, bg="red", **kwargs)
self.grid(row=0, column=0, pady=3)
self.separator = Frame(self.bigFrame, height=2, bd=1, width=280, relief=SUNKEN)
self.separator.grid(row=1, column=0)
self.l = Label(self, text=lbl)
self.l.grid(row=0, column=0)
def grid_(self, **kwargs): ######## grid -> grid_
self.bigFrame.grid(**kwargs)
if __name__ == "__main__":
root=Tk()
Frame1 = FunFrame(root, "hello")
Frame2 = FunFrame(root, "world")
Frame1.grid_(row=0, column=0) ######## grid -> grid_
Frame2.grid_(row=1, column=0) ######## grid -> grid_
root.mainloop()
I'd rather code as follow (if '....' was used to represent hierarchy visually):
from Tkinter import *
class FunFrame(Frame):
def __init__(self, master, lbl, **kwargs):
Frame.__init__(self, master)
if 'inside outer frame (self)':
innerFrame = Frame(self, width=280, height=200, bg="red", **kwargs)
innerFrame.grid(row=0, column=0, pady=3)
if 'inside inner frame':
self.l = Label(innerFrame, text=lbl)
self.l.grid(row=0, column=0)
separator = Frame(self, height=2, bd=1, width=280, relief=SUNKEN)
separator.grid(row=1, column=0)
if __name__ == "__main__":
root = Tk()
Frame1 = FunFrame(root, "hello")
Frame2 = FunFrame(root, "world")
Frame1.grid(row=0, column=0)
Frame2.grid(row=1, column=0)
root.mainloop()

Categories