Tkinter progess bar using Frame - python

I have a progress bar in Tkinter but i can figure out how to set the maximum (= number of files loaded) before to load the file with def open
from Tkinter import *
import tkFileDialog
import ttk
class MainWindow(Frame):
def __init__(self):
Frame.__init__(self)
self.master.title("FOO progress bar")
self.grid(sticky=W+N+S+E)
top = self.winfo_toplevel()
top.rowconfigure(0, weight=1)
top.columnconfigure(0, weight=1)
top_frame = Frame(self)
frame_1 = Frame(self)
top_frame.grid(row=0, sticky=W+N+S+E)
frame_1.grid(row=1, sticky=W+N+S+E)
top_frame.grid(row=0, sticky=W+N+S+E)
self.open = Button(top_frame, text="Input file(s)",
command=self.open,
activeforeground="red", width=20)
self.open.grid(row=1, column=0, pady=2, padx=2, sticky=W)
self.progressbar = ttk.Progressbar(top_frame, orient=HORIZONTAL, length=228, mode='determinate')
self.progressbar.grid(row=1, column=1, pady=2, padx=2, sticky=W)
self.process = Button(frame_1, text="process",
command=self.process,
activeforeground="red", width=20)
self.process.grid(row=2, column=0, sticky=W+N+S+E)
def open(self):
self.filename_open = tkFileDialog.askopenfilenames(defaultextension='*.*')
return self.filename_open
def process(self):
for index, image_name in enumerate(self.filename_open.split()):
self.progressbar.step(index)
self.update()
if __name__ == "__main__":
d = MainWindow()
d.mainloop()

There is a maximum setting that you can change via configure. I also fixed two or three mistakes.
import time
#in __init__
self.progressvar = IntVar()
self.progressbar = ttk.Progressbar(top_frame, orient=HORIZONTAL, length=228, mode='determinate', variable = self.progressvar)
def open(self):
self.filename_open = tkFileDialog.askopenfilenames(defaultextension='*.*')
self.progressvar.set(0)
def process(self):
self.progressbar.configure(maximum = len(self.filename_open) + 0.001) #0.001 needed to avoid progressbar empty at the end
for index, image_name in enumerate(self.filename_open):
self.progressbar.step(1)
self.update_idletasks()
time.sleep(0.5) # replace with the real process function

Related

tkinter scrollbar (frame/canvas) in application that create SubFrames

