
Я продолжаю изучать программирование. В этот раз моей затеей стал перенос калькулятора из iPhone в ReactOS. В этой статье я расскажу о том, как я переносила калькулятор из iPhone на ReactOS.

Мне понравился дизайн калькулятора из iPhone. Калькулятора из iPhone также используется в MacOS начиная с 10.10 Yosemite. Айфоновский калькулятор нравится не только мне, потому что в Google Play вы можете найти приложения в стиле калькулятора из iPhone.


Выбор IDE

Я выбрала Lazarus неслучайно. Lazarus - одно из немногих IDE (которое дружелюбно для новичков, желающих создать программу с GUI), без проблем работающих на Windows XP. В Qt5 давно прекращена поддержка Windows XP, а Qt6 окончательно доступно только на Windows 11. С работоспособностью .NET на ReactOS есть проблемы.
Я использовала IDE Lazarus 4.0, который недавно вышел в релиз. Lazarus 4.0 без проблем работает в ReactOS, по крайней мере в моей задаче.
Внутренняя кухня программирования

Для кнопок и поля ввода чисел я использовала шрифт Inter по двум причинам:
Шрифт Inter похож на шрифты Apple, которые используются в iPad, iPhone, Apple Watch, Mac и других продуктах Apple
Лицензия шрифта Inter позволяет без проблем использовать в некоммерческих проектах

