Python Tkinter listener in text box - python

I would like to know how (If Possible) to listen to a certain phrase or word that is entered in a text box and the run a command.
For instance if i type the phrase "turn me red" i would like to know if it is possible to turn it red without pressing enter.
I just started and here is what i have:
from Tkinter import *
class mywidgets:
def __init__(self,root):
frame=Frame(root)
frame.pack()
self.txtfr(frame)
return
def txtfr(self,frame):
#define a new frame and put a text area in it
textfr=Frame(frame)
self.text=Text(textfr,height=10,width=50,background='white')
# put a scroll bar in the frame
scroll=Scrollbar(textfr)
self.text.configure(yscrollcommand=scroll.set)
#pack everything
self.text.pack(side=LEFT)
scroll.pack(side=RIGHT,fill=Y)
textfr.pack(side=TOP)
return
def main():
root = Tk()
s=mywidgets(root)
root.title('textarea')
root.mainloop()
main()

So i thought it would be a little cleaner if rather than edit your code, i just provided a fresh example of working code that exhibits the behavior you are interested in.
Here's what the code below does: when you run it, you get a little widget with an empty text box (technically, a Label in Tkinter) for the user to supply some value. When they enter a numeric value (integer or float) and then click the Calculate button then equivalent value in meters appears just below. If however, the user keys in 'red' then the word 'blue' appears as soon as it is entered--i.e., Blue will appear even though the Calculate button nor anything else was clicked.
As you can see in the penultimate line below, getting the behavior you want is just a matter of describing the behavior you want in the Tkinter event syntax.
from Tkinter import *
import ttk
root = Tk()
def calculate(*args) :
value = float(feet.get())
meters.set((0.305 * value * 10000. + .5)/10000.)
def callback_function(*args) :
meters.set('blue')
mf = ttk.Frame(root, padding="3 3 12 12")
mf.grid(column=0, row=0, sticky=(N, W, E, S))
mf.columnconfigure(0, weight=1)
mf.rowconfigure(0, weight=1)
feet = StringVar()
meters = StringVar()
feet_entry = ttk.Entry(mf, width=7, textvariable=feet)
feet_entry.grid(column=2, row=1, sticky=(W, E))
ttk.Label(mf, textvariable=meters, background='#E9D66B').grid(column=2,
row=2, sticky=(W, E))
ttk.Button(mf, text="Calculate", command=calculate).grid(column=2,row=3,
sticky=W)
ttk.Label(mf, text="feet").grid(column=3, row=1, sticky=W)
ttk.Label(mf, text="is equivalent to").grid(column=1, row=2, sticky=E)
ttk.Label(mf, text="meters").grid(column=3, row=2, sticky=W)
for child in mf.winfo_children():
child.grid_configure(padx=5, pady=5)
feet_entry.focus()
root.bind('<Return>', calculate)
# this is the key line
root.bind('red', callback_function)
root.mainloop()

What you want is certainly possible. The solution depends on what you really want.
Do you want to turn something red only if the user types "turn me red" precisely? Or, if the text is "turn me blue" and they change the word "blue" to "red", will that trigger the action?
If the former (must type exactly "turn me red") you can just bind to that exact sequence (eg: widget.bind("<t><u><r><n><space><m><e>....", doSomething)). It becomes impossible to manage, however, if you also want "Turn ME Red" to do the very same thing.
If the latter (whenever you type anything it looks to see if "turn it red" surrounds the insertion point), it's a tiny bit more work. You can bind on <KeyRelease> and then look at the characters prior to the insertion point for the magic phrase.
Bottom line is, you set up a binding either on something generic like <KeyRelease> then make the decision in the callback, or set up a highly specific binding for an exact phrase.

Related

how do i send a int value typed in a text-entry box to a mathematical expression?

