I am constructing a simple hex editor in Python using Tkinter. I want to be able to indicate selection of a value (the "0000"s) in the GUI by changing the colors of a pressed button.
To implement this, I instantiated each button as a class inside a for loop and put each instance into a list to reference them later in the code. When I attempt to alter the Button API properties of the classes in the while loop, the IDLE prints an error when the hex editor is closed:
Traceback (most recent call last):
File "C:/Users/Administrator/Desktop/Files/Python/hex editor.py", line 64, in <module>
ml.button.configure(bg='#00FF00', fg='#000000')
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\tkinter\__init__.py", line 1479, in configure
return self._configure('configure', cnf, kw)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\tkinter\__init__.py", line 1470, in _configure
self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
_tkinter.TclError: invalid command name ".!frame.!frame.!button"
The intended behavior of the button is that when any "0000" is clicked, the selected button will become green and remain so until another button is pressed. (i.e the pressed button will turn green and the previously selected button will turn black)
Source Code:
from tkinter import *
selected_i = 0
selected_j = 0
data_w = 16
address_w = 8
class mem_location:
def __init__(self, row, column, data):
self.row = row
self.column = column
self.data = data
self.button = Button(subframe,
text=self.data,
font=('Consolas',9),
bd=0,
command=self.select)
self.button.pack(side=LEFT)
self.button.configure(bg='#000000', fg='#00FF00')
def select(self):
selected_i = self.row
selected_j = self.column
root = Tk()
root.configure(bg="black")
root.title('Hex Editor')
frame = Frame(root,
padx=30,
pady=10,
bg='black')
frame.pack()
ml_list = []
for i in range((1<<address_w)>>4):
subframe = Frame(frame,
padx=10,
bg='black')
subframe.pack()
addr_label = Label(subframe,
text=hex(i<<4)+" ",
bg='black',
fg='#00FF00',
width=5)
addr_label.pack(side = LEFT)
for j in range(16):
ml_list.append(mem_location(i, j, '0000'))
root.mainloop()
while True:
for ml in ml_list:
if selected_i == ml.row and selected_j == ml.column:
ml.button.configure(bg='#00FF00', fg='#000000')
else:
ml.button.configure(bg='#000000', fg='#00FF00')
I am currently in the process of learning about Tkinter. Why can't I modify the class's Button configuration and how can this be fixed?
The code after root.mainloop will not run until the window is not closed, so you are trying to modify the buttons after the window has been closed.
Instead, you could move the code in the submit method like this:
from tkinter import *
# You don’t need selected_i and selected_j anymore
data_w = 16
address_w = 8
class MemLocation:
def __init__(self, data):
# Same code without self.row and self.column
def select(self):
for ml in [ml_ for ml_ in ml_list if ml_ is not self]: # All elements except this one
ml.button.config(bg='#000', fg='#0F0')
self.button.config(bg='#0F0', fg='#000')
# Same code here
root.mainloop()
#END
Note that I renamed the class according to PEP 8 but there are many other improvement possible like making MemLocation inherit from Frame or Button, or adding event listeners to make the code cleaner.
Related
I am learning python.I follow the book example code. This code make SumGrid class in order to be attachable to containers where other widgets are being gridded or packed. The author said that it leaves its own geometry management ambiguous and requires callers to pack or grid its instances. It's OK for containers to pick either scheme for their own children because they effectively seal off the pack-or-grid choice. But attachable component classes that aim to be reused under both geometry managers cannot manage themselves because they cannot predict their parent's policy.
from tkinter import *
from tkinter.filedialog import askopenfilename
from PP4E.Gui.Tour.quitter import Quitter # reuse, pack, and grid
class SumGrid(Frame):
def __init__(self, parent=None, numrow=5, numcol=5):
Frame.__init__(self, parent)
self.numrow = numrow # I am a frame container
self.numcol = numcol # caller packs or grids me
self.makeWidgets(numrow, numcol) # else only usable one way
def makeWidgets(self, numrow, numcol):
self.rows = []
for i in range(numrow):
cols = []
for j in range(numcol):
ent = Entry(self, relief=RIDGE)
ent.grid(row=i+1, column=j, sticky=NSEW)
ent.insert(END, '%d.%d' % (i, j))
cols.append(ent)
self.rows.append(cols)
self.sums = []
for i in range(numcol):
lab = Label(self, text='?', relief=SUNKEN)
lab.grid(row=numrow+1, column=i, sticky=NSEW)
self.sums.append(lab)
Button(self, text='Sum', command=self.onSum).grid(row=0, column=0)
Button(self, text='Print', command=self.onPrint).grid(row=0, column=1)
Button(self, text='Clear', command=self.onClear).grid(row=0, column=2)
Button(self, text='Load', command=self.onLoad).grid(row=0, column=3)
Quitter(self).grid(row=0, column=4) # fails: Quitter(self).pack()
def onPrint(self):
for row in self.rows:
for col in row:
print(col.get(), end=' ')
print()
print()
def onSum(self):
tots = [0] * self.numcol
for i in range(self.numcol):
for j in range(self.numrow):
tots[i] += eval(self.rows[j][i].get()) # sum current data
for i in range(self.numcol):
self.sums[i].config(text=str(tots[i]))
def onClear(self):
for row in self.rows:
for col in row:
col.delete('0', END) # delete content
col.insert(END, '0.0') # preserve display
for sum in self.sums:
sum.config(text='?')
def onLoad(self):
file = askopenfilename()
if file:
for row in self.rows:
for col in row: col.grid_forget() # erase current gui
for sum in self.sums:
sum.grid_forget()
filelines = open(file, 'r').readlines() # load file data
self.numrow = len(filelines) # resize to data
self.numcol = len(filelines[0].split())
self.makeWidgets(self.numrow, self.numcol)
for (row, line) in enumerate(filelines): # load into gui
fields = line.split()
for col in range(self.numcol):
self.rows[row][col].delete('0', END)
self.rows[row][col].insert(END, fields[col])
if __name__ == '__main__':
import sys
root = Tk()
root.title('Summer Grid')
if len(sys.argv) != 3:
SumGrid(root).pack() # .grid() works here too
else:
rows, cols = eval(sys.argv[1]), eval(sys.argv[2])
SumGrid(root, rows, cols).pack()
root.mainloop()
When I run this .py file in my window shell. It can't work. The err message like below. I think SumGrid is a Frame. The caller can decide to pack or grid this Frame. But it can't work on my computer. Why? Thank you.
Traceback (most recent call last):
File "C:\Users\hp\PP4E-Examples-1.4\Examples\PP4E\Gui\Tour\Grid\grid5c.py", line 84, in <module>
SumGrid(root).pack() # .grid() works here too
File "C:\Users\hp\PP4E-Examples-1.4\Examples\PP4E\Gui\Tour\Grid\grid5c.py", line 12, in __init__
self.makeWidgets(numrow, numcol) # else only usable one way
File "C:\Users\hp\PP4E-Examples-1.4\Examples\PP4E\Gui\Tour\Grid\grid5c.py", line 35, in makeWidgets
Quitter(self).grid(row=0, column=4) # fails: Quitter(self).pack()
File "C:\Users\hp\PP4E-Examples-1.4\Examples\PP4E\Gui\Tour\quitter.py", line 12, in __init__
self.pack()
File "C:\Users\hp\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 2425, in pack_configure
self.tk.call(
_tkinter.TclError: cannot use geometry manager pack inside .!sumgrid which already has slaves managed by grid
Like the error says, you can't use both grid and pack on widgets that have the same parent.
Let's look at these two lines of code:
Button(self, text='Load', command=self.onLoad).grid(row=0, column=3)
Quitter(self).grid(row=0, column=4) # fails: Quitter(self).pack()
Notice how both Quitter and Button are using self as the parent. That means that you must only use one of grid or pack for both widgets (and the other widgets that have self as the parent). If you use grid for the button, you cannot use pack for Quitter, which is exactly what the error is telling you.
I have a python script for teachers that works very well on my terminal and I'm trying to use Tkinter so I can share this script with other people. In the script, the user uploads a file and other information to an SQLite database.
Below is part of the script that shows just the content for the 1st tab (of 3). The problem is that when people interact with the database the tab needs to get refreshed to show something has happened and that the list of files in the database has changed.
Everything I've read shows you need a button to refresh. But that is not user-friendly. What people want to do is upload a file and then see that file in the list. Is this possible with Tkinter and if so how?
class AppWindow():
my_list = [4]
def __init__(self, parent):
global my_list
# Create the window
self.window = parent
self.window.geometry("700x600")
#self.center_window()
self.window.title("Test app")
# Create a text label and place it in the window
self.hello_label = tk.Label(self.window, text="Hello world!")
self.hello_label.place(x=20, y=20)
# Create 3 tabs
self.tab_container = tk.Frame(self.window)
self.tab_container.place(x=0,y=0,width=700,height=400)
self.tabs = ttk.Notebook(self.tab_container)
self.tab_2 = tk.Frame(self.tabs)
self.tabs.add(self.tab_2, text="Parameters")
self.tabs.place(x=0,y=0,height=400,width=700)
# Content for tab 2
self.label2 = tk.Label(self.tab_2, text="")
self.label201=tk.Label(self.tab_2, text="Put in your target GPA")
self.label201.place(x=50, y=50)
btn1 = tk.Button(self.tab_2,text="Target GPA", command=self.getGPA)
btn1.place(x=50, y=80)
for lst in self.my_list:
btn99=tk.Button(self.tab_2,text=lst)
btn99.grid()
def getGPA(self):
userInput = sd.askstring('User Input','Enter target GPA')
self.my_list.append(userInput)
if __name__ == "__main__":
root = tk.Tk()
app = AppWindow(root)
root.mainloop()
This is merely a guess because of the all the reasons I've already mentioned in comments under your question. Generally speaking, to update or what you call "refresh" a tab requires adding, changing, or deleting the widgets you put on it.
The code below is based what's currently in your code. Every time the Target GP button is clicked another Button is added to the self.tab_2 frame as well as appended to my_list. Changing the widgets doesn't have to be triggered by clicking on a button, it could be the result of some other event (such as the completion of a file upload in the background for example).
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.simpledialog as sd
class AppWindow():
def __init__(self, parent):
# Create the window
self.window = parent
self.window.geometry("700x600")
#self.center_window()
self.window.title("Test app")
# Create and initialize data list.
self.my_list = [4]
# Create a text label and place it in the window
self.hello_label = tk.Label(self.window, text="Hello world!")
self.hello_label.place(x=20, y=20)
# Create 3 tabs
self.tab_container = tk.Frame(self.window)
self.tab_container.place(x=0, y=0, width=700, height=400)
self.tabs = ttk.Notebook(self.tab_container)
self.tab_2 = tk.Frame(self.tabs)
self.tabs.add(self.tab_2, text="Parameters")
self.tabs.place(x=0, y=0, height=400, width=700)
# Content for tab 2
self.label201 = tk.Label(self.tab_2, text="Put in your target GPA")
self.label201.place(x=50, y=50)
btn1 = tk.Button(self.tab_2, text="Target GPA", command=self.getGPA)
btn1.place(x=50, y=80)
# Create a Button for each item currently in list.
for item in self.my_list:
btn = tk.Button(self.tab_2, text=item)
btn.grid()
def getGPA(self):
userInput = sd.askstring('User Input', 'Enter target GPA')
if userInput is None: # User closed the dialog or clicked Cancel?
return
self.my_list.append(userInput)
btn = tk.Button(self.tab_2, text=userInput) # Create another Button.
btn.grid()
if __name__ == "__main__":
root = tk.Tk()
app = AppWindow(root)
root.mainloop()
I try find solution in google but all solution in google not work for me maybe here I get The correct answer.
I have this code:
from tkinter import *
class gui_main:
def __init__(self):
self.win_about = Tk() #creat new windows
self.win_about.title("About software") # Get title to new windows -> "About software"
self.win_about.geometry("400x120+600+200") # Get size to window
self.win_about.resizable(width=False, height=False) # Off option Increase / decrease window
lab = Label(self.win_about, text="""
welcome to app
For Enter to app click on button Next.
""", justify='center') # Create new text in the window
lab.place(x=-18, y=-11) # Position of text in window (x - up/down , y - left/right)
btn_next = Button(self.win_about, text="Next", fg="red", command=gui_main.screen_menu()) # Create new button
btn_next.place(x=350, y=90) # Position of button in window (x - up/down , y - left/right)
btn_exit = Button(self.win_about, text="Exit", fg="red", command=self.win_about.destroy) # Create new button
btn_exit.place(x=10, y=90) # Position of button in window (x - up/down , y - left/right)
self.win_about.mainloop() # Run the cod in loop
def screen_menu(self):
self.win_menu = Tk()
self.win_menu.title("Menu")
self.win_menu.geometry("500x500+400+400")
self.win_about.destroy()
self.win_menu.mainloop()
if __name__ == "__main__":
g = gui_main()
g.win_about()
And I get this Error:
Traceback (most recent call last): File "location file", line 42, in
g = gui_main() File "location file", line 26, in init
btn_next = Button(self.win_about, text="Next", fg="red", command=gui_main.screen_menu()) # Create new button TypeError: screen_menu() missing 1 required positional argument: 'self'
Ty for help, I will hope find any solution
the problem is you should use self instead of class name apart from that i prefer and many people prefer to use lambda methods in command=. inside class you have to call each methods and variables with self. in order to work inside class.
apart from that i made few changes in your code also.
you don't need to call g.about_screen()
since you running mainloop() inside def __init__(self): method. because its already running when you are initializing the class object here g = class_name();.
here is the code
from tkinter import *
class gui_main:
def __init__(self):
self.win_about = Tk() #creat new windows
self.win_about.title("About software") # Get title to new windows -> "About software"
self.win_about.geometry("400x120+600+200") # Get size to window
self.win_about.resizable(width=False, height=False) # Off option Increase / decrease window
lab = Label(self.win_about, text="""
welcome to app
For Enter to app click on button Next.
""", justify='center') # Create new text in the window
lab.place(x=-18, y=-11) # Position of text in window (x - up/down , y - left/right)
btn_next = Button(self.win_about, text="Next", fg="red", command=lambda:self.screen_menu()) # Create new button
btn_next.place(x=350, y=90) # Position of button in window (x - up/down , y - left/right)
btn_exit = Button(self.win_about, text="Exit", fg="red", command=lambda:self.quit()) # Create new button
btn_exit.place(x=10, y=90) # Position of button in window (x - up/down , y - left/right)
self.win_about.mainloop() # Run the cod in loop
def quit(self):
self.win_about.quit()
def screen_menu(self):
self.win_menu = Tk()
self.win_menu.title("Menu")
self.win_menu.geometry("500x500+400+400")
# self.win_about.destroy()
self.win_menu.mainloop()
if __name__ == "__main__":
g = gui_main()
Remove the parenthesis from the Button command and refer to self instead of gui_main
btn_next = Button(self.win_about, text="Next", fg="red", command=self.screen_menu) # Create new button
You want to pass the callable itself, not the return value of gui_main.screen_menu
I am trying to bind this function self.copyTextToClipboard(self,t) to multiple different trees to make it more flexible (please see binding below).
from tkinter.ttk import Treeview
from tkinter import *
class App:
def __init__(self, master):
self.master = master
frame = Frame(master)
master.geometry("{}x{}".format(master.winfo_screenwidth() - 100, master.winfo_screenheight() - 100))
master.resizable(False, False)
self.leftFrame = Frame(master, bg="#DADADA", width=375, relief=SUNKEN)
self.leftFrame.pack_propagate(0)
self.leftFrame.pack(side=LEFT, fill=Y, padx=1)
# This table (TreeView) will display the partitions in the tab
self.partitionsOpenDiskTree = Treeview(self.leftFrame, columns=("#"), show="headings", selectmode="browse", height=23)
yscrollB = Scrollbar(self.leftFrame)
yscrollB.pack(side=RIGHT, fill=Y)
self.partitionsOpenDiskTree.column("#", width=50)
self.partitionsOpenDiskTree.heading("#", text="#")
self.partitionsOpenDiskTree.configure(yscrollcommand=yscrollB.set)
# Bind left click on text widget to copy_text_to_clipboard() function
self.partitionsOpenDiskTree.bind("<ButtonRelease-1>", lambda t=self.partitionsOpenDiskTree: self.copyTextToClipboard(self,t))
# Adding the entries to the TreeView
for i in range(3):
self.partitionsOpenDiskTree.insert("", "end", i, values=(i), tags=str(i))
self.partitionsOpenDiskTree.pack(anchor=NW, fill=Y)
#todo: figure out where this is getting called and put in tree
def copyTextToClipboard(self, tree, event=None):
print(type(tree))
# triggered off left button click on text_field
root.clipboard_clear() # clear clipboard contents
textList = tree.item(tree.focus())["values"]
line = ""
for text in textList:
if line != "":
line += ", " + str(text)
else:
line += str(text)
root.clipboard_append(line) # append new value to clipbaord
root = Tk()
app = App(root)
root.mainloop()
However, I am unable to bind it to a TreeView object it seems; when I run the code, I get:
Exception in Tkinter callback
<class '__main__.App'>
Traceback (most recent call last):
File "C:\Users\user1\Anaconda3\lib\tkinter\__init__.py", line 1699, in __call__
return self.func(*args)
File "C:/Users/user1/main_merged.py", line 56, in <lambda>
lambda t=self.partitionsOpenDiskTree: self.copyTextToClipboard(self,t))
File "C:/Users/user1/main_merged.py", line 70, in copyTextToClipboard
textList = tree.item(tree.focus())["values"]
AttributeError: 'App' object has no attribute 'item'
If I try to print out tree type, I get that it's a not a TreeView object. Any ideas on how I can get a TreeView object, so that I can figure out which item was selected?
Thanks!
-FF
So, apparently, taking out the self call seemed to work:
from tkinter.ttk import Treeview
from tkinter import *
class App:
def __init__(self, master):
self.master = master
frame = Frame(master)
master.geometry("{}x{}".format(master.winfo_screenwidth() - 100, master.winfo_screenheight() - 100))
master.resizable(False, False)
self.leftFrame = Frame(master, bg="#DADADA", width=375, relief=SUNKEN)
self.leftFrame.pack_propagate(0)
self.leftFrame.pack(side=LEFT, fill=Y, padx=1)
# This table (TreeView) will display the partitions in the tab
self.partitionsOpenDiskTree = Treeview(self.leftFrame, columns=("#"), show="headings", selectmode="browse", height=23)
yscrollB = Scrollbar(self.leftFrame)
yscrollB.pack(side=RIGHT, fill=Y)
self.partitionsOpenDiskTree.column("#", width=50)
self.partitionsOpenDiskTree.heading("#", text="#")
self.partitionsOpenDiskTree.configure(yscrollcommand=yscrollB.set)
# Bind left click on text widget to copy_text_to_clipboard() function
self.partitionsOpenDiskTree.bind("<ButtonRelease-1>", lambda event, t=self.partitionsOpenDiskTree: self.copyTextToClipboard(t))
# Adding the entries to the TreeView
for i in range(3):
self.partitionsOpenDiskTree.insert("", "end", i, values=(i), tags=str(i))
self.partitionsOpenDiskTree.pack(anchor=NW, fill=Y)
#todo: figure out where this is getting called and put in tree
def copyTextToClipboard(self, tree, event=None):
print(type(tree))
# print(type(tree.partitionsOpenDiskTree))
# triggered off left button click on text_field
root.clipboard_clear() # clear clipboard contents
textList = tree.item(tree.focus())["values"]
line = ""
for text in textList:
if line != "":
line += ", " + str(text)
else:
line += str(text)
root.clipboard_append(line) # append new value to clipbaord
print(line)
root = Tk()
app = App(root)
root.mainloop()
Output:
0
When you use bind, the callback function must have an event as its first argument, custom arguments should be put after. But as your callback does not need the event parameters, you may mask it with your lambda. So you have to change both the binding and the def of your callback:
self.partitionsOpenDiskTree.bind("<ButtonRelease-1>", lambda event, t=self.partitionsOpenDiskTree: self.copyTextToClipboard(t))
...
def copyTextToClipboard(self, tree):
should solve the problem
I'm a complete newbie. I started last week with python in which I'm trying to create a functional GUI. This gui will make use of multiple tab's using ttk notebook. However, I'm experiencing a problem regarding to adding multiple listboxes in my programm. I do have a working listbox, in "tab11". But, whenever I try to add a simple listbox it won't render when I run the program. The shell however supplies me with an error, I don't have any clue what the problem is.
The error I get is:
Traceback (most recent call last):
File "/Users/nielsschreuders/Documents/01_TUe_B32_Feb13_Jun13/Project/Concept/prototype/python/RaspberryBackup/B32Project/PythonExperiments/multipleListboxTest.py", line 133, in <module>
listbox2 = tk.Listbox(tab12, width=50, height=-1)
File "/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/tkinter/__init__.py", line 2608, in __init__
Widget.__init__(self, master, 'listbox', cnf, kw)
File "/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/tkinter/__init__.py", line 2075, in __init__
(widgetName, self._w) + extra + self._options(cnf))
_tkinter.TclError: can't invoke "listbox" command: application has been destroyed
This is a simplefied version of the code:
import tkinter as tk
#import RPi.GPIO as gpio
import sys
import os
from tkinter import ttk
mGui = tk.Tk()
mGui.geometry('800x480')
mGui.title("Apps on Wheels")
nb = ttk.Notebook(mGui, name="notebook")
nb.pack(fill=tk.BOTH, expand=tk.Y, padx=2, pady=3)
dispColor="Yellow"
#create tabs
tab1 = ttk.Frame(nb, name="audioTab")
#assign tabs to notebook children
nb.add(tab1, text="Audio")
nbAS = ttk.Notebook(tab1, name="audioSource")
nbAS.pack(pady=100)
#nbAS.pack(fill=tk.BOTH, expand=tk.Y, padx=2, pady=3)
tab11 = ttk.Frame(nbAS, name="radioTab")
tab12 = ttk.Frame(nbAS, name="mp3Tab")
nbAS.add(tab11, text="Radio")
nbAS.add(tab12, text="MP3")
##################Radio Controller###################
def get_list(event):
#get selected line index
index = listbox1.curselection()[0]
#get the line's text
seltext=listbox1.get(index)
#delete previous text in enter1
enter1.delete(0, 50)
#display selected text
enter1.insert(0, "You are listening to: " +seltext)
intIndex = int(index)
intRadioFreq = intIndex +1
radioFreq = str(intRadioFreq)
os.system("mpc play " + radioFreq)
def set_list(event):
try:
index = listbox1.curselection()[0]
#delete old listbox line
listbox1.delete(index)
except IndexError:
index = tk.END
#insert edited item back into listbox1 at index
listbox1.insert(index, enter1.get())
def sort_list():
temp_list = list(listbox1.get(0, tk.END))
temp_list.sort(key=str.lower)
#delete contents of present listbox
listbox1.delete(0, tk.END)
for item in temp_list:
listbox1.insert(tk.END, item)
def save_list():
#get a list of listbox lines
temp_list = list(listbox1.get(0, tk.END))
#add a trailing newline char to each line
temp_list=[radio + '\n' for radio in temp_list]
#give the file new name
fout = open("radio_data2.txt", "w")
fout.writelines(temp_list)
fout.close()
#create the data file
str1 = """Radio 1
Radio 2
3FM Serious Radio
538 Radio
Radio 6 Soul & Jazz
"""
fout = open("radio_data.txt", "w")
fout.write(str1)
fout.close()
fin = open("radio_data.txt", "r")
radio_list= fin.readlines()
fin.close()
radio_list= [radio.rstrip() for radio in radio_list]
RadioFrequencies = tab11
#creat listbox
listbox1 = tk.Listbox(RadioFrequencies , width=50, height=-1)
listbox1.grid(row=0, column=0)
#use entry widget to display/edit selection
enter1 = tk.Entry(RadioFrequencies , width=44, bg=dispColor, fg="black", justify=tk.CENTER, font=("Arial" ,16, "bold"))
#enter1.insert(0, "Choose your radio station")
enter1.grid(row=1, column=0)
for item in radio_list:
listbox1.insert(tk.END, item)
listbox1.bind("<ButtonRelease-1>", get_list)
RadioFrequencies.mainloop()
listbox2 = tk.Listbox(tab12, width=50, height=-1)
listbox2.place(x=100, y=150)
listbox2.insert(tk.END, "entry here")
for item2 in ["one", "two", "three", "four"]:
listbox2.insert(tk.END, item2)
mGui.mainloop()
Your program calls mainloop() in two places:
RadioFrequencies.mainloop()
...
mGui.mainloop()
Generally speaking, a Tkinter app should call mainloop only once, and it is usually the tk.Tk() instance that makes the call. Once the call is made, the program hands over the flow of control to the Tkinter event loop which manages all the GUI events.
Usually the call to mainloop() would therefore be the last call in the script. When the GUI is exited, the script exits as well.
So remove the line
RadioFrequencies.mainloop()
The reason you are getting the error
_tkinter.TclError: can't invoke "listbox" command: application has been destroyed
is because after you close the GUI, Python returns from
RadioFrequencies.mainloop()
and then tries to call
listbox2 = tk.Listbox(tab12, width=50, height=-1)
but by this point the application has already ended.