When I highlight my entry(tkinter) and press backspace, nothing happens? - python

I'm working on a program regarding math equations, so in my program there are tons of entries but I'm having difficulties clearing them.
For the entries I'm restricting both a character limit and I only allow number and (",") or ("."). If I type for example ' 1000 ' in my entry, then highlight it and press backspace everything works out. But as soon as I type ' 100,25 ' and add a comma into the mix. It wont delete after pressing backspace.
from tkinter import *
root = Tk()
def validatecontent(var):
return (var.isdigit() == bool(var)) or var == (",") or var == (".")
vcmd = (root.register(validatecontent), '%S')
def character_limit6(var):
if len(var.get()) > 0:
var.set(var.get()[:6])
var = StringVar()
entry = Entry(root, textvariable=var, validate='all',
validatecommand=vcmd)
entry.pack()
var.trace("w", lambda *args: character_limit6(var))
root.mainloop()

Edit: It seems that the problem is that it refuses to recognize a string of "," or ".", alternatively a string of numbers and "," / "." as legitimate. The following seems to work:
from tkinter import *
root = Tk()
var = StringVar()
var.trace("w", lambda *args: character_limit6(var))
def validatecontent(var):
return var.isdigit() == bool(var) or "," in var or "." in var
def character_limit6(var):
if len(var.get()) > 0:
var.set(var.get()[:6])
vcmd = (root.register(validatecontent), '%S')
entry = Entry(root, textvariable=var, validate='all',
validatecommand=vcmd)
entry.pack()
root.mainloop()

In the question when you delete a selection the var parameter in validatecontent is a string eg. '0,0' which fails your validation routine.
Do you want to accept only valid float strings?
Are you expecting strings like '1,234.45' or '123,45'?
Below I've assumed '123,45'
Validatecontent tries to convert the string to a float after replacing any ',' with '.'.
If it can it returns true otherwise it returns True only if the string is empty.
from tkinter import *
root = Tk()
def validatecontent(var): # Amended var is now the complete string.
try:
temp = var.replace(',', '.') # Replace ','' with '.' for float conversion assumes , is decimal point.
# temp = var.replace(',',"") # Or replace , with empty if , is a thousands delimiter.
fl = float(temp)
# if temp converts to a float return length of string is less than 7
return len(var) < 7
except ValueError:
return var == "" # If it doesn't convert to a float only accept an empty string.
vcmd = (root.register(validatecontent), '%P') # '%P' passes the whole new string to validate content.
entry = Entry(root, validate='key', validatecommand=vcmd) # Validate on key only.
entry.pack()
root.mainloop()
There may well be better validation functions involving regular expressions. This is reasonably easy to follow though. The entry can still be linked to a StringVar if required. It's not required to do the validation though.

Related

Keybinding in tkinter Python

If I type '*' in keyboard, it should be typed as 'x' in the entry field. Below is the sample code. I'm new to tkinter.
from tkinter import *
def func(number):
x = str(e1.get())
e1.delete(0, END)
e1.insert(0, str(x) + str('x'))
main = Tk()
main.geometry('200x50')
e1=Entry()
e1.bind('*',func)
e1.pack()
main.mainloop()
Here I'm getting 'x*'. But I need only 'x' to be typed in the entry field. Any suggestions will be really helpful.
You need to ignore the * character entered by returning 'break' at the end of func(). Also your logic will not work if the input cursor is not at the end of the input string.
Below is a modified func():
def func(event):
# add the "x" at the insertion position
event.widget.insert('insert', 'x')
# ignore the entered "*" character
return 'break'

taking an integer value from an entry widget in tkinter

I wrote some simple code to describe my problem: I want to take an integer value from an entry to use it later.I tried also to use a spin box. here is my code:
from tkinter import*
win=Tk()
win.geometry('300x200')
e=Entry(width=10)
e.pack()
y=int(e.get())
print(y*2)
I always get the same error:
y = int(e.get())
ValueError: invalid literal for int() with base 10 ' '
I don't know why this is happening!
ValueError: invalid literal for int() with base 10 ' '
means that you are trying to convert the string "" to an integer. This, of course, is invalid. The reason you are trying to convert an empty string to an integer is that you are not allowing any value to be placed into the entry.
A good way to allow this to happen would be using a button, which calls a function to get the value within the entry and print it. Also, you are missing the line win.mainloop() which you would need at the end of your code.
Here is the example code you are probably asking for:
from tkinter import *
win = Tk()
win.geometry('300x200')
def printVal():
y = int(e.get())
print(y*2)
e = Entry(width=10)
e.pack()
b = Button(text="push me to print the value in e")
b.pack()
win.mainloop()
This code will still return errors if the value in the entry is not a valid integer, so if you want it to be robust, you'll have to play around with it.
there is several problems in your example, for example. in which moment you are trying to get value from Entry?
your code should looks something like:
from tkinter import *
def validate(value):
print (value)
try:
if value:
return int(value)
except:
return None
def calculate():
x = e1.get()
x_validate = validate(x)
if x_validate == None:
e1.delete(0, END)
e1.insert(0, 'you need to enter integer')
Label1.config(text='')
else:
result = x_validate*2
Label1.config(text=result)
win = Tk()
e1 = Entry(win)
e1.grid(row=0, column=0)
Button(win,text='Calculate', command = calculate).grid(row=0, column=1)
Label(win,text='Result').grid(row=1, column=0)
Label1 = Label(win)
Label1.grid(row=1, column=1)
win.mainloop()
Example if you enter integer and press calculate
Example if you enter string and press calculate

