Create a variable from 2 Tkinter entries - python

I am trying to get the first three characters of a Tkinter entry, and then add them to another tkinter entry.
For example:
name = Entry=(root, text="Name: ")
age = Entry=(root, text="Age: ")
username = First three characters of name + age
Then I want the first three letters of their name to add to the age to create a user name.
If the user enters 'Taylor' as a 'name' and '13' as a 'age', I want to make a variable called 'username' which would contain 'Tay13'
Not sure if I made it too clear, but hopefully you understand. Thanks
EDIT: Just tried something else and it says 'StringVar' object is not subscriptable.

Just found out how to do it on Reddit. If any one else need this, then here is the answer:
username = name.get()[:3] + age.get()
This gets the first 3 letters from 'name' and adds 'age' on to the end of it.
Thanks to the people who helped.

You can do this to get the username. The [:3] pulls the first 3 letters of a string.
username = str(name[:3]) + str(age)
print username

Below example adds/updates id to users dictionary each time the button is pressed:
try: # In order to be able to import tkinter for
import tkinter as tk # either in python 2 or in python 3
except ImportError:
import Tkinter as tk
def update_users():
global users, name, age
user_id = name.get()[:3] + age.get()
users[user_id] = None
print(users)
if __name__ == '__main__':
root = tk.Tk()
users = dict()
name = tk.Entry(root)
age = tk.Entry(root)
update_btn = tk.Button(root, text="Update Users", command=update_users)
name.pack()
age.pack()
update_btn.pack()
root.mainloop()

This how to go about this create two entry widget to receive the content in the entry.Then your funtion to print the content in the entry and slice the first three letters of the name and print plus the age.
from tkinter import *
def Print_variable():
e1 = name.get()
e2 = age.get()
print(e1[:3] + e2)
root = Tk()
root.geometry("400x400")
name = StringVar()
e1 = Entry(root, textvariable=name) # this entry accept the name
e1.pack()
age = StringVar()
e2 = Entry(root, textvariable=age) # this entry accept the age
e2.pack()
b = Button(root, text="print name and age variable", command=Print_variable)
b.pack()
root.mainloop()

Related

nested while loop in python tkinter

The following code searches a text file for a name and displays the related number in a tkinter entry box in Python.
so original text file includes:
bob 19
dan 20
shayne 17
I would like add another nested loop so that if there are two names the same then two numbers are returned to the entry box. Sorry, I am new to Python, have tried but always come up with an error.
bob 18
bob 19
dan 20
shayne 17
#https://www.youtube.com/watch?v=lR90cp1wQ1I
from tkinter import *
from tkinter import messagebox
race = []
def displayInfo(race, name):
found = False
pos = 0
while pos < len(race) and not found:
if race[pos][0] == name:
found = True
pos+=1
if found:
return race[pos-1][1]
else:
messagebox.showerror(message = "Invalid input, please try again.")
def clickArea():
fin.set(displayInfo(race, name.get()))
def createlist():
raceFile = open ("C:/python/files/number_list.txt", 'r')
for line in raceFile:
racer = line.split()
race.append(racer)
raceFile.close()
return race
root = Tk()
root.title("Read From text File/List GUI")
Label(root, text="Name").grid(row=0, column=0)
name = StringVar()
Entry(root, textvariable=name).grid(row=0, column =1)
Label(root, text="Finish Time").grid(row=2, column=0)
fin=IntVar()
Label(root, textvariable=fin).grid(row=2, column=1)
button = Button(root, text="Finish Time", command=clickArea)
button.grid(row=3, column=0, columnspan=2)
createlist()
print(race)
your question is not related to tkinter, so I made the code without it.
It works like this: you enter the name you're looking for, then it looks for matches using the count method. If there is a match, then the index is written to the 'B' array. Further, since there is a space between the name and number, we take the space index + 1 and start outputting the string from this position to the end.
name = input('who do you want to find: ') + " "
with open("number_list.txt", "r") as file:
A = file.readlines()
#remove program entry '\n'
for i in range(len(A)):
A[i] = A[i].strip()
#getting matching names
B = [] #the court records the names we need
for i in A:
if i.count(name): #truth check
#this notation is equivalent to the notationsi: if i.count(name) == 1:
B.append(i)
print('the following numbers match:')
for i in B:
index_space = i.index(' ') + 1
print(i[index_space:])
If you want to get all the values for a name, you need to go through all the items in race:
def displayInfo(race, name):
# go through the race list and return values for given name
found = [x[1] for x in race if x[0] == name]
if found:
# return the values separated by comma
return ", ".join(found)
# no item found for the given name
return "not found"

Validate Python Tkinter name entry by clicking button?

