Close Tkinter window while using try and except. (Window variable is self) - python

What I want my code to do, is when any exception happens it should close the program and allow me to call a function which opens up the "program has crashed".
When using a try and except around the whole program, I can't access my self variable inside the except because it's created inside the try
so, I'm trying by putting the try and except inside each class
The current error I get is this: "TclError: bad window path name ".!frame.!startpage"
I added a copy of the code below. (My full program is 6000 lines, this is a shortened down version of 100 lines to figure out the issue)
Save New Duplicate & Edit Just Text Twitter
import tkinter as tk
from tkinter import ttk
from tkinter import *
LARGE_FONT= ("Verdana", 12)
Information_Font = ("Verdana", 10)
new = ""
class Application(tk.Tk):
def __init__(self, *args, **kwargs, ):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "Title")
container = tk.Frame(self, width=1768, height=20000)
container.pack(side="top", fill='both' , expand = 1)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.geometry("500x500")
self.title("Program Title")
self.frames = {}
for F in (StartPage, PageOne):
frame = F(container, self)
self.frames[F] = frame
#frame.pack()
frame.grid(row=0, column=0)
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.grid(row=0, column=0, sticky='nsew')
frame.tkraise()
frame.update()
frame.event_generate("<<ShowFrame>>")
class StartPage(tk.Frame,):
def __init__(self, parent, controller):
try:
tk.Frame.__init__(self, parent)
label = ttk.Label(self, text="Start Page/Please Login", font=LARGE_FONT)
label.pack(pady=0,padx=100)
labelempty = ttk.Label(self, text="", font=LARGE_FONT)
labelempty.pack(pady=12,padx=100)
ConsolePasswordeLabel = Label(self, text="Console Password")
ConsolePasswordeLabel.pack(side = "top", pady=10,padx=10)
Console = StringVar()
ConsoleEntry = Entry(self, show = "*", textvariable=Console).pack(pady=2,padx=2)
EnablePasswordeLabel = Label(self, text="Enable Password")
EnablePasswordeLabel.pack(side = "top", pady=10,padx=10)
Enable = StringVar()
EnableEntry = Entry(self, show = "*", textvariable=Enable).pack(pady=2,padx=2)
def login():
Enable1 = Enable.get()
Console1 = Console.get()
print(Console1)
print(Enable1)
def dologin():
login()
controller.show_frame(PageOne)
def showpasswords():
pass
Login = tk.Button(self, text ="Login", command= dologin)
Login.pack(padx = 10, pady = 10)
Login.place(x = "260", y = "220", width = "90")
ShowButton = tk.Button(self, text ="Show passwords", command= "")
ShowButton.pack(padx = 10, pady = 10)
ShowButton.place(x = "140", y = "220")
print(ABCD) # Raising an error on purpose to test the try and except
except:
print("Excepting")
self.destroy()
print("1. Program should have closed")
print('2. "Program has crashed" page can now be opened, from seperate mainloop"')
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
label = ttk.Label(self, text="Switchport Menu", font=LARGE_FONT,) #background="red")
label.pack(pady=0,padx=100)
app = Application()
app.mainloop()

You need to override report_callback_exception method of Tk class, e.g.:
from tkinter import messagebox
class Application(tk.Tk):
...
def report_callback_exception(self, exc_type, exc_value, exc_traceback):
# The following line is optional, it will print info about the exception to the console (the default tkinter behaviour)
super().report_callback_exception(exc_type, exc_value, exc_traceback)
filename, line, *_ = traceback.extract_tb(exc_traceback).pop()
messagebox.showerror(
"Program has crashed",
f"{exc_type.__name__}: {exc_value}\n"
f"{filename}, Line: {line}"
)
self.quit()

Related

Pass opened file name to function