How can I have a Tkinter program scan a text box for inputs in real time?

Ultimately I want to make a small program with a text box where you have to type in the first 50 or so digits of Pi. What I want is for nothing to happen if the user types the correct characters, but I want something to flash red if they input the wrong character. For example, if the user types "3.1", nothing happens but the text showing up in the text box, but if they then type the wrong number, like "3.15", I want something to flash red.
from tkinter import *
def input(event):
inp = (ent.get('1.0', END))
if inp == '3':
print(inp)
else:
print(('--') + (inp))
root = Tk()
root.title('pi, okay')
root.geometry('425x50')
ent = Text(root, width = 50, height = 1)
ent.bind('<KeyRelease>', input)
ent.pack()
mainloop()
What I think SHOULD happen with this is for the console to print "3" IF the user inputs a "3", and for the console to print "--(whatever else the user would have typed)" if it is not a 3. But what actually happens is that the program will print "--(input)" no matter what.
You can use something like this if you need only one line of Input:
var = StringVar()
ent = Entry(root, width=50, textvariable=var)
def check_value(var, ent, *args):
pi = "3.1415"
if not pi.startswith(var.get()):
print("wrong input")
ent.config(fg="red")
else:
ent.config(fg="black")
var.trace('w', lambda *args: check_value(var, ent, *args))
ent.pack()
Here, var.trace() will call function check_value everytime when user types anything in Entry widget. You can add you logic there to verify the input value and change UI(or print logs) based on verification result.

How to print Python Output in Entry widget?

I've searched through the whole Internet for how to do this, and nothing came to me. There were some similar topics, when programmers asked of how to parse 'int' numbers to the Entry output. But it is much simpler because you just use getters, then insert() - and voila.
I am trying to do the following thing. I print the text written in one line. And for each word I want to count how many times it appeared in the same text.
E.g., I print in my first Entry "one two one two three" - I get "0 0 1 1 0" in the second Entry widget.
Any non-space sequence of characters is considered a word.
from tkinter import *
class DM_3_1:
def __init__(self):
root = Tk()
root.geometry('250x150')
root.title("DiscreteMaths_3_1")
usertext = StringVar()
Label_1 = Label(root, text="Input")
Label_2 = Label(root, text="Output")
inputField = Entry(root, textvariable = usertext)
outputField = Entry(root)
inputField.bind('<Return>', lambda _: printLine())
def printLine():
counter = {}
for word in inputField.get():
counter[word] = counter.get(word, 0) + 1
Ans = print(counter[word] - 1, end=' ')
outputField.insert(0, str(Ans))
Label_1.grid(row = 0)
Label_2.grid(row = 1)
inputField.grid(row = 0, column = 1)
outputField.grid(row = 1, column = 1)
root.mainloop()
DM_3_1()
What I get in the output now: Here is the screenshot
As far as you can see, the application works, but there's 'NoneNoneNone...'(depends on the number of characters, including whitespaces) instead of '0 0 1 1 0'. How do I solve my problem? Where's a logical mistake? I guess, it's about the function, but I don't actually see the mistake.
You have set Ans to be equal to print rather than the value it was supposed to be. Also your for loop was getting every character rather than every word.
Corrected code:
from tkinter import *
class DM_3_1:
def __init__(self):
root = Tk()
root.geometry('250x150')
root.title("DiscreteMaths_3_1")
usertext = StringVar()
Label_1 = Label(root, text="Input")
Label_2 = Label(root, text="Output")
inputField = Entry(root, textvariable = usertext)
outputField = Entry(root)
inputField.bind('<Return>', lambda _: printLine())
def printLine():
counter = {}
words=inputField.get().split()
for word in words:
counter[word] = counter.get(word, 0) + 1
Ans = counter[word] - 1
print(Ans, end=" ")
outputField.insert(END, str(Ans))
Label_1.grid(row = 0)
Label_2.grid(row = 1)
inputField.grid(row = 0, column = 1)
outputField.grid(row = 1, column = 1)
root.mainloop()
DM_3_1()
edit:
As Mike-SMT pointer out its easier to use .split
code edited to use .split
So my solutions to this kind of counter is to track each word and keep a list of all the words. Then keep a list of all the unique words. The count each time a unique word appears in the complete list.
I restructured your code a bit to conform a bit better with standards.
I rewrote your printLine method to keep track of all the words in a string and create a dictionary that contains a list of all the unique words and how many times they show up in the string.
When writing a class you will need to learn to use self. to convert standard variables into class attributes. Class attributes can be accessed from anywhere in the class including methods within the class. Using regular variables will likely cause problems as they are not available to methods after __init__ has completed.
take a look at the below code.
import tkinter as tk
class DM_3_1:
def __init__(self, parent):
self.root = parent
self.root.geometry('250x150')
self.root.title("DiscreteMaths_3_1")
Label_1 = tk.Label(self.root, text="Input")
Label_2 = tk.Label(self.root, text="Output")
Label_1.grid(row=0)
Label_2.grid(row=1)
self.inputField = tk.Entry(self.root)
self.outputField = tk.Entry(self.root)
self.inputField.grid(row=0, column=1)
self.outputField.grid(row=1, column=1)
self.inputField.bind('<Return>', self.printLine)
def printLine(self, Event):
word_list = []
counter = 0
unique_words_in_string = []
total_times_word_appears = {}
for word in self.inputField.get().split():
word_list.append(word)
if word not in unique_words_in_string:
unique_words_in_string.append(word)
for word in unique_words_in_string:
counter = 0
for other_word in word_list:
if word == other_word:
counter += 1
total_times_word_appears[word]=counter
self.outputField.delete(0, "end")
self.outputField.insert("end", total_times_word_appears)
if __name__ == "__main__":
root = tk.Tk()
DM_3_1(root)
root.mainloop()

