Это продолжение, остальные статьи:
- Создание приложения калькулятор
Создание приложения Kivy
Один из лучших способов выучить новый навык - создать что-то полезное. Имея это в виду, вы будете использовать Kivy для создания калькулятора, который поддерживает следующие операции:
- Сложение
- Вычитание
- Умножение
- Деление
Для этого приложения вам понадобится ряд кнопок в какой-то раскладке. Вам также понадобится поле в верхней части вашего приложения для отображения уравнений и их результатов. Вот эскиз вашего калькулятора:
Теперь, когда у вас есть цель для пользовательского интерфейса, вы можете написать код:
1 from kivy.app import App
2 from kivy.uix.boxlayout import BoxLayout
3 from kivy.uix.button import Button
4 from kivy.uix.textinput import TextInput
5
6 class MainApp(App):
7 def build(self):
8 self.operators = ["/", "*", "+", "-"]
9 self.last_was_operator = None
10 self.last_button = None
11 main_layout = BoxLayout(orientation="vertical")
12 self.solution = TextInput(
13 multiline=False, readonly=True, halign="right", font_size=55
14 )
15 main_layout.add_widget(self.solution)
16 buttons = [
17 ["7", "8", "9", "/"],
18 ["4", "5", "6", "*"],
19 ["1", "2", "3", "-"],
20 [".", "0", "C", "+"],
21 ]
22 for row in buttons:
23 h_layout = BoxLayout()
24 for label in row:
25 button = Button(
26 text=label,
27 pos_hint={"center_x": 0.5, "center_y": 0.5},
28 )
29 button.bind(on_press=self.on_button_press)
30 h_layout.add_widget(button)
31 main_layout.add_widget(h_layout)
32
33 equals_button = Button(
34 text="=", pos_hint={"center_x": 0.5, "center_y": 0.5}
35 )
36 equals_button.bind(on_press=self.on_solution)
37 main_layout.add_widget(equals_button)
38
39 return main_layout
Вот как работает код вашего калькулятора:
- В строках 8 до 10, необходимо создать список операций и пару удобных значений, last_was_operator и last_button, что вы будете использовать в дальнейшем.
- В строках с 11 по 15 вы создаете макет верхнего уровня main_layout и добавляете в него TextInput виджет только для чтения .
- В строках с 16 по 21 вы создаете вложенный список списков, содержащий большую часть ваших данных buttons для калькулятора.
- В строке 22 вы начинаете for цикл по buttons. Для каждого вложенного списка вы будете делать следующее:
- В строке 23 вы создаете BoxLayout горизонтальную ориентацию.
- В строке 24 вы запускаете еще один for цикл над элементами во вложенном списке.
- В строках с 25 по 39 вы создаете кнопки для строки, привязываете их к обработчику событий и добавляете кнопки в горизонталь BoxLayout от строки 23.
- В строке 31 вы добавляете этот макет в main_layout.
- В строках с 33 по 37 вы создаете кнопку равенства ( =), привязываете ее к обработчику событий и добавляете к нему main_layout.
Следующим шагом является создание on_button_press() обработчика событий. Вот как выглядит этот код:
41 def on_button_press(self, instance):
42 current = self.solution.text
43 button_text = instance.text
44
45 if button_text == "C":
46 # Clear the solution widget
47 self.solution.text = ""
48 else:
49 if current and (
50 self.last_was_operator and button_text in self.operators):
51 # Don't add two operators right after each other
52 return
53 elif current == "" and button_text in self.operators:
54 # First character cannot be an operator
55 return
56 else:
57 new_text = current + button_text
58 self.solution.text = new_text
59 self.last_button = button_text
60 self.last_was_operator = self.last_button in self.operators
Большинство виджетов в вашем приложении будут вызывать .on_button_press(). Вот как это работает:
- Строка 41 принимает instance аргумент, чтобы вы могли получить доступ к тому, какой виджет вызвал функцию.
- Строки 42 и 43 извлекают и сохраняют значение solution кнопки и text.
- Строки 45–47 проверяют, какая кнопка была нажата. Если пользователь нажал C, то вы очистите solution. В противном случае перейдите к else утверждению.
- Строка 49 проверяет, имеет ли решение какое-либо ранее существующее значение.
- Строки 50–52 проверяют, была ли последняя нажатая кнопка кнопкой оператора. Если это было, то solution не будет обновляться. Это сделано для того, чтобы у пользователя не было двух операторов подряд. Например, 1 */недопустимое утверждение.
- Строки с 53 по 55 проверяют, является ли первый символ оператором. Если это так, то solution обновляться не будет, поскольку первое значение не может быть значением оператора.
- Строки с 56 по 58 опускаются до else пункта. Если ни одно из предыдущих условий не выполнено, обновите solution.
- Строка 59 устанавливает last_button метку последней нажатой кнопки.
- Линия 60 комплектов last_was_operator в True или в False в зависимости от того, был ли он или нет оператор символов.
Последний бит кода для записи on_solution():
62 def on_solution(self, instance):
63 text = self.solution.text
64 if text:
65 solution = str(eval(self.solution.text))
66 self.solution.text = solution
Еще раз, вы берете текущий текст solution и используете встроенный в Python eval() для его выполнения. Если пользователь создал формулу наподобие 1+2, то eval()запустит ваш код и вернет результат. Наконец, вы устанавливаете результат как новое значение для solution виджета.
Примечание: eval() несколько опасно, потому что может запускать произвольный код. Большинство разработчиков избегают использовать его из-за этого факта. Однако, поскольку вы разрешаете вводить только целые числа, операторы и точку eval(), использование в этом контексте безопасно.
Когда вы запустите этот код, ваше приложение будет выглядеть на настольном компьютере следующим образом:
Вот полный код приложения.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
class MainApp(App):
def build(self):
self.operators = ["/", "*", "+", "-"]
self.last_was_operator = None
self.last_button = None
main_layout = BoxLayout(orientation="vertical")
self.solution = TextInput(
multiline=False, readonly=True, halign="right", font_size=55
)
main_layout.add_widget(self.solution)
buttons = [
["7", "8", "9", "/"],
["4", "5", "6", "*"],
["1", "2", "3", "-"],
[".", "0", "C", "+"],
]
for row in buttons:
h_layout = BoxLayout()
for label in row:
button = Button(
text=label,
pos_hint={"center_x": 0.5, "center_y": 0.5},
)
button.bind(on_press=self.on_button_press)
h_layout.add_widget(button)
main_layout.add_widget(h_layout)
equals_button = Button(
text="=", pos_hint={"center_x": 0.5, "center_y": 0.5}
)
equals_button.bind(on_press=self.on_solution)
main_layout.add_widget(equals_button)
return main_layout
def on_button_press(self, instance):
current = self.solution.text
button_text = instance.text
if button_text == "C":
# Clear the solution widget
self.solution.text = ""
else:
if current and (
self.last_was_operator and button_text in self.operators):
# Don't add two operators right after each other
return
elif current == "" and button_text in self.operators:
# First character cannot be an operator
return
else:
new_text = current + button_text
self.solution.text = new_text
self.last_button = button_text
self.last_was_operator = self.last_button in self.operators
def on_solution(self, instance):
text = self.solution.text
if text:
solution = str(eval(self.solution.text))
self.solution.text = solution
if __name__ == "__main__":
app = MainApp()
app.run()
Продолжение следует.
Если вам понравилось подписывайтесь на канал, ставьте лайки, комментируйте!