
Я продолжаю изучать программирование. В этот раз моей затеей стал перенос калькулятора из 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.
Надеюсь, вам понравился мой интересный опыт в программировании. Хорошего вам дня.