So here I have a program which first displays a information message and then you click next and it tells you to input your name before opening up the main window.
INFO ->(next) ENTER NAME ->(next)
When I enter my name in the entry box I want it to be checked that it does not contain 1.numbers and 2.is not blank. under the validate="key" option it means that once I start typing it validates. But rather I want it to only check the name once i press the NEXT button... If not it will open errorbox()
class errorbox():
def __init__(self):
windowError = Tk()
windowError.title("Error")
windowError.geometry('300x400')
error_message = Label(windowError, font=("Bold", 10), justify="left", text="Please enter a valid name")
def clicked1():
description.configure(text="Please enter your name")
nameBox = Entry(windowSplash, width=20, textvariable=name)
nameBox.place(rely=0.5, x=130, anchor=W)
reg = windowSplash.register(validate)
nameBox.config(validate="none",validatecommand=clicked2)
button2 = Button(text="Next", bg="white", width=5, command=lambda:[clicked2(),validate()])
button2.place(rely=0.5, x=300, anchor=E)
button1.destroy()
def validate(input):
if input.isdigit():
print("Invalid name was entered" + input)
errorbox()
return False
elif input is "":
print("No name entered")
errorbox()
return False
else:
return True
def clicked2():
print(name.get(), "logged in...")
windowSplash.destroy()
windowTool = Tk()
windowTool.title("Radial Measurements Calculator Tool")
windowTool.geometry('300x400')
name = StringVar()
windowSplash.mainloop()
Welcome to Stack Overflow Community.
I might have interpreted your question, but please make sure that next time you provide a minimal, reproducible example when you ask.
Here are a couple of things that I have observed.
The validate function takes input as a parameter, so make sure you pass that in the lambda function by lambda input = name.get(): [clicked2(),validate(input)].
By checking input.isdigit() does not guarantee that there might not be numbers after/between characters, so I suggest you to iterate through the string and check for isdigit()/type() or use re module. Also, an efficient way to check for empty string could be if not name.get():.
If you aim to open the new window only after the validation, I suggest you to call clicked2 from the validate function under a condition and not form the next button, because in this case your return form validate isn't used for anything.

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 to validate entry in tkinter?

I have found some answers to this question but none of the answers have worked on my program.
I am trying to validate the name variable in my code but isalpha() is not a function used in tkinter.
Here is my code so far:
class newUser:
root.title("Sign Up")
header = Label(root, text = "Sign Up!\n")
header.grid(row = 0, column = 0, sticky = E)
global results
results = False
def getName(): #Getting name of the user
global name
nameX = Label(root, text = "Please enter your name: ")
nameX.grid(row = 1, column = 0, sticky = W)
name = Entry(root)
name.grid(row =1, column = 1)
#name = name.get()
if name.isalpha() and name != "":
name = name
#newUser.getAge()
else:
print("Please ensure you have entered your name. Thank you. ")
newUser.getName()
root.mainloop()
newUser.getName()
I tried to use the name.get() but it created an endless loop.
Any ideas?
isalpha() is a built-in function of str objects. Calling isalpha() on name, which was defined to be a tkinter.Entry object will raise an exception because tkinter.Entry has no such function. While you are correct in attempting to use the get() function, which is a function of tkinter.Entry objects and does return a str which supports isalpha() calls, your implementation is a bit off.
You are entering into a recursion because name.get() immediately returns a string which fails the conditional on the name != "" check causing the Python interpreter to fall into the catch-all else clause which calls newUser.getName(), the function we were already in, and the process repeats until you exceed Python's maximum recursion depth. You don't want to call get() on the tkinter.Entry object immediately because that gives the user no time to enter anything. Instead, get() should be called after some event has occurred, such as a submit button being pressed.
Instead, try something like the following:
import tkinter as tk
root = tk.Tk()
class NewUser:
def __init__(self):
self.name = None
root.title("Sign Up")
self.headerLabel = tk.Label (root, text = "Sign Up!\n")
self.nameLabel = tk.Label (root, text = "Please enter your name: ")
self.nameField = tk.Entry (root)
self.submitButton = tk.Button(root, text = "Submit", command = self.saveName)
self.headerLabel.grid (row = 0, column = 0, columnspan = 2)
self.nameLabel.grid (row = 1, column = 0, sticky = "W")
self.nameField.grid (row = 1, column = 1)
self.submitButton.grid(row = 2, column = 0, columnspan = 2, sticky = "EW")
def saveName(self):
name = self.nameField.get()
if name.isalpha() and name != "":
self.name = name
print("Name saved: {}".format(self.name))
else:
print("Please ensure you have entered your name. Thank you.")
user = NewUser()
root.mainloop()
This code will generate the following window:
At this point, if you hit the Submit button, name will be an empty string and will fail the name != "" comparison. Consequently, the following is printed to the console:
Please ensure you have entered your name. Thank you.
However, if you enter your name, assuming you only include alpha characters like so:
The following is printed to the console upon pressing Submit:
Name saved: Erick
And the saved name is now accessible via the self.name member variable of our NewUser class.

str AttributeError: 'str' object has no attribute 'set' (updating label)

