Getters in python, tkinter - python

I need access to information from my class "makeEntry" precisely textvariables. I tried make get function but i read that in python it's not necessary.
def temp():
print(e_full_name.get_text())
class makeEnetry:
def __init__(self, i_parent, i_width, i_row, i_column, i_text):
test.set(i_text)
test = StringVar()
entry = Entry(master = i_parent, width = i_width, textvariable = test)
entry.grid(row = i_row, column = i_column, padx = 5, pady =5 )
def get_text(self):
return self.test.get()
I tried to move my test = StringVar() above function, just in class to refer to it in another function but it doesn't work. I'm newbie in python and I have no idea what I have done wrong.
def temp():
print(e_full_name.get_text())
class makeEnetry:
test = StringVar()
def __init__(self, i_parent, i_width, i_row, i_column, i_text):
test.set(i_text)
.
.
.

I have written a working solution. As I mentioned in my comment, the test variable should be an instance variable (self). I have added several comments to my example code for the better understanding.
Code:
import tkinter as tk
def temp():
print(entry_inst.get_text()) # Printing the result of "get_text" method of "entry_inst" object.
root = tk.Tk()
class makeEnetry:
def __init__(self, i_parent, i_width, i_row, i_column, i_text):
self.test = tk.StringVar()
self.test.set(i_text)
entry = tk.Entry(master=i_parent, width=i_width, textvariable=self.test)
entry.grid(row=i_row, column=i_column, padx=5, pady=5)
def get_text(self):
return self.test.get()
entry_inst = makeEnetry(root, 20, 1, 1, "TEST") # Creating an object from "makeEnetry" class
button = tk.Button(root, text="PUSH ME", command=temp) # Creating a button which will call the "temp" function
button.grid(row=2, column=1)
tk.mainloop()
GUI:
Console output:
FYI: I have changed the text in the entry box and clicked to button.
>>> python3 test.py
TEST
TEST1
TEST12
TEST123

Any variable that you want external functions to have access to need to be a instance variable.
For example, if you do self.test = StringVar(), and use self.test everywhere inside the class instead of just test, then any code that has a reference to the instance of the class can access the variable.
the_entry = makeEnetry(root, 20, 1, 1, "Hello, world!")
...
print(the_entry.test.get())
However, there's nothing wrong with creating a getter or setter. For example, StringVar has a getter (.get()) and setter (.set(...)). The advantage of creating getters and setters is that it separates the internal implementation from the external interface. With a getter or setter, you can hide the fact that you're using a StringVar, the caller doesn't need to know.
The thing with functions, instance variables, and with getters and setters, is that you are creating a user interface or API. You are creating an object and then telling the outside world "this is how you interact with this object". Sometimes getters and setters make sense, sometimes they don't. It depends on what you want the object UI/API to be, and whether or not you want to expose internal implementation details to the outside world.
In this specific case it seems like the_entry.get_text() is a cleaner interface than the_entry.test.get(...) since it gives you more freedom in changing the internal implementation without affecting code that uses this object. It all boils down to how you want external code to interact with the object you've created. Should the caller know that this object uses a StringVar, or should it just know that it can call get_text to interact with it?

Related

Unable to access a variable in a function which belongs to other function of same class

I am creating a GUI with tkinter in python.I am trying to access a variable in a function which belongs to other function in same class.Getting Frame2 object has no attribute self.workingarea.The error comes from tools function.I am trying to access self.workingarea from projectwindow function in tools function.line no:28
class Frame2:
def __init__(self,root):
self.list=["label","Button","Entry","Text","Frame","RadioButton","Checkbutton","Canvas","LabelFrame","Notebook","ScaleWidget"]
self.w2=root
self.w2.state('zoomed')
self.w2.title("IDE")
self.w2.configure(background="white")
self.tools()
self.projectwindow()
#=============
def projectwindow(self):
self.workingarea=Tk()
self.workingarea.geometry('930x660+5+25')
self.workingarea.mainloop()
#================
def tools(self):
self.prop=ttk.Notebook(self.w2,width=self.w2.winfo_screenwidth()-int(self.w2.winfo_screenwidth()*0.7),height=self.w2.winfo_screenheight())
self.prop.place(x=self.w2.winfo_screenwidth()-int(self.w2.winfo_screenwidth()*0.3),y=0)
self.widgets=Frame(self.prop,bg="white")
self.root_properties=Frame(self.prop,bg="white")
self.properties=Frame(self.prop)
self.prop.add(self.widgets,text='Widgets',compound=TOP)
self.prop.add(self.root_properties,text='Root Window Properties',compound=TOP)
self.prop.add(self.properties,text='Properties',compound=TOP)
#=========
self.widget_section=LabelFrame(self.widgets,text='TK Widgets',padx=5,pady=15,bg='white')
self.widget_section.place(x=10,y=10)
self.obj=labels(self.workingarea,self.properties)
for self.i in range(11):
self.btn_widgets=Button(self.widget_section,text=self.list[self.i], borderwidth=2, relief="groove",width=33,font=("",14,""),command=self.obj.label)
self.btn_widgets.grid(row=self.i,column=0,pady=2)
The error is thrown as self.workingarea is not initialized.
Interchange calls to self.tools() and self.projectwindow() in the __init__ function.
TIP - Do not use 2 mainloop in the same thread. Rather use TopLevel widget

