tkinter frame not expanding with canvas - python-3.x

I'm trying to create a GUI for timeseries data. It has 2 scrollable canvas and a frame within each. The top frame contains other frames within. The main_frame seems to expand with the canvas but catmainframes don't seem to do that. catmainframe is used to generate frames dynamically.
import os
import tkinter as tk
#from tkinter import ttk
from tkinter import filedialog as fd
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
def on_configure(event):
# update scrollregion after starting 'mainloop'
canvas1.configure(scrollregion=canvas1.bbox('all'))
canvas2.configure(scrollregion=canvas2.bbox('all'))
def enterCategory():
global cat
global catmainframe
global rownum
global add_file
cat = category.get()
catmainframe = tk.Frame(main_frame, borderwidth=2, relief="solid")
catmainframe.grid(row=rownum,column=0,sticky='nsew', padx=3, pady=3)
#canvas1.create_window((0,0), window=catmainframe,anchor='nw')
catmainframe.grid_rowconfigure(rownum, weight=1)
catmainframe.grid_columnconfigure(0, weight=1)
catframe = tk.Frame(catmainframe, borderwidth=2, relief="solid")
catframe.grid(row=0,column=0, sticky='nsew', padx=1, pady=1)
catlabel = tk.Label(catframe, text=cat)
catlabel.grid(row=0, column=0, sticky='nsew')
add_file = tk.Button(catframe,text="Add File",command=openFile)
add_file.grid(row=0, column=1, sticky='nsew')
global catchildframe
catchildframe = tk.Frame(catmainframe, borderwidth=2, relief="solid")
catchildframe.grid(row=1,column=0,sticky='nsew', padx=1, pady=1)
catchildframe.grid_rowconfigure(1, weight=1)
catchildframe.grid_columnconfigure(1, weight=1)
global box1, box2, box3
box1 = tk.Frame(catchildframe, borderwidth=2, relief="solid")
box2 = tk.Frame(catchildframe, borderwidth=2, relief="solid")
box3 = tk.Frame(catchildframe, borderwidth=2, relief="solid")
box1.grid(row=1, column=0, sticky='nsew', padx=10, pady=10)
box2.grid(row=1, column=1, sticky='nsew', padx=10, pady=10)
box3.grid(row=1, column=2, sticky='nsew', padx=10, pady=10)
box1.propagate(1)
box2.propagate(1)
box3.propagate(1)
rownum = rownum +1
def openFile():
global fname
global mindatetime
global maxdatetime
parentname = catmainframe.winfo_parent()
parent = catmainframe._nametowidget(parentname)
#childname = catchildframe.winfo_parent()
#child = catchildframe._nametowidget(childname)
child = add_file.master
print("Catmainframe parent:"+parentname)
#print("Catchildframe parent:"+child)
file_path=fd.askopenfilename()
#print(file_path)
file_name = os.path.basename(file_path)
print(file_name)
file_list = []
file_list.append(file_name)
df = pd.read_csv(file_path)
names = list(df.columns[0:])
indexcol = names[0]
#print(indexcol)
df = df.rename(columns = {indexcol:'datetime'})
names = list(df.columns[1:])
#print(names)
df.datetime = pd.to_datetime(df.datetime)
df.set_index('datetime',inplace=True)
if mindatetime == pd.to_datetime('1900-01-01 00:00:00'):
mindatetime = df.index.min()
elif mindatetime > df.index.min():
mindatetime = df.index.min()
if maxdatetime == pd.to_datetime('1900-01-01 00:00:00'):
maxdatetime = df.index.max()
elif maxdatetime < df.index.max():
maxdatetime = df.index.max()
print(mindatetime)
print(maxdatetime)
global unique_dates
unique_dates = []
unique_dates = df.index.map(pd.Timestamp.date).unique()
for x in range(len(names)):
if(len(names)==1):
l = tk.Checkbutton(box1, text=names[x], variable=names[x],state='disabled')
l.select()
l.pack(anchor = 'w')
else:
l = tk.Checkbutton(box1, text=names[x], variable=names[x])
l.select()
l.pack(anchor = 'w')
figure = plt.Figure(figsize=(4,3), dpi=100)
ax2 = figure.add_subplot(111)
line = FigureCanvasTkAgg(figure, box2)
line.get_tk_widget().grid(row=1,column=1,sticky='nsew')
df.plot(kind='line', legend=False, ax=ax2, fontsize=10)
ax2.set_title(cat)
ax2.set_xlim(mindatetime,maxdatetime)
for x in range(len(unique_dates)):
d = tk.Checkbutton(box3, text=unique_dates[x], variable=unique_dates[x])
d.select()
d.pack(anchor = 'w')
root = tk.Tk()
root.geometry('{}x{}'.format(800, 600))
# layout all of the main containers
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(0, weight=1)
#Global variables
category = tk.StringVar()
global rownum
rownum =0
mindatetime = pd.to_datetime('1900-01-01 00:00:00')
maxdatetime = pd.to_datetime('1900-01-01 00:00:00')
#Top frame
top_frame = tk.Frame(root)
top_frame.grid(row=0, column=0, sticky='nsew')
category_name = tk.Label(top_frame, text='Category:')
category_name.grid(row=0, column=0, sticky='nsew')
entry_category = tk.Entry(top_frame, background="pink",textvariable = category)
entry_category.grid(row=0, column=1, sticky='nsew')
entry_category.focus()
ok_button = tk.Button(top_frame, text="OK", command=enterCategory)
ok_button.grid(row=0, column=2, sticky='nsew')
xscrollbar = tk.Scrollbar(root, orient='horizontal')
xscrollbar.grid(row=3, column=0, sticky='ew')
yscrollbar = tk.Scrollbar(root)
yscrollbar.grid(row=1, column=1, sticky='ns')
canvas1 = tk.Canvas(root, bd=0,#scrollregion=(0, 0, 1000, 1000),
yscrollcommand=yscrollbar.set)
canvas1.grid(row=1, column=0, sticky='nsew')
# create the center widgets
canvas1.grid_rowconfigure(1, weight=1)
canvas1.grid_columnconfigure(0, weight=1)
canvas2 = tk.Canvas(root, bd=0,#scrollregion=(0, 0, 1000, 1000),
xscrollcommand=xscrollbar.set)
canvas2.grid(row=2, column=0, sticky='nsew')
xscrollbar.config(command=canvas2.xview)
yscrollbar.config(command=canvas1.yview)
canvas1.config(scrollregion=canvas1.bbox("all"))
canvas2.config(scrollregion=canvas2.bbox("all"))
main_frame = tk.Frame(canvas1)
canvas1.create_window((0,0), window=main_frame,anchor='nw')
#main_frame.grid(row=0,column=0,stick='nsew')
time_box = tk.Frame(canvas2)
canvas2.create_window((0,0), window=time_box,anchor='nw')
root.bind('<Configure>', on_configure)
root.mainloop()
Below is the error even though the application seems to run fine.
Traceback (most recent call last):
File "C:\Users\ranji\Anaconda3\lib\tkinter\__init__.py", line 1702, in __call__
return self.func(*args)
File "C:\Users\ranji\Anaconda3\lib\tkinter\__init__.py", line 3069, in set
self.tk.call(self._w, 'set', first, last)
_tkinter.TclError: invalid command name ".!scrollbar2"
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\ranji\Anaconda3\lib\tkinter\__init__.py", line 1702, in __call__
return self.func(*args)
File "C:\Users\ranji\Anaconda3\lib\tkinter\__init__.py", line 3069, in set
self.tk.call(self._w, 'set', first, last)
_tkinter.TclError: invalid command name ".!scrollbar"

