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')
Related
I wanted to position in the username and password such that it is next to each other. In order to achieve that I used the grid method but I keep getting an error that says:
_tkinter.TclError: cannot use geometry manager grid inside .!frame.!adminlogin.!frame which already has slaves managed by pack.
Is there a way I can let it use even grid?
import tkinter as tk
from tkinter import font as tkfont
import PIL.Image
from PIL import ImageTk
from tkinter import *
import tkinter.font as font
import sqlite3, hashlib
from datetime import date
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")
# the container is where we'll stack a bunch of frames
# on top of each other, then the one we want visible
# will be raised above the others
self.geometry ("1024x768")
container = tk.Frame(self)
container.pack(fill="both", side= 'top',expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (StartPage, StudentLogin, AdminLogin):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
# put all of the pages in the same location;
# the one on the top of the stacking order
# will be the one that is visible.
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
frame = tk.Frame(self, width = 1024, height = 768, bg="teal")
frame.pack(fill="both", expand=True, side="top")
label = tk.Label(frame, text="WELCOME", font=controller.title_font)
label.pack(side="top", fill="x", pady=50)
button1 = tk.Button(frame, text="Admin Login",
command=lambda: controller.show_frame("AdminLogin"), width = 50, height=10, font=30, bg='powder blue')
button2 = tk.Button(frame, text="Student Login",
command=lambda: controller.show_frame("StudentLogin"), width=50, height=10, font=30, bg='powder blue')
button1.pack(pady=10)
button2.pack(pady=10)
class AdminLogin(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
frame = tk.Frame(self, width = 1024, height = 768, bg='teal')
frame.pack(fill="both", side ="top", expand=True)
label = tk.Label(frame, text="Enter username and password to login", font=controller.title_font)
label.pack(side="top", fill="x", pady=30, padx =10)
userLabel = tk.Label(frame, text = "Enter Username: ", font=50)
userLabel.pack(padx=10, pady=10)
userEntry = tk.Entry(frame)
userEntry.pack(padx=10, pady=10)
passwordL = tk.Label(frame, text = "Enter Password: ", font=50)
passwordL.pack(padx=10, pady=10)
passEntry = tk.Entry(frame, show="*")
passEntry.pack(padx=10, pady=10)
button = tk.Button(frame, text="Back",
command=lambda: controller.show_frame("StartPage"), bg='powder blue')
button.pack()
class StudentLogin(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
frame = tk.Frame(self, width = 1024, height = 768, bg='teal')
frame.pack(fill="both", side ="top", expand=True)
label = tk.Label(frame, text="Enter username and password to login", font=controller.title_font)
label.pack(side="top", fill="x", pady=30, padx =10)
button = tk.Button(frame, text="Back",
command=lambda: controller.show_frame("StartPage"), bg='powder blue')
button.pack()
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
Unfortunately you cannot mix both the pack and grid methods. You have to only pick one, which you will use throughout that master. Pack is easier to use, but with grid you have more control over where your widgets are going to be displayed in the window. (I would have done this as a comment to your post, not an answer, but i do not have enough reputation to do so) I hope this helps :)
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()
I was trying to program a kind of calculator in Python using the Tkinter library. My problem is that I watch some pages that says that the way to set de heidth and weidth of a button is using rowconfigure and columnconfigure. The problem is that when I run the script it doesn't work. I don't know what I'm doing bad so pls help me
Here is the code
import tkinter as tk
def insert_number(variable, entry):
result = variable + entry
return result
conjunt = ""
class MainWindow(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.parent = parent
self.grid()
self.config(bg="blue")
self.button1 = tk.Button(text="1", command=insert_number(conjunt, "1")).grid(
column=0, row=0)
self.button1 = tk.Button(text="2", command=insert_number(conjunt, "2")).grid(
column=1, row=0)
self.button1 = tk.Button(text="3", command=insert_number(conjunt, "3")).grid(
column=2, row=0)
self.button1 = tk.Button(text="4", command=insert_number(conjunt, "1")).grid(
column=0, row=1)
self.button1 = tk.Button(text="5", command=insert_number(conjunt, "1")).grid(
column=1, row=1)
self.button1 = tk.Button(text="6", command=insert_number(conjunt, "1")).grid(
column=2, row=1)
self.button1 = tk.Button(text="7", command=insert_number(conjunt, "1")).grid(
column=0, row=2)
self.button1 = tk.Button(text="8", command=insert_number(conjunt, "1")).grid(
column=1, row=2)
self.button1 = tk.Button(text="9", command=insert_number(conjunt, "1")).grid(
column=2, row=2)
self.button1 = tk.Button(text="0", command=insert_number(conjunt, "1")).grid(
column=1, row=3)
self.columnconfigure(0, weight=1)
self.columnconfigure(1, weight=1)
self.rowconfigure(0, weight=1)
self.rowconfigure(1, weight=1)
def give_result(self):
pass
def main():
root = tk.Tk()
root.title("Calculadora")
buttons_frame = MainWindow(root)
buttons_frame.grid()
root.mainloop()
if __name__ == "__main__":
main()
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()
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()