my name is VĂ­tor. I'm totally new in programming, it is my second or third day in self learling python. I'm trying to build a metabolical rate calculator, it is the first thing that i could iamgine to do, i know about nothing from python. Then, i did it, but only stay in text editor (im using vs code), if i change the value in code, and run, i get the right value in terminal. But im tryint to operate it by a GUI, and i dont know how i type a numeric value in a text box, and this value are changed in my writed recipe. Ill show all my code from now, sorry for the weird words and long code, i'm really new in programming world, im from B. Anyway, thanks for reading.
import tkinter as tk
from tkinter import *
#FUNCAO DO BOTAO
def click1():
typed_text1=textentry1.get()
def click2():
typed_text2=textentry2.get()
def click3():
typed_text3=textentry3.get()
####MAIN
#TOP LEVEL CONTAINER
window = Tk()
window.title("Calculadora TMB")
#CONTAINER DE FUNDO
canvas = tk.Canvas(window, height=400,width=400, bg="green") .grid()
#CONTAINER QUADRO
frame1 = tk.Frame(canvas, height=200,width=200, bg="blue") .grid(row=0, column=1)
#IMAGEM
#LABEL
Label (frame1, text="CALCULADORA TMB", fg="red") .grid(row=0, column=0)
#CAIXA DE ENTRADA DE TEXTO
textentry1=Entry(frame1) .grid(row=1, column=1)
textentry2=Entry(frame1) .grid(row=2, column=1)
textentry3=Entry(frame1) .grid(row=3, column=1)
#SEND INPUT BUTTON
okbutton=tk.Button(frame1,text='Send', command=lambda:[click1(),click2(),click3()]) .grid(row=4, column=0)
#CANCEL BUTTON
cancelbutton=tk.Button(frame1,text='Cancel') .grid(row=5, column=0)
#OUTPUT TEXT
output= Text(frame1) .grid(row=6, column=0, padx=0.8, pady=0.8, columnspan=2)
#VARIABLES
Massa_corporal=66
Estatura=167
Idade=66
#RECIPES
Formula_HB_Homem=66.473+(13.752*Massa_corporal)+(5.003*Estatura)-(6.755*Idade)
Formula_HB_Mulher=655.1+(9.563*Massa_corporal)+(1.850*Estatura)-(4.676*Idade)
Formula_Williams1_H=(60.9*Massa_corporal)-54
Formula_Williams2_H=(22.7*Massa_corporal)+495
Formula_Williams3_H=(17.5*Massa_corporal)+651
Formula_Williams4_H=(15.3*Massa_corporal)+679
Formula_Williams5_H=(11.6*Massa_corporal)+879
Formula_Williams6_H=(13.5*Massa_corporal)+487
Formula_Williams1_M=(61*Massa_corporal)-51
Formula_Williams2_M=(22.5*Massa_corporal)+499
Formula_Williams3_M=(12.2*Massa_corporal)+746
Formula_Williams4_M=(14.7*Massa_corporal)+496
Formula_Williams5_M=(8.7*Massa_corporal)+829
Formula_Williams6_M=(10.5*Massa_corporal)+596
Formula_KTG=(((((1.255*Estatura)+(0.928*Massa_corporal)-64.8)*60)/1000)*24)*5
if Idade>=60:
print ((Formula_HB_Homem+Formula_Williams6_H+Formula_KTG)/3)
elif Idade>=30:
print((Formula_HB_Homem+Formula_Williams5_H+Formula_KTG)/3)
elif Idade>=18:
print((Formula_HB_Homem+Formula_Williams4_H+Formula_KTG)/3)
elif Idade>=10:
print((Formula_HB_Homem+Formula_Williams3_H+Formula_KTG)/3)
elif Idade>=3:
print((Formula_HB_Homem+Formula_Williams2_H+Formula_KTG)/3)
elif Idade>=0:
print((Formula_HB_Homem+Formula_Williams2_H+Formula_KTG)/3)
window.mainloop()```
To receive the value from a widget, you would want to use the get() function. The get() function will return whatever is in the text-box. See this page for more from the documentation.
You should also see the example on here

Updating a label from an entry field on button push with tkinter in Python 3.5.2

I am trying to create a window with a line label, an entry field, a current value label, and an "Update Value" button.
Here is an example:
This is what I have so far. I can get the entered value to print to console, but I can't seem to work out how to get an entered value and change the currentValue Label to reflect that value by pressing the button:
from tkinter import*
main=Tk()
#StringVar for currentValue in R0C2
currentValue = StringVar(main, "0")
#Called by the setValues button, looks for content in the entry box and updates the "current" label
def setValues():
content = entry.get()
print(content)
#This kills the program
def exitProgram():
exit()
#Title and window size
main.title("Title")
main.geometry("350x200")
#Descriptions on the far left
Label(main, text="Duration (min): ").grid(row=0, column=0)
#Entry boxes for values amidship
entry=Entry(main, width=10)
entry.grid(row=0, column=1)
#Displays what the value is currently set to.
currentValue = Label(textvariable=currentValue)
currentValue.grid(row=0,column=2)
#Takes any inputted values and sets them in the "Current" column using def setValues
setValues=Button(text='Set Values',width=30,command=setValues)
setValues.grid(row=9, column=0, columnspan=2)
#Red button to end program
exitButton=Button(main, text='Exit Program',fg='white',bg='red',width=30, height=1,command=exitProgram)
exitButton.grid(row=20, column = 0, columnspan=2)
main.mainloop()
There are a couple of problems with your code.
Firstly, you are overwriting the setValues function with the setValues Button widget, and similarly, you are overwriting the currentValue StringVar with the currentValue Label.
To set a StringVar, you use its .set method.
Don't use plain exit in a script, that's only meant to be used in an interactive interpreter session, the proper exit function is sys.exit. However, in a Tkinter program you can just call the .destroy method of the root window.
Here's a repaired version of your code.
import tkinter as tk
main = tk.Tk()
#StringVar for currentValue in R0C2
currentValue = tk.StringVar(main, "0")
#Called by the setValues button, looks for content in the entry box and updates the "current" label
def setValues():
content = entry.get()
print(content)
currentValue.set(content)
#This kills the program
def exitProgram():
main.destroy()
#Title and window size
main.title("Title")
main.geometry("350x200")
#Descriptions on the far left
tk.Label(main, text="Duration (min): ").grid(row=0, column=0)
#Entry boxes for values amidship
entry = tk.Entry(main, width=10)
entry.grid(row=0, column=1)
#Displays what the value is currently set to.
currentValueLabel = tk.Label(textvariable=currentValue)
currentValueLabel.grid(row=0,column=2)
#Takes any inputted values and sets them in the "Current" column using def setValues
setValuesButton = tk.Button(text='Set Values',width=30,command=setValues)
setValuesButton.grid(row=9, column=0, columnspan=2)
#Red button to end program
exitButton = tk.Button(main, text='Exit Program',fg='white',bg='red',width=30, height=1,command=exitProgram)
exitButton.grid(row=20, column = 0, columnspan=2)
main.mainloop()
BTW, it's a Good Idea to avoid "star" imports. Doing from tkinter import * dumps 130 names into your namespace, which is unnecessary and creates the possibility of name collisions, especially if you do star imports from several modules. It also makes the code less readable, since the reader has remember which names you defined and which ones came from the imported module(s).
In my opinion the easiest way to do this would be using an object orientated method. This way you could declare a button with a command that calls a def which runs self.label.configure(text=self.entry.get()).
This can be seen below:
import tkinter as tk
class App:
def __init__(self, master):
self.master = master
self.label = tk.Label(self.master)
self.entry = tk.Entry(self.master)
self.button = tk.Button(self.master, text="Ok", command=self.command)
self.label.pack()
self.entry.pack()
self.button.pack()
def command(self):
self.label.configure(text=self.entry.get())
root = tk.Tk()
app = App(root)
root.mainloop()
The above creates a label, entry and button. The button has a command which calls a def within the class App and updates the value of the label to be the text contained within the entry.
This all works very smoothly and cleanly and more importantly is drastically easier (in my opinion) to read and update in the future.
From your code you are setting the 'currentValue', which is a StringVar:
#StringVar for currentValue in R0C2
currentValue = StringVar(main, "0")
to an object Label further down in your code. You cannot do this!
#Displays what the value is currently set to.
currentValue = Label(textvariable=currentValue) ** this line is wrong
currentValue.grid(row=0,column=2)
You should name the label something different like:
#Displays what the value is currently set to.
lblCurrentValue = Label(textvariable=currentValue)
lblCurrentValue.grid(row=0,column=2)
Then in your "setValues" method you should use 'StringVar.set(value) to update the label like so:
def setValues():
content = entry.get()
currentValue.set(entry.get())------------------Here I set the value to the entry box value
print(content)
I tend to avoid stringVar and just use:
Label.config(text='*label's text*')
If you need more help I can post you my solution but try and solve it first becasue its the best way to learn. My tip is to make sure you are using correct naming conventions. In tkinter I tend to use lbl..., entryBox... etc before widgets so I know what they are and not to confuse them with variables.

Radio button values in Python Tkinter

I am trying to create a dialog box in Python using Tkinter. The goal is to have a dialog box with two radio buttons and an "OK" button. Radio button one selects the option "default". Radio button two selects the option "user defined." The "OK" button closes the window.
Question 1: How do I save the value from the radio button? That is, how do I pass the selected radio button to the rest of my script?
Question 2: How can I have the second radio button include user text input (along the lines of tkSimpleDialog.askstring)? I would like that button to show a radiobutton, a prompt ("Enter value:"), and a space for the user to enter text -- all on one line as a single radiobutton option.
So the whole dialog should have the top radio button be a normal radio button, and the second button specify user input and include a space for that user input (and the OK button).
So far I have a dialog open with two options, but the value doesn't get passed to anything I can see; selection is returned as 0 even before I select a radiobutton.
Any help on either question would be greatly appreciated, thank you.
Here's my script so far:
from Tkinter import*
master = Tk()
var = IntVar()
Label(master, text = "Select OCR language").grid(row=0, sticky=W)
Radiobutton(master, text = "default", variable = var, value = 1).grid(row=1, sticky=W)
Radiobutton(master, text = "user-defined", variable = var, value = 2).grid(row=2, sticky=W)
Button(master, text = "OK", command = master.quit).grid(row=3, sticky=W)
selection = var.get()
print "Selection:", selection
mainloop()
#If selection == 0 do one thing
#If selection == 1 do something else...
A bit late to the party, but I stumbled upon this question while trying to find something on Tkinter radiobuttons.
Question 1:
I changed three things:
1) I immediately set the value of var to 1 after you've defined it. This is done by doing var.set(1) and will make sure your first radio button is selected (which has a value of 1, as you defined it later on in the code).
2) I've replaced your master.quit command with a function called quit_loop. In this function:
The var value is printed through a print and get statement. The get will 'get' the current value of var, which depends on which radio button is selected.
I create a global variable within this function, which will then get the current value of var.
I added parentheses to master.quit() because this is no longer in the command of a radio button. Note that if you plan on using IDLE, master.destroy() might be a more suitable alternative.
3) Due to the creation of the selection variable in the function we now have your wanted value stored in a variable. There is one final if-statement at the end of the code to show it's working.
from Tkinter import *
master = Tk()
var = IntVar()
var.set(1)
def quit_loop():
print "Selection:",var.get()
global selection
selection = var.get()
master.quit()
Label(master, text = "Select OCR language").grid(row=0, sticky=W)
Radiobutton(master, text = "default", variable=var, value = 1).grid(row=1, sticky=W)
Radiobutton(master, text = "user-defined", variable=var, value = 2).grid(row=2, sticky=W)
Button(master, text = "OK", command=quit_loop).grid(row=3, sticky=W)
master.mainloop()
if selection == 1:
print "My Value is equal to one."
elif selection == 2:
print "My value is equal to two."
Question 2:
I would keep it simple and just add a label and an entry box right after your radio button. This means that we also have to work with columns as you didn't have any defined in your previous code, which makes everything default to column 0. We want your second radio button to be 'radio, label, entry' which takes three columns.
1) The previous label containing "Select OCR language" will be spanned over three columns with columnspan=3 added to the grid arguments. The same goes for your first radio button.
2) I added a Label and an Entry after your second radio button. Note that the columns go from 0 to 2, defining our three columns. The label has a simple "Enter value:" text, whereas the entry has the variable textvariable=entry_text. I added this variable entry_text to the beginning of your code and immediately set its value to ###. Note that this is a string (hence, textvariable) so adding checks for integer numbers only is up to you.
3) Of course, this is not linked to the second radio button. It still has a value of 2 if we select it, not the value of the Entry widget. That's why, in the previously created quit_loop function, I added a small if statement that assigns the value of the entry to selection if the second radio button was selected.
from Tkinter import *
master = Tk()
var = IntVar()
var.set(1)
entry_text = StringVar()
entry_text.set("###")
def quit_loop():
print "Selection:",var.get()
global selection
selection = var.get()
if selection == 2:
selection = entry_text.get()
master.quit()
# Add columnspan to these widgets
Label(master, text = "Select OCR language").grid(row=0, sticky=W, columnspan=3)
Radiobutton(master, text = "default", variable=var, value = 1).grid(row=1, sticky=W, columnspan=3)
# Order these widgets in their appropriate columns
Radiobutton(master, variable=var, value = 2).grid(row=2, sticky=W, column=0)
Label(master, text="Enter value:").grid(row=2, sticky=W, column=1)
Entry(master, textvariable=entry_text).grid(row=2, sticky=W, column=2)
# Example of what happens without columnspan
Button(master, text = "OK", command=quit_loop).grid(row=3, sticky=W)
master.mainloop()
print selection
Tip
If this simple GUI remains this small, it's ok to write code in this manner. However, expanding a lot on this further I would suggest taking an object oriented approach as it really improves readability a lot, especially when functions are being defined. That way they don't have to be necessarily defined beforehand.
Instead of directly using master.quit in the Button's command, define a function that finishes up the program then calls master.quit():
def end_program(event=None):#event will let it be used as .bind callbacks too if you need it.
selection = var.get()
if selection:
NotImplemented
else:
NotImplemented
master.quit()
...
Button(master, text = "OK", command = end_program).grid(row=3, sticky=W)
one the master is closed some of the data from the widgets is cleaned up so master.quit() needs to be called only after you are done accessing the widgets.
As set the selection value will be set before the window appears (selection = 0).
If you want to run tests after mainloop(), selection = var.get() should also be after mainloop() with tests.
If you do not want to close the master window before tests, use command=function:
from Tkinter import *
def function():
selection = var.get()
if selection == 1:
# Default
elif selection == 2:
# User-defined
else:#selection==0
#No choice
master.quit()
master = Tk()
var = IntVar()
Label(master, text = "Select OCR language").grid(row=0, sticky=W)
Radiobutton(master, text = "default", variable = var, value = 1).grid(row=1, sticky=W)
Radiobutton(master, text = "user-defined", variable = var, value = 2).grid(row=2, sticky=W)
Button(master, text = "OK", command = function).grid(row=3, sticky=W)
mainloop()

Dynamically changing Label variable

What I am trying to do is build a window with a number(default value=1) and
3 buttons underneath it named: "UP","DOWN" and "QUIT". "Up" button is going to increment the number by 1 and the rest of the buttons are clear what they do.
from Tkinter import *
root=Tk()
number=1
Label(root,text=number,height=10,width=7).grid(row=0,pady=10,padx=10,column=10,columnspan=2,sticky=W+E)
def auksisi(number):
number+=1
return number
def meiosi(number):
number = number -1
return number
Label(root, text=auksisi(number),height=10,width=7).grid(row=0,pady=10,padx=10,column=10,columnspan=2,sticky=W+E)
Button(root, text="up",command=lambda: auksisi(number)).grid(row=3,column=2,columnspan=2)
Button(root, text="down",command=lambda: meiosi(number)).grid(row=3,column=3,columnspan=2)
Button(root, text="quit",command=root.destroy).grid(row=3,column=4,columnspan=2)
root.update()
root.mainloop()
What is happening is when I press the buttons nothing changes.Don't worry about the layout I will fix it, I just want the buttons to work.
The grid method returns None, and calling it directly after the creation of your objects, would make your eventual references to be None as well. To change the values of your label, you need a reference to it:
label_reference = Label(root, text=auksisi(number), height=10, width=7)
label_reference.grid(row=0, pady=10, padx=10, column=10, columnspan=2, sticky=W+E)
Now, through label_reference you can change the text using for example the config() method. You can do this in the method that is called when you click your buttons:
def auksisi(number):
number += 1
label_reference.config(text=number)
return number

Python program is outputting a strange value to my 16x2 Character LCD

I've built a small program with a Tkinter GUI to let me enter 2 lines of text and make it display it on the character screen. It all works pretty neatly until I press apply text, because then I just seem to get a weird value on both lines of the LCD.
e.g.
Wanted line 1: "Test"
Wanted line 2: "Please work"
Actual result
Line 1: .3047332040L.304
Line 2: 7332320L
This is my code:
__author__ = 'David'
from Tkinter import *
from Adafruit_CharLCD import Adafruit_CharLCD
from time import sleep
import psutil
chargui = Tk()
lcd = Adafruit_CharLCD()
lcd.begin(16, 1)
class FrameWork:
def __init__(self, master):
frame = Frame(master)
frame.pack()
# Creation
self.lbl_enter1 = Label(frame, text="Enter the first line:")
self.lbl_enter2 = Label(frame, text="Enter the second line:")
self.ent_line1 = Entry(frame)
self.ent_line2 = Entry(frame)
self.btn_apply = Button(frame, text="Apply Text", command=self.applymessage)
self.btn_cpum = Button(frame, text="CPUMem", command=self.CPUMem)
self.btn_quit = Button(frame, text="Quit", command=frame.master.destroy)
# Griding
self.lbl_enter1.grid(row=0, column=0, sticky=E, padx=2)
self.lbl_enter2.grid(row=1, column=0, sticky=E, padx=2)
self.ent_line1.grid(row=0, column=1, sticky=W)
self.ent_line2.grid(row=1, column=1, sticky=W)
self.btn_apply.grid(row=2, column=1, sticky=W, padx=24)
self.btn_cpum.grid(row=2, column=0, columnspan=2, sticky=W, padx=85)
self.btn_quit.grid(row=2, column=1, sticky=E)
def applymessage(self):
lcd.clear()
lcd.message(str(self.ent_line1))
lcd.message(str(self.ent_line2))
def CPUMem(self):
while 1:
lcd.clear()
lcd.message("CPU: " + str(psutil.cpu_percent()) + "%\n")
lcd.message("MEM: " + str(psutil.virtual_memory().percent) + "%")
sleep(1)
g = FrameWork(chargui)
chargui.mainloop()
Don't mind the CPUMem function. This function works nicely.
It's just applymessage(self): that gives me trouble. I get no error at all. If I remove srt() from the 2 lcd.message functions though, it says it can't concatenate a string with an int.
Any solutions?
Edit:
I tried to just print the value to the console instead of putting it onto the LCD, and it still gives me the weird values (are they memory locations? wild guess) for both lines
Line 1: .3047815368L.3047815608L
Line 2: .3047815368L.3047815648L
As you found, the LCD has nothing to do with it. The problem is trying to convert a Tkinter Entry object into a str:
str(self.ent_line1)
calls a special method, self.ent_line1.__str__() to get the string representation of the object (as does print). There is no expectation that __str__ is defined to do something useful.
Actually, investigating using the interactive shell, you can find that this special method is defined in a parent class, and it's docstring is "Return the window path name of this widget." That's what you're seeing.
What you actually want, the text typed into the widget as a string, is given by get():
print self.ent_line1.get()
EDIT: Hm, it appears that you don't need to couple widgets to variables at all, as per the other answer to this question. The few times I've used TK that's the way I've always done it, but calling get() directly on the widget is probably certainly easier in this instance. I'm leaving this answer up for additional background.
I'm far from an expert in tkinter but unless someone more knowledgeable replies, I'll do my best.
The problem is that you're attempting to print the widget objects themselves, but the API doesn't work quite like that. If you read through the documentation for the Entry widget, you'll see that you need to associate a StringVar instance with it. This page has some more details, and there's a section in the Python docs too.
So, you'll need to do something like this when building your Entry wigets:
self.ent_line1_text = StringVar()
self.ent_line2_text = StringVar()
self.ent_line1 = Entry(frame, textvariable=self.ent_line1_text)
self.ent_line2 = Entry(frame, textvariable=self.ent_line2_text)
And then your applymessage() would look something like:
def applymessage(self):
lcd.clear()
lcd.message(self.ent_line1.get())
lcd.message(self.ent_line2.get())
As well as the get() method to retrieve the current contents of the entry box, there's also set() if you need to change it programmatically (e.g. to initialise the text boxes with some default text).

Categories

Resources