Кнопки я создавала не в Lazarus, а в Figma - потому что в Figma есть больше свободы в плане создания кнопок. Кнопки я экспортировала в формате PNG с альфа-каналом. В Lazarus 4.0 есть поддержка прозрачных PNG-картинок.
Я использовала PNG-картинки в качестве кнопок вместо кнопок или фигура+текст, потому что в PNG-картинке есть и круги и текст. Это позволяет удобно структурировать объекты в проекте Lazarus для удобства. В проекте на Lazarus применены только 2 типа объекта: EditBox и PNG-картинки, на языке Lazarus это TEdit и TImage соответственно.
Код
Это на самом деле не фотошоп, а реальный кодинг. Поэтому я вам демонстрирую исходный код:
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls;
type
{ TiCalc }
TiCalc = class(TForm)
Image0Button: TImage;
ImageDelButton: TImage;
ImagePercentButton: TImage;
ImagePlusMinusButton: TImage;
ImageACButton: TImage;
ImageUmnButton: TImage;
Image9Button: TImage;
Image8Button: TImage;
Image7Button: TImage;
ImageMinusButton: TImage;
Image6Button: TImage;
Image5Button: TImage;
Image4Button: TImage;
ImagePlusButton: TImage;
Image3Button: TImage;
Image2Button: TImage;
Image1Button: TImage;
ImageEqualButton: TImage;
ImageDotButton: TImage;
Label1: TLabel;
procedure FormCreate(Sender: TObject);
procedure Image0ButtonClick(Sender: TObject);
procedure Image1ButtonClick(Sender: TObject);
procedure Image2ButtonClick(Sender: TObject);
procedure Image3ButtonClick(Sender: TObject);
procedure Image4ButtonClick(Sender: TObject);
procedure Image5ButtonClick(Sender: TObject);
procedure Image6ButtonClick(Sender: TObject);
procedure Image7ButtonClick(Sender: TObject);
procedure Image8ButtonClick(Sender: TObject);
procedure Image9ButtonClick(Sender: TObject);
procedure ImageACButtonClick(Sender: TObject);
procedure ImageDelButtonClick(Sender: TObject);
procedure ImageDotButtonClick(Sender: TObject);
procedure ImageEqualButtonClick(Sender: TObject);
procedure ImageMinusButtonClick(Sender: TObject);
procedure ImagePercentButtonClick(Sender: TObject);
procedure ImagePlusButtonClick(Sender: TObject);
procedure ImagePlusMinusButtonClick(Sender: TObject);
procedure ImageUmnButtonClick(Sender: TObject);
private
public
end;
var
iCalc: TiCalc;
implementation
{$R *.lfm}
{ TiCalc }
procedure TiCalc.FormCreate(Sender: TObject);
begin
end;
procedure TiCalc.Image0ButtonClick(Sender: TObject);
begin
if Label1.Caption = '0' then
begin
Label1.Caption := '';
end;
Label1.Caption := Label1.Caption + '0';
end;
procedure TiCalc.Image1ButtonClick(Sender: TObject);
begin
if Label1.Caption = '0' then
begin
Label1.Caption := '';
end;
Label1.Caption := Label1.Caption + '1';
end;
procedure TiCalc.Image2ButtonClick(Sender: TObject);
begin
if Label1.Caption = '0' then
begin
Label1.Caption := '';
end;
Label1.Caption := Label1.Caption + '2';
end;
procedure TiCalc.Image3ButtonClick(Sender: TObject);
begin
if Label1.Caption = '0' then
begin
Label1.Caption := '';
end;
Label1.Caption := Label1.Caption + '3';
end;
procedure TiCalc.Image4ButtonClick(Sender: TObject);
begin
if Label1.Caption = '0' then
begin
Label1.Caption := '';
end;
Label1.Caption := Label1.Caption + '4';
end;
procedure TiCalc.Image5ButtonClick(Sender: TObject);
begin
if Label1.Caption = '0' then
begin
Label1.Caption := '';
end;
Label1.Caption := Label1.Caption + '5';
end;
procedure TiCalc.Image6ButtonClick(Sender: TObject);
begin
if Label1.Caption = '0' then
begin
Label1.Caption := '';
end;
Label1.Caption := Label1.Caption + '6';
end;
procedure TiCalc.Image7ButtonClick(Sender: TObject);
begin
if Label1.Caption = '0' then
begin
Label1.Caption := '';
end;
Label1.Caption := Label1.Caption + '7';
end;
procedure TiCalc.Image8ButtonClick(Sender: TObject);
begin
if Label1.Caption = '0' then
begin
Label1.Caption := '';
end;
Label1.Caption := Label1.Caption + '8';
end;
procedure TiCalc.Image9ButtonClick(Sender: TObject);
begin
if Label1.Caption = '0' then
begin
Label1.Caption := '';
end;
Label1.Caption := Label1.Caption + '9';
end;
procedure TiCalc.ImageACButtonClick(Sender: TObject);
begin
Label1.Caption := '0';
end;
procedure TiCalc.ImageDelButtonClick(Sender: TObject);
begin
Label1.Caption := Label1.Caption + '/';
end;
procedure TiCalc.ImageDotButtonClick(Sender: TObject);
begin
Label1.Caption := Label1.Caption + '.';
end;
procedure TiCalc.ImageEqualButtonClick(Sender: TObject);
var
Expr: string;
OpPos, i: Integer;
Num1, Num2, Result: Double;
Op: Char;
HasMinus: Boolean;
begin
Expr := Label1.Caption;
// Удаляем пробелы (если есть)
Expr := StringReplace(Expr, ' ', '', [rfReplaceAll]);
// Ищем оператор (+, -, *, /), пропуская первый минус (если число отрицательное)
OpPos := 0;
for i := 2 to Length(Expr) do // Начинаем с 2-го символа, чтобы не учитывать минус в начале
begin
if Expr[i] in ['+', '-', '*', '/'] then
begin
OpPos := i;
Break;
end;
end;
// Если оператор не найден, выводим ошибку
if OpPos = 0 then
begin
ShowMessage('Ошибка: не найден оператор (+, -, *, /)');
Exit;
end;
// Извлекаем оператор
Op := Expr[OpPos];
// Разделяем строку на два числа (учитывая отрицательные)
try
Num1 := StrToFloat(Copy(Expr, 1, OpPos - 1));
Num2 := StrToFloat(Copy(Expr, OpPos + 1, Length(Expr)));
// Вычисляем результат
case Op of
'+': Result := Num1 + Num2;
'-': Result := Num1 - Num2;
'*': Result := Num1 * Num2;
'/':
if Num2 = 0 then
begin
ShowMessage('Ошибка: деление на ноль!');
Exit;
end
else
Result := Num1 / Num2;
else
begin
ShowMessage('Неподдерживаемый оператор: ' + Op);
Exit;
end;
end;
// Выводим результат в Label1
Label1.Caption := FloatToStr(Result);
except
on E: EConvertError do
ShowMessage('Ошибка: неверный формат числа!');
end;
end;
procedure TiCalc.ImageMinusButtonClick(Sender: TObject);
begin
Label1.Caption := Label1.Caption + '-';
end;
procedure TiCalc.ImagePercentButtonClick(Sender: TObject);
var
a: Double;
begin
a:= StrToFloat(Label1.Caption) / 100;
Label1.Caption := '';
Label1.Caption := FloatToStr(a);
end;
procedure TiCalc.ImagePlusButtonClick(Sender: TObject);
begin
Label1.Caption := Label1.Caption + '+';
end;
procedure TiCalc.ImagePlusMinusButtonClick(Sender: TObject);
var
a: Double;
begin
a:= StrToFloat(Label1.Caption) * -1;
Label1.Caption := '';
Label1.Caption := FloatToStr(a);
end;
procedure TiCalc.ImageUmnButtonClick(Sender: TObject);
begin
Label1.Caption := Label1.Caption + '*';
end;
end.
Весь код содержится в одном файле. Это неудивительно, ибо это простейший калькулятор.
Наверное итоги
Калькулятор из iPhone без проблем работает на ReactOS. По идее без переписывания кода будет доступен и на Windows 11, и на Linux, и на FreeBSD, и на Haiku - то есть на ОС, где доступно IDE Lazarus.
Надеюсь, вам понравился мой интересный опыт в программировании. Хорошего вам дня.
Комментарии (5)
kalapanga
12.05.2025 09:22Что-то уж сильно упрощенный калькулятор какой-то. Заголовок статьи - по сути обман. Здесь калькулятор только внешне похожий на эппловский. И я сейчас даже не о том, что у эппловского калькулятора есть стандартный и научный вид. Здесь даже функционал стандартного калькулятора не реализован. Вот что сразу в глаза бросилось:
В оригинале в строке может быть больше двух чисел и, соответственно, больше одного оператора.
По кнопке "равно" в оригинале в одной строке отображается выражение, во второй результат.
По нажатию кнопок операторов или точки у автора в строку будет добавляться по символу на каждое нажатие, а не надо.
AngelNet
12.05.2025 09:22Это перевод статьи? И где ссылка на скомпиленный файл, мне чтобы приобщиться придется качать лазарус и собирать этот "код" самостоятельно?
P.S. сам код сильно напоминает продукт нейросетки, нежели живого человека(*Error1024
12.05.2025 09:22Ха-ха, вспомните свои первые "серьезные" программы. Я вот помню - треш был еще тот в форматировании(его отсутствии), нейминге, и т.д.
Рандомный нейминг, сломанное форматирование и т.д. теперь напротив выделает начинающего, который хоть что-то сам пытается делать, а не копипастит код из нейросети, которая всегда делает "минимально приемлемое именование". Т.е. теперь это плюс с позиции оценки преподавателем.
LAutour
12.05.2025 09:22По сборке самостоятельно: если сравнивать компиляцию исходных кодов в lazarus с компиляцией многих исходных кодов на с\с++, то в lazarus после его установки это делается обычно одной кнопкой и быстро (плюс lazarus, по нынешним временам, не занимет много места на диске).
randomsimplenumber
Это тот самый автор(ка), который(ая) не шарит в программировании , но легко лабает код и дизайн на любом языке под никому не известную ось?