Compare tkinter Entry to actual addition answer

I'm trying to compare the input of an Entry box to the actual answer. This is one of my first python projects and I'm still very confused and to be honest I don't even know how to start asking the question.
The user will click either the addition or subtraction button. A string will appear asking "What does 4 + 5 equal?" The numbers are generated randomly.
I then insert an Entry box using the tkinter library. I don't know how to get() the input and compare it to the sum or difference of the actual numbers.
I was trying to follow this video but I've failed using other methods as well. FYI, I was focusing on the addition method mostly so if you test, that with addition first.
from tkinter import Entry
import tkinter as tk
import random as rand
root = tk.Tk()
root.geometry("450x450+500+300")
root.title("Let's play Math!")
welcomeLabel = tk.Label(text="LET'S PLAY MATH!").pack()
startLabel = tk.Label(text='Select a math operation to start').pack()
def addition():
a = rand.randrange(1,10,1)
b = rand.randrange(1,10,1)
global Answer
Answer = a + b
tk.Label(text="What does " + str(a) + " + " + str(b) + " equal? ").place(x=0, y=125)
global myAnswer
myAnswer = Entry().place(x=300, y= 125)
def checkAnswer():
entry = myAnswer.get()
while int(entry) != Answer:
if int(entry) != Answer:
tk.Label(text="Let's try again.").pack()
elif int(entry) == Answer:
tk.Label(text="Hooray!").pack()
addBtn = tk.Button(text="Addition", command=addition).place(x=100, y = 60)
subBtn = tk.Button(text="Subtraction", command=subtraction).place(x=200, y=60)
checkBtn = tk.Button(text="Check Answer", command=checkAnswer).place(x=300, y = 150)
tk.mainloop()
All you need to do to fix your issue is separate the creation of your Entry() object from the placing of it:
def addition():
a = rand.randrange(1,10,1)
b = rand.randrange(1,10,1)
global Answer
Answer = int(a + b)
tk.Label(text="What does " + str(a) + " + " + str(b) + " equal? ").place(x=0, y=125)
global myAnswer
myAnswer = Entry()
myAnswer.place(x=300, y= 125)
Entry() returns the entry object, which has a get() method. However, when you chain .place(), you return its result instead, which is None. Therefore you never actually store the Entry object in your variable.
Also, it is a good idea to ensure that Answer is an int as well.
to get the value of the answer do answer = myanswer.get() or any other variable name. To compare it to the correct answer do
if int(answer) == correctAnswer:
#the code
is that what you were asking?
Consider this and below is an example that responds to whether or not the number entered to answer is "Correct!" or "False!" when the user clicks on answer_btn:
import tkinter as tk
import random as rand
def is_correct():
global answer, check
if answer.get() == str(a + b):
check['text'] = "Correct!"
else:
check['text'] = "False!"
def restart():
global question, check
random_nums()
question['text'] = "{}+{}".format(a, b)
check['text'] = "Please answer the question!"
def random_nums():
global a, b
a = rand.randrange(1, 10, 1)
b = rand.randrange(1, 10, 1)
root = tk.Tk()
#create widgets
question = tk.Label(root)
answer = tk.Entry(root, width=3, justify='center')
check = tk.Label(root)
tk.Button(root, text="Check", command=is_correct).pack()
tk.Button(root, text="New question", command=restart).pack()
#layout widgets
question.pack()
answer.pack()
check.pack()
restart()
root.mainloop()

Categories

Resources