How to execute a class method from another class with the method passed a parameter in Python

I'm a beginner in learning python..
I'm looking for help in solving an OOP problem
My main program has something simplified like below:
class abc(Frame):
def _init_(self, master)
Frame.__init__(self)
self.B1 = Mybutton(self.master, self.cmd)
def cmd(self):
print("hello world")
In the main program, I import Mybutton class in another file, which is simplified as below:
class Mybutton():
def _init_(self, parent, command):
self.command = command
def A_ramdom_fcn(self):
...
self.command() ------------------>> here I want to execute the command
in class abc, not in class Mybutton.
How to execute a method from another class that is passed as an instance method, you may ask why not just execute it in class abc, but I have event attached to button press, it needs to do a roundabout to achieve this..
First, fix the typos: missing : in abc's init method, and it should be __init__ (with two underscores) for both classes.
It seems like you've gotten yourself turned around. You've set things up correctly using composition: an abc has a Mybutton, and it looks like you correctly pass the function to Mybutton so that it can execute it. In fact, your code will work as written if you do, for example
a = abc(master) # no context for what master is, but I assume you have it
a.B1.A_ramdom_fcn()
With the way you've set things up, you don't want to import and make instances of Mybutton in your main program (what abc would they belong to?). You want to import and make instances of abc. You then access their internal Mybutton like I've shown in the example above. This works because when you pass self.cmd to the Mybutton constructor while inside the abc constructor, it's already a bound method of the abc you're constructing.
As an addendum, it looks like you might be having an XY problem with regards to why you need such a roundabout method. Is there any reason why you can't simply pass abc.cmd to the button press handler?
Theoretically, what you are trying is possible, you can capture the object method into variable and call it later (python 3):
class Window:
def __init__(self):
self.my_button = Mybutton(self.cmd)
def cmd(self):
print("hello world")
class Mybutton:
def __init__(self, command):
self.command = command
def a_ramdom_fcn(self):
self.command.__call__()
win = Window()
win.my_button.a_ramdom_fcn()
I assume you are trying to make the generic Button class which doesn't know what to do when it's clicked and you want to put the actual logic into your Window class.
That makes sense, but it would be even better to extract the logic into the third, Command class. This allows us to limit the Window responsibility and also avoid the trick with method-as-variable (the command we pass to the button object is just another object):
class HelloWorldCommand:
def execute(self):
print("Hello world")
class Window:
def __init__(self):
self.my_button = Mybutton(
HelloWorldCommand()
)
class Mybutton:
def __init__(self, command):
self.command = command
def a_ramdom_fcn(self):
self.command.execute()
win = Window()
win.my_button.a_ramdom_fcn()

Python - tkinter - How to capture bind function

from tkinter import StringVar, messagebox, Entry, Tk
def accept(event):
acceptInput=messagebox.askquestion("Input Assessment","do you accept this input?")
return acceptInput
window=Tk()
userInput=StringVar()
e=Entry(window,textvariable=userInput)
e.pack()
e.bind('<Return>',accept)
window.mainloop()
My question is: How do I capture the returned value of the accept function?
I've tried:
e.bind('<Return>',a=accept.get())
and
a=e.bind('<Return>',accept).get()
bound functions don't "return". Your callback needs to set a global variable or call some other function. For example:
def accept(event):
global acceptInput
acceptInput=messagebox.askquestion("Input Assessment","do you accept this input?")
... or ...
def accept(event):
acceptInput=messagebox.askquestion("Input Assessment", "do you accept this input?")
do_something(acceptInput)
It is up to you to define what you want to do in do_something (eg: write the data to disk, show an error, play a song, etc), or how you want to use the global variable in some other function.
Generally speaking, these things are easiest to accomplish if pieces of your application are instances of a class -- Then accept can just set an attribute on the class. In this case, you might want to bind that functionality up in the Entry:
class AcceptEntry(Entry):
def __init__(self, *args, **kwargs):
Entry.__init__(self, *args, **kwargs)
self.bind('<Return>', self.accept)
self.acceptInput = None
def accept(self, event):
self.acceptInput = messagebox.askquestion("Input Assessment",
"do you accept this input?")
For the function bind, the <Return> doesn't mean the return of a function. Instead, it does mean the event "Enter key" that is pressed by the user.
So, if you like to get the response from the messagebox, then you have do it with other ways. Possibly using with another StringVar() option with your messagebox, or using any global variable.

Tkinter entry widget get is undefined, not updating to my main function,