I am building a small app where I am doing some calculations and want to save the variables and results into a *.csv file.
My desire is to open the *.csv file via a menu point in Tkinter and, after calculations done, save the results with a button to the *.csv file.
What I am not able to do is to save the data, as I am passing the file name in the wrong way.
I have tried to assign the file name to a variable, declare it as global but have not find any solution.
This is the code snippet requested, not just the 2 functions:
import tkinter as tk
from tkinter import *
# Used for styling the GUI
from tkinter import ttk
from math import *
import csv
from tkinter import filedialog as fd
from tkinter.filedialog import asksaveasfile
from tkinter.messagebox import showinfo
from datetime import datetime
# global database
class windows(tk.Tk):
def __init__(self, *args, **kwargs):
global database
tk.Tk.__init__(self, *args, **kwargs)
# Adding a title to the window
self.wm_title("calculator and database")
#
tire_menu = Menu(self)
self.config(menu=tire_menu)
def command_open():
filename = fd.askopenfilename(
title = 'Select database',
filetypes = [("CSV files", "*.csv")])
showinfo(
title = 'You have selected',
message = filename)
database = filename
return(database)
def command_new():
extensions = [("csv file(*.csv)", "*.csv")]
file = asksaveasfile(filetypes=extensions,
defaultextension=extensions)
headerlist = [
"Date",
"Track"]
database = file.name
with open(database, "w") as f:
writer = csv.writer(f)
writer.writerow(headerlist)
# create a menu item
file_menu = Menu(tire_menu)
db_menu = Menu(tire_menu)
tire_menu.add_cascade(label="File", menu = file_menu)
file_menu.add_command(label="Exit", command=self.quit)
tire_menu.add_cascade(label="Database", menu = db_menu)
db_menu.add_command(label="New DB", command=command_new)
db_menu.add_command(label="Open DB", command=command_open)
# creating a frame and assigning it to container
container = tk.Frame(self, height=600, width=800)
# specifying the region where the frame is packed in root
container.pack(side="top", fill="both", expand=True)
# configuring the location of the container using grid
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
# We will now create a dictionary of frames
self.frames = {}
# we'll create the frames themselves later but let's add the components to the dictionary.
for F in (MainPage, SidePage, CompletionScreen):
frame = F(container, self)
# the windows class acts as the root window for the frames.
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
# Using a method to switch frames
self.show_frame(MainPage)
def show_frame(self, cont):
frame = self.frames[cont]
# raises the current frame to the top
frame.tkraise()
class MainPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
title_main = tk.Label(
self,
text="calculator")
title_main.config(font=("Times 18 bold"), bg="white")
title_main.grid(row=0, column=0, columnspan=2, pady=5)
def savetodb():
data = [
datetime.today().strftime('%Y-%m-%d'),
]
with open(database, "w") as f:
writer = csv.writer(f)
writer.writerow(data)
## Create reference tire pressures frame
frame_reference = tk.LabelFrame(
self,
text = "1: Enter reference data: ")
frame_reference.grid(row=1, column=0, padx=5, pady=5, columnspan = 2)
lbl_track = Label(
frame_reference,
text = "Track: ",
font = 'Times 11',
justify = tk.CENTER)
lbl_track.grid(row = 0, column = 0)
# entries for database save
ent_track = Entry(
frame_reference,
justify = tk.CENTER,
width = 23).grid(row=0, column=1)
btn_savetodb = Button(
frame_reference,
text="Save to DB!",
font = 'Times 11 bold',
command=savetodb)
btn_savetodb.grid(row=2, column=0, columnspan=2, padx=10, pady=5)
class SidePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="This is the Side Page")
label.pack(padx=10, pady=10)
switch_window_button = tk.Button(
self,
text="Go to the Completion Screen",
command=lambda: controller.show_frame(CompletionScreen),
)
switch_window_button.pack(side="bottom", fill=tk.X)
class CompletionScreen(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Completion Screen, we did it!")
label.pack(padx=10, pady=10)
switch_window_button = ttk.Button(
self, text="Return to menu", command=lambda: controller.show_frame(MainPage)
)
switch_window_button.pack(side="bottom", fill=tk.X)
if __name__ == "__main__":
testObj = windows()
testObj.mainloop()
Could you please provide some help?
You have declared global database in wrong place. It should be put inside command_open() as I said in my comment:
class windows(tk.Tk):
def __init__(self, *args, **kwargs):
...
def command_open():
global database
...
database = filename
return database
...
...
However I would suggest to use a class variable inside windows class instead of global variable, so that it can be accessed using controller.database inside MainPage class:
class windows(tk.Tk):
def __init__(self, *args, **kwargs):
...
self.database = None
...
def command_open():
...
self.database = filename
return self.database
...
...
...
class MainPage(tk.Frame):
def __init__(self, parent, controller):
...
def savetodb():
...
with open(controller.database, "w") as f:
...
...
...
Note that you have to change all occurrences of database to self.database inside windows class.

How do I reinitialize a frame before I raise it in tkinter?

I have a problem regarding updating frames in tkinter. When I am in the Search frame, I update a file with some information, and then switch frames to the ShowSearch class. However, when the mainloop runs for the first time, it runs and initializes all the classes, so that my ShowSearch frame will display information in the file from the previous run of the program. My question is if there is a way for me to send data to the file storeSearch.txt, and then when I have called controller.show_frame(ShowSearch), my ShowSearch class will reinitialize and retrieve the data from the file storeSearch.txt and then display it. I only need help with reinitializing/updating the class since I already have written the code that retrieves the data from the file and displays it in my ShowSearch class.
import tkinter as tk
import Projekt_KTH_GUI as PK
import functools
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(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 (Homescreen, Menuscreen, Create, ShowUpcoming, ShowAll, OpenList, Search, Edit, ShowSearch):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky = "nsew")
self.show_frame(Homescreen)
def show_frame(self, container):
frame = self.frames[container]
frame.tkraise()
class Search(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
tk.Label(self, text = "Sök efter packningslista", font = ("Times new Roman", 30)).place(x = 110, y = 0)
self.objectList = PK.main()
self.search = tk.StringVar()
tk.Label(self, text = "Var god mata in ditt sökord:").place(x = 150, y = 100)
search = tk.Entry(self, textvariable = self.search, width = 40).place(x = 60, y = 120)
search_button = tk.Button(self, text = "Enter", command = self.getList).place(x = 430, y = 122.5)
menuButton = tk.Button(self, text = "Meny", command = lambda: self.controller.show_frame(Menuscreen)).place(x = 100, y = 300)
def getList(self):
searchWord = self.search.get()
objectList = self.objectList
objectList = PK.search(objectList, searchWord)
PK.filesUpdate(objectList, "storeSearch.txt")
return self.controller.show_frame(ShowSearch)
I tried to use the methods .update() and .destroy(), one line before i execute frame.tkraise(), but the .update() method doesn't do anything and when I use the .destroy() method, I get an error saying _tkinter.TclError: bad window path name ".!frame.!showsearch".

How to reach and modify child class's variables from parent class when child class is one of many Tkinter frames made visible container and tkraise()

I am writing a Python GUI application with Tkinter where I have several frames that I want to manage separately. I want to put these "child" frames in separate classes (and ultimately in different files) to make the overall code more manageable. Each child class is basically a Tkinter frame with input elements. Based on selections from the main GUI, the relevant child class frame is shown. This is achieved using container and tkraise(). I want to reach child class variables from the main class but I cannot with my current code which is given below. I believe there is a problem with the initialization of child classes and/or the inheritance scheme of my app.
What is the correct way to structure a Python application in a setting where you have child classes being shown with container and tkraise() scheme and you want to reach child class variables form the main class? I appreciate your help.
import tkinter as tk
from tkinter import ttk
import math
# Padding values.
tab_padx = (10, 0)
tab_pady = (20, 0)
# Font settings.
font_1 = ("Arial", 13, "bold")
# Main class.
class Main_GUI(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.title("DEMO")
self.frame_blue_circle = BlueCircle(self, self)
self.frame_green_square = GreenSquare(self, self)
# Available shapes.
self.available_shapes = ["CIRCLE", "SQUARE"]
# Available colors.
self.available_colors = ["BLUE", "GREEN"]
# Function to run when color is changed.
def color_change(*args):
self.color = self.option_var_color.get()
if self.color == "BLUE" and self.shape == "CIRCLE":
self.type = "BlueCircle"
self.show_frame("BlueCircle")
elif self.color == "GREEN" and self.shape == "SQUARE":
self.show_frame("GreenSquare")
else:
self.show_frame("Unimplemented")
print(f"{self.color} {self.shape}")
# Function to run when shape is changed.
def shape_change(*args):
self.shape = self.option_var_shape.get()
if self.color == "BLUE" and self.shape == "CIRCLE":
self.show_frame("BlueCircle")
elif self.color == "GREEN" and self.shape == "SQUARE":
self.show_frame("GreenSquare")
else:
self.show_frame("Unimplemented")
print(f"{self.color} {self.shape}")
#GUI tabs
self.nb = ttk.Notebook(self)
self.nb.grid(row=1, column=0, sticky="w", padx=10, pady=10)
#GUI tab1 - Type selection.
self.tab1 = tk.Frame(self.nb)
self.nb.add(self.tab1, text="Type")
#GUI tab2 - Unput for selected type.
self.tab2 = tk.Frame(self.nb)
self.nb.add(self.tab2, text="Input")
#GUI tab3 - Calculate result for selected type with its specific inputs.
self.tab3 = tk.Frame(self.nb)
self.nb.add(self.tab3, text="Result")
# Tab-1 types.
# Shapes.
self.Label_shape = tk.Label(self.tab1, text = "Shape: ", font=font_1)
self.Label_shape.grid(row=10, column=0, padx=tab_padx, pady=tab_pady, sticky="W")
# Setup variable for disk type dropdown menu.
self.option_var_shape= tk.StringVar()
self.option_var_shape.set(self.available_shapes[0])
self.option_var_shape.trace("w", shape_change)
self.shape = self.option_var_shape.get()
self.shape_dropdown_menu = tk.OptionMenu(self.tab1, self.option_var_shape, *self.available_shapes)
self.shape_dropdown_menu.grid(row=10, column=1, sticky="WE", padx=tab_padx, pady=tab_pady)
self.shape_dropdown_menu.config(font=font_1, width=20)
self.shape_dropdown_menu["menu"].config(font=font_1)
# Colors.
self.Label_color = tk.Label(self.tab1, text = "Color: ", font=font_1)
self.Label_color.grid(row=20, column=0, padx=tab_padx, pady=tab_pady, sticky="W")
# Setup variable for disk type dropdown menu.
self.option_var_color= tk.StringVar()
self.option_var_color.set(self.available_colors[0])
self.option_var_color.trace("w", color_change)
self.color = self.option_var_color.get()
self.color_dropdown_menu = tk.OptionMenu(self.tab1, self.option_var_color, *self.available_colors)
self.color_dropdown_menu.grid(row=20, column=1, sticky="WE", padx=tab_padx, pady=tab_pady)
self.color_dropdown_menu.config(font=font_1, width=20)
self.color_dropdown_menu["menu"].config(font=font_1)
# Tab-2. Show frame based on selection in Tab-1.
# Container for frames.
container = tk.Frame(self.tab2)
container.grid(row=0, column=0)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (BlueCircle, GreenSquare, Unimplemented):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("BlueCircle")
# Tab-3. Calculate and display result based on Tab-1 and Tab-2.
# Label to display result.
result_text = "Result will be displayed here."
self.Label_result = tk.Label(self.tab3, text = result_text, font=font_1, fg="RED")
self.Label_result.grid(row=10, column=0, padx=tab_padx, pady=tab_pady, sticky="W")
self.button = tk.Button(self.tab3, text=f"Print", command=self.print_info)
self.button.grid(row=20, column=0, sticky="W")
# print(self.Label_result)
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
def print_info(self):
bc_text = f"Blue circle radius: {self.frame_blue_circle.radius}"
print(bc_text)
# Class defining GUI for BlueCircle.
class BlueCircle(tk.Frame):
def __init__(self, parent, controller, *args, **kwargs):
super().__init__(*args, **kwargs)
self.parent = parent
self.radius = 0
# Function to run when rim radius is changed.
def Entry_change(*args):
value = self.Entry_var_radius.get()
if value == "":
self.Entry_var_radius.set(".0")
else:
try:
self.radius = float(value)
print(self.radius)
except ValueError:
self.Entry_var_radius.set("")
print(f"Warning! Floating point number only!")
tk.Frame.__init__(self, parent)
self.controller = controller
self.label = tk.Label(self, text="Blue Circle", font=font_1, fg="BLUE")
self.label.grid(row=0, column=0)
self.label = tk.Label(self, text="Radius:")
self.label.grid(row=1, column=0)
# Setup variable for entry to use in callback trace.
self.Entry_var_radius = tk.StringVar()
self.Entry_var_radius.trace("w", lambda name, index, mode, sv=self.Entry_var_radius: Entry_change(self.Entry_var_radius))
# Entry.
self.Entry_radius = tk.Entry(self, font=font_1, textvariable=self.Entry_var_radius)
self.Entry_radius.grid(row=1, column=1)
self.radius = self.Entry_radius.get()
# Class defining GUI for GreenSquare.
class GreenSquare(tk.Frame):
def __init__(self, parent, controller):
super().__init__()
self.parent = parent
# Function to run when rim radius is changed.
def Entry_change(*args):
value = self.Entry_var_lenght.get()
if value == "":
self.Entry_var_lenght.set(".0")
else:
try:
self.lenght = float(value)
self.green_square_area = self.lenght**2
# print(f"Side lenght: {self.lenght}. Area: {self.green_square_area:.2f}")
except ValueError:
self.Entry_var_lenght.set("")
print(f"Warning! Floating point number only!")
# Inıtialize variable.
self.green_square_area = 0
tk.Frame.__init__(self, parent)
self.controller = controller
self.label = tk.Label(self, text="Green Squire", font=font_1, fg="GREEN")
self.label.grid(row=0, column=0)
self.label = tk.Label(self, text="Side lenght:")
self.label.grid(row=1, column=0)
# Setup variable for entry to use in callback trace.
self.Entry_var_lenght = tk.StringVar()
self.Entry_var_lenght.trace("w", lambda name, index, mode, sv=self.Entry_var_lenght: Entry_change(self.Entry_var_lenght))
# Entry.
self.lenght = tk.Entry(self, font=font_1, textvariable=self.Entry_var_lenght)
self.lenght.grid(row=1, column=1)
self.lenght = self.Entry_var_lenght.get()
# Class defining GUI for unimplemented options.
class Unimplemented(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.label = tk.Label(self, text="To be implemented...", font=font_1, fg="RED")
self.label.grid(row=0, column=0)
if __name__ == "__main__":
app = Main_GUI()
app.mainloop()
Note that self.frame_blue_circle is not the instance of BlueCircle shown inside the notebook, so self.frame_blue_circle.radius is not the one input inside the "Input" tab.
The correct instance should be self.frames['BlueCircle'], so you need to use self.frames['BlueCircle'].radius instead:
def print_info(self):
bc_text = f"Blue circle radius: {self.frames['BlueCircle'].radius}"
print(bc_text)
In your __init__() method you have: self.frame_blue_circle = BlueCircle(self, self). This means that anywhere in your Main_GUI class (I mean typically other methods) you can access this and then its radius attribute.
In fact, you already do this here:
def print_info(self):
bc_text = f"Blue circle radius: {self.frame_blue_circle.radius}"
print(bc_text)

Python - Inheritance from a Tk class

I'm trying to create a modular class ( for some gui buttons ).
CoreButton should consist of most methods for a common button, including tk frame.
Goal is to inheret CoreButton - and to use its frame to build rest of button's GUI - it does not appear.
any help will be appriciated
class CoreButton(ttk.Frame):
def __init__(self, master,nickname, hw_in=[], hw_out=[],ip_in='', ip_out='', sched_vector=[]):
ttk.Frame.__init__(self, master)
self.master = master
if ip_in == '': ip_in = ip_out # in case remote input is not defined
self.grid()
#####Rest of code
and class that inherits:
class ToggleBut2(CoreButton):
def __init__(self, master, hw_in=[], hw_out=[],ip_in='', ip_out='', sched_vector=[]):
CoreButton.__init__(self, master, nickname="JOHM", hw_in=hw_in, hw_out=hw_out, ip_in=ip_in, ip_out=ip_out, sched_vector=sched_vector)
self.master = master
def build_gui(self, nickname='babe', height=3, width=13):
self.button = tk.Checkbutton(self, text=nickname, variable=self.but_var, indicatoron=0, height=height, width=width, command=self.sf_button_press)
self.button.grid(row=0, column=0)
I don't know what you try to do but I would do something like this
I don't use self.grid() inside class, so outside class I can use tb1.pack() or tb1.grid() depends on which layout manager I use in window.
In __init__ I execute self.build_gui() so I don't have to do it manually, but now all classes have to create self.build_gui() without arguments.
I add Label only for test - to display "selected"/"not selected". You don't need it.
import tkinter as tk
from tkinter import ttk
class CoreButton(ttk.Frame):
def __init__(self, master, nickname, hw_in=None, hw_out=None, ip_in=None, ip_out=None, sched_vector=None):
ttk.Frame.__init__(self, master)
self.nickname = nickname
self.hw_in = hw_in
if self.hw_in is None:
self.hw_in = []
#self.hw_in = hw_in or []
self.hw_out = hw_out
if self.hw_out is None:
self.hw_out = []
#self.hw_out = hw_out or []
self.ip_out = ip_out
self.ip_in = ip_in
if self.ip_in is None:
self.ip_in = self.ip_out # in case remote input is not defined
#self.ip_in = hw_in or self.ip_out
self.sched_vector = sched_vector
if sched_vector is None:
sched_vector = []
#self.sched_vector = sched_vector or []
self.build_gui() # <--- to build it automatically
def build_gui(self):
# you will overide it in child widgets
raise NotImplementedError('You have to override method build_gui()')
class ToggleBut2(CoreButton):
def __init__(self, master, hw_in=None, hw_out=None, ip_in=None, ip_out=None, sched_vector=None, height=3, width=13):
self.height = height
self.width = width
# `self.but_var` is used in `build_gui` so it has to be created before `__init__` which executes `build_gui`
# or create it directly in `build_gui`
#self.but_var = tk.StringVar()
CoreButton.__init__(self, master, "JOHM", hw_in, hw_out, ip_in, ip_out, sched_vector)
def build_gui(self, nickname='babe'):
self.but_var = tk.IntVar()
self.button = tk.Checkbutton(self, text=self.nickname, variable=self.but_var, indicatoron=0, height=self.height, width=self.width, command=self.sf_button_press)
self.button.grid(row=0, column=0)
self.label = tk.Label(self, text='[not selected]')
self.label.grid(row=1, column=0)
def sf_button_press(self):
print(self.but_var.get())
if self.but_var.get() == 0:
self.label['text'] = '[ not selected ]'
else:
self.label['text'] = '[ selected ]'
# --- main ---
root = tk.Tk()
tb1 = ToggleBut2(root, height=1, width=10)
tb1.pack()
tb2 = ToggleBut2(root, height=3, width=30)
tb2.pack()
tb2 = ToggleBut2(root, height=5, width=50)
tb2.pack()
root.mainloop()

Tkinter does not show one frame

I am trying to make a GUI for my program but I have changed my code a lot and I saw that GUI misses one frame but it was fine before.
Could anyone help me and tell why a frame with a button does not appear on the bottom?
Whole "button_part" object does not appear.
from tkinter import *
import tkinter as tk
import os
import glob
BOUNDS = ["Last week", "Last 2 weeks", "Last 3 weeks"]
class settings_part:
path_to_copy = 0
def __init__(self, master, update_func):
path_to_copy = StringVar()
settings_frame = Frame(master, background="")
settings_frame.pack(side=TOP, fill=X)
date_bound = StringVar()
date_bound.set(BOUNDS[1])
date_option = OptionMenu(settings_frame, date_bound, *BOUNDS, command=update_func)
date_option.config(background="#732c30")
date_option.config(foreground="white")
date_option.config(bd=0)
date_option.pack(side=LEFT, padx=5, pady=5)
path_to_copy.set("~/Python/usun")
box_with_path = Entry(settings_frame, textvariable=path_to_copy)
box_with_path.pack(side=RIGHT, padx=5, pady=5)
# s = path_to_copy.get()
class songs_part:
def __init__(self, master, root):
self.songs_frame = Frame(master)
self.update_songs(root.list_of_songs)
self.songs_frame.pack()
def update_songs(self, l):
for song in l:
c = Checkbutton(self.songs_frame, text=song[0], variable=song[1])
c.pack()
class button_part:
def __init__(self, master, copyFunc):
self.button_frame = Frame(master)
btn_image = PhotoImage(file="copybtn.png")
self.copy_button = Button(self.button_frame, command=copyFunc, text="Copy",
image=btn_image, highlightthickness=0, bd=0, activebackground="#732c30")
self.copy_button.pack()
class App:
def __init__(self):
root = Tk()
root.title("Copying songs")
root.geometry("500x500")
root.option_add("*Font", "Calibra")
back_image = PhotoImage(file="back.png")
self.window = Label(root, image=back_image)
self.window.pack(fill="both", expand="yes")
self.list_of_songs = list()
self.make_list_of_songs()
self.set_part = settings_part(self.window, self.update_list)
self.son_part = songs_part(self.window, self)
self.but_part = button_part(self.window, self.copy_songs)
root.mainloop()
def make_list_of_songs(self):
owd = os.getcwd()
os.chdir("/home/stanek/Music/usun")
for file in glob.glob("*.mp3"):
self.list_of_songs.append([file, tk.IntVar()])
os.chdir(owd)
def copy_songs(self):
for s in self.list_of_songs:
print(s)
def update_list(self, arg):
print("updating list with songs from " + arg)
self.son_part = songs_part(self.window, self)
if __name__ == '__main__':
App()
You never pack the button frame.

Categories