You have to manually manage the size of an inner frame yourself. You can do this by explicitly setting the width of the inner window to be the width of the canvas (minus any desired borders or margins) whenever the canvas changes size. You can get a callback when the window changes size by binding to the <Configure> event.
I've pared your code down to just the issue being asked about. Notice in the following code that I added a tag to the embedded window object so that it can be referenced in the on_configure function. I've also colorized the inner frame to make it easier to visualize, and given it a height since there are no widgets inside.
The important part of this example is the call to canvas1.itemconfigure in on_configure:
import tkinter as tk
def on_configure(event):
width = canvas1.winfo_width()
canvas1.itemconfigure("main_frame", width=width)
root = tk.Tk()
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(0, weight=1)
yscrollbar = tk.Scrollbar(root)
canvas1 = tk.Canvas(root, bd=0,yscrollcommand=yscrollbar.set)
canvas1.grid(row=1, column=0, sticky='nsew')
yscrollbar.grid(row=1, column=1, sticky='ns')
main_frame = tk.Frame(canvas1, background="bisque", height=200)
canvas1.create_window((0,0), window=main_frame,anchor='nw', tags=("main_frame",))
root.bind('<Configure>', on_configure)
root.mainloop()

Related

Is it possible to grab input from the topview tkinter window and retrieve saved entry field value from within master tk window

