Итак, причина, по которой eval
не работает, заключается в том, что при первом запуске вашей программы expression
- это просто пустая строка. Если вы перейдете к оболочке python и введите eval('')
, вы увидите ту же ошибку.
Одно решение было бы проверить, если expression
пустая строка или нет, и сделать что-то вроде этого:
expression = inp.get()
if expression != '':
solved = eval(expression)
else:
solved = '?'
Однако, даже после применения этого исправления, ваша программа не будет работать, для несвязанный причины. Основная причина заключается в том, что вы никогда не вызываете tk.mainloop()
(или как бы там ни называлось), поэтому окно не будет отображаться.
Это из-за вашей петли while
. Вы хотели бы постоянно проверять поле ввода и обновлять свой холст всякий раз, когда вы получаете новый ввод после запуска через eval
.
Однако программы GUI, в общем, не работают таким образом, и при их написании требуют иного подхода и подхода. Вместо написания циклов для проверки и обновления состояния программы вы записываете функции, которые будут автоматически вызываться всякий раз, когда изменяется состояние программы (которые называются событиями). Сначала это будет немного назад, но со временем это поможет сделать ваш код более чистым и простым в управлении.
Вы на самом деле уже делаете это в одной части своей программы - с помощью функции exitbtn
. Теперь вам просто нужно преобразовать петлю while
в аналогичную функцию и привязать ее к объекту Entry
.
EDIT:
Вот пример кода, который делает то, что вы хотите:
import sys
from tkinter import *
# Create the GUI
tk = Tk()
tk.title('Calculator')
inp = Entry(tk, text="Enter Expression Here", width=20)
inp.pack()
btn = Button(tk, text="Quit?")
btn.pack()
canvas = Canvas(tk, width=200, height=200)
canvas.pack()
# Create callback functions
def end_program(event):
'''Destroys the window and ends the program without needing
to use global variables or a while loop'''
tk.destroy()
sys.exit() # Automatically ends any Python program
def update_canvas(event):
'''Gets the input, tries to eval it, and displays it to the canvas'''
expression = inp.get()
try:
solved = eval(expression)
except SyntaxError:
# The expression wasn't valid, (for example, try typing in "2 +")
# so I defaulted to something else.
solved = '??'
canvas.delete('all') # remove old text to avoid overlapping
canvas.create_text(100, 100, text=expression,font=('Times', 15))
canvas.create_text(100, 150, text=solved,font=('Times', 15))
# Bind callbacks to GUI elements
btn.bind('<Button-1>', end_program)
inp.bind('<KeyRelease>', update_canvas)
# Run the program
tk.mainloop()
Некоторые вещи, чтобы отметить:
- я переехал код для проверки
inp
и записи холст к функции update_canvas
, и избавился от цикла while
.
- Функция
update_canvas
будет автоматически вызываться всякий раз, когда кто-то отпускает ключ при вводе объекта inp
(событие <KeyRelease>
).
- Это может вызвать некоторые проблемы - это будет означать, что ваша функция
update_canvas
будет вызываться, пока пользователь находится в процессе ввода текста в ваш калькулятор. Например, что делать, если пользователь вводит 2 + 2 *
? Это не полное выражение, поэтому не может быть проанализировано eval
.
- Чтобы решить эту проблему, я просто обернул
eval
в попытке, за исключением того, чтобы предотвратить какой-либо плохой ввод из программы.
- Аналогично,
end_program
будет вызываться всякий раз, когда кто-нибудь левые нажимает на btn
объект (<Button-1>
событий).
Что вы имеете в виду? у вас есть простой пример, на который я мог бы лучше понять? – user2155059
@ user2155059 - Я добавил пример кода – Michael0x2a
, где вы определили tk.mainloop? – user2155059