I'm quite new to Python and have a problem which I can't solve.
I want to write a Class which displays a configuration file (dict) in a tkinter frame. It should choose a tk.widged by type of value and for bool values create checkboxes, and for int and strings it should create entries.
After all it should give back a dict with the same keys, but the values changed to tk.*Var()
However, with the checkboxes there is no problem.
But the int and strings from the entries will not be written through the save_config() function.
It seems the tk.IntVar() and the tk.StringVar() don't update when typing something in the entries.
Hope my question is clear.
Can anybody please help?
code updated like asked by Bryan Oakley:
It also contains the changes suggested by Martin Finke which brings the solution for me!!
#!/usr/bin/env python3.9
import tkinter as tk
from tkinter import ttk
class MainFrame(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self)
self.test_dict = {"name": "Ares"}
self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=0)
self.save_config_button = ttk.Button(
self, text="Print Configuration", command=self.save_config)
self.save_config_button.grid(row=0, column=0, padx=5, pady=5)
self.configuration_frame = ConfigurationFrame
self.config_frame = self.configuration_frame(
self, "Configurations", self.test_dict)
self.config_frame.grid(row=1, column=0, padx=5, pady=5)
self.configuration = self.config_frame.get_configuration()
def save_config(self):
conf = {}
for key, value in self.configuration.items():
conf[key] = value.get()
print(conf)
class ConfigurationFrame(tk.LabelFrame):
def __init__(self, parent, widget_name, config, * args, **kwargs):
tk.LabelFrame.__init__(
self, parent, * args, **kwargs)
self.config(bd=2, text=widget_name)
self.grid(sticky=tk.NSEW)
self.configuration = {}
self.rowconfigure(0, weight=0)
self.columnconfigure(0, weight=1)
count = 0
for key, value in config.items():
if type(value) == str:
name = key
entry_text = tk.StringVar(self)
entry_text.set(value)
frame_label = tk.Frame(
self, height=1)
frame_label.grid(
row=count, column=0, padx=10, pady=2, sticky=tk.W)
self.entry_str = ttk.Entry(
frame_label, textvariable=entry_text, text=name, width=10)
self.entry_str.grid(row=0, column=0, padx=5,
pady=2, sticky=tk.W)
self.entry_str.insert(tk.END, str(value))
self.name_label = tk.Label(
frame_label, text=name)
self.name_label.grid(row=0, column=1, padx=5,
pady=2, sticky=tk.W)
self.configuration[name] = self.entry_str
count += 1
def get_configuration(self):
return self.configuration
def main():
MainFrame().mainloop()
if __name__ == "__main__":
main()
Thanks to enyone!
I suggest a simple change in the __ init __ function of the ConfigurationFrame class:
line self.configuration[name] = entry_int_txt replace self.configuration[name] = self.entry_int
line self.configuration[name] = entry_text replace self.configuration[name] = self.entry_str
Related
I have built my first few scripts with a nice little GUI on them, as the tutorials have shown me, but none of them address what to do for a little more complex program.
I want to print the values entered in InputPage in second_page.when I try to run my program every frame is getting ready even before entering my input.Here I tried to print the first entry in second_page frame by using a variable named "alpha" .How can I deal with this?
from tkinter import *
from tkinter import ttk
LARGE_FRONT=("Verdana",12)
class simmulator(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 (InputPage,second_page):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(InputPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
def get_page(self, page_class):
return self.frames[page_class]
class InputPage(Frame):
def __init__(self, parent, controller):
self.controller = controller
Frame.__init__(self,parent)
label = Label(self, text="simmulator",font=LARGE_FRONT)
label.grid(row=0, column=0, sticky ='n', columnspan =2)
# i brought your variable in the class for example sake
namesInput = ["Na:", "Nd:", "Temp(t):"]
self.entryWidgets = [] # we want to call this in another function so we assign it as self.variableName
labelWidgets = []
self.alpha = None
#LOOP TO CREATE WIDGETS
for i in range(0, len(namesInput)):
labelWidgets.append(Label(self, text = namesInput[i]))
self.entryWidgets.append(Entry(self))
labelWidgets[-1].grid(row= i+1, column =0, sticky='e')
self.entryWidgets[-1].grid(row= i+1, column = 1, sticky='w')
submit = ttk.Button(self, text = "Submit", command = lambda:[self.push_retrieve_solutions(),controller.show_frame(second_page)])
submit.grid(row = 6, column =0, columnspan =2)
def getEntries(self):
results = []
for x in self.entryWidgets: # i.e for each widget in entryWidget list
results.append(x.get())
self.alpha = results[0]
return results
def push_retrieve_solutions(self):
print(self.getEntries())
class second_page(Frame):
def __init__(self, parent, controller):
self.controller = controller
Frame.__init__(self,parent)
label = Label(self, text="Parameter",font=LARGE_FRONT)
label.grid(row=0, column=0, sticky ='n', columnspan =2)
ctrler = self.controller.get_page(InputPage)
label1 = Label(self,text = "Na =")
label1.grid(row= 1, column =1, sticky='e')
fabel1 = Label(self, text = ctrler.alpha)
fabel1.grid(row= 1, column = 2, sticky='w')
app = simmulator()
app.mainloop()
I'm trying to dynamically change the text of a label within one frame from another frame. Both frames are within an instance of an object class.
This is not my actual problem but it illustrates the principle.
How can I address app.frame0.label1.text from app.frame1.button1.click?
(I appreciate that this is not the correct syntax)
Thank you in advance.
from tkinter import *
txt = 'Hi'
def change():
# idea was to put some code here to change frame0-label1-text
pass
class HST(Tk):
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
frame0 = Frame(self)
frame0.grid(row=0, column=0)
label1 = Label(frame0, text=txt, width=20, height=5)
label1.grid(row=0, column=0)
frame1 = Frame(self)
frame1.grid(row=1, column=0)
button1 = Button(frame1, text='Click', width=20, height=5, command=change)
button1.grid(row=0, column=1)
app = HST()
app.mainloop()
Managed to solve my own problem! It is often helpful to lay out the issue to explain to someone else. Revised code using StringVar
from tkinter import *
def change():
app.txt.set('hello') # added
pass
class HST(Tk):
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
self.txt = StringVar() # added
frame0 = Frame(self)
frame0.grid(row=0, column=0)
label1 = Label(frame0, textvariable=self.txt, width=20, height=5) # changed to use StringVar
label1.grid(row=0, column=0)
frame1 = Frame(self)
frame1.grid(row=1, column=0)
button1 = Button(frame1, text='Click', width=20, height=5, command=change)
button1.grid(row=0, column=1)
app = HST()
app.txt.set('Hi') # added to replace original line txt = 'Hi'
app.mainloop()
Im just simply trying to print the values of the entry fields and it tells me its not defined. I been looking online for a long while now. The lastest thing that I tried was adding self as a parameter of add_student but that didn't work.
This is the code
from tkinter import *
class window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.widgets()
def add_student(self):
print(f"Student's name (first, last): {self.fname_textbox}, {self.lname_textbox}")
def widgets(self):
self.master.title("Student Test Score & Grade")
self.master.minsize(200,200)
""" Labels """
# First name
self.fname_label = Label(root, text='First Name: ')
self.fname_label.grid(row=0, column=0, padx=5, pady=5)
# Last Name
self.lname_label = Label(root, text='Last name: ')
self.lname_label.grid(row=1, column=0, padx=5, pady=5)
""" Entry boxes """
# First Name
self.fname_textbox = Entry(root, width=30)
self.fname_textbox.grid(row=0, column=1, padx=5)
# Last name
self.lname_textbox = Entry(root, width=30)
self.lname_textbox.grid(row=1, column=1, padx=5)
""" Buttons """
# Add Button
self.add_btn = Button(root, text="Add Student", command=self.add_student).grid(row=4, column=2, padx=2, pady=2)
if __name__=="__main__":
root = Tk()
root.resizable(width=False, height=False)
app = window(root)
root.mainloop()
It prints this
Student's name (first, last): .!entry, .!entry2
Instead of: Student's name (first, last): John, Doe
What does this mean?
You need to get the value of the entries in order to use them in your print statement
You do this by putting:
firstname = self.fname_textbox.get()
lastname = self.1fname_textbox.get()
before you print and using these values in your print statement.
Ah, Try something like this:
def __init__(self, master):
self.nameEntry = Entry(master)
self.contents = StringVar()
self.nameEntry["textvariable"]=self.contents
self.nameEntry.pack()
self.nameEntry.grid(row=0,column=1)
self.buttonSave = Button(master,text="Save",command=self.save).grid(row=9,columnspan=2, sticky=W+E+N+S)
def save(self):
print self.nameEntry.get()
This question already has answers here:
No input possible after tk
(2 answers)
Closed 4 years ago.
I'm using the following code to open a file, read its lines into a list and filter them using a substring from an Entry:
def get_entries(self):
"""
Open a file and load entries into a list.
"""
try:
# self.file_name = "p1.py"
self.file_name = askopenfilename(title="Open file")
self.file_handle = open(self.file_name, "r")
except IOError:
messagebox.showinfo("Info", "No file has been openned.")
self.destroy()
else:
self.entry_list = self.file_handle.readlines()
self.update_list()
def update_list(self, *args):
"""
Update the list after each editing of the search filter
"""
search_term = self.search_var.get()
self.lbox.delete(*self.lbox.get_children())
for index, item in enumerate(self.entry_list):
if search_term.lower() in item.lower():
self.lbox.insert('', END, values=(index, item))
Why does it work fine using self.file_name = "p1.py" but using askopenfilename() disables editing the Entry?
Minimizing and restoring the window with the Entry fixes the problem.
I'm using PyCharm on Windows 10
Here is the rest of the code for reference:
from tkinter import *
from tkinter import messagebox
from tkinter import ttk
from tkinter.filedialog import askopenfilename
class Application(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.pack()
self.file_name = ""
self.file_handle = ""
self.entry_list = None
self.search_label = Label(self, text="Filter: ")
self.search_var = StringVar()
self.search_var.trace("w", self.update_list)
self.search_entry = Entry(self, textvariable=self.search_var)
self.lbox = ttk.Treeview(self, columns=('indices', 'entries'), displaycolumns='entries', show='headings')
self.lbox.heading('entries', text="Entries", anchor="w")
self.confirm = Button(self, text="Confirm", width=10, command=self.confirm_action)
self.cancel = Button(self, text="Cancel", width=10, command=quit)
self.search_label.grid(row=0, column=0, sticky=E, padx=12, pady=5)
self.search_entry.grid(row=0, column=1, sticky=W, columnspan=4, pady=5)
self.lbox.grid(row=1, column=0, columnspan=3, sticky=(N, W, S, E), padx=12, pady=5)
self.cancel.grid(row=2, column=0, pady=5)
self.confirm.grid(row=2, column=1, sticky=W, padx=12, pady=5)
self.grid_columnconfigure(0, weight=1, uniform="u")
self.grid_columnconfigure(1, weight=1, uniform="u")
self.grid_columnconfigure(2, weight=4, uniform="u")
self.get_entries()
def get_entries(self): ...
def update_list(self, *args): ...
def confirm_action(self): ...
root = Tk()
root.title('Filter Listbox Test')
app = Application(master=root)
app.mainloop()
This seems to be a problem due to calling the askfilename before the root window is drawn. As a workaround you can add self.update() before you call askopenfilename.
class Application(Frame):
def __init__(self, master=None):
# ... stuff ...
self.update()
self.get_entries()
I'll file a bug report about this right now.
Ok so, I am building an Sqlite browser in python(3) tkinter
Here is the problem. If you look at my code
The code derived from: http://stackoverflow.com/questions/7546050/switch-between-two-frames-in-tkinter
License: http://creativecommons.org/licenses/by-sa/3.0/
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
from sqlite3 import *
import operator
file = 'chinook.db'
conn = connect(file)
c = conn.cursor()
c.execute("SELECT name FROM sqlite_master WHERE type = 'table'")
tables = c.fetchall()
tmplist = []
for i in tables:
tmplist.append(i[0])
LARGE_FONT= ("Verdana", 12)
print("done",tables)
global tabnam
tabnam = ''
def asign(sigh): #ok, yeah it was late and i didnt care much about naming convention
tabnam = sigh
#this function is supposed to assign the value given to the variable
def combine_funcs(*funcs):
def combined_func(*args, **kwargs):
for f in funcs:
f(*args, **kwargs)
return combined_func
#wrapper function
class SeaofBTCapp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "Sea of BTC Client")
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 (StartPage, PageOne):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
print("done")
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
label = ttk.Label(self, text=file, font=LARGE_FONT)
label.pack(pady=10,padx=10)
for i in tmplist:
button = ttk.Button(self, text="Visit Page " + str(i),
command=lambda:controller.show_frame(PageOne))
button.pack()
print("done")
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = ttk.Label(self, text='values', font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = ttk.Button(self, text="Back to Home",command=lambda: controller.show_frame(StartPage))
button1.pack()
try:
c.execute("select * from {y}".format(y=tabnam))
for i in c.fetchall():
label = ttk.Label(text=i[0], font=LARGE_FONT)
label.pack(pady=10,padx=20)
except Exception as e:
print(e) # the error message indicates that the string formating identifies tabnam as " "
print("done")
app = SeaofBTCapp()
print("done")
app.mainloop()
print("done")
I'm trying to iterate an sqlite query. MEANING: i made it so that for every table, tkinter creates a button. This works. Tkinter displays a button with the name of every table. Now I want this code to be able to display every value in that table when that button is clicked. I have made a wrapping function to show the frame and reassign the current value of tabnam, the variable that represents the table name clicked by the user ; When the button is clicked, I reassign the value of a global variable named tabnam . But before the the buttons are even made, python just goes ahead and executes the query (thats yet to be formatted because user hasnt clicked button) and throws me an error. How do i fix this?