I have defined a new Entry subclass: NewEntry, but it can't get the numbers which are put in it. How can I fix this?
When I click the button, the error message is showed:
ValueError: could not convert string to float:
from Tkinter import *
root = Tk()
class NewEntry(Entry):
def __init__(self,parent,cusdef='1'): #Initiation default number is '1'
Entry.__init__(self,parent)
self.cusdef = cusdef
v=StringVar()
v.set(self.cusdef)
self = Entry(self,textvariable=v)
self.pack()
return
def GetNum():
a=e.get()
print float(a)
return
e = NewEntry(root)
e.pack(fill='x')
button = Button(root,command=GetNum)
button.pack(fill='x')
root.mainloop()
You seem to be trying to initialize your Entry subclass here:
self = Entry(self,textvariable=v)
self.pack()
But instead, you're merely overwriting the variable called self and creating a new Entry which gets discarded.
Instead you need to do the Entry.__init__ call once, with the correct arguments:
class NewEntry(Entry):
def __init__(self,parent,cusdef='1'):
self.cusdef = cusdef
v=StringVar()
v.set(self.cusdef)
Entry.__init__(self,parent, textvariable=v)
self.pack()
return
Related
the code below is part of a class.
def expected_callback(self,expected_val_var,index,mode):
dictionary[self.row][3] = expected_val_var
def dataType callback(self,event):
expected_val_var = StringVar()
expected_val_var.trace("w",self.expected_callback)
expected_val = Entry(self.root, width=20, textvariable= expected_val_var)
expected_val.insert(0,"Expected value")
expected_val.grid(row=self.row,column=self.col+2)
Im trying to get a text from a tkinter entry and put it inside a dictionary but I get PY_VAR(some number) instead.
I also tried dictionary[self.row][3] = expected_val_var.widget.get() but it said that str has no get(). What can I do to get the users input from expected_val entry into the dictionary?
It is because the first argument of the callback for .trace() is the internal name (string) of the tkinter variable.
If you want to pass expected_val_var (instance of StringVar) to expected_callback(), use lambda on .trace() instead:
def expected_callback(self, expected_val_var):
dictionary[self.row][3] = expected_val_var.get()
def dataType_callback(self, event):
...
expected_val_var.trace("w", lambda *args: self.expected_callback(expected_val_var)
...
not sure, shouldn't it be
dictionary[self.row][3] = expected_val.get()
but I would rename
expected_val
to something like
entry_field
for to be clearer that it is the input
element which value is to be red
and are you sure about
deff
, I know it as
def
I am trying to use a variable that I get from an entry field in tkinter to another script.
In short:
I want to use the user's input in an entry field in another script. This does not work at all.
Any help highly appreciated!
I tried so far for Script2:
from Script1 import App
test = App()
print(test.write_slogan(self))
TypeError: init() missing 1 required positional argument: 'master'
and
from Script1 import App
print(App.write_slogan())
write_slogan() missing 1 required positional argument: 'self'
and
from Script1 import App
print(App.write_slogan(self))
NameError: name 'self' is not defined
and
import Script1
print(Script1.App.a)
AttributeError: type object 'App' has no attribute 'a'
Script1:
from tkinter import *
class App:
a = 0
def __init__(self, master):
frame = Frame(master)
frame.pack()
self.slogan = Button(frame,
text="Hello",
command=self.write_slogan)
self.slogan.pack(side=LEFT)
self.entry1 = Entry(root, width=15)
self.entry1.pack(side=LEFT)
self.importbutton = Button(frame,
text="import",
command=self.importing)
self.importbutton.pack(side=LEFT)
def write_slogan(self):
print ("Test!")
App.a = self.entry1.get()
print(App.a)
return App.a
def importing(self):
print('Import')
import Script2
if __name__ == '__main__':
root = Tk()
app = App(root)
root.mainloop()
Script2:
import Script1
You've since fixed this I believe, but I'm remarking the information for others that may find their way here: The self within a class function is the instance python will automatically pass when calling the defs. (Unless you're using classmethod or staticmethod for which are not useful in your use case and are a slightly more advanced topic)
# -- Script1 \/
class App:
def __init__(self, master):
# self here is automatically passed
# but you need to pass the "master" arg.
frame = Frame(master)
# ... Example:
self._value = 0
def set_value(self, val):
self._value = val
def get_value(self):
return self._value
# -- Use (probably in Scipt2)
master = Tk()
app = App(master)
print (app.get_value()) # Notice how we don't pass self
>>> 0
app.set_value("my new value") # This string is the "val" arg
print (app.get_value())
>>> my new value
Scipt1.App.a issue
The main issue you're having with is most likely to do with the way python manages modules. The class is writing to App.a in Script1.App but not Script2.Script1.App.a. This is expected behavior so I recommend instead trying to work with something like:
class App:
def __init__(self, master):
# ... Make your tk widgets as you already have
def set_entry_value(self, val):
self.entry1.set(val)
def get_entry_value(self):
self._last_recieved_entry_value = self.entry1.get()
# -- Script2 \/
# The if __name__ == '__main__' is not run on imported
# scripts, only the script python starts execution on
# ~$> python Script2.py
import Script1
if __name__ == '__main__':
root = Tk()
app = Script1.App(root)
# Possibly set a default?
app.set_entry_value("Default value")
root.mainloop()
# - Some time after the mainloop is over
my_lastest_value = root.get_entry_value()
This way, you're letting the local instance of objects handle their internal values. If you're looking to set a class member of an alternate module, then doing so in Script2 may work.
if __name__ == '__main__':
root = Tk()
app = Script1.App(root)
# Do something to set the entry
Script1.App.a = app.get_entry_value()
But be warned, that may not scale across multiple modules.
I was looking for an IP address entry widget for tkinter for use with python3.7 and came across ipentry in the tklib.
https://core.tcl-lang.org/tklib/doc/trunk/embedded/www/tklib/files/modules/ipentry/ipentry.html#section2
This is not a terribly complicated need to 'recreate the wheel' for and there are several examples on stackoverflow for IP entry boxes but I'd really like to understand how to use the modules and widgets in the tklib with tkinter. Documentation or examples appear to be few and far between. Here's how far I've gotten:
First of all, I have to tell Python that this widget exists.
import tkinter as tk
root = tk.Tk()
root.tk.call(‘package’,’require’,’ipentry’)
Then I created a class for the widget.
class iPentry(tk.Widget):
def __init__(self, master):
tk.Widget.__init__(self, master, '::ipentry::ipentry’)
Then I create an instance of it and pack it in my window.
enterIp = iPentry(root)
enterIp.pack()
So far so good. I get a window with a familiar looking input box for an IPV4 address.
The problem is that I haven't figured out how to use the get or complete or insert widget commands. When I try to get from the enterIp widget that I created, I get an error.
myip = enterIp.get()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'iPentry' object has no attribute 'get'
I suspect that I'm missing some syntax concepts. Any suggestions for how to do this?
You need to define get() function in your wrapper class iPentry:
def get(self):
return self.tk.call(self._w, 'get')
Actually you need to define every functions that ipentry provides like above if you want to call them.
Thanks to acw1668 I was able to work through some bone headed mistakes and figure this out a bit. Here is some sample code for someone else who might like to work with these in Python. They are pretty limited and I found a few things that didn't work even though they are documented on the lib page. But they might be useful for some situations. The rdial in particular was surprising because it is visually a "thumbwheel" rather than a typical round dial. I have included a screenshot of what some of these look like in Macos.
This code displays an iPentry with a label below that will populate with the address when you press enter. Then there is a bank of 3 sliders whose values will show in a label below. Then an rdial whose value shows in a label below and finally a "voltmeter" that bounces around based on a random number. Enjoy.
# This Python file uses the following encoding: utf-8
# Python 3.7 and Tk version 8.6
import sys
import tkinter as tk
import random
class iPentry(tk.Widget):
def __init__(self, master):
tk.Widget.__init__(self, master, '::ipentry::ipentry')
def get(self):
return self.tk.call(self._w, 'get')
def complete(self):
return self.tk.call(self._w, 'complete')
class CWslider(tk.Widget):
def __init__(self, master, placeholder):
tk.Widget.__init__(self, master, '::controlwidget::slider',
{'variable':placeholder, 'from_':0, 'to':20, 'number':3,
'width':55, 'background':'yellow'})
def get(self):
getvalue = self.tk.call(self._w, 'get')
getvalue = [int(x) for x in getvalue]
return getvalue
def set(self, value):
self.tk.call(self._w, 'set', value)
def complete(self):
return self.tk.call(self._w, 'complete')
class CWrdial(tk.Widget):
def __init__(self, master):
tk.Widget.__init__(self, master, '::controlwidget::rdial',
{'width':50, 'orient':'vertical', 'height':100, 'background':'green'})
def get(self):
return self.tk.call(self._w, 'get')
def complete(self):
return self.tk.call(self._w, 'complete')
class CWvoltmeter(tk.Widget):
def __init__(self, master, variable):
tk.Widget.__init__(self, master, '::controlwidget::voltmeter',
{'min':0, 'max':100, 'variable':variable})
def getIP(event):
myip = enterIp.get()
labelvar.set(myip)
print(f"myip is {myip}")
def updating(master, myValuesvar, myvoltvar, interval):
#we can't get value from placeholder because slider corrupts the IntVar?
slidervalues = slider.get() #so we use the get method
myValuesvar.set(slidervalues)
mydialvalue.set(mydial.get())
myvoltvar.set( random.randrange(0, 100, 1))
root.after(interval, updating, root, myValuesvar, myvoltvar, interval)
root = tk.Tk()
root.geometry("300x550+280+0")
root.tk.call('package','require','ipentry')
root.tk.call('package','require','controlwidget')
enterIp = iPentry(root)
enterIp.pack()
labelIP = tk.Label(root, text="Show The IP")
labelIP.pack()
labelvar = tk.StringVar()
label2 = tk.Label(root, textvariable=labelvar)
label2.pack()
root.bind('<Return>', getIP)
myvalues = [5,15,3]
myValuesvar = tk.IntVar()
placeholder = tk.IntVar() #necessary for slider to change values
slider = CWslider(root, placeholder)
slider.pack()
slider.set(myvalues)
labelSlider = tk.Label(root, textvariable=myValuesvar)
labelSlider.pack()
mydialvalue = tk.StringVar()
mydial = CWrdial(root)
mydial.pack()
labeldial = tk.Label(root, textvariable=mydialvalue)
labeldial.pack()
myvoltvar = tk.IntVar()
myvolt = CWvoltmeter(root, myvoltvar)
myvolt.pack()
interval = 300 #milliseconds for GUI
updating(root, myValuesvar, myvoltvar, interval)
root.mainloop()
sys.exit()
I'm working on an application in tkinter. I have many Entry widgets in UI, and a few classes in app engine. I need to bind tkinter variables of those entries to instances attributes.
i.e.:
class Pipe(Variable):
"""class for pipes"""
def __init__(self):
self.diameter = 0
self.variables = {}
pipe1 = Pipe(self)
pipe2 = Pipe(self)
I want to bind value from one entry to pipe1.diameter, and value from another entry to pipe2.diameter. I'm doing it by a trace function, where is lambda statement, pointing to a function, which identifies entry, and, using a dictionary proper for each instance, pass a value from entry to dictionary value. Dictionaries are produced like here, and then passed as instance attribute:
def pipe1_vars(object_):
variables = {
'ui_variable_name_for_pipe1_diameter': [object_.diameter]
}
return variables
def pipe2_vars(object_):
variables = {
'ui_variable_name_for_pipe2_diameter': [object_.diameter]
}
return variables
pipe1.variables = pipe1_vars(pipe1)
pipe2.variables = pipe2_vars(pipe2)
Unfortunately, Variable class method, assigning value, isn't working properly.
class Variable():
def set_var_value(variable_name, value):
ui_variable = tkinterbuilder.get_variable(variable_name)
self.variables[variable_name][0] = value
if ui_variable.get() != value:
ui_variable.set(value)
Obviously self.variables[variable_name][0] is something different than self.diameter. The dictionary value is changing, but instance.diameter stays the same.
How can I pass a real instance attribute to this method, instead of a copy in a dictionary value?
I'm assuming it is important to my app, to build something working as those dictionaries, because i need to bind similar attributes of different pipes to different entries - so it's have to be defined outside of a Pipe() class. I don't know if I should change dictionary to something else, or maybe should I rebuild those functions, building dictionary. I've run out of ideas, what to ask google.
Code is much complex, I've posted only most important elements, but if any other details are important, please note in comment.
If the number of Pipe attributes is small, make them properties, and when you create a Pipe object, pass it the corresponding tk binded variable:
import tkinter as tk
from tkinter import Tk, ttk
root = Tk()
var_e1 = tk.StringVar()
def print_e1():
print(var_e1.get())
def inc_e1():
var_e1.set(int(var_e1.get())+1)
class Pipe():
def __init__(self, tkvar):
self.tkvar = tkvar
tkvar.set('')
#property
def diameter(self):
return self.tkvar.get()
#diameter.setter
def diameter(self, value):
self.tkvar.set(value)
e1 = tk.Entry(root, textvariable=var_e1)
b1 = tk.Button(root, text='Print e1', command=print_e1)
b2 = tk.Button(root, text='Increment e1', command=inc_e1)
e1.pack(side=tk.LEFT)
b1.pack()
b2.pack()
p1 = Pipe(var_e1)
p1.diameter = 200
root.mainloop()
In the little GUI app below. When I use button's command option to call a function. It doesn't work like this: self.update() rather it works like this: self.update. Why so? Is is some special way that command option of a button works? I think a method or a function should be called with those braces (), unless it's a property:
i.e.
#name.setter:
def setter(self, name):
self.name = name
#main
object.name = "New_obj"
Note: The above is just a template so you might get my point. I didn't write the complete valid code. Including class and everything.
from tkinter import *
class MuchMore(Frame):
def __init__(self, master):
super(MuchMore,self).__init__(master)
self.count =0
self.grid()
self.widgets()
def widgets(self):
self.bttn1 = Button(self, text = "OK")
self.bttn1.configure(text = "Total clicks: 0")
self.bttn1["command"] = self.update # This is what I am taking about
self.bttn1.grid()
def update(self):
self.count += 1
self.bttn1["text"] = "Total clicks" + str(self.count)
#main
root = Tk()
root.title("Much More")
root.geometry("324x454")
app = MuchMore(root)
It is a high order function, meaning you are referencing a function as an object. You are not calling the function and assigning the command to the return value of the function. See here for more information.
The command parameter takes a reference to a function -- ie: the name of the function. If you add parenthesis, you're asking python to execute the function and give the result of the function to the command parameter.