This question already exists:
"Unexpected EOF while parsing" in calculator
Closed 8 years ago.
I have a calculator in Python 3 but for some reason my code doesn't work. It works fine until I press the "=" button to calculate my thing (using tkinter for the gui). Here is my code (it is quite long, sorry for that, it is just a part from my code)
from tkinter import *
from tkinter.ttk import *
def SMATH():
#PUT TEXT IN ENTRY FUNCTION
def puttext(text):
sm_ent.insert(0,text)
return
#CLEAR THE ENTRY FUNCTION
def cleartext():
sm_ent.delete(0, END)
return
#GET THE OUTCOME FUNCTION
def Coutcome():
calc = caltext.get()
answer = eval(calc)
sm_ent = Entry(e_frame, textvariable=caltext, text=answer)
smathW = Tk()
smathW.title("Simple Math")
smathW.resizable(0,0)
smathW.wm_iconbitmap('icon.ico')
def quitSmath():
smathW.destroy()
#ENTRY FRAME
e_frame = Frame(smathW)
e_frame.pack()
#BUTTONS FRAME
b_frame = Frame(smathW)
b_frame.pack()
#ENTRY
caltext= StringVar()
sm_ent = Entry(e_frame, textvariable=caltext)
sm_ent.pack(fill=Y)
#LABEL
sm_inf = Label(smathW, text="Here is the Simple Math mode from CalfoWin")
sm_inf.pack()
#BUTTON 7
sm_butt0 = Button(b_frame, text="7", command=lambda: puttext('7'))
sm_butt0.grid(row=1, column=0)
#BUTTON 8
sm_butt1 = Button(b_frame, text="8", command=lambda: puttext('8'))
sm_butt1.grid(row=1, column=1)
#BUTTON 9
sm_butt2 = Button(b_frame, text="9", command=lambda: puttext('9'))
sm_butt2.grid(row=1, column=2)
#BUTTON 4
sm_butt3 = Button(b_frame, text="4", command=lambda: puttext('4'))
sm_butt3.grid(row=2, column=0)
#BUTTON 5
sm_butt4 = Button(b_frame, text="5", command=lambda: puttext('5'))
sm_butt4.grid(row=2, column=1)
#BUTTON 6
sm_butt5 = Button(b_frame, text="6", command=lambda: puttext('6'))
sm_butt5.grid(row=2, column=2)
#BUTTON 1
sm_butt6 = Button(b_frame, text="1", command=lambda: puttext('1'))
sm_butt6.grid(row=3, column=0)
#BUTTON 2
sm_butt7 = Button(b_frame, text="2", command=lambda: puttext('2'))
sm_butt7.grid(row=3, column=1)
#BUTTON 3
sm_butt8 = Button(b_frame, text="3", command=lambda: puttext('3'))
sm_butt8.grid(row=3, column=2)
#BUTTON 0
sm_butt9 = Button(b_frame, text="0", command=lambda: puttext('0'))
sm_butt9.grid(row=4, column=0)
#BUTTON KOMMA
sm_buttKomma = Button(b_frame, text=".", command=lambda: puttext('.'))
sm_buttKomma.grid(row=4, column=1)
#BUTTON EQUALSIGN!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
sm_buttEsign = Button(b_frame, text="=", command=Coutcome())
sm_buttEsign.grid(row=4, column=2)
#BUTTON ADDITION
sm_buttPlus = Button(b_frame, text="+", command=lambda: puttext('+'))
sm_buttPlus.grid(row=2, column=3)
#BUTTON SUBTRACKTION
sm_buttMin = Button(b_frame, text="-", command=lambda: puttext('-'))
sm_buttMin.grid(row=3, column=3)
#BUTTON DIVISION
sm_buttDiv = Button(b_frame, text="/", command=lambda: puttext('/'))
sm_buttDiv.grid(row=3, column=4)
#BUTTON MULTIPLICATION
sm_buttMult = Button(b_frame, text='x', command=lambda: puttext('*'))
sm_buttMult.grid(row=2, column=4)
#BUTTON CLEAR
sm_buttClear = Button(b_frame, text="Clear", command=lambda: cleartext())
sm_buttClear.grid(row=1, column=3)
#BUTTON QUIT
sm_buttquit = Button(b_frame, text="Quit", command=lambda: quitSmath())
sm_buttquit.grid(row=1, column=4)
You use command = Coutcome() which passes the return value of Coutcome as the funtion to call when the button is pressed. So what happens now is that Coutcome is called when the button is created, and caltext is still empty. This means that you are running eval(''), which gives you the error you are seeing.
This is not what you want, you want Coutcome to be called when the button is pressed. So You should pass the function name, without parentheses, as the command
sm_buttEsign = Button(b_frame, text="=", command=Coutcome)
For your quit and clear buttons you should do the same thing, get rid of the parentheses and the lambda. The reason you need to use lambda sometimes is because when you have to leave out the parentheses, you can't pass variables to the command. When you don't need to pass variables, the lambda is superfluous.
In addition, you should be careful using eval. With the wrong input, it can be dangerous. So watch out with letting users input stuff to eval without proper restrictions.
Related
I have a tkinter GUI code that executes different functions which are mapped to different buttons/widgets, I want to give users the option of choosing to open the GUI window or directly execute from the command line.
I tried keeping mainloop() inside an optional switch like:
if gui == "1":
root.mainloop()
else:
#command mode
# call required functions here using user switches.
Is this the correct way of doing this? this is working when i tried in linux system.
root = Tk()
root.title('ATM v.keypad buttons //////dont acc work///////')
# creates the buttons adds no value tho
# size of button
gridlabel1 = Button(root, text='1', padx=50, pady=50)
gridlabel2 = Button(root, text='2', padx=50, pady=50)
gridlabel3 = Button(root, text='3', padx=50, pady=50)
gridlabel4 = Button(root, text='4', padx=50, pady=50)
gridlabel5 = Button(root, text='5', padx=50, pady=50)
gridlabel6 = Button(root, text='6', padx=50, pady=50)
gridlabel7 = Button(root, text='7', padx=50, pady=50)
gridlabel8 = Button(root, text='8', padx=50, pady=50)
gridlabel9 = Button(root, text='9', padx=50, pady=50)
gridlabel0 = Button(root, text='0', padx=50, pady=50)
cancelbutton = Button(root, text='cancel', padx=75, pady=50)
clearbutton = Button(root, text='clear', padx=75, pady=50)
enterbutton = Button(root, text='enter', padx=75, pady=50)
# prints the button at set location
gridlabel1.grid(row=0, column=0)
gridlabel2.grid(row=0, column=1)
gridlabel3.grid(row=0, column=2)
gridlabel4.grid(row=1, column=0)
gridlabel5.grid(row=1, column=1)
gridlabel6.grid(row=1, column=2)
gridlabel7.grid(row=2, column=0)
gridlabel8.grid(row=2, column=1)
gridlabel9.grid(row=2, column=2)
gridlabel0.grid(row=3, column=1)
cancelbutton.grid(row=0, column=4)
clearbutton.grid(row=1, column=4)
enterbutton.grid(row=2, column=4)
root.mainloop()
that was my example notice how I put root.mainloop() at the end
was indented because it was in a if statement
I've made a really simple desktop app using Tkinter. When I set up everything in py2app the program looks like its generated fine, but when I click on it to open my computer restarts everytime. The code will run fine when I run it out of the Python IDE, but my screen goes black and restarts and brings me back to the MacOS login page when I try to run it by clicking on the icon or running the py2app version from the terminal. Has anyone run into this issue?
from tkinter import *
import tkinter
# importing everyting from tkinter
# expression to access among all the functions
expression = ""
# functions
def input_number(number, equation):
# accessing the global expression variable
global expression
# concatenation of string
expression = expression + str(number)
equation.set(expression)
def clear_input_field(equation):
global expression
expression = ""
# setting empty string in the input field
equation.set("Enter the expression")
def evaluate(equation):
global expression
# trying to evaluate the expression
try:
result = str(eval(expression))
# showing the result in the input field
equation.set(result)
# setting expression to empty string
expression = ""
except:
# some error occured
# showing it to the user equation.set("Enter a valid expression")
expression = ""
def new_calc():
new_window = Tk()
new_window.title("A whole new window")
# set the configuration of GUI window
new_window.geometry("450x220")
print('This is a new window!')
# creating the GUI
def main():
# main window
window = Tk()
# setting the title of GUI window
window.title("Calculator")
# set the configuration of GUI window
window.geometry("450x220")
# varible class instantiation
equation = StringVar()
# input field for the expression
input_field = Entry(window, textvariable=equation)
input_field.place(height=100)
# we are using grid position
# for the arrangement of the widgets
input_field.grid(columnspan=4, ipadx=100, ipady=5)
# settin the placeholder message for users
equation.set("Enter the expression")
# creating buttons and placing them at respective positions
_1 = Button(window, text='1', bd=0, command=lambda: input_number(1, equation), height=2, width=7)
_1.grid(row=2, column=0)
_2 = Button(window, text='2', bd=0, command=lambda: input_number(2, equation), height=2, width=7)
_2.grid(row=2, column=1)
_3 = Button(window, text='3', bd=0, command=lambda: input_number(3, equation), height=2, width=7)
_3.grid(row=2, column=2)
_4 = Button(window, text='4', bd=0, command=lambda: input_number(4, equation), height=2, width=7)
_4.grid(row=3, column=0)
_5 = Button(window, text='5', bd=0, command=lambda: input_number(5, equation), height=2, width=7)
_5.grid(row=3, column=1)
_6 = Button(window, text='6', bd=0, command=lambda: input_number(6, equation), height=2, width=7)
_6.grid(row=3, column=2)
_7 = Button(window, text='7', bd=0, command=lambda: input_number(7, equation), height=2, width=7)
_7.grid(row=4, column=0)
_8 = Button(window, text='8', bd=0, command=lambda: input_number(8, equation), height=2, width=7)
_8.grid(row=4, column=1)
_9 = Button(window, text='9', bd=0, command=lambda: input_number(9, equation), height=2, width=7)
_9.grid(row=4, column=2)
_0 = Button(window, text='0', bd=0, command=lambda: input_number(0, equation), height=2, width=7)
_0.grid(row=5, column=0)
plus = Button(window, text='+', bd=0, command=lambda: input_number('+', equation), height=2, width=7)
plus.grid(row=2, column=3)
minus = Button(window, text='-',bd=0, command=lambda: input_number('-', equation), height=2, width=7)
minus.grid(row=3, column=3)
multiply = Button(window, text='*', bd=0, command=lambda: input_number('*', equation), height=2, width=7)
multiply.grid(row=4, column=3)
divide = Button(window, text='/', bd=0, command=lambda: input_number('/', equation), height=2, width=7)
divide.grid(row=5, column=3)
equal = Button(window, text='=', bd=0, command=lambda: evaluate(equation), height=2, width=7)
equal.grid(row=5, column=2)
clear = Button(window, text='Clear', bd=0, command=lambda: clear_input_field(equation), height=2, width=7)
clear.grid(row=5, column=1)
# showing the GUI
window.mainloop()
# start of the program
if __name__ == '__main__':
main()
Here is the setup file:
from setuptools import Extension, setup
APP = ['CalcApp.py']
DATA_FILES = []
OPTIONS = {
'iconfile':'Calculator.icns',
'argv_emulation': True,
'packages': ['certifi'],
}
setup(
app=APP,
data_files=DATA_FILES,
options={'py2app': OPTIONS},
setup_requires=['py2app'],
)
I have a window with two parts. One part is to do some settings. I want to hide it until the user press a setting button. is it possible to hide a part of the frame that contains many widgets?
I have seen many examples to hide a widget in tkinter (eg. pack_forget and grid_forget). In my case, I am trying to hide a part of the frame through a button press (that contains more than one widgets). Any suggestions please
I can't use more than one frames because of some issues.
import tkinter as tk
def startFn():
pass
#fn body
def stopFn():
pass
#fn body
def FnToShow():
pass
#fn body ???
def FnToHide():
pass
#fn body ???
root = tk.Tk()
root.geometry('600x400')
#two containers like this.
#trying to hide container_2 untill the user press settingBtn
container_1 = tk.Frame(root, borderwidth=2, relief="solid")
container_2 = tk.Frame(root, borderwidth=2, relief="solid")
startBtn = tk.Button(container_1, text = "Start", command =startFn)
startBtn.grid(row=4, column=4)
stopBtn = tk.Button(container_1, text = "Stop", command= stopFn)
stopBtn.grid(row=5, column=4)
settingBtn = tk.Button(container_1, text = "Settings", command= FnToShow)
settingBtn.grid(row=6, column=4)
setting_1 = tk.Label(container_2, text = "Setting-1", fg='#000000')
setting_1.grid(row=3, column=10)
setting_2 = tk.Label(container_2, text = "Setting-2", fg='#000000')
setting_2.grid(row=4, column=10)
closeSettingBtn = tk.Button(container_2, text = "close Settings", command= FnToHide)
closeSettingBtn.grid(row=5, column=10)
container_1.pack(side="left", expand=True, fill="x", padx=1, pady=1)
container_2.pack(side="right",expand=True, fill="x", padx=1, pady=1)
root.mainloop()
You could show/hide the entire container_2 using the functions FnToShow and FnToHide:
something like this:
import tkinter as tk
def startFn():
pass
def stopFn():
pass
def FnToShow():
container_2.pack(side="right",expand=True, fill="x", padx=1, pady=1)
def FnToHide():
container_2.pack_forget()
root = tk.Tk()
root.geometry('600x400')
container_1 = tk.Frame(root, borderwidth=2, relief="solid")
container_2 = tk.Frame(root, borderwidth=2, relief="solid")
startBtn = tk.Button(container_1, text="Start", command =startFn)
startBtn.grid(row=4, column=4)
stopBtn = tk.Button(container_1, text="Stop", command= stopFn)
stopBtn.grid(row=5, column=4)
settingBtn = tk.Button(container_1, text="Settings", command= FnToShow)
settingBtn.grid(row=6, column=4)
setting_1 = tk.Label(container_2, text="Setting-1", fg='#000000')
setting_1.grid(row=3, column=10)
setting_2 = tk.Label(container_2, text="Setting-2", fg='#000000')
setting_2.grid(row=4, column=10)
closeSettingBtn = tk.Button(container_2, text="close Settings", command= FnToHide)
closeSettingBtn.grid(row=5, column=10)
container_1.pack(side="left", expand=True, fill="x", padx=1, pady=1)
root.mainloop()
Please Help! I'm at my wits end over here... I am new to learning Python and tkinter and I have not found anyone trying to do what I am, so I keep trying different people's answers and nothing is working. I can't understand the docs, and every tutorial I find is not quite exactly what I need to do, so I end up with irrelevant code bits that just lead to more problems.
I want to build a GUI for a touchscreen program for a Raspberry Pi that will allow me to program a relay to turn on for "x" seconds, then turn off for "y" seconds, then repeat forever until I stop it. The touchscreen needs to have large buttons for each of the numbers 0 - 9, a button to clear the values, buttons to confirm each value once it has been input in the entry box, a button to start the cycle, and a button to exit. There also needs to be 2 entry boxes, one for "On", and one for "Off", so that the user can see the numbers they have entered for each value. This is what is messing me up. I can get it to work for one entry box, but not two.
Please someone tell me what is wrong. I don't know how to tell each button to place its value only in the entry field that has focus. I can only figure out how to tell it to input in one entry or the other, regardless of which has focus.
I also need the numbers to appear in the entry boxes in the correct sequence, so that when you type a "3" and then a "0", the program reads "30". Right now it is producing "03".
Here's the code. I have some things commented out currently, and yes, I know it's ugly:
#!/usr/bin/env python
try:
# for Python 2
from Tkinter import *
except ImportError:
# for Python 3
from tkinter import *
import ttk as ttk
import RPi.GPIO as GPIO
import time
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(4, GPIO.OUT)
GPIO.setup(4, GPIO.LOW)
running = True
def water():
go.grid(column=4, row=3, rowspan=6, columnspan=6, sticky=W)
def go():
running = True
x = on.get()
y = off.get()
y = float(y)
x = float(x)
if running:
GPIO.output(4, False)
print("Off")
time.sleep(y)
GPIO.output(4, True)
print("On")
time.sleep(x)
root.after(10, go)
def clear():
on.set('')
off.set('')
global running
running = False
go.grid_forget()
on_entry.focus()
def select(value):
if on_entry.focus():
on_entry.set(value)
elif off_entry.focus():
off_entry.set(value)
def geton():
on_entry.get()
off_entry.focus()
def getoff():
off_entry.get()
water()
#this is the PROBLEM!!!!
def set_text(text):
on_entry.insert(0,text)
#buttons = ['1','2','3','4','5','6','7','8','9','0']
#varRow = 5
#varColumn = 0
root = Tk()
root.geometry("740x480+0+0")
root.title("Waterboy")
#need to make this fullscreen
mainframe = Frame(root)
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)
go = Button(mainframe, text="GO", command=go, bg="green", width=6, height=11)
#seconds on and off
on = StringVar()
off = StringVar()
on_entry = Entry(mainframe, width=8, textvariable=on)
on_entry.grid(column=2, row=1, sticky=(W, E))
off_entry = Entry(mainframe, width=8, textvariable=off)
off_entry.grid(column=2, row=2, sticky=(W, E))
on_entry.focus_set()
onok = Button(mainframe, text="OK", command=geton, bg="white", width=6, height=1)
onok.grid(column=4, row=1, sticky=W)
offok = Button(mainframe, text="OK", command=getoff, bg="white", width=6, height=1)
offok.grid(column=4, row=2, sticky=W)
reset = Button(mainframe, text="Reset Values", command=clear, bg='yellow', width=16, height=2)
reset.grid(column=0, row=7, sticky=W)
adios = Button(mainframe, text="EXIT", command=exit, bg="red", width=16, height=2)
adios.grid(column=2, row=7, sticky=W)
secon = ttk.Label(mainframe, text="Input # Seconds Water ON and press 'OK' -->", width=36)
secon.grid(column=0, row=1, columnspan=2)
secoff = ttk.Label(mainframe, text="Input # Seconds Water OFF and press 'OK' -->", width=36)
secoff.grid(column=0, row=2, columnspan=2)
one = Button(mainframe, text="1", width=16, height=2, command=lambda:set_text("1")
one.grid(column=0, row=4, sticky=W)
two = Button(mainframe, text="2", width=16, height=2, command=lambda:set_text("2")
two.grid(column=1, row=4, sticky=W)
three = Button(mainframe, text="3", width=16, height=2, command=lambda:set_text("3")
three.grid(column=2, row=4, sticky=W)
four = Button(mainframe, text="4", width=16, height=2, command=lambda:set_text("4")
four.grid(column=0, row=5, sticky=W)
five = Button(mainframe, text="5", width=16, height=2, command=lambda:set_text("5")
five.grid(column=1, row=5, sticky=W)
six = Button(mainframe, text="6", width=16, height=2, command=lambda:set_text("6")
six.grid(column=2, row=5, sticky=W)
seven = Button(mainframe, text="7", width=16, height=2, command=lambda:set_text("7")
seven.grid(column=0, row=6, sticky=W)
eight = Button(mainframe, text="8", width=16, height=2, command=lambda:set_text("8")
eight.grid(column=1, row=6, sticky=W)
nine = Button(mainframe, text="9", width=16, height=2, command=lambda:set_text("9")
nine.grid(column=2, row=6, sticky=W)
zero = Button(mainframe, text="0", width=16, height=2, command=lambda:set_text("0")
zero.grid(column=1, row=7, sticky=W)
#for child in mainframe.winfo_children(): child.grid_configure(padx=4, pady=4)
#root.bind('<Return>', go)
#for button in buttons:
# command = lambda x=button: select(x)
# Button(mainframe, text=button, width=5, bg="white", command = command).grid(row = varRow, column=varColumn)
# varColumn += 1
# if varColumn > 2 and varRow == 4:
# varColumn = 0
# varRow += 1
# if varColumn > 2 and varRow == 5:
# varColumn = 0
# varRow += 1
# if varColumn > 2 and varRow == 6:
# varColumn = 0
# varRow += 1
root.mainloop()
You can use the method focus_get on the root window to get the widget that has focus. You can then insert text using that widget. You can specify the special index of "end" to have the text inserted at the end of the widget.
For example:
def set_text(text)
widget = root.focus_get()
widget.insert("end", text)
Of course, you'll want to do some validation to make sure that the widget is a text or entry widget.
Also, be careful with using ttk -- the default behavior of ttk button widgets is to steal the keyboard focus.
I am in the process of learning basic Python. I am currently attempting to create a simple calculator program that only has addition and subtraction. I have one issue though. I am not sure how I would add text to my Python label upon button press. Right now, upon pressing the '1' button, my program will change the display label to the text "1". However, I want my program to add text, not set it.
For example, if I press 'button 1' 5 times, it currently will reset the label text 5 times and will result with a single 1. I want it to add the number to the label upon press, not replace.
Current Result after pressing button 5 times: 1
Requested result after pressing button 5 times: 11111
Here is my current code for the program. If anything is unclear, just ask; thanks.
from tkinter import *
window = Tk()
# Creating main label
display = Label(window, text="")
display.grid(row=0, columnspan=3)
def add_one():
display.config(text='1')
# Creating all number buttons
one = Button(window, text="1", height=10, width=10, command=add_one)
two = Button(window, text="2", height=10, width=10)
three = Button(window, text="3", height=10, width=10)
four = Button(window, text="4", height=10, width=10)
five = Button(window, text="5", height=10, width=10)
six = Button(window, text="6", height=10, width=10)
seven = Button(window, text="7", height=10, width=10)
eight = Button(window, text="8", height=10, width=10)
nine = Button(window, text="9", height=10, width=10)
zero = Button(window, text="0", height=10, width=10)
# Placing all number buttons
one.grid(row=1, column=0)
two.grid(row=1, column=1)
three.grid(row=1, column=2)
four.grid(row=2, column=0)
five.grid(row=2, column=1)
six.grid(row=2, column=2)
seven.grid(row=3, column=0)
eight.grid(row=3, column=1)
nine.grid(row=3, column=2)
# Creating all other buttons
add = Button(window, text="+", height=10, width=10)
subtract = Button(window, text="-", height=10, width=10)
equal = Button(window, text="=", height=10, width=10)
# Placing all other buttons
add.grid(row=4, column=0)
subtract.grid(row=4, column=1)
equal.grid(row=4, column=2)
window.mainloop()
You should use a StringVar for this. And your callback needs to get the current contents of the StringVar, modify it, and use the modified string to set the new value of the StringVar. Like this:
import tkinter as tk
window = tk.Tk()
# Creating main label
display_text = tk.StringVar()
display = tk.Label(window, textvariable=display_text)
display.grid(row=0, columnspan=3)
def add_one():
s = display_text.get()
s += '1'
display_text.set(s)
one = tk.Button(window, text="1", height=10, width=10, command=add_one)
one.grid(row=1, column=0)
window.mainloop()
BTW, you should try to make your program a little more compact by using for loops to create and lay out your buttons, in accordance with the DRY principle.
Also, it's not a good idea to use from tkinter import *. It imports over 130 names into your namespace, making it easy to create name collisions if you accidentally use a Tkinter name for one of your own variables or functions.
You can define add_one like the following, to first get the existing value and then append a new value to it:
def add_one():
current_value = display.cget("text")
new_value = current_value + "1"
display.config(text=new_value)
Is this what you're looking for:
from tkinter import *
root = Tk()
var = StringVar()
def f1():
var.set(" ")
var.set("1")
def f2():
var.set(" ")
var.set("2")
label = Label(root, textvariable=var)
label.pack()
button1 = Button(root, text="One", command=f1)
button1.pack()
button2 = Button(root, text="Two", command=f2)
button2.pack()
?