i'm following a few different guides to re-learn Tkinter by writing a little application that grabs stock prices. My issue that I am up a wall against is calling the .get() method from my entry widget variable. I've seen a couple other suggestions to put all the widget creating inside a function and then call the function in the init method, however I'm getting the same error, even when using the self argument in front of my entry variables. I know it's an issue with the way i'm passing data from function to function, but I can't wrap my head around it. Here's the code, sorry for the wall of text:
class MyApp:
def __init__(self, parent):
self.myParent = parent
self.myContainer1 = Frame(parent)
self.myContainer1.pack()
self.createWidgets()
button1 = Button(self.myContainer1, command = self.button1Click)
button1.configure(text = "get quote")
button1.pack()
def createWidgets(self):
root.title("Stock App")
self.symbol = Entry(self.myContainer1)
self.symbol.pack()
self.symbol.focus_set()
def button1Click(self):
stock = symbol.get()
print stock
I've taken it down to simplest form even and just had the button1Click call a callback function-
def button1Click(self):
print callback()
def callback():
print symbol.get()
This returns the exact same error:
NameError: global name 'symbol' is not defined
Is it getting destroyed too early? how do I fix this?
I've referenced multiple documents for tkinter and have seen some great fixes but none are extensible, or um unable to see how they relate to me using it inside of an object.
Thanks in advance for the help.
As far as I can tell inside of your button1Click method you need to add self as in:
def callback():
print self.symbol.get()
You're missing self. to make the callback:
def callback():
print self.symbol.get()
instead.

Python Attribute Error with multiple classes and Tkinter

I'm trying create a gui using Tkinter that grabs a username and password and connects to a remote server and does a function. I slapped together some messy code and it more or less worked, but when I tried to recreate it in a tidy module, it broke. Its probably a newbie python error, but I can't spot it. EDIT: to clarify, when it worked, the only class was setupGui and any methods were under that class. Now that I've separated the gui from the methods, its not working.
class setupGui(object):
def __init__(self, parent):
##omited general frame stuff
self.userIn = ttk.Entry(self.topFrame, width = 20)
self.userIn.grid(row = 1, column = 1)
self.passIn = ttk.Entry(self.topFrame, width = 20, show ="*")
self.passIn.grid(row = 2, column = 1)
#Buttons
self.setupbtn = ttk.Button(self.topFrame, text = "Start Setup", command = setup().startSetup())
self.setupbtn.grid(row = 3, column = 0, pady = 10)
class setup(object):
def__init__(self):
self.userName = setupGui.userIn.get()
self.userPass = setupGui.passIn.get()
def startSetup(self):
self.another_related_fucntion # about 4 related functions actually
if __name__ == '__main__':
root = Tk()
gui = setupGui(root)
root.mainloop()
And if I don't have the command attached to the button, everything works fine (but obviously does diddly squat except look pretty). And when I attached the command, I get this error:
Traceback (most recent call last):
File "macSetup.py", line 211, in <module>
gui = setupGui(root)
File "macSetup.py", line 45, in __init__
self.setupbtn = ttk.Button(self.topFrame, text = "Start Setup", command = setup().startSetup())
File "macSetup.py", line 69, in __init__
self.userName = setupGui.userIn.get()
AttributeError: type object 'setupGui' has no attribute 'userIn'
In your code, userIn is set up as an instance variable of setupGui objects, not as an attribute of the setupGui class itself.
The simplest solution would be to merge the setupGui and setup classes to move startSetup in as a method of setupGui, then use command=self.startSetup when you initialize setupbtn—this calls startSetup as a bound method, and self should thus refer to the setupGui object, which you can then use e.g. self.userIn.get() and self.passIn.get() on.
If you'd rather keep the logic you have in the setup class out of the setupGui class, you can separate it out like this:
class setup(object):
def __init__(self, username, userpass):
self.userName = username
self.userPass = userpass
def startSetup(self):
# as before
then add this method to the setupGui class:
def dosetup(self):
setup(self.userIn.get(), self.passIn.get()).startSetup()
and instantiate the Button with command=self.dosetup. (I would personally make the setup class a standalone function, but I don't know how complicated your startSetup routine actually is, so I assume you have a good reason for making it a class.)
The command attribute takes a reference to a function, but you're calling the function and giving the result to the command attribute. The net result is that you're calling the setup function at the time that you create the button, not at the time that you click the button. Things aren't fully initialized yet, so you get the error.
You're doing this:
self.setupbtn = ttk.Button(self.topFrame, text = "Start Setup", command = setup().startSetup())
... when you should be doing something like this:
self.setupbtn = ttk.Button(self.topFrame, text = "Start Setup", command = setup().startSetup)
Note the lack of the trailing () on startSetup.
If you don't want to instantiate setup until the button is clicked, you have a couple of choices. The best, arguably, is to create a method:
def _launch_setup(self):
setup().setupGui()
...
self.setupbtn = ttk.Button(..., command=self._launch_setup)
You could also use a lambda, but in this case I recommend a named method.
The class setupGui itself doesn't have the attribute userIn.
In the __init__ method of setupGui you give the attribute to the instance, not the class.

Categories

Resources