I'm somewhat new to Tkinter with minor Python experience so I hope the answer's not too obvious, I've attempted to search for an answer but couldn’t find anything helpful. Essentially I'm trying to build a program where (as a placeholder test for now), if a user enters 1 in the entry field and hits submit, a window appears telling them they typed 1, otherwise they're told to type 1. If my understandings correct, this should work:
from Tkinter import *
#-----------------------------------------------------------
import tkMessageBox
root = Tk()
#-----------------------------------------------------------
root.title('Payroll System')
#-----------------------------------------------------------
def on_printtext(root):
global entryform
string = entryform.get()
if string == 1:
tkMessageBox.showinfo('You typed 1')
elif string != 1:
tkMessageBox.showinfo('Please type 1')
#-----------------------------------------------------------
entryform = Entry(root)
entryform.pack()
submit = Button(root, text="Submit", command=on_printtext)
submit.pack()
root.mainloop()
However when I try to run it and enter 1 in the entry form after hitting submit I get this:
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1489, in call
return self.func(*args)
TypeError: on_printtext() takes exactly 1 argument (0 given)
The issue is that tkinter is trying to call the function registered as the command for the button without any arguments, but your function has 1 argument - root without any default variable, and hence that is causing the issue you are having.
Also some other issues in your code -
Entry.get() returns a string, but you are trying to compare that against an integer , it would never be equal, so even if you enter 1 it would still show Please type 1 .
When you do - tkMessageBox.showinfo('You typed 1') - you are actually setting the title to You typed 1 , not the actual message. For the functions of tkMessageBox, the first argument is the title, and the second argument is the message. If you want that as the message, set it as themessage` using keyword argument. Example -
tkMessageBox.showinfo(message='You typed 1')
Example code that works -
from Tkinter import *
import tkMessageBox
root = Tk()
root.title('Payroll System')
def on_printtext():
global entryform
strng = entryform.get()
if strng == '1':
tkMessageBox.showinfo(message='You typed 1')
else:
tkMessageBox.showinfo(message='Please type 1')
entryform = Entry(root)
entryform.pack()
submit = Button(root, text="Submit", command=on_printtext)
submit.pack()
root.mainloop()
If you are using Python 3.x, the code above does not work since tkMessageBox has been changed to messagebox.
Here's the modified code:
from tkinter import * # modif 1 Tkinter with minus t !
import tkinter.messagebox # modif 2:tkMessageBox no longer valid
root = Tk()
root.title('Payroll System')
def on_printtext():
global entryform
strng = entryform.get()
if strng == '1':
tkinter.messagebox.showinfo(message='You typed 1') # modif 3
else:
tkinter.messagebox.showinfo(message='Please type 1') # modif 4
entryform = Entry(root)
entryform.pack()
submit = Button(root, text="Submit", command=on_printtext)
submit.pack()
root.mainloop()
Related
I am Python coder and got stuck in a question that "How to check input in textbox of tkinter python". The problem is that it is not giving output on writing this code .
def start(event):
a = main.get(1.0,END)
if a == 'ver':
print('.....')
main = Text(root)
main.pack()
root.bind('<Return>',start)
We can do this by get() method:
from tkinter import *
a=Tk()
def check():
print(x.get('1.0',END)[:-1])
x=Text(a)
b=Button(a,text='Check',command=check)
x.pack()
b.pack()
a.mainloop()
The text widget guarantees that there is always a trailing newline. When you do get(1.0,END) you're getting that trailing newline even if the user doesn't enter a newline.
If you want to get exactly what the user entered, use get("1.0", "end-1c"). That will get all of the characters up to the end, minus one character.
Note: text indexes are strings of the form line.character. Your code is using the floating point value 1.0 which is incorrect. It works fine in some cases, but it won't work in all. You should always use a string rather than a float for text indexes.
from tkinter import *
from threading import Thread
root = Tk()
def check():
while True :
a = main.get(1.0,END)[:-1]
if a == 'ver':
print('.....')
main = Text(root)
main.pack()
Thread(target=check).start()
root.mainloop()
You should write something like
def start(event):
t = var.get()
if t == 'something':
pass
var = StringVar()
e = Entry(master, textvariable=var)
e.pack()
e.bind(bind('<Return>',start)
from tkinter import *
window = Tk()
window.title("Registration")
window.configure(background="blue")enter code here
Label (window, text= "Firstname: ", bg="blue", fg="white", font="verdana 12 bold") .grid(row=0, sticky=E)
firstname = Entry(window, width=100, bg="white")
firstname.grid(row=0, column=1, sticky=W)
firstname = firstname.get()
firstname = firstname.strip()
firstname = firstname.lower()
Label (window, bg = "blue") .grid(row=2)
Label (window, text= "Surname: ", bg="blue", fg="white", font="verdana 12 bold") .grid(row=3, sticky=E)
surname = Entry(window, width=100, bg="white")
surname.grid(row=3, column=1, sticky=W)
surname = surname.get()
surname = surname.lower()
surname = surname.strip()
Label (window, bg = "blue") .grid(row=4)
Label (window, text = "Pick a number between 0 and 10: ", bg="blue", fg="white", font = "verdana 12 bold") .grid(row=5, sticky=E)
number = Entry(window, width=100, bg="white")
number.grid(row=5, column=1)
while True:
try:
number = number.get()
if (number > 10) or (number < 0): 1/0
except:
print("Sorry, your response must be a number between 0 and 10")
continue
break
window.mainloop()
This is my code so far. I am trying to create a registration system for a quiz I'm making, however, now that I am dealing with GUI, I don't know how to use my validation code in the GUI way/environment. for example, just having "print("sorry, your response must be a number between 0 and 10")" won't and isn't working with my program.
My question: How do I output a message into a textbox like an error message and how do I implement my validation code?
Also, I made my validation code onths ago when I was new to python and used a stack overflow piece of code to help apply it to my program. Anyway, could someone help explain how this code actually works. I don't seem to understand it now and my teacher has struggled to explain it in an understandable way. Specifically the : 1/0 bit. I'm not used to using try and except, I only know how to use for and while loops usually.
Many thanks
Showing messages in tkinter (1st question)
To show the user basic massages and get basic options (show an error, ask OK/Cancel or yes/no...) you can use tkinter.messagebox. It provides show*() and ask*() functions. In your case, showerror() or showwarning() is probably best.
To get basic input, tkinter.simpledialog can be used. It provides the functions askinteger, askfloat and askstring that will ask the user for the respective data type.
To get file (path) input, use tkinter.filadialog.
For more complex situations, it is best you use the tkinter.Toplevel widget.
2nd question
Your code
I am going to play interpreter and go through your code. If you just want the solutions (not recommended), jump below.
firstname = Entry(...) => create an Entry widget and assign it to firstname
firstname.grid(...) => put the widget in/on the window
firstname = firstname.get() => get the text currently in the widget and assign it to firstname.
OK, you want to get the text. Just, the window isn't even visible yet. These instructions will work in the IDLE shell, because of special reasons and you wait to call .get() until you typed your name. In "real" execution, the interpreter won't wait and your user can't type (because there isn't a window) before you call .mainloop(). One solution, if you read above, is to use simpledialog. But also this should run after the GUI started, i.e. after .mainloop() is called. I'll get to that part later.
-- same for surname --
Your validation
Interpreter:
number = Entry(...) => create a new Entry widget and assign it to number
number.grid(...) => show it
# while True here
# try here
number = number.get() => call number.get() and assign the value (a str) to number -- keep that in mind
# if condidtion below
number > 10 => check if a str is larger/greater than an int; can't do that, raise a TypeError
# error -> go to the except
print("I asked how to do this on SO") => show this (in the console); in future hopefully via messagebox
continue => go to the beginning of the loop
# in try
number = number.get() => call the .get() method of the str number; can't find it, raise an AttributeError
# error -> go to the except
print(...) => as before
continue => as before
You get caught in an infinite loop of exception that won't stop even if the user enters a correct number (which can't happen anyway, we don't have a window yet). This is a very good reason for avoiding a bare except - you will also catch lots of stuff you don't want.
Why the method you are trying to use wooooould work (you said you found it here -- do you still have a link or remember the title?):
Code (this example in the console for simplicity):
while True:
try:
value = int(input())
if not 0<value<10:
1/0
except ZeroDivisionError: # let ValueError through (you willl want to catch it separately)
print('by executing 1/0, I raised a ZeroDivisionError. This code therefore will execute.')
else:
print('Everything did fine. I will exit the loop to continue.')
break
Interpreter:
# loop
# in try
value = int(input()) => read input and try to convert to an int; we assume this doesn't fail.
# if condition
not 0<value<10 => is value not between 0 and 10? (we assume it isn't)
# if block
1/0 => what?!? I can't do that, I'll raise a ZeroDivisionError
# except block
print(...) => show the text
# loop again
# in try
value = int(input()) => as above
# if condition
not 0<value<10 => we assume value is between 0 and 10 (evaluetes to False)
# else part of the try...except...else
print(...) => show text
break => exit the loop
You intentionally perform 1/0, which will raise a ZeroDivisionError and act on that in the except. Since you said you don't usually do it, I recommend you try to understand what it does.
How to do it better
Make the window appear before expecting user input: Put all code that should execute at application start in a function and either delay it with tkinter.Tk.after (window.after) or add a nice "Start!"
Button.
Don't (ab)use exceptions when a simple if will do (if you really want to (show off), define your own class MyFancyException(Exception): pass)
Look up on concepts you don't understand before using them and insert comments to remind you if something is so complicated you're afraid you won't remember later.
.
import tkinter as tk
from tkinter.simpledialog import askstring, askinteger
from tkinter.messagebox import showwarning
def do_stuff(first_name, surname, number):
...
def start():
# if you want to use Entry, add a "Submit" Button
first_name = askstring('Title', 'first name:')
surname = askstring('Title', 'last name:')
while True: # ask* return None when cancel is pressed
number = askinteger('Title', 'insert a number between 0 and 10:')
if number is not None and 0<number<10: # what we want
break
do_stuff(first_name, surname, number)
# GUI preparation code
window = tk.Tk()
button_start = tk.Button(window, text='Start!', command=start)
button_start.pack() # for use with other widgets (that use grid), you must .grid() here
window.mainloop() # the GUI appears at this moment
I really did my best to find the solution on my own, but haven't. I want to have the value from a slider and then save it to a csv file (which is working fine), at the click of a button. Alas, I can't get the value of the tkinter.Scale during my button event. I wonder if it global variables might solve my problem, but I haven't gotten them to work. I'm particularly surprised because I can print a live stream of the scale's value as I change it, but can't save it in a useful way. If you could answer any of my befuddlement or let me know if my question is unclear or in anyway could be better, I'd greatly appreciate it. Here are some links to things that helped me get this far:
https://www.programiz.com/python-programming/global-local-nonlocal-variables
Tkinter - Get the name and value of scale/slider
Here is my attempt to print the final value 10 times:
from tkinter import *
root = Tk()
def scaleevent(v): #Live update of value printed to shell
print(v)
variable = v
def savevalue():
global variable #This is what I want to work, but doesn't
for i in range(10):
print(variable)
scale = Scale(orient='vertical', command=scaleevent).grid(column=0,row=0)
button = Button(text="button", command=savevalue).grid(column=1, row=0)
root.mainloop()
And here is my attempt to solve my problem using .get():
from tkinter import *
root = Tk()
def savevalue(): #print value 10 times. In final version I will save it instead
for i in range(10):
print(scale.get()) #I really want this to work, but it doesn't,
root.destroy #is it because .get is in a function?
scale = Scale(orient='vertical', command=scaleevent).grid(column=0,row=0)
button = Button(text="button", command=savevalue).grid(column=1, row=0)
root.mainloop()
(Python 3.5, Windows 10)
Edit:
This is the error I get from the first attempt using a global variable:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Me\AppData\Local\Programs\Python\Python35\lib\tkinter\__init__.py", line 1550, in __call__
return self.func(*args)
File "C:\Users\Me\Documents\programing\tkinter scale question.py", line 15, in savevalue
print(variable)
NameError: name 'variable' is not defined
That's what happened when I run the first example of code, and similarly my actual project. Thanks Bryan Oakley!
You have to use global in scaleevent because you try to assing value to variable. Without global it assigns v to local variable and then it doesn't exists in savevalue
from tkinter import *
root = Tk()
def scaleevent(v):
global variable
print(v)
variable = v
def savevalue():
print(variable)
Scale(orient='vertical', command=scaleevent).grid(column=0,row=0)
Button(text="button", command=savevalue).grid(column=1, row=0)
root.mainloop()
As for second version you made mistake with var = Widget(...).grid()
It assigns None to var because grid()/pack()/place() returns None.
You have to do it in two lines:
var = Widget(...)
var.grid(...)
Code
from tkinter import *
root = Tk()
def savevalue():
print(scale.get())
root.destroy() # you forgot ()
scale = Scale(orient='vertical')
scale.grid(column=0,row=0)
button = Button(text="button", command=savevalue)
button.grid(column=1, row=0)
root.mainloop()
from tkinter import *
root = Tk()
variable=0 # only you forgot this
def scaleevent(v):
print(v)
global variable
variable=v
def savevalue():
print(variable)
Scale(orient='vertical', command=scaleevent).grid(column=0,row=0)
Button(text="button", command=savevalue).grid(column=1, row=0)
root.mainloop()
i am facing a problem. I'm runnig this code.
import tkinter as tk
root = tk.Tk()
def check():
if len(e.get().split("a")) > 1:
print("contains a")
e = tk.Entry(frame1)
e.grid(row=4,column=1,columnspan=2,padx = (10,10), pady=(5,10), sticky="w e")
e.bind("<Key>",check)
when i type "a" to the entry I wont get nothing printed. I'll get the result by tiping a second character. I think that it happens because the function gets executed before the content has actualy changed. I tried to add a timer on the beginning of the function but it does nothing.
I want get the result by entering the first "a". What should I do?
I think that it happens because the function gets executed before the content has actualy changed.
You're right. If you want the callback to be able to see the character you just typed, you should create a StringVar and bind to that instead of binding to a "<Key>" event on the widget.
import tkinter as tk
frame1 = tk.Tk()
def check(*args):
if "a" in s.get():
print("contains a")
s = tk.StringVar()
e = tk.Entry(frame1, textvariable=s)
s.trace("w", check)
e.grid(row=4,column=1,columnspan=2,padx = (10,10), pady=(5,10), sticky="w e")
frame1.mainloop()
My program should check if the first three letters of the input word are similar to a predefined word.
I've made a GUI with Tkinter and want to get the letters of the input field.
Somehow I can't implement it in like I would do without Tkinter.
That's how I do it just for the shell:
text = raw_input('Enter a word: ')
if (text[0] + text[1] + text[2] == 'sag'):
print "sagen"
else:
print "error"
So, when I input the word "sagst" it checks the first three letters and should put out "sagen". Works fine.
I learned that e.g. inputfield.get() gets the input of the entry "inputfield".
But how can I check the first letters of that "inputfield"?
A small selection:
from Tkinter import*
root = Tk()
def check():
if (text[0] + text[1] + text[2] == 'sag'):
print "True"
else:
print "False"
inputfield = Entry(root)
inputfield.pack()
but = Button(root,text='Check!', command = check)
but.pack()
text = inputfield.get()
root.mainloop()
Does not work...
I hope you can understand my question and will answer soon. (Sorry for my bad english and my bad Python skills) ;-)
Thanks!
Your check function will have to retrieve the textfield after the button has been pressed:
def check():
text = inputfield.get()
print text.startswith('sag')
I've changed your test a little, using .startswith(), and directly printing the result of that test (print will turn boolean True or False into the matching string).
What happens in your code is that you define inputfield, retrieve it's contents (obviously empty), and only then show the TKInter GUI window by running the mainloop. The user never gets a chance to enter any text that way.
You can also check this without the need for a button (Now it will check whenever the user presses "Enter"):
from Tkinter import *
root = Tk()
def check(*event):
text = inputfield.get()
print text.startswith('sag')
inputfield = Entry(root)
inputfield.bind('<Return>',check)
inputfield.pack()
root.mainloop()
You can also do other things to have your widget validate the entry as you type. (The link is old, but it also points to newer features that allow you to do this without subclassing).
You're not actually putting the value in the input field into the text variable.
I renamed the value from text to input_text because it was confusing to me. I also changed from using text[0] + text[1] + text[2] to using startswith(). This will keep you from getting IndexErrors on short strings, and is much more pythonic.
from Tkinter import*
root = Tk()
def check():
input_text = inputfield.get()
if input_text.startswith('sag'):
print "True"
else:
print "False"
inputfield = Entry(root)
inputfield.pack()
input_text = inputfield.get()
print input_text # Note that this never prints a string, because it only prints once when the input is empty.
but = Button(root, text='Check!', command=check)
but.pack()
root.mainloop()
The key change is that the check function needs to actually get the value in the inputfield.
Here is a version which uses an Entry widget which validates its contents as the user types (so the user does not have to click a button or even press Return).
import Tkinter as tk
class MyApp(object):
'''
http://effbot.org/zone/tkinter-entry-validate.htm
http://effbot.org/tkinterbook/entry.htm
http://www.tcl.tk/man/tcl8.5/TkCmd/entry.htm#M-validate
'''
def __init__(self, master):
vcmd = (master.register(self.validate),
'%d', '%i', '%P', '%s', '%S', '%v', '%V', '%W')
self.entry = tk.Entry(master, validate = 'key',
validatecommand = vcmd)
self.entry.pack()
self.entry.focus()
def validate(self, action, index, value_if_allowed,
prior_value, text, validation_type, trigger_type, widget_name):
dtype = {'0':'delete', '1':'insert', '-1':'other'}[action]
n = min(3, len(value_if_allowed))
valid = False
if dtype == 'insert':
if value_if_allowed[:n] == 'sag'[:n]: valid = True
else: valid = False
else: valid = True
print(valid)
return True
root = tk.Tk()
app = MyApp(root)
root.mainloop()