from tkinter import *
class MainBattle(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
global canvas
self.parent.title('Python')
self.pack(fill = BOTH, expand = 1)
canvas = Canvas(self)
self.Label_My = Label(self, text = 'MyObject')
self.Label_My.place(x = 470, y = 35)
canvas.pack(fill = BOTH, expand = 1)
canvas.update()
def aa(self):
self.Label_My['text'] = 'HisObject'
def Change():
Label_My['text'] = 'HisObject'
root = Tk()
ex = MainBattle(root)
root.geometry('700x500')
it should use global method?
I would defind labels inside the class and change it's text outside class if possible.
You don't need global variables. You have a reference to the instance, which allows you to access all instance variables:
ex.Label_My["text"] = "HisObject"
If your question is "can I use global to set variable values from outside the class" then yes.
Whenever you want to change the value of a global variable you need to write global.
def changetext():
global label_text
label_text = "new text"
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.
I am starting to learn OOP and I've been struggling with some basic stuff.
In the code below, I have created a class Scales() that I want to use to create 2 very similar scales, with only their variable option being different.
How can I pass the name of these variables as a parameter when I call Scales() and make both of them a DoubleVar type?
from tkinter import *
from tkinter import ttk
from PIL import Image, ImageTk
import numpy as np
class Scales(Frame):
def __init__(self, parent, variable_name, label_text, initial_value,
final_value):
self.parent = parent
self.bar_length = 200
self.variable_name = variable_name
self.label_text = label_text
self.initial_value = initial_value
self.final_value = final_value
# self.variable_name = DoubleVar()
self.scale_name = Scale(self.parent, variable=self.variable_name,
orient=HORIZONTAL,
from_=self.initial_value,
to=self.final_value,
length=self.bar_length, cursor="hand",
label=self.label_text)
class MainApplication(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.slice_number_scale = Scales(self.parent, slice_number,
"Slice Number", 1, 24)
if __name__ == '__main__':
root = Tk()
root.geometry("800x600")
MainApplication(root)
root.mainloop()
If the variables are going to live as instance variables of your Scales class, then there's absolutely no reason to give them separate names; every reference to them is going to be in the context of some particular instance. You'd probably want to define a get() method that does something like return self.variable.get(), for the convenience of the class's user.
If the variables live somewhere outside the class, then Scales should not care what their names are; pass the variable itself as a parameter to the class constructor, and pass it on as the variable= option to Scale().
Just create the variables in each Scale class instance that is created, then access them through the instance's name. Here's what I mean:
from tkinter import *
#from tkinter import ttk
#from PIL import Image, ImageTk
#import numpy as np
class Scale(Frame):
""" Dummy version of class for testing and illustration. """
def __init__(self, parent, orient=None, from_=None, to=None, length=None,
cursor=None, label=None):
Frame.__init__(self, parent) # initialize base class
self.variable = DoubleVar() # create variable and make attribute
class Scales(Frame):
def __init__(self, parent, label_text, initial_value,
final_value):
self.parent = parent
self.bar_length = 200
# self.variable_name = variable_name
self.label_text = label_text
self.initial_value = initial_value
self.final_value = final_value
# self.variable_name = DoubleVar()
self.scale1 = Scale(self.parent,
# variable=self.variable_name,
orient=HORIZONTAL,
from_=self.initial_value,
to=self.final_value,
length=self.bar_length,
cursor="hand",
label=self.label_text)
self.scale1.pack()
class MainApplication(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
slice_number = 42
self.slice_number_scale = Scales(self.parent, slice_number, 1, 24)
root = Tk()
app = MainApplication(root)
app.mainloop()
After doing this you can access the variable for each Scale instance within a Scales instance as self.scale1.variable (and self.scale2.variable after you add it). Within the MainApplication instance they can be referred to as self.slice_number_scale.scale1.variable (and self.slice_number_scale2.variable).
For the latter you might want to add methods to class MainApplication to make such references more succinct, such as:
class MainApplication(Frame):
....
def get_scale_var1(self):
return self.slice_number_scale.scale1.variable.get()
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