I have the following code:
class Test:
def __init__(self, master): # master is a Tk or Toplevel instance
self.master, self.typeFrame = master, tk.Frame(master)
self.typeVar = tk.StringVar(self.typeFrame)
for column, wordType in enumerate(['Noun', 'Verb', 'Adjective', 'Adverb'], 1):
typeRadioButton = tk.Radiobutton(self.typeFrame, text = wordType, textvariable = self.typeVar, value = wordType, command = self.createLambda(wordType))
typeRadioButton.grid(row = 1, column = column)
self.typeFrame.grid()
def createLambda(self, obj):
return lambda: self.changeInfo(obj)
def changeInfo(self, obj):
pass # this will do something later
However, when I run the code like this, the Radiobuttons have no text associated with them.
root = tk.Tk()
test_instance = Test(root)
test_instance.master.mainloop()
How can I fix this? Thanks in advance!
Change textvariable=... to variable=....
BTW, your example does not contain self.typeFrame.pack() or self.typeFrame.grid(..).
Related
I'm trying to program a application that carries over user inputs from one page to the other where the pages are separated by classes. A problem I'm having is that the array output on page 2 isn't updating. Basically the output is just [] which is just the starting initialized variable. I've tried some solutions I've found on stack overflow such as calling it a global variable again at the init bit of the PageTwo class as well as trying to use PageOne.overall_data and using self.overall_data but the problem persists although there weren't any errors. This is a part of the code before I tried anything. I tried to cut out the irrelevant bits but I'm not sure if I cut out too much, feedback is much appreciated. Thanks for reading!
import tkinter as tk
import tkinter_nav as tknav
from tkinter import ttk
import numpy as np
class App(tknav.Wrapper):
def __init__(self):
tknav.Wrapper.__init__(
self,
pages=[PageOne, PageTwo],
start_state={'previous_page': None}
)
self.geometry('450x450')
self.show_page('page_one')
class PageOne(tknav.Page):
def __init__(self, parent):
tknav.Page.__init__(self, parent, 'page_one')
player_details = []
global overall_data
overall_data = []
my_notebook = ttk.Notebook(self)
my_notebook.pack(pady = 15)
my_notebook.pack(fill="both", expand=True)
my_frame1 = tk.Frame(my_notebook, width = "500", height = "500")
def submit(): #called every time inputs are made to be appended to player_details then overall_data
player_details = []
global overall_data
player_details.append(name.get())
player_details.append(health.get())
player_details.append(ac.get())
player_details.append(initiative.get())
overall_data.append(player_details)
overall_data = sorted(overall_data, key = lambda x:x[3])
print(str(overall_data))
class PageTwo(tknav.Page): #second page of the application
def __init__(self, parent):
tknav.Page.__init__(self, parent, 'page_two')
tk.Label(
self,
text='Page Two'
).pack()
tk.Button(
self,
text='Navigate to Page One',
command=lambda: self.__navigate(),
).pack()
line21 = tk.Label(self, text = str(overall_data), font = ('Times New Roman', 12))
line21.place(x = 30, y = 30, width = 100, height = 25)
def __navigate(self):
print('navigating to page one')
self.navigate('page_one')
if __name__ == '__main__':
App().mainloop()
You can put your data at the class level in PageOne like this:
class PageOne(tknav.Page):
overall_data = []
and use it everywhere like this:
PageOne.overall_data.append(player_details)
Since you have used tkinter_nav, you can use its provided app_state to share data between pages:
class App(tknav.Wrapper):
def __init__(self):
tknav.Wrapper.__init__(
self,
pages=[PageOne, PageTwo],
start_state={'previous_page': None, 'overall_data': []} # added 'overall_data'
)
self.geometry('450x450')
self.show_page('page_one')
Then you can access this shared data in each page by:
self.app_state['overall_data']
I'm trying to avoid to multiply functions in code by using
def Return_Label(self,number)
with a parameter.
Any Idea how to use string in order to define variable name usable to .set value to StringVar()?
Example code below:
import tkinter as tk
from tkinter import *
class WINDOW():
def __init__(self):
self.Settings_Window()
def Settings_Window(self):
self.settings_window = tk.Tk()
self.settings_window.minsize(200,200)
self.entry = Entry(self.settings_window)
self.entry.pack()
self.entry2 = Entry(self.settings_window)
self.entry2.pack()
self.label1input = StringVar()
self.label = Label(self.settings_window,textvariable=self.label1input, bg='yellow')
self.label.pack(expand='yes',fill='x')
self.label2input = StringVar()
self.label2 = Label(self.settings_window, textvariable=self.label2input, bg='yellow')
self.label2.pack(expand='yes', fill='x')
self.button = Button(self.settings_window,text='SETUP1',command=self.Next)
self.button.pack()
self.button2 = Button(self.settings_window,text='SETUP2',command=self.Next2)
self.button2.pack()
self.settings_window.mainloop()
def Next(self):
self.number=1
self.Return_Label(self.number)
def Next2(self):
self.number=2
self.Return_Label(self.number)
def Return_Label(self,number):
self.entry_field_value = self.entry.get()
print(self.entry_field_value)
#self.label1input.set(self.entry_field_value)
setattr(self,'label'+str(number)+'input.set',self.entry_field_value)
window=WINDOW()
I prefer a list approach to managing multiple entry fields and updating values.
By using list you can use the index value to manage the labels as well :D.
See the below example of how you can use list to deal with all the values and updates.
import tkinter as tk
from tkinter import *
class Window(tk.Tk):
def __init__(self):
super().__init__()
self.minsize(200, 200)
self.entry_list = []
self.label_list = []
entry_count = 2
for i in range(entry_count):
self.entry_list.append(Entry(self))
self.entry_list[i].pack()
for i in range(entry_count):
self.label_list.append(Label(self,bg='yellow'))
self.label_list[i].pack(expand='yes', fill='x')
Button(self, text='SETUP', command=self.Return_Label).pack()
def Return_Label(self):
for ndex, lbl in enumerate(self.label_list):
lbl.config(text=self.entry_list[ndex].get())
if __name__ == '__main__':
Window().mainloop()
Create lists of objects rather than individual attributes for each object. For example,
import tkinter as tk
from tkinter import *
class Window:
def __init__(self):
self.settings_window()
def Settings_Window(self):
self.settings_window = tk.Tk()
self.settings_window.minsize(200,200)
self.entries = [
Entry(self.settings_window),
Entry(self.settings_window)
]
for e in self.entries:
e.pack()
self.labelinputs = [
StringVar(),
StringVar()
]
self.labels = [
Label(self.settings_window, textvariable=label, bg='yellow')
for label in self.labelinputs
]
for l in self.labels:
l.pack(expand='yes', fill='x')
self.buttons = [
Button(self.settings_window,text='SETUP1',command=lambda: self.return_label(0))
Button(self.settings_window,text='SETUP2',command=lambda: self.return_label(1))
]
for b in self.buttons:
b.pack()
self.settings_window.mainloop()
def return_label(self,number):
entry_field_value = self.entry.get()
self.labelsinput[number].set(entry_field_value)
window=WINDOW()
Dynamicly computing variable names should be avoided at all costs. They are difficult to do correctly, and it makes your code hard to understand, hard to maintain, and hard to debug.
Instead, store the widgets in a dictionary or list. For example:
def __init___(self):
...
self.vars = {}
...
self.vars[1] = StringVar()
self.vars[2] = StringVar()
...
def Return_Label(self,number):
self.entry_field_value = self.entry.get()
var = self.vars[number]
var.set(self.entry_field_value)
Though, you really don't need to use StringVar at all -- they usually just add extra overhead without providing any extra value. You can save the labels instead of the variables, and call configure on the labels
self.labels[1] = Label(...)
...
self.labels[number].configure(text=self.entry_field_value)
#___________________________________________________________
def open_files(self):
file_name_list = []
FM_file_name_list = []
RG_file_name_list = []
path = easygui.fileopenbox(multiple=True)
#print(path)
for i in range(len(path)):
file_name_list.append(path[i])
filename, file_extension = os.path.splitext(path[i])
#print (file_extension)
if file_extension == '.FDV':
FM_file_name_list.append(os.path.basename(path[i]))
if file_extension == '.R':
RG_file_name_list.append(os.path.basename(path[i]))
class GraphPage(tk.Frame):
def __init__(self, parent, controller):
self.controller=controller
tk.Frame.__init__(self, parent)
self.FM_List_Box =tk.Listbox(self)
self.FM_List_Box.config(highlightbackground='steelblue', highlightthickness = 1)
self.FM_List_Box.pack(side=tk.LEFT, fill=tk.Y, padx = 5)
I'm trying to get the values within the list 'FM_file_name_list' into the list box 'self.FM_List_Box'. The method 'open_files' is contained within the menu bar of the application in a different class, so the list box has been initially created before it is run.
It would be greatly appreciated if some could help me understand how you can update the values of a list box from a method in a different class.
This is relatively simple.
You simply need to call the class's variable from the other class.
This can be done something like the below:
from tkinter import *
class OtherClass:
def __init__(self):
OtherClass.list = ["1", "2", "3"]
class App:
def __init__(self, root):
self.root = root
self.listbox = Listbox(self.root)
self.listbox.pack()
for i in OtherClass.list:
self.listbox.insert(END, i)
OtherClass()
root = Tk()
App(root)
root.mainloop()
So here we have a class OtherClass which contains a list OtherClass.list. We can then access this list from our App class by calling OtherClass.list.
If you run the program you will see that we are successfully able to pull the list from one class to the other.
If i want an entry box in Tkinter that only accepts floating point numbers that are greater than or equal to 0.0 and less than or equal to 1.0 how would i do that?
The proper way it to use tkinter's validate capabilities. But it's really a PIA to use.
dsgdfg has a good answer, but I can make that a lot neater, robust, and more dynamic:
import Tkinter as tk
class LimitedFloatEntry(tk.Entry):
'''A new type of Entry widget that allows you to set limits on the entry'''
def __init__(self, master=None, **kwargs):
self.var = tk.StringVar(master, 0)
self.var.trace('w', self.validate)
self.get = self.var.get
self.from_ = kwargs.pop('from_', 0)
self.to = kwargs.pop('to', 1)
self.old_value = 0
tk.Entry.__init__(self, master, textvariable=self.var, **kwargs)
def validate(self, *args):
try:
value = self.get()
# special case allows for an empty entry box
if value not in ('', '-') and not self.from_ <= float(value) <= self.to:
raise ValueError
self.old_value = value
except ValueError:
self.set(self.old_value)
def set(self, value):
self.delete(0, tk.END)
self.insert(0, str(value))
You use it just like an Entry widget, except now you have 'from_' and 'to' arguments to set the allowable range:
root = tk.Tk()
e1 = LimitedFloatEntry(root, from_=-2, to=5)
e1.pack()
root.mainloop()
If you want to call a button to check whether, this is a way to do it.
from tkinter import *
class GUI():
def __init__(self, root):
self.Entry_i = Entry(root, bd = 5)
self.test = StringVar()
Label_i = Label(root, textvariable = self.test)
Button_i = Button(root, text = "Go", command = self.floatornot)
self.Entry_i.grid()
Label_i.grid()
Button_i.grid()
mainloop()
def floatornot(self):
test = self.Entry_i.get()
if float(test) < 0 or float(test) > 1:
self.test.set("Good")
else:
self.test.set("")
root = Tk()
GUI(root)
The button will call the floatornot function. This will get the value of the entry and check if it okay or not. Depending on the result the value of the label will be changed.
I am currently building a user based system, where I have a class for a login screen in pythons tkinter. Once the user information is correct it will initiate a class for the menu. I'm using an SQL database which python reads and checks user information with. I'm going to need the username of the user to be passed to the menu class so the class knows what information to display on that menu.
from tkinter import *
class Login:
def __init__(self, master):
self.master = master
self.label = Label(self.master, text = "enter name")
self.entry = Entry(self.master)
self.button = Button(self.master, text = "submit", command = self.loadMenu)
self.label.grid(row = 0, column = 0)
self.entry.grid(row = 0, column = 1)
self.button.grid(row = 1, column = 0, columnspan = 2)
self.name = self.entry.get()
def loadMenu(self):
self.menu = Toplevel(self.master)
self.app = Menu(self.menu)
class Menu:
def __init__(self, master):
self.master = master
self.label = Label(self.master, text = "dave")
self.label.grid(row = 0, column = 0)
def main():
root = Tk()
run = Login(root)
root.mainloop()
if __name__ == '__main__':
main()
In the above example code, what method could be used to pass the variable 'self.name' to class menu so that it can be displayed in a label? I am trying not to use a global variable. Many Thanks.
Your class Menu, needs a method to set the name. e.g.:
class myMenu:
def __init__(self,...):
....
def set_Me(self,some_name):
self.some_name = some_name
# or
self.label.setName(some_name)
in the main program you call:
self.app.set_Me(self.name)
The above is pseudo code. But you should get the idea.
This technique you can use to pass variables to any class at any time.
If you need to pass variable only once:
class my_class:
def __init__(self,my_variable):
self.my_variable = my_variable