The program is made up of classes and I am trying to use a tkinter topview from within a function so that when it's called it is able to retrieve the entryfield value to the master class
from tkinter import
from PIL import Image, ImageTk
Below is the driver code handling the transitioning from one class to another
class SeaofBTCapp(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 (
WelcomePage, Register_new_user): # ,PageThree,PageFour):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(WelcomePage)
# def show_frame(self, cont):
# frame = self.frames[cont]
# frame.tkraise()
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
frame.update()
frame.event_generate("<<show_frame>>")
def get_page(self, cont):
for page in self.frames.values():
if str(page.__class__.__name__) == cont:
return page
return None
class Register_new_user(object):
pass
Below is the entry point of the program and is the first page to be displayed
class WelcomePage(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
# self.bind("<<show_frame>>", self.main_prog)
def resize_image(event):
global photo
new_width = event.width
new_height = event.height
image = copy_of_image.resize((new_width, new_height))
photo = ImageTk.PhotoImage(image)
label.config(image=photo)
label.image = photo # avoid garbage collection
def pin_input():
top = Toplevel()
top.geometry("180x100")
top.title("toplevel")
l2 = Label(top, text="This is toplevel window")
global entry_1
global password
password = StringVar
entry_1 = None
def cleartxtfield():
global password
new = "3"
password.set(new)
# ############# Function to parse for only numerical input
def validate(input):
if input.isdigit():
return True
elif input == "":
return True
else:
return False
def enternumber(x):
global entry_1
setval = StringVar()
setval = str(x)
# print(setval)
entry_1.insert(END, setval)
entry_1 = Entry(top, textvariable=password, width=64, show='*')
entry_1.place(x=200, y=100)
entry_1.focus()
reg = top.register(validate)
entry_1.config(validate="key", validatecommand=(reg, '%P'))
def getcreds():
# check if four digit entered and is not empty
global passwd
passwd = password.get()
print(f"The Credentials are {passwd}")
def funcbackspace():
length = len(entry_1.get())
entry_1.delete(length - 1, 'end')
def killwindow():
# when the user quits it should clear all the data input fields filled in in the previous steps. and should display information that it is about to quit in a few seconds
command = top.destroy()
# Label(top,text="Goodbye\n (Closing in 2 seconds)")
top.after(2000, top.quit())
cancel = Button(top, width=8, height=3, text="Cancel", bg="red", fg="black", command=killwindow)
cancel.place(x=220, y=150)
backspace = Button(top, width=8, height=3, text="Backspace", bg="red", fg="black", command=funcbackspace)
backspace.place(x=500, y=150)
# ----number Buttons------
def enternumber(x):
global entry_1
setval = StringVar()
setval = str(x)
# print(setval)
entry_1.insert(END, setval)
btn_numbers = []
for i in range(10):
btn_numbers.append(
Button(top, width=8, height=3, text=str(i), bd=6, command=lambda x=i: enternumber(x)))
btn_text = 1
for i in range(0, 3):
for j in range(0, 3):
btn_numbers[btn_text].place(x=220 + j * 140, y=250 + i * 100)
btn_text += 1
btn_zero = Button(top, width=15, height=2, text='0', bd=5, command=lambda x=0: enternumber(x))
btn_zero.place(x=330, y=550)
clear = Button(top, text="Clear", bg="green", fg="white", width=8, height=3, command=cleartxtfield)
clear.place(x=220, y=550)
okbtn = Button(top, text="Enter", bg="green", fg="black", width=8, height=3, command=getcreds)
okbtn.place(x=500, y=550)
val = getcreds()
print("The value to be returned is %s" % val)
return val
password = pin_input()
print("Gotten password is %s" % password)
copy_of_image = Image.open("image.png")
photoimage = ImageTk.PhotoImage(copy_of_image)
label = Label(self, image=photoimage)
label.place(x=0, y=0, relwidth=1, relheight=1)
label.bind('<Configure>', resize_image)
top_left_frame = Frame(self, relief='groove', borderwidth=2)
top_left_frame.place(relx=1, rely=0.1, anchor=NE)
center_frame = Frame(self, relief='raised', borderwidth=2)
center_frame.place(relx=0.5, rely=0.75, anchor=CENTER)
Button(top_left_frame, text='REGISTER', bg='grey', width=14, height=1,
command=lambda: controller.show_frame(Register_new_user)).pack()
Button(center_frame, text='ENTER', fg='white', bg='green', width=13, height=2,
command=lambda: controller.show_frame(Register_new_user)).pack()
if __name__ == '__main__':
app = SeaofBTCapp()
app.title("Password return on topview window")
width = 1000
height = 700
screenwidth = app.winfo_screenwidth()
screenheight = app.winfo_screenheight()
alignstr = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
app.geometry(alignstr)
# app.resizable(width=False, height=False)
app.resizable(width=True, height=True)
app.mainloop()
If I understand this correctly you want to enter a password in a dialog and then get the password from the dialog when you close it.
Have a look at Dialog Windows at effbot for a discussion about creating dialog windows.
Here is an example of how you can implement a simple dialog:
from tkinter import *
from tkinter import simpledialog
class MyDialog(simpledialog.Dialog):
def body(self, master):
'''create dialog body.
return widget that should have initial focus.
This method should be overridden, and is called
by the __init__ method.'''
Label(master, text='Value:').grid(row=0)
self.e1 = Entry(master)
self.e1.grid(row=0, column=1)
return self.e1 # initial focus
def apply(self):
'''process the data
This method is called automatically to process the data, *after*
the dialog is destroyed. By default, it does nothing.'''
value = self.e1.get()
self.result = value
def validate(self):
'''validate the data
This method is called automatically to validate the data before the
dialog is destroyed. By default, it always validates OK.'''
return 1 # override
def buttonbox(self):
'''add standard button box.
override if you do not want the standard buttons
'''
box = Frame(self)
w = Button(box, text="OK", width=10, command=self.ok, default='active')
w.pack(side='left', padx=5, pady=5)
w = Button(box, text="Cancel", width=10, command=self.cancel)
w.pack(side='left', padx=5, pady=5)
self.bind("<Return>", self.ok)
self.bind("<Escape>", self.cancel)
box.pack()
if __name__ == '__main__':
root = Tk()
root.geometry('200x100+800+50')
def do():
d = MyDialog(root)
print(d.result)
b = Button(root, text='Go!', width=10, command=do)
b.pack(expand=True)
Did that answer your question?

Tkinter scrollbar for frame in a Frame

I'm creating a dynamic container that can change between frames. In one of the frames I have a list of values that I need to scroll through because it is so long. However I cannot get the scrollbar to work with the canvas and frame set up.
i have tried using Listbox and this works but does not give me the control over the displays that I am looking for. I want to be able to configure the names of the tag and then to the right the value.
#!Python
import matplotlib
matplotlib.use("TkAgg")
from matplotlib import style
import tkinter as tk
from tkinter import *
from YahooParser import Yahoo_Parser
TITLE_FONT = ("Helvetica", 10, "bold")
LARG_FONT = ("Helvetica", 12)
NORM_FONT = ("Helvetica", 10)
AIR_FONT = ("Arial", 10)
SMALL_FONT = ("Helvetica", 8)
style.use("ggplot")
#style.use("ggplot")
Gray = "#%02x%02x%02x" % (85, 85, 85)
Wight ="#%02x%02x%02x" % (220, 220, 220)
class Midas_Screen(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# Title
tk.Tk.wm_title(self, "Midas Program")
tk.Tk.geometry(self,"500x400")
#tk.Tk.configure(self, background='black')
# This set the seting for the container
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 = {}
# Makes all the frames and stores them
for F in (HomePage,):
# You pass the container to your page function. this makes the frame
frame = F(container, self)
# this aligns the frame "nsew" = North, South etc
frame.grid(row=0, column=0, sticky="nsew")
# This uses the function as a key in the dic
self.frames[F] = frame
self.show_frame(HomePage)
def show_frame(self, key):
frame = self.frames[key]
frame.tkraise()
class HomePage(tk.Frame):
def __init__(self, perent, controller):
self.yp = Yahoo_Parser()
self.names = []
self.values = {}
for tag in self.yp.values_sum:
self.names.append(tag[0])
for tag in self.yp.values_sta:
self.names.append(tag[0])
for tag in self.names:
self.values[tag]='0'
tk.Frame.__init__(self, perent)
frame = Frame(perent)
frame.grid(row=1, column=1)
canvas = Canvas(frame)
canvas.configure(scrollregion=(0,0,500,500), width=200, height=200)
myscrollbar = Scrollbar(frame, orient="vertical")
myscrollbar.grid(row=1, column=2, sticky="ns")
myscrollbar.config(command=canvas.yview)
canvas.config(yscrollcommand=myscrollbar.set)
R = 1
for key in self.values:
label = tk.Label(canvas, text=key + ':', font=AIR_FONT, bg=Gray, fg=Wight, borderwidth=0,
relief="solid")
value = tk.Label(canvas, text=self.values[key], font=AIR_FONT, bg=Gray, fg=Wight, borderwidth=0,
relief="solid")
label.grid(row=R, column=1, sticky="nsew")
value.grid(row=R, column=2, sticky="nsew")
R += 1
canvas.grid(row=1, column=1)
app = Midas_Screen()
app.mainloop()
The canvas can't scroll things added to the canvas with grid. The most common solution is to add a frame to the canvas with create_window, and then adding the labels to the frame.
See Adding a scrollbar to a group of widgets in Tkinter
So i made a few changes thanks and got it working :)
Bye using pack as you sugeted it works
#!Python
import matplotlib
matplotlib.use("TkAgg")
from matplotlib import style
import tkinter as tk
from tkinter import *
from YahooParser import Yahoo_Parser
TITLE_FONT = ("Helvetica", 10, "bold")
LARG_FONT = ("Helvetica", 12)
NORM_FONT = ("Helvetica", 10)
AIR_FONT = ("Arial", 10)
SMALL_FONT = ("Helvetica", 8)
style.use("ggplot")
#style.use("ggplot")
Gray = "#%02x%02x%02x" % (85, 85, 85)
Wight ="#%02x%02x%02x" % (220, 220, 220)
class Midas_Screen(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# Title
tk.Tk.wm_title(self, "Midas Program")
tk.Tk.geometry(self,"500x400")
#tk.Tk.configure(self, background='black')
# This set the seting for the container
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 = {}
# Makes all the frames and stores them
for F in (HomePage,):
# You pass the container to your page function. this makes the frame
frame = F(container, self)
# this aligns the frame "nsew" = North, South etc
frame.grid(row=1, column=1, sticky="nsew")
# This uses the function as a key in the dic
self.frames[F] = frame
self.show_frame(HomePage)
def show_frame(self, key):
frame = self.frames[key]
frame.tkraise()
class HomePage(tk.Frame):
def __init__(self, perent, controller):
self.values = {}
for tag in range(20):
self.values['Text'+str(tag)+':']='0'
tk.Frame.__init__(self, perent)
def myfunction(event):
canvas.configure(scrollregion=canvas.bbox("all"), width=200, height=200)
canvas = Canvas(perent)
frame = Frame(canvas)
myscrollbar = Scrollbar(frame, orient="vertical", command=canvas.yview)
canvas.config(yscrollcommand=myscrollbar.set)
myscrollbar.pack(side=RIGHT, fill=Y)# sticky="ns")
canvas.grid(row=0, column=0, sticky="nw")
#canvas.pack(side=LEFT)
canvas.create_window((0, 0), window=frame, anchor='nw')
R = 1
for key in self.values:
row = Frame(frame)
label = tk.Label(row, text=key + ':', font=AIR_FONT, bg=Gray, fg=Wight, borderwidth=0,
relief="solid")
value = tk.Label(row, text=self.values[key], font=AIR_FONT, bg=Gray, fg=Wight, borderwidth=0,
relief="solid")
label.pack(side=LEFT, fill=X)
value.pack(side=LEFT,fill=X)
row.pack(side=TOP, fill=X)
R += 1
frame.bind("<Configure>", myfunction)
app = Midas_Screen()
app.mainloop()

Why can I not get the value of tkinter variables?

I am trying to add a configuration window in my coupled oscillator simulation. But when I want to get the value of tkinter variables to set up the system, I only get ''.
I tried to change the type from tk.DoubleVar() to tk.StringVar() but nothing seems to works...
Here the code for the configuration frame for one object. Then I create two of them and add them to the configuration frame.
import tkinter as tk
class MassConfig(tk.Frame):
def __init__(self, root, **kwargs):
tk.Frame.__init__(self, root, kwargs)
self.grid()
# Variables :
self.weight = tk.StringVar()
self.vitesse = tk.StringVar()
self.position = tk.StringVar()
self.lbl_weight = tk.Label(self, text='Masse :')
self.lbl_weight.grid(row=0, column=0)
self.entry_weight = tk.Entry(self, textvariable=self.weight, width=5)
self.entry_weight.grid(row=0, column=1)
self.lbl_vit = tk.Label(self, text='Vitesse :')
self.lbl_vit.grid(row=1, column=0, pady=5)
self.entry_vit = tk.Entry(self, textvariable=self.vitesse, width=5)
self.entry_vit.grid(row=1, column=1)
self.lbl_pos = tk.Label(self, text='Position :')
self.lbl_pos.grid(row=2, column=0)
self.entry_pos = tk.Entry(self, textvariable=self.position, width=5)
self.entry_pos.grid(row=2, column=1)
Here the code of the configuration frame, which has two 'MassConfig' frame inside.
import tkinter as tk
from gui.masse_config import MassConfig
class Configuration(tk.Frame):
def __init__(self, root, **kwargs):
tk.Frame.__init__(self, root, **kwargs)
self.root = root
self.grid()
self.update()
self.is_alive = True
self.data = {}
self.m1_frame = tk.LabelFrame(self, text='Masse 1', width=200, height=200)
self.m1_frame.grid(column=0, row=0, padx=(10, 5), pady=(10, 10))
self.m2_frame = tk.LabelFrame(self, text='Masse 2', width=200, height=200)
self.m2_frame.grid(column=1, row=0, padx=(5, 10), pady=(10, 10))
self.config_1 = MassConfig(self.m1_frame)
self.config_2 = MassConfig(self.m2_frame)
self.config_1.grid(padx=10, pady=10)
self.config_2.grid(padx=10, pady=10)
self.btn_validation = tk.Button(self, text='Valider', command=self.validation)
self.btn_validation.grid(row=3, column=1, padx=10, pady=(0, 10), sticky=tk.E)
self.update()
def validation(self):
print(":", self.config_1.position.get())
self.data['Mass 1'] = {}
self.data['Mass 1']['Position'] = self.config_1.position.get()
self.data['Mass 1']['Vitesse'] = self.config_1.vitesse.get()
self.data['Mass 1']['Masse'] = self.config_1.weight.get()
self.data['Mass 2'] = {}
self.data['Mass 2']['Position'] = self.config_2.position.get()
self.data['Mass 2']['Vitesse'] = self.config_2.vitesse.get()
self.data['Mass 2']['Masse'] = self.config_2.weight.get()
self.is_alive = False
self.root.destroy()
I want to have the value of the tkinter variables self.weight, self.vitesse and self.position from the MassConfig class in a dictionary (self.data from Configuration class). But nothing come out, except ''.

tkinter error calling function through entries in listbox

Recently, I tried to make a full application window with a side panel menu with separate frames running some functions and submitting forms in the canvas frame.
But I found that every time I click on any entry in listbox it runs the function or method without clearing the existing one .
I tried destroy() and forget() didn't work for me (maybe I didn't know exactly how to use it?!, and the destroy() function prevent using the function again till I close the whole application and run it again!) this is a photo of my problem
this is my code :
import tkinter as tk
from tkinter import ttk
class MainWindow() :
def __init__(self,root):
# menu left
self.menu_upper_frame = tk.Frame(root, bg="#dfdfdf")
self.menu_title_label = tk.Label(self.menu_upper_frame, text="menu title", bg="#dfdfdf")
self.menu_title_label.pack()
self.menu_left_container = tk.Frame(root, width=150, bg="#ababab")
self.menu_left_upper = tk.Frame(self.menu_left_container, width=150, height=150, bg="red")
self.menu_left_upper.pack(side="top", fill="both", expand=True)
# create a listbox of items
self.Lb1 = tk.Listbox(self.menu_left_upper,bg ="red", borderwidth=0, highlightthickness=0 )
self.Lb1.insert(1, "Python")
self.Lb1.insert(2, "Perl")
self.Lb1.insert(3, "C")
self.Lb1.insert(4, "PHP")
self.Lb1.insert(5, "JSP")
self.Lb1.insert(6, "Ruby")
self.Lb1.bind("<<ListboxSelect>>", self.OnClick ) #return selected item
self.Lb1.pack(fill="both", expand=True, pady=50 )
# right area
self.inner_title_frame = tk.Frame(root, bg="#dfdfdf")
self.inner_title_label = tk.Label(self.inner_title_frame, text="inner title", bg="#dfdfdf")
self.inner_title_label.pack()
self.canvas_area = tk.Canvas(root, width=500, height=400, background="#ffffff")
self.canvas_area.grid(row=1, column=1)
# status bar
self.status_frame = tk.Frame(root)
self.status = tk.Label(self.status_frame, text="this is the status bar")
self.status.pack(fill="both", expand=True)
self.menu_upper_frame.grid(row=0, column=0, rowspan=2, sticky="nsew")
self.menu_left_container.grid(row=1, column=0, rowspan=2, sticky="nsew")
self.inner_title_frame.grid(row=0, column=1, sticky="ew")
self.canvas_area.grid(row=1, column=1, sticky="nsew")
self.status_frame.grid(row=2, column=0, columnspan=2, sticky="ew")
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(1, weight=1)
def OnClick(self,event):
widget = event.widget
selection = widget.curselection()
value = widget.get(selection)
if value == 'Python':
self.tabtop()
def tabtop(self):
self.tabControl = ttk.Notebook(self.canvas_area, width=400) # Create Tab Control
self.tab1 = ttk.Frame(self.tabControl) # Create a tab
self.tab2 = ttk.Frame(self.tabControl)
self.tab3 = ttk.Frame(self.tabControl)
self.tab4 = ttk.Frame(self.tabControl)
self.tab5 = ttk.Frame(self.tabControl)
self.tabControl.add(self.tab1, text='Login data' ) # Add the tab
self.tabControl.add(self.tab2, text='Permission')
self.tabControl.add(self.tab3, text='Roles')
self.tabControl.add(self.tab4, text='Personal data')
self.tabControl.add(self.tab5, text='Business data')
self.tabControl.pack(expand=1, fill="both") # Pack to make visible
self.l2 = tk.Label(self.tab2, text="label 2").pack()
self.l3 = tk.Label(self.tab3, text="label 3").pack()
root = tk.Tk()
root.title("Control Panel")
root.style = ttk.Style()
root.style.theme_use("clam")
user = MainWindow(root)
root.mainloop()
If what you're really asking is how to replace an existing notebook with a new notebook, all you need to do is call destroy() on the old notebook before creating the new one.
First, define self.tabControl to None somewhere in MainWindow.__init__. Then, in tabtop you can delete the old notebook before creating the new one:
def tabtop(self):
if self.tabControl is not None:
self.tabControl.destroy()
...

Tkinter listbox entry pagination

Recently, I tried to find a way to paginate through listbox entries that runs functions that opens frames with forms, tabs or else, but I didn't find it.
Clearly, I wanna create a control panel application which has a side panel which can switch between pages/frames that hold widgets that user will interact with.
this is the code which I wrote to try to achieve this manner:
import tkinter as tk
from tkinter import ttk
class MainWindow() :
def __init__(self,root):
# menu left
self.menu_upper_frame = tk.Frame(root, bg="#dfdfdf")
self.menu_title_label = tk.Label(self.menu_upper_frame, text="menu title", bg="#dfdfdf")
self.menu_title_label.pack()
self.menu_left_container = tk.Frame(root, width=150, bg="#ababab")
self.menu_left_upper = tk.Frame(self.menu_left_container, width=150, height=150, bg="red")
self.menu_left_upper.pack(side="top", fill="both", expand=True)
# create a listbox of items
self.Lb1 = tk.Listbox(self.menu_left_upper,bg ="red", borderwidth=0, highlightthickness=0 )
self.Lb1.insert(1, "Python")
self.Lb1.insert(2, "Perl")
self.Lb1.insert(3, "C")
self.Lb1.insert(4, "PHP")
self.Lb1.insert(5, "JSP")
self.Lb1.insert(6, "Ruby")
self.Lb1.bind("<<ListboxSelect>>", self.OnClick ) #return selected item
self.Lb1.pack(fill="both", expand=True, pady=50 )
# right area
self.inner_title_frame = tk.Frame(root, bg="#dfdfdf")
self.inner_title_label = tk.Label(self.inner_title_frame, text="inner title", bg="#dfdfdf")
self.inner_title_label.pack()
self.canvas_area = tk.Canvas(root, width=500, height=400, background="#ffffff")
self.canvas_area.grid(row=1, column=1)
# status bar
self.status_frame = tk.Frame(root)
self.status = tk.Label(self.status_frame, text="this is the status bar")
self.status.pack(fill="both", expand=True)
self.menu_upper_frame.grid(row=0, column=0, rowspan=2, sticky="nsew")
self.menu_left_container.grid(row=1, column=0, rowspan=2, sticky="nsew")
self.inner_title_frame.grid(row=0, column=1, sticky="ew")
self.canvas_area.grid(row=1, column=1, sticky="nsew")
self.status_frame.grid(row=2, column=0, columnspan=2, sticky="ew")
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(1, weight=1)
def OnClick(self,event):
widget = event.widget
selection = widget.curselection()
value = widget.get(selection)
# print ("selection: ",selection, ": '%s'"% value)
if value == 'Python':
self.tabtop()
def tabtop(self):
self.tabControl = ttk.Notebook(self.canvas_area, width=400)
self.tab1 = ttk.Frame(self.tabControl)
self.tab2 = ttk.Frame(self.tabControl)
self.tab3 = ttk.Frame(self.tabControl)
self.tab4 = ttk.Frame(self.tabControl)
self.tab5 = ttk.Frame(self.tabControl)
self.tabControl.add(self.tab1, text='Login data' )
self.tabControl.add(self.tab2, text='Permission')
self.tabControl.add(self.tab3, text='Roles')
self.tabControl.add(self.tab4, text='Personal data')
self.tabControl.add(self.tab5, text='Business data')
self.tabControl.pack(expand=1, fill="both")
self.l2 = tk.Label(self.tab2, text="label 2").pack()
self.l3 = tk.Label(self.tab3, text="label 3").pack()
root = tk.Tk()
root.title("Control Panel")
root.style = ttk.Style()
root.style.theme_use("clam")
user = MainWindow(root)
root.mainloop()
If you have an idea to achieve the same manner with a different algorithm please suggest!

Resources