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

  1. Шрифт Inter похож на шрифты Apple, которые используются в iPad, iPhone, Apple Watch, Mac и других продуктах Apple

  2. Лицензия шрифта 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)


  1. randomsimplenumber
    12.05.2025 09:22

    Это тот самый автор(ка), который(ая) не шарит в программировании , но легко лабает код и дизайн на любом языке под никому не известную ось?


  1. kalapanga
    12.05.2025 09:22

    Что-то уж сильно упрощенный калькулятор какой-то. Заголовок статьи - по сути обман. Здесь калькулятор только внешне похожий на эппловский. И я сейчас даже не о том, что у эппловского калькулятора есть стандартный и научный вид. Здесь даже функционал стандартного калькулятора не реализован. Вот что сразу в глаза бросилось:

    • В оригинале в строке может быть больше двух чисел и, соответственно, больше одного оператора.

    • По кнопке "равно" в оригинале в одной строке отображается выражение, во второй результат.

    • По нажатию кнопок операторов или точки у автора в строку будет добавляться по символу на каждое нажатие, а не надо.


  1. AngelNet
    12.05.2025 09:22

    Это перевод статьи? И где ссылка на скомпиленный файл, мне чтобы приобщиться придется качать лазарус и собирать этот "код" самостоятельно?
    P.S. сам код сильно напоминает продукт нейросетки, нежели живого человека(*


    1. Error1024
      12.05.2025 09:22

      Ха-ха, вспомните свои первые "серьезные" программы. Я вот помню - треш был еще тот в форматировании(его отсутствии), нейминге, и т.д.

      Рандомный нейминг, сломанное форматирование и т.д. теперь напротив выделает начинающего, который хоть что-то сам пытается делать, а не копипастит код из нейросети, которая всегда делает "минимально приемлемое именование". Т.е. теперь это плюс с позиции оценки преподавателем.


    1. LAutour
      12.05.2025 09:22

      По сборке самостоятельно: если сравнивать компиляцию исходных кодов в lazarus с компиляцией многих исходных кодов на с\с++, то в lazarus после его установки это делается обычно одной кнопкой и быстро (плюс lazarus, по нынешним временам, не занимет много места на диске).