I have researched and tested a number of solutions on stackoverflow and other sites but I cannot get a scrollbar to work with my application.
I'm looking for a scrollbar capable of scrolling the SubFrame group that my application creates. I also need to delimit a minimum window height, and that this window can be extended, but without breaking the scrollbar.
Thank you in advance to all who will help me.
I admit not having understood which should go above the other, the Canvas or the Frame.
Here is a piece of code, with all the graphical widgets to visualize the scrollbar effect :
import tkinter as tk
from tkinter import ttk
class FrameStack(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
self.subframes = []
self.topFrame = tk.Frame(root)
self.topFrame.pack(side="top", fill="x")
self.groupOfFrames = tk.Frame(root)
self.groupOfFrames.pack(side="top", fill="both", expand=True, pady=(32,0))
self.scrollbar = tk.Scrollbar(self.groupOfFrames, orient="vertical")
self.scrollbar.pack(side="right",fill="y")
#self.canvas = tk.Canvas(self.groupOfFrames, yscrollcommand=self.scrollbar.set)
#self.canvas.pack()
#self.canvas_window = self.canvas.create_window(0, 0, anchor="nw", window=self.groupOfFrames)
self.create_widget()
def create_widget(self):
tk.Label(self.topFrame, text="BUS").grid(row=0, column=0)
tk.Label(self.topFrame, text="IP").grid(row=1, column=0)
tk.Label(self.topFrame, text="REG").grid(row=2, column=0)
tk.Label(self.topFrame, text="SIZE").grid(row=3, column=0)
self.combobox_bus = ttk.Combobox(self.topFrame, values=list(dic.keys()), width=40, justify='center', state="readonly")
self.combobox_bus.bind('<<ComboboxSelected>>', self.getUpdateDataIP)
self.combobox_bus.grid(row=0, column=1, sticky="nsew")
self.combobox_ip = ttk.Combobox(self.topFrame, justify='center', width=40, state="readonly")
self.combobox_ip.bind('<<ComboboxSelected>>', self.getUpdateDataReg)
self.combobox_ip.grid(row=1, column=1, sticky="nsew")
self.button_read = tk.Button(self.topFrame, text="Read", command=self.read)
self.button_write = tk.Button(self.topFrame, text="Write", command=self.write)
self.button_read.grid(row=0, column=2, columnspan=2, sticky="nsew")
self.button_write.grid(row=1, column=2, columnspan=2, sticky="nsew")
self.button_hsid = tk.Button(self.topFrame, text="HSID")
self.button_hsid.grid(row=0, column=4, columnspan=2, sticky="nsew")
self.button_add = tk.Button(self.topFrame, text="+", command=self.add_frame)
self.button_add.grid(row=1, column=4, columnspan=2, sticky="nsew")
self.combobox_reg_dl = ttk.Combobox(self.topFrame, width=40, justify='center', state="readonly")
self.combobox_reg_dl.bind('<<ComboboxSelected>>', self.getUpdateDisplayReg)
self.combobox_reg_dl.grid(row=2, column=1, sticky="nsew")
self.button_dump = tk.Button(self.topFrame, text="Dump", command=self.dump)
self.button_load = tk.Button(self.topFrame, text="Load", command=self.load)
self.button_dump.grid(row=2, column=2, columnspan=2, sticky="nsew")
self.button_load.grid(row=2, column=4, columnspan=2, sticky="nsew")
self.select_size = tk.StringVar()
self.select_size.set("0")
self.entry_size = tk.Entry(self.topFrame, textvariable=self.select_size, justify='center')
self.entry_size.grid(row=3, column=1, sticky="nsew")
tk.Scale(self.topFrame, from_=0, to=1024, variable=self.select_size)
self.select_read_size = tk.IntVar()
self.select_read_size.set(8)
self.radio_8 = tk.Radiobutton(self.topFrame, text=" 8", variable=self.select_read_size, value=8)
self.radio_16 = tk.Radiobutton(self.topFrame, text="16", variable=self.select_read_size, value=16)
self.radio_32 = tk.Radiobutton(self.topFrame, text="32", variable=self.select_read_size, value=32)
self.radio_64 = tk.Radiobutton(self.topFrame, text="64", variable=self.select_read_size, value=64)
self.radio_8.grid(row=3, column=2)
self.radio_16.grid(row=3, column=3)
self.radio_32.grid(row=3, column=4)
self.radio_64.grid(row=3, column=5)
def getUpdateDataIP(self, event):
self.combobox_ip['values'] = list(dic[self.combobox_bus.get()].keys())
self.combobox_ip.set('')
self.combobox_reg_dl['values'] = ['']
self.combobox_reg_dl.set('')
for f in self.subframes:
f.combobox_reg_rw['values'] = ['']
f.combobox_reg_rw.set('')
def getUpdateDataReg(self, event):
self.combobox_reg_dl['values'] = list(dic[self.combobox_bus.get()][self.combobox_ip.get()].keys())
self.combobox_reg_dl.set('')
for f in self.subframes:
f.combobox_reg_rw['values'] = list(dic[self.combobox_bus.get()][self.combobox_ip.get()].keys())
f.combobox_reg_rw.set('')
def getUpdateDisplayReg(self, event):
self.combobox_reg_dl.set(self.combobox_reg_dl.get()+" ("+dic[self.combobox_bus.get()][self.combobox_ip.get()][self.combobox_reg_dl.get()]+")")
def delete_frame(self, frame):
self.subframes.remove(frame)
frame.destroy()
def add_frame(self):
f = SubFrame(parent=self.groupOfFrames, controller=self)
if self.combobox_bus.get()!="" and self.combobox_ip.get()!="":
f.combobox_reg_rw['values'] = list(dic[self.combobox_bus.get()][self.combobox_ip.get()].keys())
self.subframes.append(f)
f.pack(side="top", fill="x", pady=(0,5))
def read(self):
pass
def write(self):
pass
def dump(self):
pass
def load(self):
pass
class SubFrame(tk.Frame):
def __init__(self, parent, controller):
super().__init__(parent)
self.parent = parent
self.controller = controller
self.create_widget()
def create_widget(self):
self.combobox_reg_rw = ttk.Combobox(self, width=47, justify='center', state="readonly")
self.combobox_reg_rw.bind('<<ComboboxSelected>>', self.getUpdateDisplayReg)
self.select_val = tk.StringVar()
self.entry_value = tk.Entry(self, bd=1.5, width=20, textvariable=self.select_val, justify='center')
self.button_write = tk.Button(self, text="Write", command=self.write)
self.button_read = tk.Button(self, text="Read", command=self.read)
self.button_help = tk.Button(self, text="?", command=self.help)
self.button_remove = tk.Button(self, text="-", command=self.remove)
self.combobox_reg_rw.grid(row=0, column=0, columnspan=2, sticky="ew")
self.entry_value.grid(row=0, column=2, columnspan=2, sticky="ew")
self.button_write.grid(row=1, column=0, sticky="ew")
self.button_read.grid(row=1, column=1, sticky="ew")
self.button_help.grid(row=1, column=2, sticky="nsew")
self.button_remove.grid(row=1, column=3, sticky="nsew")
def remove(self):
self.controller.delete_frame(self)
def getUpdateDisplayReg(self, event):
self.combobox_reg_rw.set(self.combobox_reg_rw.get()+" ("+dic[self.controller.combobox_bus.get()][self.controller.combobox_ip.get()][self.combobox_reg_rw.get()]+")")
def write(self):
print(self.entry_value.get())
def read(self):
print(self.combobox_reg_rw.get())
def help(self):
pass
if __name__ == "__main__":
#dic = extractor.main()
dic = {'1': {'1.1': {'1.1.1': 'A', '1.1.2': 'B'}, '1.2': {'1.2.1': 'C', '1.2.2': 'D'}}, '2': {'2.1': {'2.1.1': 'E', '2.2.2': 'F'}, '2.2': {'2.2.1': 'G', '2.2.2': 'H'}}}
root = tk.Tk()
root.title("XXXXXX")
root.resizable(False, True)
fs = FrameStack(root)
fs.pack(fill="both", expand=True)
root.mainloop()
It is the canvas that has the ability to scroll, so your self.groupOfFrames needs to go inside the canvas. And since you want the scrollbar and canvas to appear as a single complex object, they should go in a frame.
You need to make sure that when the window is resized, the frame inside the canvas is resized as well. And you also need to make sure that when you add something to self.groupOfFrames you also update the scrollregion. These can be done by binding to the <Configure> event of each widget.
Thus, I would create the FrameStack like the following. Please note that self.topFrame and self.bottomFrame are children of self rather than root. That is a mistake I didn't catch in the code I gave you in your previous question.
class FrameStack(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
self.subframes = []
self.topFrame = tk.Frame(self)
self.bottomFrame = tk.Frame(self)
self.topFrame.pack(side="top", fill="x")
self.bottomFrame.pack(side="bottom", fill="both", expand=True)
self.canvas = tk.Canvas(self.bottomFrame, bd=0)
vsb = tk.Scrollbar(self.bottomFrame, command=self.canvas.yview)
self.canvas.configure(yscrollcommand=vsb.set)
vsb.pack(side="right", fill="y")
self.canvas.pack(side="left", fill="both", expand=True)
self.groupOfFrames = tk.Frame(self.canvas)
self.canvas.create_window(0, 0, anchor="nw", window=self.groupOfFrames, tags=("inner",))
self.canvas.bind("<Configure>", self._resize_inner_frame)
self.groupOfFrames.bind("<Configure>", self._reset_scrollregion)
def _reset_scrollregion(self, event):
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
def _resize_inner_frame(self, event):
self.canvas.itemconfig("inner", width=event.width)

setting a changeable Variable into a menubar entry

I am currently working on my Graphical User Interface for my program and I want to create an Entry widget in a menubar (in my case in the menubaroptions method) that shows an IntVar which is set to a certain number (in my case: 9) but is changeable by the user. In my Code i tried it with self.entrystring.get() but got the "self is not defined" error.
This is part of my code:
import tkinter
from tkinter.constants import *
from tkinter import messagebox
from struct import unpack
from codecs import decode
class Graphicaluserinterface(tkinter.Frame):
#classmethod
def main(cls):
root = tkinter.Tk()
root.title('Program')
root.minsize(560, 105)
gui = cls(root)
gui.grid(row=0, column=0, sticky=NSEW)
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root['menu'] = gui.menubar
root.mainloop()
def __init__(self, master=None):
super().__init__(master)
self.inputliste = []
self.check1 = tkinter.IntVar()
self.check2 = tkinter.IntVar()
self.check3 = tkinter.IntVar()
self.check5 = tkinter.IntVar()
self.inputfilenamelist = []
self.fileopenname = tkinter.StringVar()
self.fileopenname1 = tkinter.StringVar()
self.filesavename =tkinter.StringVar()
self.entrystring = tkinter.IntVar()
self.taktzykluszeit = tkinter.DoubleVar()
self.taktunterschiedboolean = tkinter.BooleanVar()
self.fileopeningcounter = tkinter.IntVar()
self.fileopeningcounter.set(0)
self.menubar = tkinter.Menu(self)
self.file_menu = tkinter.Menu(self.menubar, tearoff=FALSE)
self.help_menu = tkinter.Menu(self.menubar, tearoff=FALSE)
self.program_start = tkinter.Button(self, text='Start Program')
self.check_button1 = tkinter.Checkbutton(
self, text="Drehzahl und Drehmoment", variable=self.check1,
onvalue=1, offvalue=0
)
self.check_button2 = tkinter.Checkbutton(
self, text="Analogvoltsensoren", variable=self.check2,
onvalue=1, offvalue=0
)
self.check_button3 = tkinter.Checkbutton(
self, text="Analogamperesensoren", variable=self.check3,
onvalue=1, offvalue=0
)
self.check_button4 = tkinter.Checkbutton(
self, text="Thermoelemente", variable=self.check4,
onvalue=1, offvalue=0
)
self.check_button5 = tkinter.Checkbutton(
self, text="Pt-100-Elemente", variable=self.check5,
onvalue=1, offvalue=0)
self.input_path_display = tkinter.Label(
self, textvariable=self.fileopenname1, bg='white', width=60
)
self.output_path_display = tkinter.Label(
self, textvariable=self.filesavename, bg="white", width=60
)
self.input_path_display_label = tkinter.Label(self, text="Inputfile")
self.output_path_display_label = tkinter.Label(self, text="Outputfile")
self.create_widgets()
self.entrystring.set(9)
self.taktzykluszeit.set(0.0)
self.taktunterschiedboolean.set(False)
def create_widgets(self):
self.menubar.add_cascade(label="File", menu=self.file_menu)
self.file_menu.add_command(label="Open", command=lambda:[self.inputfilenamelist.clear(),self.fileopening()])
self.file_menu.add_command(label="Save As")
self.file_menu.add_command(label="Options",command=self.menubaroptions)
self.file_menu.add_command(label="Exit", command=self.master.destroy)
self.menubar.add_cascade(label="Extras", menu=self.help_menu)
self.help_menu.add_command(label="Help")
self.help_menu.add_command(label="Credits")
pad = dict(padx=5, pady=5)
self.check_button1.grid(row=0, column=0, **pad)
self.check_button2.grid(row=1, column=0, **pad)
self.check_button3.grid(row=2, column=0, **pad)
self.check_button4.grid(row=3, column=0, **pad)
self.check_button5.grid(row=4, column=0, **pad)
self.input_path_display_label.grid(row=0, column=1, sticky=EW, **pad)
self.input_path_display.grid(row=1, column=1, sticky=NSEW, **pad)
self.output_path_display_label.grid(row=2, column=1, sticky=EW, **pad)
self.output_path_display.grid(row=3, column=1, sticky=NSEW, **pad)
self.program_start.grid(row=4, column=1, sticky=EW, **pad)
#self.program_start["command"]=lambda:[self.fileselectwarning(),self.writealldatafile(),self.writeselecteddata(),
# self.inputliste.clear(),self.fileopeningcounter.set(0),
# self.inputfilenamelist.clear()]
self.grid_rowconfigure(1, weight=1)
self.grid_columnconfigure(1, weight=1)
def menubaroptions(root):
optionswindow = tkinter.Toplevel(root)
optionswindow.title("Options")
optionswindow.minsize(300,150)
trennzeichenlabel = tkinter.Label(optionswindow,text="Length of Separator in Byte:").pack()
trennzeichenentry = tkinter.Entry(optionswindow,textvariable=self.entrystring.get(),width=30,justify="center").pack()
taktzykluszeitlabel = tkinter.Label(optionswindow,text="Measurementtime for all \n Temperature-Sensors in sec").pack()
taktzykluszeitentry = tkinter.Entry(optionswindow,textvariable=self.taktzykluszeit.get(),width=30,justify="center").pack()
if __name__ == '__main__':
Graphicaluserinterface.main()
i know there is a line which should be indented but it wasn´t working here, i have it indented in my code though.
There are a few issues:
In the function menubaroptions() you assign the textvariable to the IntVar.get() method when you should assign to the object:
trennzeichenentry = tkinter.Entry( ... textvariable=self.entrystring.get(), ...).pack()
should be:
trennzeichenentry = tkinter.Entry( ... textvariable=self.entrystring, ...).pack()
Then you define the function with the instance name root instead of self which means that self.entrystring will generate a NameError.
Then you try to create a Toplevel window as a child to root. But root is a local variable in the main() function and the menubaroptions() can't find it.
Now; you are using the decorator #classmethod and I'm not one with decorators yet, so I can't say if that affects the problem. But the things I mentioned above will get you part of the way.

Passing values between classes for Tkinter

I'm working on a small GUI to query information from our CMDB to display for users. The trouble I am having is after an event in one class occurs(button), I want to update a combobox in another class. I thought I should use tk.StringVar() to pass the list, but the combobox only shows a 'PC_VAR#' value and doesn't update. Could anyone offer any assistance please?
#!/usr/bin/python
import Tkinter as tk
import ttk
import signal
class LoginUI:
def __init__(self, frame):
self.frame = frame
# Set default list entry
self.dc_list = tk.StringVar()
self.dc_list.set(['Login first'])
# Add a button to log in
self.button = tk.Button(self.frame, text='Login', command=self.change_combobox)
self.button.grid(column=0, row=0, pady=5)
def change_combobox(self):
# Change combobox values
dc_list = ['Site_1', 'Site_2', 'Site_3']
self.dc_list.set(dc_list)
class QueryUI:
def __init__(self, frame, dc_list):
self.frame = frame
self.dc = tk.StringVar()
self.dc_list = tk.StringVar()
self.dc_list.set(dc_list)
# Create site combobox
tk.Label(self.frame, text='Site:').grid(column=0, row=0, sticky="w")
self.dc_combobox = ttk.Combobox(
self.frame,
textvariable=self.dc,
width=20,
state='readonly'
)
self.dc_combobox['values'] = self.dc_list.get()
self.dc_combobox.grid(column=1, row=0, sticky="w")
class App:
def __init__(self, root):
self.root = root
self.root.title('Logging Handler')
self.root.columnconfigure(0, weight=1)
self.root.rowconfigure(0, weight=1)
# Create the left frame panels
left_frame = tk.Frame(self.root, padx=5, pady=5)
login_frame = tk.LabelFrame(left_frame, text="Login", borderwidth=2, relief="groove", padx=5, pady=5)
query_frame = tk.LabelFrame(left_frame, text="Query", borderwidth=2, relief="groove", padx=5, pady=5)
# Align frames
left_frame.grid(row=0, column=0, sticky="nw")
login_frame.grid(row=0, column=0, pady=5, sticky="nw")
query_frame.grid(row=1, column=0, pady=5, sticky="nw")
# Initialize all frames
self.login = LoginUI(login_frame)
self.query = QueryUI(query_frame, self.login.dc_list)
self.root.protocol('WM_DELETE_WINDOW', self.quit)
self.root.bind('<Control-q>', self.quit)
signal.signal(signal.SIGINT, self.quit)
def quit(self, *args):
self.root.destroy()
def main():
root = tk.Tk()
app = App(root)
app.root.mainloop()
if __name__ == '__main__':
main()
What I would do here is pass the controlling class (app) to the class needed to update the combobox. This way we can interact with it later if need be. By passing self of App to LoginUI we can then interact with the class attributes and methods of App from within LoginUI. This makes it a simple matter to update the combobox.
That said you really don't Need all the StringVars. Just past the list as a list and you will be good to go.
import Tkinter as tk
import ttk
import signal
class LoginUI:
def __init__(self, controller, frame):
self.controller = controller
self.frame = frame
self.dc_list = ['Login first']
self.button = tk.Button(self.frame, text='Login', command=self.change_combobox)
self.button.grid(column=0, row=0, pady=5)
def change_combobox(self):
self.controller.query.dc_combobox['values'] = ['Site_1', 'Site_2', 'Site_3']
self.controller.query.dc.set('Site_1')
class QueryUI:
def __init__(self, frame, dc_list):
self.frame = frame
self.dc = tk.StringVar()
tk.Label(self.frame, text='Site:').grid(column=0, row=0, sticky="w")
self.dc_combobox = ttk.Combobox(self.frame, textvariable=self.dc, width=20, state='readonly')
self.dc_combobox['values'] = dc_list
self.dc_combobox.grid(column=1, row=0, sticky="w")
class App:
def __init__(self, root):
self.root = root
self.root.title('Logging Handler')
self.root.columnconfigure(0, weight=1)
self.root.rowconfigure(0, weight=1)
left_frame = tk.Frame(self.root, padx=5, pady=5)
login_frame = tk.LabelFrame(left_frame, text="Login", borderwidth=2, relief="groove", padx=5, pady=5)
query_frame = tk.LabelFrame(left_frame, text="Query", borderwidth=2, relief="groove", padx=5, pady=5)
left_frame.grid(row=0, column=0, sticky="nw")
login_frame.grid(row=0, column=0, pady=5, sticky="nw")
query_frame.grid(row=1, column=0, pady=5, sticky="nw")
self.login = LoginUI(self, login_frame)
self.query = QueryUI(query_frame, self.login.dc_list)
self.root.protocol('WM_DELETE_WINDOW', self.quit)
self.root.bind('<Control-q>', self.quit)
signal.signal(signal.SIGINT, self.quit)
def quit(self, *args):
self.root.destroy()
if __name__ == '__main__':
root = tk.Tk()
app = App(root)
app.root.mainloop()

How to save text from textbox to file (Tkinter)

Whenever the function save() runs I get an error saying that the variable that holds the Text() function does not exist. I want the GUI to save whatever is inputted at the point when the Activate button is pressed.
from tkinter.ttk import *
class Example(Frame):
def __init__(self, parent= None):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("TL;DR")
self.style = Style()
self.style.theme_use("default")
self.pack(fill=BOTH, expand=1)
self.columnconfigure(1, weight=1)
self.columnconfigure(3, pad=7)
self.rowconfigure(3, weight=1)
self.rowconfigure(5, pad=7)
lbl = Label(self, text="Enter Text")
lbl.grid(sticky=W, pady=4, padx=5)
area = Text(self)
area.grid(row=1, column=0, columnspan=2, rowspan=4,
padx=5, sticky=E+W+S+N)
abtn = Button(self, text="Activate", command= self.save)
abtn.grid(row=1, column=3)
cbtn = Button(self, text="Close", command = self.client_exit)
cbtn.grid(row=2, column=3, pady=4)
hbtn = Button(self, text="Help", command= self.help1)
hbtn.grid(row=5, column=0, padx=5)
def save(self):
text = self.area.get("1.0",'end-1c')
with open("filepy.txt", "a") as outf:
outf.write(text)
def help1(self):
messagebox.showinfo('Help')
def client_exit(self):
exit()
def main():
root = Tk()
root.geometry("400x300+300+300")
app = Example(root)
if __name__ == '__main__':
main()
My question is: how do I save any text in the TextBox when the activate button is pressed?
In save() method, you are trying to access self.area but you did not created it.
area = Text(self) # class variable
self.area = Text(self)# instance variable
To be able to use self to access area you should change your code:
...
self.area = Text(self)
self.area.grid(row=1, column=0, columnspan=2, rowspan=4,
padx=5, sticky=E+W+S+N)
...

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