This is a simple math game. The function of interest is checkAnswer(). I am trying to update label1 so that the label updates with the new str instead of continuously printing multiple labels.
Error:
AttributeError: 'str' object has no attribute 'set'
from tkinter import *
from random import randint
num1 = 0
num2 = 0
userAnswer = 0
answer = 0
score = 0
labeltext = ""
#PROGRAM FUNCTIONS
def question():
global num1, num2
global answer
num1 = randint(1,10)
num2 = randint(1,10)
question = Label(text = "What is " + str(num1)+ " + " + str(num2) + "?").pack()
answer = num1+num2
print(answer) #testing purposes
def userAnswer():
global userAnswer
userAnswer = IntVar()
entry = Entry(root, textvariable = userAnswer).pack()
submit = Button(root, text = "submit", command = checkAnswer).pack()
def checkAnswer():
global labeltext
print(userAnswer.get())
if userAnswer == answer:
labeltext.set("good job")
score += 1
elif userAnswer != answer:
labeltext.set("oh no")
labeltext = StringVar()
label1 = Label(root, textvariable = labeltext).pack()
#INTERFACE CODE
root = Tk()
question()
userAnswer()
root.mainloop()
You are getting that AttributeError because you initially bind a string "" to the global name labeltext, and a Python string doesn't have a .set method. (That wouldn't make sense because Python strings are immutable). You eventually bind a Tkinter StringVar to labeltext, and StringVars do have a .set method, but your code does that after it's already tried to call .set on the plain Python string.
A similar problem will occur with the IntVar you named userAnswer. That has an additional problem: its name clashes with one of your functions. You can't do that!
Here's a repaired version of your code, with a few other minor changes. There's no need to use the global directive on those StringVars or the IntVar since you are simply calling methods of those objects. You only need global if you need to perform an assignment on a global object, merely accessing the existing value of a global or calling one of its methods doesn't need the global directive.
from tkinter import *
from random import randint
#PROGRAM FUNCTIONS
def question():
global true_answer
num1 = randint(1,10)
num2 = randint(1,10)
Label(text="What is " + str(num1)+ " + " + str(num2) + "?").pack()
true_answer = num1 + num2
print(true_answer) #testing purposes
def answer():
Entry(root, textvariable=userAnswer).pack()
Button(root, text="submit", command=checkAnswer).pack()
def checkAnswer():
global score
print(userAnswer.get()) #testing purposes
if userAnswer.get() == true_answer:
labeltext.set("good job")
score += 1
else:
labeltext.set("oh no")
label1 = Label(root, textvariable=labeltext).pack()
#INTERFACE CODE
root = Tk()
true_answer = 0
score = 0
userAnswer = IntVar()
labeltext = StringVar()
question()
answer()
root.mainloop()
However, that code still has several problems. It can only ask a single question. And each time you hit the "submit" button it adds a new Label widget, which I don't think you really want.
It's not a good idea to use global variables. They break modularity, which makes the code harder to understand, and harder to modify and re-use.
Here's an enhanced version of your program which puts everything into a class, so we can use instance attributes instead of globals.
This version asks multiple questions. It doesn't have a "submit" button, instead the question is automatically submitted when the user hits the Enter / Return key, either on the main keyboard or the numeric keypad.
import tkinter as tk
from random import randint
class Quiz(object):
def __init__(self):
root = tk.Tk()
# The question
self.question_var = tk.StringVar()
tk.Label(root, textvariable=self.question_var).pack()
# The answer
self.user_answer_var = tk.StringVar()
entry = tk.Entry(root, textvariable=self.user_answer_var)
entry.pack()
# Check the answer when the user hits the Enter key,
# either on the main keyboard or the numeric KeyPad
entry.bind("<Return>", self.check_answer)
entry.bind("<KP_Enter>", self.check_answer)
self.true_answer = None
# The response
self.response_var = tk.StringVar()
self.score = 0
tk.Label(root, textvariable=self.response_var).pack()
# Ask the first question
self.ask_question()
root.mainloop()
def ask_question(self):
num1 = randint(1, 10)
num2 = randint(1, 10)
self.question_var.set("What is {} + {}?".format(num1, num2))
self.true_answer = num1 + num2
#print(self.true_answer) #testing purposes
def check_answer(self, event):
user_answer = self.user_answer_var.get()
#print(user_answer) #testing purposes
if int(user_answer) == self.true_answer:
text = "Good job"
self.score += 1
else:
text = "Oh no"
self.response_var.set('{} Score={}'.format(text, self.score))
# Clear the old answer and ask the next question
self.user_answer_var.set('')
self.ask_question()
Quiz()
Please note the import tkinter as tk statement. It's much better to use this form than from tkinter import * since that "star" import dumps 130 names into your namespace, which is messy, and can lead to name collisions, especially if you do star imports with other modules. The import tkinter as tk form requires you to do a little more typing, but it also makes the code much easier to read, since it's obvious which names are coming from Tkinter.
I've also changed the names of the variables and the class methods (functions) so they conform to the Python PEP-0008 style guide.
There are various further enhancements that could be made. In particular, this code doesn't gracefully handle user input that isn't a valid integer.

Categories

Resources