Принято считать, что программирование это сложно, но это миф (все проще чем кажется), и все что нужно чтобы стать программистом это немного упорства и изобретательности.

В этой статье мы получим все базовые навыки, которые нужны Delphi программисту (включая базовые знания RunTime, работу с Com‑объектами и Canvas, вводом\выводом, файлами, парсингом, ооп, и тд), по окончании статьи.

И первое что нужно знать это то, что язык, который мы изучим называется Object Pascal, люди далекие от ИТ и программирования называют его Delphi (по названию самого популярного компилятора (редактора кода) для этого языка).

(Не знаю почему это никто не читает, но эта статья не будет интересная тем, кто уже знаком с программированием, она будет интересная начинающим программистам!)

Итак, ближе к делу.

Создадим программу, которая будет разбирать текст в редакторе, и (на основании команд из редактора) рисовать фигуры определенного размера в определенном месте на специальной области справа:

Немного теории и много практики, также тебе будет гораздо проще если ты перед прочтением этой статьи, прочитаешь статью, посвященную тому «как войти в айти с 0 за час, на языке С++»

Чуть-чуть теории и много практики.

Программирование построено на 4 основных концептах:

1) Переменные
2) Конструкции условий
3) Конструкции циклов
4) И конструкции функций

В двух словах мы хитроумно играем с базовым функционалом, предоставляемым на уровне процессора\биоса\системы, комбинируем те базовые функции с какими‑то данными из переменных, добавляем условия и циклы и оборачиваем это все в новые функции.

К примеру:

У нас есть функция на уровне системы (для изменения цвета пикселя на экране, которая выходит от драйвера видеокарты, а та из комбинированной работы процессора и видеокарты).

Мы несколько раз вызываем эту функцию (в каких‑либо координатах), таким образом рисуем линию, оборачиваем это в функцию для рисования линий, 4 раза вызываем эту функцию чтобы нарисовать (к примеру) кнопку, потом оборачиваем это в функцию для рисования кнопок и уже рисуем в зависимости от положения курсора разными цветами, и тд.

Надеюсь, логика понятна, немного по сути:

Переменная — условный «маркер данных», подстановочное значение, ключевое слово, с которым что‑то ассоциировано, хранилище данных.

Конструкция условий — какое либо правило для выполнения одной части кода, либо альтернативной (состоит из заголовка «условия» и блока кода, между ключевыми словами begin и end «тела»).

Конструкция цикла — тоже условие, но вместо альтернативного, когда повторяет код внутри тела (между ключевыми словами begin и en), до тех пор, пока условие выполняется.

Функция — ключевое слово, которое выполняет какой‑либо блок кода, и возвращает на место своего использования какие‑либо данные (функция может не только возвращать какие‑либо данные, но и принимать в себя данные (аргументы функции), которые вместе с функцией указаны в месте вызова, в коде, функция также состоит из заголовка и тела).

Нечто важное, что нужно знать это «типы данных» для переменных, существуют стандартные числовые и строковые, но большая часть «типов данных» это пользовательские типы данных, которые могут состоять как из 2 числовых переменных в одной, так и из нескольких окон программы в одной переменной (иначе говоря типы данных для переменных позволяют создавать любые переменные, а эти «любые переменные могут иметь внутри себя, как просто число, так и функции, циклы, условия, переменные, и другие, кнопки, окна, и тд).

Ничего страшного если непонятно разберемся на ходу.

Последнее из теории это GetMessage() и SendMessage(), две ключевых функции, на которых построены все графические приложения, первая получает сообщения от системы, вторая отправляет сообщения в систему.

К примеру: получаем от системы сообщение «координаты мыши изменены», в коде создаем условие, проверяющие пересекают ли новые координаты местоположение кнопки, и, если да, меняем цвет кнопки. Отправляем сообщение примерно также (из программы в систему), и такой цикл происходит все время, пока запущенна программа (система: нажата кнопка, программа: изменен размер окна, система: создан новый файл, программа: окно перерисовано, и тд).

А для тех, кто уже читал мою предыдущую статью расскажу в двух словах:

Object Pascal по сути ни чем не отличается от С++ (кроме синтаксиса), вся архитектура и подходы идентичны, за исключением одного большого минуса — Особенности концепции языка предполагают создание новых переменных только в заголовках, при этом наполнение (ассоциация) переменных с какими то данными не может происходить в моменте создания переменой (что в принципе логично, так как они объявляются в заголовке, а не в теле, где происходит реализация).

Это является очень большим минусом языка (вообще синтаксис (в целом) объектного паскаля крайне паскудный и шакальный), в случаях если у тебя в коде есть очень емкие функции, тебе приходится без конца прокручивать мышкой вверх‑вниз чтобы добавить переменные.

Еще у паскаля есть одна уникальная причуда, это процедуры (наравне с функциями), так как это высокоуровневый язык программирования (спроектированный под концепцию ооп) работа предполагается со сложно составными объектами (с классами), и, специально для свойств внутри этих классов (для переменных внутри класса, класс — это пользовательский тип данных) были созданы процедуры (для изменения содержимого, которое ассоциировано со свойством).

Не в обиду разработчикам с++ и с (которые работали всю жизнь только с С, С++, «сибразины»), но у паскаля есть множество неоспоримых плюсов перед с++ (хе‑хе ну вы поняли с++ и плюсы), просто мало кто о них знает в меру собственных знаний.

К примеру, богатая палитра Com объектов (компонентов, или готовых шаблонов для кнопок, полей ввода текста, картинок, и тд, кароч не надо изобретать велосипеды).

Полная изолированность от низкоуровневого программирования, но с прямым доступом (при помощи языка assembler, который можно встраивать прямо в код для работы с объектами), при необходимости.

Отсутствие мусора обратной совместимости (в с++ очень много библиотек, созданных в концепции «индуиского кода», который непонятно как работает, и зачастую многие такие «библиотеки» могут вызывать ошибки на пустом месте из‑за конфликтов друг с другом, к примеру с доступом к памяти для переменных).

Даже несмотря на то, что мой любимый язык это C# (за простоту и за «есть все из коробки»), больше всего программ я написал именно на паскале.

Много практики.

Запускаем редактор (я буду использовать Lazarus, вы можете какой ни будь другой, они все одинаковы), у нас «из коробки» сразу есть готовая форма и редактор для «натыканья» компонентов на форму программы.

Побалуемся, запустим, все работает, отлично закрываем. Разберем немного сгенерированный код.

НАЧИНАЕМ НАЧИНАТЬ
// ключевое слово юнит определяет название,
// куска кода в файле, то есть если мы где то
// в коде используем слово Unit1, на его место
// будет вставлено все содержимое этого файла
// (или не все, так как компилятор вырежет из
// файла только использованные функции, и вставит
// их
unit Unit1;

// над этим пока заморачиваться не нужно, можно пропустить
//
// это команда для компилятора, которая выполняется в момент
// перед генерацией скомпилированного файла нашего приложения
// в данном случае команда {$mode objfpc} заставит редактор кода
// сгенерировать файл с готовым кодом в стиле (скомпилированным)
// лазаруса, команда {$H+} заставит редактор конвертировать
// все содержимое этого файла в кодировку Ansi
{$mode objfpc}{$H+}

// ключевое слово интерфейс, пока не нужно забивать себе голову
// и можно пропустить
//
// ключевое слово interface говорит о том что все описанное ниже
// (наш условный тип данных) является шаблоном для того чтобы на
// базе нашего типа данных создавать другие (дочерние) типы данных
//
// если в с++ концепция ооп была просто условностью, то в object
// pascal это необходимость, продиктованная использованием COM
// объектов (заготовок кнопок, текстовых полей, и тд), в с++
// все переменные имеют строгий размер и статичны, в паскале нет,
// (это основное отличие от с++), то есть тут могут быть переменные
// (или мультипеременные), которые на ходу могут изменять свой
// максимальный размер, удалять данные, изменять данные, и тд
//
// мало кто помнит, но концепция интерфейсов появилась вместе с
// концепцией COM объектов, интерфейсы, по сути, это абстрактные
// классы (типы данных), или один большой шаблон для заголовка
// пользовательского типа данных, нашим типам данных (для того
// чтобы быть совместимыми с COM объектами из библиотек), нужно
// иметь какие-либо универсальные свойства (для всех объектов, как
// доступных "из коробки", так и наших, потому что в нашу программу
// не встроена логика для работы с данными, которые еще неизвестны
// универсальным функциям, но функции должны уметь их обрабатывать)
//
// к примеру у нас есть функция FindComponent (ее модификация,
// которая находит компонент по имени типа данных), она должна
// каким-то образом узнать сколько (и каких) компонентов на форме
// в данный момент, а потом еще догадаться каким именем обладает
// наш тип данных, для этого у нас есть базовый тип данных, от
// интерфейса (шаблона), от которого в роли наследуемых (вместе с
// базовыми свойствами, и решениями из шаблона) выступают все
// компоненты (включая компоненты "из коробки" и наши), а так
// как шаблоном (интерфейсом) определено наличие свойства name,
// даже если оно не описано и не задействовано (и разработчик
// даже не знает о нем), базовый функционал сам даст ему уникальное
// имя, по которому функция FindComponentByName сможет его найти,
// а учитывая, что все компоненты описаны на общем интерфейсе
// разгадать свойства и поведение (для какой-нибудь функции
// аналогичной FindComponent) не составит труда
//
// разумеется, с таким подходом необходимо изолировать низкоуровневые
// процессы (к примеру выделение памяти под переменные) и передать
// в автономный обработчик, который анализирует через интерфейс
// потребности объекта, поэтому такой подход к программированию
// называют высокоуровневым (ничего страшного если не понятно,
// станет понятно по ходу)
interface

// и начать отсюда
// подключаем сторонние библиотеки по аналогии с Unit (вверху),
// берет готовые юниты и добавляет какие-то фрагменты их
// содержимого сюда, через запятую перечисляются все подключаемые
// библиотеки
uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Grids, Unit2;

// ключевое слово, после которого идет описание нашего типа данных,
// (или заголовка нашего типа данных) в данном случае так как наш
// тип данных может выступать родителем для других, и соответствуют
// концепции интерфейсов, мы определяем ожидаемое содержимое в нем
// (для других классов, дочерних от этого)
type

{  символом {} фигурных скобочек в паскале обозначены комментарии
   (мультистрочные) }
  { TForm1 }

  // задаем ключевое слово (название нашего пользовательского
  // типа данных), далее символом = указываем редактору что это ключевое
  // слово "соответствует" (в паскале "=" является указателем соответствия)
  // классу (или болванке для типа данных,
  // на базе универсального типа данных COM), после чего в ()
  // круглых скобках указываем что наш тип данных должен быть
  // унаследован от шаблона формы окна программы (тип данных TForm),
  // благодаря чему в нашем типе данных "из коробки" есть пустая форма
  TForm1 = class(TForm)

    // так как наш тип данных не просто унаследован от другого типа
    // данных, но и сам может быть типом данных прародителем, описываем
    // в заголовке содержимое, которым мы "расширили" тип данных TForm,
    // чтобы потенциальный дочерний тип данных знал, что ему нужно
    //
    // по сути, мы тут просто создаем переменные с компонентами (полно
    // функциональные заготовки, с которыми потом ассоциируем результат
    // создания нового экземпляра какого-либо объекта), просто
    // я попутно объясняю суть ооп, сейчас вся наша программа состоит
    // из наследованных типов данных, в которых уже есть весь функционал
    //
    // объявим переменную типа заготовка для кнопки, для создания 
    // переменной нужно написать ключевое слово var, после чего любое 
    // имя переменной, и в конце тип данных, который можно ассоциировать 
    // с этой переменной
    Button1: TButton;

    // объявим переменную типа заготовка для выпадающего списка
    ComboBox1: TComboBox;

    // объявим переменную типа поле ввода текста
    Edit1: TEdit;

    // объявим переменную типа "готовый эксель"
    StringGrid1: TStringGrid;

    // объявим заголовок процедуры (аналог функции, просто
    // не возвращает какой-либо результат на место своего
    // вызова), в качестве данных, передаваемых в функцию
    // передаем переменную, которая (тип данных TObject
    // универсальный), которая вызвала эту процедуру,
    // указываем псевдоним, под которым внутри процедуры
    // эта переменная будет доступна как Sender, саму процедуру
    // назовем FormCreate
    //
    // на самом деле этот код был весь сгенерирован и добавлен
    // автоматически (чудеса высокоуровневого программирования)
    procedure FormCreate(Sender: TObject);

    // private указатель на секции доступности содержимого
    // нашего типа данных для других классов, все описанное
    // ранее находится по умолчанию в другой секции (она
    // называется published, секция специально для работы в ран
    // тайме), пока не надо загружаться, можно пропустить
  private

    // общедоступная секция
  public

    // конец заголовка нашего типа данных
  end;

  // объявляем переменную типа наш тип данных (TForm1)
  // под названием Form1, обратите внимание на хитроумный прием,
  // создание переменной Form1 происходит вне заголовка, или
  // тела нашего типа данных, то есть файл сам по себе по
  // мимо того, что является источником шаблона для себя, определяет
  // свое собственное создание
var
  Form1: TForm1;

  // ключевое слово implementation говорит редактору
  // что все дальше будет "телом" нашего типа данных,
  // или логикой работы нашего типа данных (все это
  // также будет включено в состав интерфейса TForm1,
  // на базе которого также описан класс (пользовательский
  // тип данных) TForm1
implementation

// команда для компилятора, $R, если задано какое либо
// значение после команды $R, редактор кода попробует
// найти в одной папке с нашим исходим файлом, файл
// ресурсов с указанным именем, так как в параметре
// команды указано *.lfm, это подразумевает найти и
// добавить на место этой команды все содержимое всех
// файлов в папке с юнитом, в которых тип файла указан .lfm,
// в этом файле содержатся координаты объектов, которые я
// накидал на форму, и другие параметры
{$R *.lfm}

// опять комментарий
{ TForm1 }

// реализация процедуры FormCreate (мы ранее описывали
// ее в заголовке, сейчас мы ее реализуем), так как
// процедура (читай функция) FormCreate является частью
// интерфейса TForm1, мы указываем имя функции (процедуры)
// через "." - универсальное обращение к свойствам (переменным),
// и методам (функциям) класса (нашего пользовательского
// типа данных)
procedure TForm1.FormCreate(Sender: TObject);

// ключевые слова begin и end формируют собой "блочок" кода,
// который должен принадлежать к какой-либо конструкции,
// то есть отдельный фрагмент кода для последовательного
// выполнения
begin

  // внутри функции я просто обращаюсь к свойству (мультипеременной
  // Cells, она же "массив"), и меняю значение записей, так как
  // Cells это свойство объекта StringGrid1 (его мы также объявили
  // в заголовке нашего типа данных), соответственно данными
  // манипуляциями я просто ассоциирую какой-либо текст с конкретной
  // записью мультипеременной, которая отвечает за отрисовку содержимого
  // конкретной ячейки, исходя из ее порядкового номера в мультипеременной
  // (двойной мультипеременной, или же матрице, это когда каждая переменная,
  // внутри мультипеременной Cells сама является мультипеременной)
  StringGrid1.Cells[0,0]:='б';  
  StringGrid1.Cells[1,0]:='ы';
  StringGrid1.Cells[2,0]:='д';
  StringGrid1.Cells[3,0]:='л';
  StringGrid1.Cells[4,0]:='о';
  StringGrid1.Cells[5,0]:='к';
  StringGrid1.Cells[6,0]:='о';
  StringGrid1.Cells[7,0]:='д';
  StringGrid1.Cells[8,0]:='е';
  StringGrid1.Cells[9,0]:='РРР';

  // конец нашей процедруы
end;

// конец реализации нашего типа данных, который начался
// после ключевого слова implementation
end.

Надеюсь, стало хоть немного понятно (несмотря на то что строк очень мало, код очень сложный). Так как мы истинные "делфи программисты" (паскаль), откроем меню проекта, и оттуда исходный файл проекта. Этот файл также называют файлом начальной загрузки, или бутстрап, он же само загрузочный файл, файл инициации, и тд.

Рассмотрим его:

ДОБАВИМ КУСОК В ПРОГРАММУ
// наша программа (ее "заголовочный"
// блок кода)
program project1;

// выбираем режим компиляции этого файла
{$mode objfpc}{$H+}

// подключаем библиотеки
uses
  // указываем компилятору условие,
  // в зависимости от которого подключаем
  // библиотеки для работы с мультипоточностью
  {$IFDEF UNIX}
  cthreads,
  {$ENDIF}
  {$IFDEF HASAMIGA}
  athreads,
  {$ENDIF}

  // подключаем библиотеки
  Interfaces, // this includes the LCL widgetset
  Forms, Unit1
  { you can add units after this }
    ,Classes, SysUtils, Controls, Graphics, Dialogs, StdCtrls, Grids;

// подгружаем на место команды содержимое всех файлов
// с расширением *.res
{$R *.res}

// блочок кода тела нашей программы
begin

  // в глобальную переменную нашей программы, которая
  // отвечает за проверку ресурсов, перед загрузкой в
  // формы помещаем false, чтобы программа не выдавала
  // фатальных ошибок, и просто отобразила пустую форму,
  // оператор присвоения (ассоциации данных, с каким то
  // ключевым словом) это ":=", или математический аналог
  // присвоения
  RequireDerivedFormResource:=True;

  // в переменную, которая отвечает за масштабирование
  // окон нашей программы помещаем true (иначе говоря
  // включаем масштабирование, у объекта Application)
  Application.Scaled:=True;

  // вызываем функцию, которая выполнит нормализацию,
  // и регистрацию нашей программы в системе
  Application.Initialize;

  // вызываем функцию, которая создает новое окно программы,
  // в качестве параметров (аргументов функции, или в нашем
  // случае процедуры), передаем тип данных, которыми нужно
  // попробовать создать окно программы, и имя переменной,
  // с которой нужно ассоциировать результат создания
  // нового экземпляра окна программы, типом данных передаем
  // TForm1, переменной Form1
  Application.CreateForm(TForm1, Form1);

  // запускаем бесконечный цикл отлова сообщений
  // от системы, и передачи сообщений в систему
  Application.Run;

end.

Вообще существует хороший способ определить программиста, дело в том, что под понятием бутстрапа изначально понимался подход к разработке программ, где основной файл содержал минимум кода, и просто служил триггером для запуска всех решений (хранил функцию main, winmain, initapplication, и тд), которые были описаны в других файлах. В зависимости от ответа собеседника можно сделать выводы, так как именно с приходом делфи появилось первое понятие «быдлакодер», и такие программисты (на самом деле независимо от языка) легко себя выявляли. Врочем я отхожу от темы, если сейчас все еще ничего непонятно, это не проблема, перейдем к коду, добавим этот код между Application.CreateForm(TForm1, Form1); и Application.Run;

// команду, которая отвечает за создание и показ готового
// диалогового окна с текстом и кнопкой ok, для того чтобы
// текст сообщения воспринимался редактором как "текст",
// а не как команда, или ключевое слово, берем его в 
// одиночные кавычки
ShowMessage('ololo');  

Теперь давайте попробуем создать кнопку (а за одно удалить компоненты, которые уже есть на форме), для начала переместимся в секцию до начала тела программы, создадим переменную:

// объявим переменную типа заготовка кнопки
var MyBTN: TButton;  

После чего в теле программы напишем это:

  // с переменной типа заготовка кнопки ассоциируем
  // результат выполнения функции Create, которая создаст
  // новый экземпляр объекта кнопка, в соответствии с шаблоном
  MyBTN:= TButton.Create(Form1);

  // поместим созданную кнопку на Form1, через указание в свойстве нашей
  // кнопки Parent, имени объекта, который должен владеть этой кнопкой,
  MyBTN.Parent:=Form1;

  // обратимся к переменной Caption, которая является
  // унаследованным (от шаблона типа данных TButton)
  // свойством объекта, с которым ассоциирована надпись
  // на кнопке, и ассоциируем с переменной Caption текст,
  // после чего переменная запустит функцию (унаследованную
  // от шаблона типа данных TButton), которая изменит надпись
  // на кнопке
  MyBTN.Caption:='ААА КНОПКААААА';  

Запустим и увидим сообщение, далее жмем ок и запускается форма:

Теперь на форму можно накидать несколько кнопок и полей ввода, дополним наш код, объявим пару переменных после кнопки:

iA, iB:integer;  

А тело программы дополним кодом (между Application.CreateForm(TForm1, Form1); и Application.Run;)

ДОБАВИМ КОД УДАЛЕНИЯ КОМПОНЕНТОВ В РУНТАЙМЕ
  // создадим условие, если переменная ComponentCount,
  // которая была наследована от типа данных TForm
  // и при запросе которой срабатывает функция
  // для поиска и подсчета всех компонентов на форме,
  // вернула на место своего вызова значение большее
  // чем 0, выполняем код условия (внутри условия,
  // то есть между begin и end), переменная ComponentCount
  // это так называемое "свойство класса", или переменная,
  // которой назначены две функции, первая чтобы получить
  // значение в переменную, вторая чтобы изменить значение
  // переменной (Get и Set функции, но в паскале для Set процедура)
  if Form1.ComponentCount > 0 then
  begin

    // показываю сообщение, к которому добавляю количество
    // компонентов на форме, из переменной ComponentCount,
    // которая есть у моей формы из наследованного типа данных
    // TForm, и в которую при помощи специальной функции попадает
    // количество компонентов на форме (при помощи метода Get,
    // у свойства ComponentCount, если назвать это иначе)
    ShowMessage('Слишком много компонентов, надо удалить '+IntToStr(Form1.ComponentCount));

    // переместимся в секцию begin и end начала программы,
    // и объявим переменную счетчик, а с переменной ассоциируем
    // результат выполнения (встроенной в тип данных TForm)
    // функции для получения количества компонентов на форме,
    // которая отправляет данные в переменную ComponentCount,
    // при любой попытке запросить значение у переменной ComponentCount,
    // так как в программировании все отсчеты начинаются с 0,
    // из количества компонентов вычитаю 1 (то есть 0 это не ничего,
    // 0 - это первый элемент списка, а ComponentCount вернет
    // количество, считая с 1)
    iA:=Form1.ComponentCount - 1;

    // запускаем цикл с условием, повторять действие внутри
    // цикла, до тех пор пока содержимое переменной iA больше,
    // или равно 0, цикл похож по конструкции на условие, только
    // повторяет код внутри своего блочка с кодом (между begin и end)
    while iA >= 0 do
    begin

      // задаю условие, если наследованное от типа данных TForm
      // свойство класса ClassName вернуло на место своего вызова
      // ключевое слово, которое соответствует заданному мной
      // ключевому слову (TEdit), выполняю код внутри блочка условия
      if Form1.Components[iA].ClassName = 'TEdit' then
      begin

        // так как удалить компонент я не могу (он находится
        // в процессе использования формой, так как вся конструкция
        // нашего кода находится между командами CreateForm и Run),
        // я отправляю свойству Visible, у компонента, который я
        // интерпретирую (через TEdit()) как компонент TEdit,
        // которым он и является, значение false, где уже переменная
        // Visible (свойство класса, иначе говоря) вызовет функцию Set,
        // которая сделает компонент невидимым
        TEdit(Form1.Components[iA]).Visible:=false;

        // вывожу сообщение с именем объекта
        ShowMessage(Form1.Components[iA].Name + ' удалено');
      end;

      // аналогично для всех компонентов на форме с именем класса
      // TButton
      if Form1.Components[iA].ClassName = 'TButton' then
      begin
        TButton(Form1.Components[iA]).Visible:=false;
        ShowMessage(Form1.Components[iA].Name + ' удалено');
      end;

      // TStringGrid
      if Form1.Components[iA].ClassName = 'TStringGrid' then
      begin
        TStringGrid(Form1.Components[iA]).Visible:=false;
        ShowMessage(Form1.Components[iA].Name + ' удалено');
      end;

      // и TComboBox
      if Form1.Components[iA].ClassName = 'TComboBox' then
      begin
        TComboBox(Form1.Components[iA]).Visible:=false;
        ShowMessage(Form1.Components[iA].Name + ' удалено');
      end;

      // также есть универсальный метод для COM объектов
      // Form1.Components[iA].Destroying;

      iA:= iA - 1;
    end;
  end;  

Мало кто знает, но концепция ооп была создана не только для решения «кризиса наименований», в первую очередь она призвана обеспечивать приложениям «динамическость», или же возможность работы с поведением программы после начала выполнения программного кода, это называется RunTime, или RT (поэтому фраза ООП в php, и веб разработке звучит как минимум странно, где «время жизни» объектной модели заканчивается на отправке страницы клиенту).

Обратите внимание что я не разу не обратился к конкретному объекту на форме, только к теоретическим ожидаемым данным, которые я могу предугадать благодаря концепции ООП и интерфейсам (абстрактным классам, или абстрактным типам данных). Вообще концепция ООП очень полезная и интересная штука, просто по началу кажется немного сложной, на деле в ней нет ничего сложного.

Для полноты понимания работы объектов COM лучше всего узнать за что отвечают их универсальные типы данных, которые являются прародителями (TObject и TComponent), а также посмотреть на то, как работают их универсальные свойства (переменные типа данных).

Сейчас еще может быть непонятно, поэтому тык по «файл\создать модуль», у нас сразу сгенерируется пустая заготовка интерфейса, к которой сразу подключены базовые библиотеки

Наполним файл кодом (так как object pascal использует COM объекты, придется (в отличии от с++ где с этим проще) работать исключительно на «эталонном» ооп, это не просто поэтому рекомендую познакомится с моей предыдущей статьей (перед началом):

ПРОДОЛЖАЕМ ПРОДОЛЖАТЬ
unit Unit2;

// способ компиляции файла
{$mode ObjFPC}{$H+}

// указатель того, что наш тип данных может быть интерфейсом
interface

// подключим библиотеки
uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Grids, Menus;

// создадим наш тип данных, после ключевого
// слова type вводим любое имя нашего "класса",
// затем продолжаем логическую конструкцию,
// символом (=) ровно, и ключевым словом class,
// всю строку можно прочитать как
// тип ТекстовыйЗагрузчикФайлов соответствующий классу,
// модификаторы доступа (public, private, и тд) можно
// не писать для простых "составных" типов данных
type TextFileLoader = class

  // создадим переменные
  //
  // объявляю переменную типа TStringList,
  // это заготовка типа данных, которая содержит
  // в себе все необходимое для загрузки текстового
  // файла в программу
  FileLoader:TStringList;

  // создам переменную типа TMemo, это заготовка
  // типа данных, в которой уже есть готовый текстовый
  // редактор, при помощи этой переменной я буду
  // отображать текст из файла
  TextViewer:TMemo;

  // создам еще одну переменную типа TStringList,
  // на этот раз для сохранения файла
  FileSaver:TStringList;

  // создам переменную типа PopupMenu, для создания
  // всплывающего меню, при правом тыке в текстовом
  // редакторе
  TextViewerMenu:TPopupMenu;

  // добавим переменную с диалоговым окном выбора файла,
  // эта заготовка также из библиотек, для загрузки,
  // и сохранения файла я буду использовать один и тот
  // же диалог
  SelectFile:TOpenDialog;

  // теперь опишем заголовки функций (для реализации
  // процесса загрузки файла, создания в окне программы
  // поля для отображения и редактирования текста, и тд)
  //
  // сначала заголовок конструктора (конструктор - это функция,
  // которая выполняет в момент создания нового экземпляра
  // объекта нашего типа данных, и ассоциируется с какой либо
  // переменной (которая таже имеет тип данных "наш тип данных",
  // или TextFileLoader функция конструктора начинается ни со
  // слова function, в качестве параметров в функцию мы будем
  // передавать в конструктор идентификатор окна программы, в котором
  // будем разворачивать наш текстовый редактор, так как все наши окна
  // являются производными от COM объекта TForm (или заготовки формы),
  // мы можем передавать в наш конструктор любую форму, которая
  // была наследником типа TForm, компилятор сделает все остальное сам
  constructor New(Owner:TForm);

  // помимо конструктора нужно объявить деструктор, это тоже функция,
  // но для описания логики разбора и уничтожения теоретической
  // переменной, с которой ассоциирован экземпляр нашего TextFileLoader,
  // но так как это высокоуровневое программирование, деструктор не
  // обязательно описывать, потому что по завершении любого блочка кода,
  // в рамках которого была объявлена эта переменная, компилятор сам
  // уничтожит переменную (и все остальные, в рамках этого блочка),
  // если параметры в функцию не нужны, скобки () тоже можно не указывать,
  // и если что компилятор также игнорирует регистр, то есть TEXTFILELOADER
  // и TextFileLoader - это одно и тоже, несмотря на то что коды символов
  // у больших и маленьких букв разные (это высокоуровневое программирование)
  destructor DestructeObject;

  // добавим заголовок функции для загрузки файла, я использую процедуру,
  // но это та же самая функция, просто не возвращает на место своего
  // вызова какой-либо результат
  function LoadFile:string;  

  // заголовок функции, которая будет сохранять данные в файл, в себя
  // функция будет получать новый текст файла, в которой нужно сохранить
  // текст, так как я не планирую что наша функция что-то будет возвращать,
  // поэтому опишу функцию как процедуру (тоже самое что и функция, но
  // не возвращает данные на место своего вызова)
  procedure SaveFile(NewText:string);

  // теперь создадим "обертку" для нашей функции, чтобы использовать в меню,
  // из-за ограничений концепции ооп мы должны привести нашу процедуру
  // к "универсальному виду", все процедуры и функции, которые назначаются
  // к событиям COM объектов должны принимать в себя ссылку на объект,
  // который вызвал эту функцию
  procedure SaveFileClick(Sender:TObject);

  // добавлю специальную функцию для сброса файла к исходному (к моменту
  // загрузки в редактор), так как TStringList сохраняет в себе текст
  // после использования, так как возврат значения не обязателен, опишу
  // функцию как процедуру
  procedure ResetFile;

  // создадим свойство класса ("условную переменную", по к которой
  // привязана функция, которая получает данные, которые просто так
  // не извлечь из переменной), это свойство будет маркером данных,
  // везде, где оно будет встречаться в коде, оно будет заменено на
  // результат выполнения функции, это свойство будет возвращать на
  // свое место оригинальный текст, свойство начинается с ключевого
  // ключевого слова property, далее идет любое название этого свойства,
  // затем тип данных, который может принять в себя и вернуть свойство,
  // затем (через пробел) ключевое слово READ, которое обозначает
  // получение данных, и имя функции, я назову свойство
  // GetContentFromTextFileLoader, а в качестве функции использую
  // SaveFile, ключевое слово public позволяет установить модификатор
  // доступа, если установлен public, значит к этому свойству можно
  // будет обратится не только из тела нашего типа данных, но и везде из кода
  PUBLIC PROPERTY GetContentFromTextFileLoader:string READ LoadFile;

  // опишем заголовок этой функции, тип данных, которые функция
  // будет возвращать на свое место будет текст (string)

  // создадим еще одно свойство, оно будет собирать и сразу
  // сохранять данные в файл, при попытке изменить содержимое
  // свойства (изменить данные, которые ассоциированы с этим
  // свойством), для этого опишем свойство аналогично предыдущему,
  // вместо функции для чтения, определим функцию для записи,
  // свойства класса позволяют использовать для одно свойства
  // одновременной и READ, и WRITE, так как функции нужны данные,
  // которая она в себя принимает при вызове, свойство автоматически
  // в качестве данных передаст значение, которое пытаются
  // ассоциировать со свойством, где-то в месте (в коде), где
  // вызвано это свойство
  PUBLIC PROPERTY SetNewContentToTextFileLoader:string WRITE SaveFile;

  //public PROPERTY OnMyEvent : TNotifyEvent READ LoadFile WRITE SaveFile;
end;

  // тело нашего типа данных (место, где описываются
  // функции и логика работы нашего типа данных
implementation


// для реализации функции надо указать заголовок функции, и ключевые слова
// begin и end, но для того чтобы редактор смог понять от какого типа данных
// эти функции, названия функций надо начинать с типа данных, к которому
// принадлежат эти функции (в одном файле может быть более одного типа данных,
// так как это интерфейс
//
// реализуем логику создания нового экземпляра нашего типа данных
constructor TextFileLoader.New(Owner:TForm);
begin

  // ассоциируем с переменной FileLoader результат
  // создания нового объекта из заготовки TStringList,
  // символ := (математическое присвоение) обозначает
  // присвоить (ассоциировать) ключевому слову слева
  // ключевое слово справа
  FileLoader:= TStringList.Create;

  // создадим из заготовки всплывающее по правому тыку меню
  TextViewerMenu:= TPopupMenu.Create(TextViewer);

  // добавим элемент меню, для этого в функцию Add нашего
  // объекта меню передать элемент меню с типом данных TMenuItem,
  // а для этого мы обращаемся к COM заготовке с соответствующим
  // названием (типа данных TMenuItem), и у заготовки вызываем
  // функцию создания нового элемента меню (функцию конструктор,
  // Create), у которой в качестве родителя указываем наш элемент
  // меню (можно указать что угодно), в результате функция Create
  // возвращает на свое место новый экземпляр объекта меню,
  // который сразу же оказывается качестве параметра для функции
  // Add (у нашего меню), и добавляется в меню
  TextViewerMenu.Items.Add(TMenuItem.Create(TextViewerMenu));

  // так как мы знаем, что это первый элемент (отсчеты начинаются с 0),
  // обращаемся к нему и изменяем текст элемента меню
  TextViewerMenu.Items[0].Caption:='Сохранить';

  // добавим (привяжем) функцию к событию нажатия по элементу меню,
  // символ собачки (@) для обратного управления с низкоуровневым
  // программированием, он позволяет "ассоциировать" какой либо
  // объект с чем-либо (в данном случае я беру ключевое слово, которое
  // является "указателем" на фрагмент кода, и ассоциирую его со значением,
  // которое должно находится в стандартном событии OnClick), то есть
  // я работаю не с прямыми объектами, а с указателем на конкретные данные,
  // в низкоуровневом программировании, также есть символ (^) - стрелка вверх,
  // которая позволяет создавать указатели на данные (ключевое слово, которое
  // напрямую не может содержать в себе какие-либо данные, только ссылку на
  // другое ключевое слово, или ссылку на конкретные (в памяти) данные),
  // особенности стандартного свойства OnClick (тип данных TNotifyEvent
  // позволяет это сделать), все свойства COM объектов, связанные с событиями
  // имеют стандартный тип данных TNotifyEvent
  TextViewerMenu.Items[0].OnClick:=@SaveFileClick;

  // ассоциирую с переменной TextViewer результат
  // создания (вызова конструктора у типа данных TMemo)
  // нового объекта текстового поля (из заготовок COM),
  // функция Create принимает в себя идентификатор объекта,
  // который является прародителем, в данном случае я передаю
  // туда объект, который будет является прародителем нашего типа
  // данных, идентификатор которого также будем получать при
  // вызове этой функции (New)
  TextViewer:= TMemo.Create(Owner);

  // разместит редактор на форме
  TextViewer.Parent:=Owner;

  // перепозициионируем, изменим отступ слева (от края окна),
  // отступ сверху на 100 пикселей
  TextViewer.Left:=100;
  TextViewer.Top:=100;

  // изменим размер редактора, исходя из размеров
  // передаваемого во время вызова функции окна программы,
  // а именно его ширины, и высоты, из которых вычитаем
  // 200 пикселей (указатель на окно программы передается в
  // свойстве Owner)
  TextViewer.Width:=Owner.Width - 200;
  TextViewer.Height:=Owner.Height - 200;

  // добавим меню по правому тыку (мы создавали его чуть выше)
  TextViewer.PopupMenu:=TextViewerMenu;

  // создадим TStringList для сохранения файла
  FileSaver:= TStringList.Create;

  // создадим из заготовки стандартное диалоговое
  // окно с выбором файла, все что оно делает - это
  // открывается, при выборе файла закрывается, наполняя
  // свое свойство FileName путем к выбранному файлу
  SelectFile:=TOpenDialog.Create(Owner);
end;

// опишем деструктор (это не обязательно, но так как я его объявил
// в заголовке класса, реализуем)
destructor TextFileLoader.DestructeObject;
begin

  // inherited это специальная команда, ключевое слово, которое
  // позволяет выполнить предустановленный (в заготовке класса)
  // код и логику, командой inherited можно изменять порядок,
  // либо сначала выполняется наш код, либо сначала код из класса
  // родителя (если, конечно, таковой вообще есть)
  inherited;
end;

// опишем логику работы функции для загрузки файла
function TextFileLoader.LoadFile:string;
begin

  // для начала проверим объект SelectFile, если он уже
  // открывался, значит там должен быть к выбранному файлу
  //
  // создадим условие, если содержимое свойства FileName,
  // у объекта SelectFile больше, меньше, чем ничего
  // выполняем код условия, иначе откроем диалог
  if SelectFile.FileName <> '' then
  begin

    // внутри просто при помощи стандартных функций,
    // доступных у объекта FileLoader (наследованных от
    // объекта TStringList) загружаем файл во встроенное
    // свойство TStringList, свойство Text, в функцию для
    // загрузки файла передаем путь к выбранному в диалоговом
    // окне файлу
    FileLoader.LoadFromFile(SelectFile.FileName);

    // со свойством Text (у редактора текста) ассоциируем
    // содержимое аналогичного свойства FileLoader, важный
    // момент, так как свойства вызывают функции, а не
    // передают напрямую объекты мы ассоциируем именно текст,
    // а не свойство объекта Text (у FileLoader), с аналогичным
    // свойством редактора (TextViewer)
    TextViewer.Text:=FileLoader.Text;
  end
  // блочок кода для конструкции "иначе"
  // (то есть что будем делать, если условие не выполнено)
  ELSE
  begin

    // создаем условие, если готовая функция Execute
    // вернула в место своего вызова значение, которое
    // соответствует заданному нами значению true, выполняем
    // код условия, так как может быть теоретическая ситуация,
    // в которой пользователь открыл окно выбора файла, и
    // просто закрыл (без выбора файла), значение FileName
    // останется пустым, поэтому мы вызываем функцию не
    // просто как команду, а в формате условия, Execute
    // вернет на свое место true если файл был выбран
    if SelectFile.Execute = true then
    begin

      // делаем все тоже самое что и в основном условии
      FileLoader.LoadFromFile(SelectFile.FileName);
      TextViewer.Text:=FileLoader.Text;
    end;
  end;

end;

// опишем логику для сохранения файла, по сути, все тоже
// самое и в обратном порядке, и вместо функции LoadFromFile
// используем функцию SaveToFile
procedure TextFileLoader.SaveFile(NewText:string);
begin
  // для начала проверим объект SelectFile, если он уже
  // открывался, значит там должен быть к выбранному файлу
  //
  // создадим условие, если содержимое свойства FileName,
  // у объекта SelectFile больше, меньше, чем ничего
  // выполняем код условия, иначе откроем диалог
  if SelectFile.FileName <> '' then
  begin

    // свойству Text, у объекта FileSaver присваиваем
    // содержимое редактора текста (TextViewer)
    FileSaver.Text:=TextViewer.Text;

    // сохраняем при помощи вызов готовой функции
    // SaveToFile, путь к файлу берем из SelectFile
    FileSaver.SaveToFile(SelectFile.FileName);
  end
  // блочок кода для конструкции "иначе"
  // (то есть что будем делать, если условие не выполнено)
  ELSE
  begin

    // создаем условие, если готовая функция Execute
    // вернула в место своего вызова значение, которое
    // соответствует заданному нами значению true, выполняем
    // код условия, так как может быть теоретическая ситуация,
    // в которой пользователь открыл окно выбора файла, и
    // просто закрыл (без выбора файла), значение FileName
    // останется пустым, поэтому мы вызываем функцию не
    // просто как команду, а в формате условия, Execute
    // вернет на свое место true если файл был выбран
    if SelectFile.Execute = true then
    begin

      // делаем все тоже самое что и в основном условии
      FileSaver.Text:=TextViewer.Text;
      FileSaver.SaveToFile(SelectFile.FileName);
    end;
  end;
end;

// опишем логику "обертки" для сохранения файла по клику в меню
procedure TextFileLoader.SaveFileClick(Sender:TObject);
begin

  // так как наша оригинальная функция принимает в себя новое содержимое,
  // которое мы пытаемся сохранить, мы возьмем текущее содержимое из редактора
  // текста, из стандартного свойства редактора Text
  SaveFile(TextViewer.Text);
end;

// так как оригинальное содержимое все еще хранится в FileLoader,
// мы можем сбросить текст
procedure TextFileLoader.ResetFile;
begin
  
  // со свойством Text (у редактора текста) ассоциируем
  // содержимое аналогичного свойства FileLoader, важный
  // момент, так как свойства вызывают функции, а не
  // передают напрямую объекты мы ассоциируем именно текст,
  // а не свойство объекта Text (у FileLoader), с аналогичным
  // свойством редактора (TextViewer)
  TextViewer.Text:=FileLoader.Text;
end;

end.

Теперь откроем графический редактор, ткнем в форму (она выберется в свойствах объекта), во вкладке события найдем событие OnShow (FormShow), два раза ткнем в пустое поле рядом и у нас сгенерируется готовый блочок процедуры для этого события, напишем туда это:

TextLDR:=TextFileLoader.New(Form1);

А вверху нашей формы (между заголовком формы, и телом формы программы, где объявленная переменная Form1) допишем это:

// объявляем переменную типа наш типа данных (TextFileLoader), название может 
// быть любым,  у меня TextLDR
TextLDR:TextFileLoader;

Запускаем и видим наш готовый редактор

Отлично! Теперь, когда у нас есть базовое представление об ООП можно сделать нечто более сложное. Единственное на что нужно обратить внимание — это то, что я использовал пример загрузки текстового файла, для считывания байтов файла, и их интерпретации существуют специальные готовые «файловые потоки», и стандартные функции Windows (ShellAPI), но этого нам хватит за глаза.

Тык по меню «файл\создать модуль», теперь дополним нашу программу:

ПЕРЕЙДЕМ К ТЕХНОКОЛДУНСТВУ
// указываем имя нашей библиотеки
unit Unit3;

// способ компиляции файла
{$mode ObjFPC}{$H+}

// указатель того, что наш тип данных может быть интерфейсом
interface

// подключим библиотеки
uses
  // подключаем нашу другую библиотеку - Unit2, нам понадобится
  // объект, который мы в ней создавали
  Unit2,
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Grids,
  ExtCtrls;

// опишем заголовок нашего типа данных
//
// то, что мы собираем в итоге, можно назвать "условным модулем" нашей
// программы, в обычной программе таких модулей много, для удобной
// реализации, и поиска вероятных ошибок, мы разбиваем наш модуль
// на составные "классы" (наши типы данных), для каждого из них отдельно
// описываем логику, запускаем, проверяем, он работает, пишем дальше,
// после чего на базе этого "класса" создаем дочерний, который сохраняет
// и копирует весь функционал и логику родителя, а также дополняет ее,
// это основная из фишек ооп, именно данный метод (которым мы сейчас
// описываем программу называется классически (из концепции ооп),
// который построен в формате зависимостей "родительский к дочернему",
//
// еще немного о "модификаторах доступа" к родительскому содержимому,
// модификаторы доступа, это ключевые слова public, private, protected,
// и тд, их задача изолировать ненужные части родительского объекта,
// в дочернем в рамках всего кода программы (для масштабных программ,
// чтобы случайно, или если забудем, не вмешаться в уже рабочий компонент
// (класс) и не сломать его, или то, что от него зависимо), мы будем
// проектировать наш "модуль" по классической логической зависимости,
// со свободным доступом ко всем элементам и родителям модуля, и для
// каждого дочернего элемента также будем оставлять общедоступным (public)
// все, и только в последнем классе нашего модуля (который уже соберет из
// всей этой матрешки классов) готовый компонент закроем все что не
// должно быть видно, и является "системным" для нашего компонента
//
// такой подход позволяет гибко (и в любой момент изменять модуль),
// это классический подход ооп (из концепции), но он не позволяет
// использовать какие-либо части нашего модуля в других компонентах,
// кроме того, для разных языков программирования существуют разные
// базовые концепции разработки, к примеру в с++ это просто условность,
// в джаве и си шарп подход иной (у веб вообще нет)
//
// точно также как разные модификаторы доступа "по умолчанию", в паскале,
// если не написать не одного модификатора доступа (внутри заголовка класса),
// редактор кода сам добавит модификатор перед компиляцией (модификатор
// PUBLISHED), учитываете это, и всегда для каждого свойства четко
// определяйте модификатор доступа, иначе могут быть глупые логические
// ошибки доступа (внутри сгенерированного кода редактором в том числе,
// так как он генерирует все объекты под одним модификатором для конкретной
// группы объектов
//
// модификатор PUBLISHED позволяет работать в рунтайме, также он может
// в нарушение логики построения компонента открывать доступ "вне очереди"
// построения (иначе говоря, содержимое доступно везде и всегда),
// модификатор PUBLIC стандартная публичная секция, все что идет после
// ключевого слова PUBLIC доступно из любой части нашей программы (по
// обращению, конечно)
// модификатор PROTECTED открывает доступ содержимого родителя только
// для дочерних классов (для базовой концепции разработки ооп), вне
// дочерних классов (в рамках кода программы), увидеть (а соответственно
// и изменить невозможно)
// модификатор PRIVATE (или специальный), добавлен для обработки исключений
// из стандартной концепции ооп, он закрывает какие-либо свойства, функции,
// детали текущего класса для всех, кроме себя, в реальной разработке
// не требуется, PUBLIC (PUBLISHED) и PROTECTED хватает с головой, но для
// каких-то особых "изобретений" может быть полезен, как и оставшиеся -
// STRICT PROTECTED, и STRICT PRIVATE для системных нужд (к PUBLISHIED)
//
// опишем этот класс, добавив в наш модуль область для рисования (из COM
// TImage), а также опишем парсер, чтобы из текста, который написан
// в редакторе извлекать какие-то данные, чтобы использовать их
// для рисования на объекте Canvas (у заготовки TImage), объект
// Canvas универсальный и есть во всех языках программирования
// (по крайней мере каноннистических), после ключевого слова class,
// в круглых () скобках указываем тип данных из которого хотим "закачать"
// все в наш тип данных (у нас это TextFileLoader)
type TComDrawer = class (TextFileLoader)

  // добавим объект TImage (область для рисования)
  PaintField:TImage;

  // создаем переменную типа TRect (четыре числовых
  // переменных в одной), будем хранить в ней размеры фигуры
  FigureSize:TRect;

  // создаем текстовую переменную, будем хранить в ней
  // ключевое слово, в соответствии с которым будем рисовать
  // ту, или иную фигуру, тип string оригинальный текстовый
  // типе данных TCaption берет его и расширяет (является дочерним)
  Figure:string;

  // переопределим конструктор, наличие одноименной функции
  // родительского класса (с идентичным набором аргументов
  // функции) позволяет переопределить логику работы этой
  // функции в нашем дочернем классе при помощи ключевого
  // слова REINTRODUCE, при этом в новой реализации можно
  // вызвать выполнение оригинальной логики, при помощи ключевого
  // слова INHERITED
  constructor New(Owner:TForm); REINTRODUCE;

  // добавим "альтернативный" конструктор для нашего класса,
  // он будет принимать в себя размер области для рисования,
  // ключевое слово OVERLOAD говорит о том, что этот метод
  // (конструктор класса, New) "перегружаем", то есть если
  // во время вызова указать определенный набор аргументов
  // функции (в круглых скобках после имени функции), с
  // определенной последовательностью, то будет вызван вариант,
  // который соответствует по набору аргументов, "перегрузок"
  // может быть сколько угодно
  PRIVATE constructor New(Owner:TForm;
                  PaintWidth:integer;
                  PaintHeight:integer
  ); OVERLOAD;

  // опишем "альтернативный" конструктор, если функция имеет
  // "модификатор" VIRTUAL - это значит что функция может быть
  // заменена на другую функцию с таким же названием (в реализации
  // логики)
  PRIVATE constructor Create(Owner:TForm); VIRTUAL;

  // опишем еще один конструктор, теперь с модификатором ABSTRACT,
  // он позволяет выполнить "отложенное" описание в логике дочерних
  // классов (то есть это заготовка для функции, просто объявленный
  // заголовок функции в заголовке класса, который предполагает свою
  // реализацию в других (дочерних) классах (в текущем - нет)
  PRIVATE constructor Create(Owner:TForm; Size:TPoint); VIRTUAL; ABSTRACT;   

  // опишем заголовок функции для парсинга (парсинг это разбор
  // строки (посимвольно) и поиск каких-либо фраз, в зависимости
  // от этих фраз извлечение каких-либо данных из строки текста
  // функция будет принимать в себя два текста, один будет началом
  // ключа, второй концом ключа, возвращать функция будет возвращать
  // извлеченные данные
  PUBLIC function ParseText(KeyStart:TCaption; KeyEnd:TCaption; Text:TCaption):TCaption;

  // создадим функцию, которую ассоциируем с событием (стандартным)
  // нажатия клавиш, у редактора текста (для объявления собственных событий
  // в класс надо добавить переменную типа TNotifyEvet, после чего свойство
  // для этой переменной, и функцию, которая будет проверять наличие
  // привязанной (к свойству) функции, и запускать, для того чтобы создать
  // свою функцию для стандартного события COM объекта, она должна
  // соответствовать универсальным параметрам (аргументам, которые функция
  // принимает в себя во время вызова), тут это код клавиши, которая была
  // нажата (Key), состояние нажатия (нажата, удержана, отпускается),
  // параметр Shift, первый параметр - это объект, который вызвал эту функцию
  PUBLIC procedure Ext_TextEditorKeyDown(
                  Sender: TObject;
                  var Key: Word;
                  Shift: TShiftState
  );

  // опишем заголовок функции для отрисовки чего-либо на области рисования
  PUBLIC function DrawOnPaintField:boolean;
end;

implementation

constructor TComDrawer.New(Owner:TForm);

// объявим вспомогательную переменную
// типа число, локальные (к какому-либо блочку кода)
// переменные автоматически уничтожаются по завершении
// этого блочка кода (блочка, в рамках которого они были
// объявлены)
var a:integer;
begin

  // сначала вызовем выполнение оригинального содержимого
  // функции New из класса TextFileLoader, в качестве аргументов
  // передаем значение, получаемое из аргумента этой функции
  INHERITED New(Owner);

  // теперь переопределим размеры редактора текста и разместим
  // область для рисования в пределах этой территории
  //
  // во вспомогательную переменную поместим текущую ширину
  // редактора текста, так как это дочерний класс, все из
  // класса родителя доступно для управления отсюда, ключевое
  // слово Self позволяет обратиться к самому себе (классу),
  // так будто класс - это готовая переменная нашего типа данных
  a:=Self.TextViewer.Width;

  // изменим ширину объекта из расчета 100 пикселей отступа
  // между областью рисования и редактором, для этого размер
  // редактора делим на 2 (div - это деление без остатка), и
  // вычитаем 50
  Self.TextViewer.Width:= (a div 2) - 50;

  // создадим из заготовки TImage новый экземпляр объекта,
  // и ассоциируем его с переменной PaintField
  PaintField:=TImage.Create(Owner);

  // зададим, где отрисовывать нашу область рисования, указав
  // родителя объекта (не связанно с родителями в классе),
  // это свойство формы
  PaintField.Parent:=Owner;

  // зададим высоту области рисования
  PaintField.Height:=Owner.Height - 200;

  // зададим ширину, исходя из содержимого переменной а 
  PaintField.Width:=(a div 2) +50;

  // перепозиционируем область рисования (по умолчанию
  // все объекты создаются в координатах 0, 0, то есть
  // в левом верхнем углу окна программы
  PaintField.Top:=100;

  // вызываем все тот же кусочек, которым вычитывали новые размеры
  // для редактора кода, только теперь не вычитаем, а прибавляем
  // плюс 50 пикселей, вместе с отступом редактора получаем 100
  PaintField.Left:=(a div 2) + 100;

  // изменяем цвет фона области рисования на черный
  PaintField.Canvas.Brush.Color:=clBlack;

  // заполняем всю область черным цветом
  PaintField.Canvas.FillRect(0,0, PaintField.Width, PaintField.Height);

  // привяжем к редактору текста процедуру, которая будет
  // обрабатывать события нажатия клавиш
  TextViewer.OnKeyDown:=@Ext_TextEditorKeyDown;

  // определим стандартные размеры фигуры, в случае если получим
  // команду рисования, без размеров и позиции, по умолчанию координаты
  // левый верхний край, 1\3 размера области рисования (позиция имеет
  // отступ от края области TImage 2 пикселя)
  FigureSize.Left:=2;
  FigureSize.Top:=2;
  FigureSize.Right:=PaintField.Width div 3;
  FigureSize.Bottom:=PaintField.Height div 3;

  // определим ключевое слово для определения фигуры "по умолчанию"
  Figure:='PARAM_CIRCLE';

end;

constructor TComDrawer.New(Owner:TForm;
                PaintWidth:integer;
                PaintHeight:integer
);
begin
  INHERITED New(Owner);

end;

constructor TComDrawer.Create(Owner:TForm);
begin
  INHERITED New(Owner);

end;

// опишем функцию для парсинга (прасинг это процесс разбора строки, и
// извлечения куска текста из строки
function TComDrawer.ParseText(KeyStart:TCaption; KeyEnd:TCaption; Text:TCaption):TCaption;

// объявляем переменные (типа число)
var a, b:integer;
    c:TCaption;
// объявляем указатель на строку, к которому можно прыгнуть
// прыгнуть вне последовательного выполнения (построчной)
// логики нашей функции
label ASMSTR;
begin

  // наполняем вспомогательные переменные
  a:=0;

  // эта переменная буде содержать количество
  // символов в передаваемом тексте (в переменную
  // Text), там, где она будет вызвана, так как
  // 1 в программировании это 0, вычитаем из
  // количества символов 1, чтобы не получить
  // ошибку (когда мы попробуем обратится к символу
  // по индексу, а там только ошибка доступа к памяти),
  // функция Length возвращает абстрактное количество
  // чего-либо (высокоуровневое программирование), поэтому
  // ее можно применять к любым объекта в коде
  b:=Length(Text);

  // объявляем внутри функции точку, к которой можно прыгнуть
  // при помощи команды GOTO
  ASMSTR:

  // передаем команду компилятору, указываем что команды
  // ассемблера надо интерпретировать при помощи концепции
  // логики INTEL (ассемблер x32, по сути, толку от него нет,
  // так как команды из набора ассемблера х64 он не поддерживает),
  //     
  {$ASMMODE INTEL}
  // ассемблер - это язык прямых логических команд для АЛУ (в процессоре),
  // в него, по сути, все компиляторы (на всех языках) компилируют файлы
  // с кодом (как этот файл), в двух слова в ассемблере есть несколько
  // фиксированных переменных разного размера (хранилища для значений,
  // или супер кэш), и около 500+ логических, и арифметических команд,
  // над значениями, которые ассоциированы с этими (фиксированными)
  // переменными, по сути, для знания ассемблера достаточно несколько
  // команд (MOV - переместить данные из eax в ebx, ADD - сложить eax и ebx,
  // внутрь eax, SUB - вычесть из eax, ebx, оставить значение в eax, DIV -
  // разедлить eax на ebx, результат в eax, MUL - умножить eax на ebx,
  // результат в eax, CMP - сравнить eax и ebx, если не равны во встроенной
  // (фиксированной, переменной, другой ZF), INC увеличить eax на 1,
  // DEC - уменьшить eax на 1, JMP - врыгнуть (тут должно быть "прыгнуть", но мне так понравилась ошибка что я решил ее оставить)к какому-либо блочку кода
  // (на подобие лейбла "label ASMSTR;" в нашей функции, хотя по сути
  // паскаль очень много чего берет из ассемблера, например концепцию
  // процедур, некоторые команды и вовсе дублируются, как и ключевые слова),
  // PUSH - отправить значение eax в свободную ячейку оперативной памяти
  // (на усмотрение процесса), POP достать данные из оперативной памяти,
  // этих команд хватит с головой чтобы делать практически все, единственная
  // проблема это eax, ebx, ecx, edx и тд (или фиксированные переменные),
  // дело в том, что таких переменных довольно много, формально с ними можно
  // делать что угодно, но на практике все эти переменные используются
  // в каких-либо операциях (к примеру, переменная ZF получает в себя 1,
  // если команда CMP сравнила два значения, и они оказались равны, и тд),
  // но если познакомится с документацией по наборам команд логики процессора
  // то проблем не будет
  //
  // напомню, что программы на чистом ассемблере (то есть
  // имеющие не естественные для компилятора сигнатуры кода) автоматически
  // объявляются вирусами (не у всех, но многих антивирусов), также если
  // программа попытается получить "неавторизированный" доступ к памяти (то
  // есть если к переменной обращается программа, которая не создавала эту
  // переменную), она рискует получить значение из песочницы антивируса,
  // либо windows просто заблокирует эту операцию (исключения составляют
  // перегружаемые программы (OLE программы, либо программы, в которых
  // предусмотрена работа с OLE объектами), иначе говоря, программы, в которых
  // реализовано предоставление доступа к своей памяти, для других программ
  // (к примеру, excel, в котором есть полный функционал для работы с этой
  // программой без графического интерфейса, которая может быть запущенна
  // из другой программы), но это ограничение легко обходится изменением
  // идентификационных данных программы (в системе), на идентификационные
  // данные программы, к чьей памяти нужно обратится (то есть кряк через
  // хук на процесс программы), но такие действия легко обнаруживаются
  // и системой, и антивирусом), в общем ассемблер надо использовать с умом
  //
  // уведомляем компилятор о том, что этот блочок кода не нужно компилировать,
  // так как это уже команды ассемблера
  asm
    ;{вызываем команду MOV, в качестве параметров}
    ;{передаем супер кэш eax и нашу переменную а,}  
    ;{то есть копируем значение переменной а в eax}
    MOV eax, a;
    ;{увеличиваем значение eax на 1}
    INC eax
    ;{вертаем в зад (в переменную а)}
    MOV a, eax
    ;{конец блочка кода ассемблера}
  end;

  // в данном примере мы организуем цикл без ключевого слова while,
  // for, repeat, мы просто задаем условие, если значение переменной, а
  // меньше значения переменной б, выполняем код условия, такая конструкция
  // все равно обращается к оперативной памяти (мы ворочим значение в а),
  // поэтому для того, чтобы реально использовать преимущества супер кэша,
  // нужно ворочить счетчик (переменную а), лимит (переменную б), в супер
  // кэш, и еще там же выполнять проверку условия
  //
  // есть несколько типов условий < - меньше, > - больше, = - соответствует,
  // <> - больше, меньше (не соответствует), и специальные (для отсчетов,
  // где 0 это 1, но при этом второе значение сравнения изначально 1),
  // <= - меньше, или ровно, >= - больше, или равно, это тот случай
  if (a <= b) then
  begin

    // внутри первого условия задаем второе, если первый символ из
    // значение переменной, передаваемой во время вызова функции
    // не соответствует символу, который находится в тексте, который
    // мы тоже передаем при вызове функции (символ для сравнения с
    // KeyStart берем из индекса буквы в тексте, а индекс берем из
    // переменной а, которая, после каждого выполнения увеличивается
    // на 1)
    if (KeyStart[1] <> Text[a]) then
    begin
      // прерываем построчное выполнение логики нашей функции,
      // и прыгаем к ключевому слову ASMSTR, чтобы продолжить
      // построчное выполнение кода оттуда
      GOTO ASMSTR;
    end
    // описываем блочок альтернативы условия (то есть если первый
    // символ из KeyStart соответствует какому-либо символу из Text)
    ELSE
    begin

      // если выполняется альтернативный блок, значит мы сейчас находимся
      // в месте, где начинается "ограничитель" значения, которые нам нужно,
      // теперь мы должны передвинутся на 1 символ вперед, и собирать весь
      // текст во вспомогательную переменную, до тех пор, пока не встретим
      // следующий ограничитель, который будет играть роль "закрывающего
      // ограничителя"
      //
      // в переменную с помещаем ничего
      c:='';
      // перемещаемся на следующий символ
      a:=a+1;

      // запускаем цикл, до тех пор, пока а меньше б
      // выполняем код цикла снова
      while a <= b do
      begin

        // задаем условие, если первый символ
        // из переменной KeyEnd соответствует
        // символу (из Text) под индексом (в тексте),
        // на место которого помещаем содержимое
        // переменной а (счетчик), выполняем код блочка
        // внутри условия
        if KeyEnd[1] = Text[a] then
        begin

          // прерываем все циклы,
          // нарушением логики, поместив
          // в а значение из б
          a:=b;

          // возвращаем результат выполнения
          // функции, присваиваем скрытой переменной
          // result (она есть у каждой функции),
          // содержимое из с
          result:=c;
        end ELSE
        begin

          // в содержимое переменной с приплюсовываем
          // ее собственное содержимое, и символ из Text,
          // с индексом буквы из переменной а, но при
          // условии что символ не соответствует символу
          // "закрывающего ключа" для парсинга текста
          // (конструкция ELSE)
          c:=c+Text[a];
        end;

        // после каждого прохода цикла увеличиваем
        // значение переменной, а на 1 (при помощи
        // специальной функции из библиотек)
        inc(a);
      end;

      // в переменную а помещаем значение переменной б
      a:=b;
    end;
  end;
end;

// опишем функцию (процедуру) для события нажатия по редактору текста,
// можно использовать библиотеки ShellAPI чтобы обрабатывать события
// нажатий вне стандартных событий, коды клавиш доступны в интернете,
// для получения координат курсора используется объект Mouse.CursorPos.Y,
// или X, также можно использовать функции из ShellAPI (GetCursorPos)
procedure TComDrawer.Ext_TextEditorKeyDown(
                  Sender: TObject;
                  var Key: Word;
                  Shift: TShiftState
  );

// создадим вспомогательные переменные
var text1, text2:string;
    a,b:integer;
begin

  // создаем условие, если код нажатой клавиши соответствует
  // коду 1B, который при помощи символа $ компилятор трансформирует
  // в х16 формат значения, выполняем действия условия (1B - код
  // клавиши Esc)
  if (Key = $1B) then
  begin

    // наполняем переменные для цикла
    a:=0;

    // если каретка в редакторе дальше строки с индексом 0
    // на всякий случай обработаем "неполное" выполнение
    // команд в текстовом редакторе (не баг а фича)
    a:=TextViewer.CaretPos.Y;

    // узнаем общее количество строк в текстовом редакторе
    b:=TextViewer.Lines.Count;

    // создаем цикл с условие, пока а меньше б выполняем
    // действия цикла
    while a < b do
    begin

      // реализуем разновидность "парсинга" при помощи
      // замены текста
      //
      // переменной text1 присваиваем (копируем) содержимое
      // строки текста с индексом, который берем из позиции   
      text1:=TextViewer.Lines.Strings[a];

      // с переменной text2 ассоциируем результат выполнения
      // функции для замены значений в тексте (встроенная
      // функция из библиотек), в качестве параметров передаем
      // текст для поиска, значение для замены (у меня ничего),
      // параметры условий замены (игнорировать РЕГИСТР, заменить
      // все найденные результаты), ну и текст, в котором производить
      // замену
      text2:=StringReplace(text1, 'размер', '', [rfReplaceAll, rfIgnoreCase]);

      // создаем условие, если содержимое text1 не соответствует
      // содержимому text2 (в которое попадает текст, после замены в
      // тексте всех ключевых слов), выполняем код условия
      if text1 <> text2 then
      begin
        text2:=ParseText('"','"',text1);

        // так как мы знаем, что ключевое слово - это "размер"
        // изменяем у переменной с размерами размер, задаем
        // размер из содержимого, которое мы распарсили в переменную
        // text2, при этом с помощью функции из библиотеке
        // конвертируем текст в число, это ширина
        FigureSize.Width:=SysUtils.StrToInt(text2);
        FigureSize.Height:=(SysUtils.StrToInt(text2) div 4) * 3;
      end;

      // аналогичные действия проделаем для всех команд     
      text1:=TextViewer.Lines.Strings[a];
      text2:=StringReplace(text1, 'позиция', '', [rfReplaceAll, rfIgnoreCase]);

      if text1 <> text2 then
      begin

        // вызываем нашу функцию для парсинга, я буду использовать
        // как метки для "распарсивания" текста символ ("), так как
        // переменная text2 больше не нужна (но еще существует, так как
        // конец функции не достигнут), использую text2 как хранилище
        text2:=ParseText('"','"',text1);

        // для расположения используем два свойства
        // (вложенных в переменную FigureSize) из нашей переменной
        // с размером
        FigureSize.Left:=SysUtils.StrToInt(text2);

        // высота будет 3\4 от ширины
        FigureSize.Top:=(SysUtils.StrToInt(text2) div 4) * 3;
      end;

      text1:=TextViewer.Lines.Strings[a];
      text2:=StringReplace(text1, 'круг', '', [rfReplaceAll, rfIgnoreCase]);

      if text1 <> text2 then
      begin

        // для определения фигуры используем другую переменную,
        // я выбрал ключевое слово PARAM_CIRCLE
        Figure:='PARAM_CIRCLE';

        // вызываем функцию (которая еще не описана), мы можем
        // получить к ней доступ, за счет отложенного описания
        // (потому что в начале класса мы объявили заголовок этой
        // функции, то есть избавлены от логической ошибки вызова
        // функции раньше, чем она будет создана, PUBLISHED может
        // нарушать этот порядок)
        DrawOnPaintField;
      end;  

      text1:=TextViewer.Lines.Strings[a];
      text2:=StringReplace(text1, 'квадрат', '', [rfReplaceAll, rfIgnoreCase]);

      if text1 <> text2 then
      begin
        Figure:='PARAM_RECTANGLE'; 
        DrawOnPaintField;
      end; 

      text1:=TextViewer.Lines.Strings[a];
      text2:=StringReplace(text1, 'текст', '', [rfReplaceAll, rfIgnoreCase]);

      if text1 <> text2 then
      begin
        Figure:='PARAM_TEXT';    
        DrawOnPaintField;
      end;


      // увеличиваем счетчик на 1 после каждого прохода
      inc(a);
    end;
  end;
end;

// опишем последнюю функцию (для отрисовки)
function TComDrawer.DrawOnPaintField:boolean;
begin  

  // меняем цвет рисоваемой линии на красный
  PaintField.Canvas.Pen.Color:=clRed;

  // размер линии задаем 2 пикселя
  PaintField.Canvas.Pen.Width:=2;

  // рисовать будем исходя из содержимого переменной Figure
  if (Figure = 'PARAM_CIRCLE') then
  begin

    // так как в переменной PaintField уже есть размеры и позиция,
    // буду брать размеры и координаты из нее
    PaintField.Canvas.Ellipse(
                                FigureSize.Left,
                                FigureSize.Top,
                                FigureSize.Width,
                                FigureSize.Height
    );
  end;

  // аналогично для квадрата
  if (Figure = 'PARAM_RECTANGLE') then
  begin

    // так как в переменной PaintField уже есть размеры и позиция,
    // буду брать размеры и координаты из нее (в качестве параметров для
    // стандартной функции отрисовки квадрата)
    PaintField.Canvas.Rectangle(
                                FigureSize.Left,
                                FigureSize.Top,
                                FigureSize.Width,
                                FigureSize.Height
    );
  end;  

  // и текста
  if (Figure = 'PARAM_TEXT') then
  begin

    // для отрисовки текста возьмем только расположение,
    // текст фиксированный

    // цвет текста задаем зеленый
    PaintField.Canvas.Font.Color:=clGreen;

    // размер 12em
    PaintField.Canvas.Font.Size:=12;

    PaintField.Canvas.TextOut(
                                FigureSize.Left,
                                FigureSize.Top,
                                'ЭТО ТЕКСТ АААААААААААА'
    );
  end;

end;

// конец описания класса (следовало бы создать еще один файл,
// в котором закрыть класс (все в наших классах имеет модификатор
// PUBLISHED, потому что я не указывал модификаторы, и был использован
// модификатор "по умолчанию"), но так как все публичное, для этого
// надо создать класс "обертку", внутри которого создать переменную
// (в закрытой секции) типа наш тип данных, сам же объект не делать
// наследующим, и просто в конструкторе создать объект, но я устал, поэтому так
end.

Теперь создадим новую переменную:

  // добавим переменную
  ololo:TComDrawer; 

И в событии OnShow добавим код:

  // команда FreeAndNil (функция из библиотек)
  // позволяет вне очереди удалить объекты,
  // по умолчанию все объекты удаляются в рамках
  // завершения своей сеции, но так как переменная
  // TextLDR объявлена в секции программы (в главной)
  // переменная удалится только после завершения программы,
  // так как я не описывал Destructor удалять придется вручную,
  // я просто удалю то, что визуально мешает, потому что устал
  FreeAndNil(TextLDR.TextViewer);           
  FreeAndNil(TextLDR);

  // создадим наш новый объект
  ololo:=TComDrawer.New(Form1);

Запускаем и видим это:

Поздравляю! Теперь ты знаешь Object Pascal, умеешь работать в RunTime, имеешь базовое представление об ООП (и умеешь его использовать), имеешь начальные навыки Assembler, работы с файлами, парсингом, и Com‑объектами.

Осталось только получше познакомится с заготовками (с палитры компонентов), их свойствами, добавить SQL и ты продвинутый Delphi программист.

Полагаю после этой статьи меня заминусят так что я уже не смогу рассказать про другие языки (насколько я понял после -20 рейтинга я получаю бан, я хотел сделать для всех основных — C++, Pascal, Java, C#, и веб девелопЁринга), обида ивановна:( буду дальше писать фанфики по вселенной SCP lol.

Я, конечно, ожидал хейта и токсика (но на этапе веб девелопёринга), но никак ни с десктопа, никогда бы не подумал, что в этих сферах тоже огромное количество токсичных, неадекватных и ЧСВшных *ыдлокодеров.

Но что имеем, то имеем, по крайней мере можно сделать выводы — я тут хоть и недавно, но успел понять, что этот сайт не столько косплей пикабу, сколько адский концентрат раскрутки крупных компаний на рекламу, а также продвижения авторских проектов (ну и еще средство придания ЧСВшному образу некоторых индивидов флера несовершеннолетия)

По поведению пользователей можно сделать выводы, где находится наибольший концентрат неадекватности, и в каких конкретных компаниях (или сферах, не считая веб девелопёринга) лучше не работать (а лучше и вовсе уехать лол) начинающему программисту.

И помни — разум и упорство это ключ к победе!

Спасибо за внимание:)

Комментарии (162)


  1. dyadyaSerezha
    11.12.2023 05:35

    Только один вопрос: а зачем становиться Delphi-программистом?


    1. iminfinitylol
      11.12.2023 05:35

      если ты не знаешь для чего нужен паскаль, соответственно тебе не нужна информация о паскале, а соответственно нет смысла писать этот комментарий (это называется последовательная логика, ваще читарская штука)

      у меня есть развернутый ответ на твой вопрос, но вместо него я решил ответить так, потому что этот комментарий в духе "когда не знаешь до чего долюбиться, но долюбиться надо" -_-


      1. Lainhard
        11.12.2023 05:35

        Так зачем программистом то становиться дельфячим?


        1. modestguy
          11.12.2023 05:35

          Курсовую работу сделать и забыть про объектный паскаль навсегда.


        1. andreykorol
          11.12.2023 05:35

          Я в основном пишу для микроконтроллеров. Но как всегда, кому-то нужно писать и программы для настройки устройства с ПК или пример взаимодействия с другим целевым устройством. И оказалось, что "набросать окошко с кнопками" проще всего в Лазарусе. Причем легко пересобирается как под win x86, так и под linux aarch64 или armf.
          И лицензионная чистота соблюдается. Легче было бы писать на си, т.к. уже описаны структуры или прочее в реализации со стороны устройства, но найти gui-фреймворк c такой же интеграцией в IDE и простотой использования - я не смог. QT монстр со сложными лицензиями и его может не оказаться на целевом девайсе. Python - тоже не везде есть и не сравниться с нативным приложением. По итогу Lazarus со своим паскалем оказался более подходящим для этой ниши.


          1. SpiderEkb
            11.12.2023 05:35

            wxWidgets внезапно. В связке с gcc работает и в винде и в линуксе. В качестве IDE - CodeBlocks или CodeLite. Ну плюсом какой-нибудь wxFormBuilder, wxSmith, wxCrafter...


            1. andreykorol
              11.12.2023 05:35

              Да, но лазарус оказался реально более проще в использовании. Как появилось приложение fpcupdeluxe, то вся кросс-компиляция добавляется в пару кликов.


              1. SpiderEkb
                11.12.2023 05:35

                Вполне возможно. Я не пробовал.

                Честно сказать, я под виндой до 17-го года работал - там на каким-то этапе был MSVC + MFC, потом ушли на Builder.

                А с 17-го года вообще на AS/400 (IBM i) перешел, а тут все вообще другое и проблемы совсем другие и принципы работы системы другие.

                Qt пробовал - во-первых монстр, во-вторых, они построены на несколько иных, нежели винда, принципах. И поверх WinAPI это все ложится несколько странновато.

                wxWidgets попроще и попонятнее, но вот с версткой интерфейсов там придется вникать в концепцию сайзеров (некий контейнер для интерфейсных объектов), что может не сразу зайти если долго на WinAPI работал.

                А Паскаль как-то сразу (еще в 90-х) мимо меня прошел. Т.е. читать код "со словарем" могу, но писать на нем никогда не приходилось. Ну просто не было такой необходимости, а без необходимости и стимула учить его не было.


                1. andreykorol
                  11.12.2023 05:35

                  Да, wxWidgets сильно похож по разметке интерфейса на Android studio.


                  1. SpiderEkb
                    11.12.2023 05:35

                    Мне как-то не зашло сразу. Но уже и нужды не было. Сейчас другая система, там нет GUI :-) А текстовые интерфейсы там совсем иначе рисуются (именно рисуются - там тоже достаточно интересная концепция)


          1. sami777
            11.12.2023 05:35

            С# - окошки в visual studio набросать проще простого. C# - Си подобный язык. Опять же опыт в мэйн-стримовском языке. Лицензионная чистота??? Lazarus - фри, в том числе для коммерческого использования??? Так зачем делфи?


            1. andreykorol
              11.12.2023 05:35

              Даже не знаю как добавить поддержку С# на образах собранных старым buildroot. Или сейчас можно собрать C#-приложение статически под gtk? У лазаруса лицензия GPL/LGPL с разрешением сборки коммерческих приложений. C делфи не работаю, но видимо их кроссплатформенная FireMonkey тоже имеет своих приверженцев. Т.ч. кто-то на Go перепрыгнул (кстати сырой по поддержке GTK показался год назад),а кто-то и на паскале сидит. Не вижу причин их винить в этом. :)


            1. HemulGM
              11.12.2023 05:35

              Затем, что Делфи на порядок быстрее развивается, особенно в последние годы. Затем, что среда разработки, RTL и фреймворки на Делфи гораздо функциональнее и да.т намного больше возможностей. В том же числе и кроссплатформенная разработка. Моим клиентом для ChatGPT (под все платформы сразу) пользуются достаточно много людей, хотя я просто опубликовал его на GitHub.


          1. dyadyaSerezha
            11.12.2023 05:35

            Я спросил, не для чего писать на Delphi, а для чего становиться Delphi-программистом человеку, не знающему программирование. Так и вижу его мысли - 1. Выучить Delphi за 2 часа; 2. Пойти программировать микроконтроллеры, благо позиций навалом, особенно для самых зеленых джуиоров; 3. Получать биг профит!

            Ага ага.


            1. andreykorol
              11.12.2023 05:35

              А почему учат brainfuck? Потому что могут. Так и паскаль учат потому, что его преподают там где учатся или есть знакомый который его знает. Не вижу причин критиковать язык как первый для обучения, для чего он и создавался.


              1. dyadyaSerezha
                11.12.2023 05:35

                Статья называется не "как понять основы программирования через Delphi" , а "как стать Delphi-программистом". Это две большие разницы. Но даже и для обучения гораздо лучше Питон - знание его можно потом просто углублять и уже становиться нужным на рынке труда.


                1. andreykorol
                  11.12.2023 05:35

                  Так тем более - если б статья называлась "как стать актуальным, в понятном для всех смысле, программистом" то я бы понял ваши претензии. А так человек как назвал - так и написал. Схожу поищу в инете статью "как стать музыкантом на лютне" и там тоже спрошу "а зачем?"

                  А какой лучше для изучения - то это вкусовщина. Я вот считаю, что для изучения нужны языки со строгой типизацией и без приколов, когда невозможно визуально увидеть ошибку из-за замены пробела табом.
                  Из-за последнего, даже js лучше питона в плане первого языка, несмотря на свои приколы с типизацией. Питон же чудо как хорош как универсальная замена bash-скриптам\batch-файлам, но как первый язык - брррр, ужас


                  1. DMGarikk
                    11.12.2023 05:35

                    даже js лучше питона в плане первого языка

                    в чемже js лучше то? в питоне хоть ооп есть похожий на настоящий

                    или скобочки важнее?

                    p.s. а чтобы не упарыватся пробелами с табом, надо просто нормальную ide юзать, а не в блокноте писать


                    1. andreykorol
                      11.12.2023 05:35

                      Я же говорю - вкусовщина. Я не готов развивать этот холивар, извините


                  1. SpiderEkb
                    11.12.2023 05:35

                    Я вот считаю, что для изучения нужны языки со строгой типизацией и без приколов

                    Я бы добавил еще "без UB"


        1. iminfinitylol
          11.12.2023 05:35

          я не пишу комменты потому что меня заминусят, а я хочу докончить хотя бы планируемые статьи, но на вопрос ветки надо ответить

          если отвечать на слова, и если ты не хочешь знать паскаль, значит тебе и базы данных ненужны (они все тоже алголаобразные, да и к тому же паскальные загоны ассемблера унаследовали, процедуры, вложенные в заголовки функции, даже циклы репиат унтил, а раз тебе ненужны базы данных значит и работать ты можешь только фронтендером)

          если ты приходишь в программирование и задаешь вот такие вопросы, значит тебе не надо быть программистом, настоящее программирование это искусство, искусство неразрывно связано с мастерством, а настоящий мастер - это вечный ученик, ты не станешь программистом зная только питон, или только веб, или только с++, для того чтобы стать настоящзим программистом надо получить полноту понимания, и только после этого (при достаточном упорстве и изобретательности ты получишь шанс стать настоящим программистом)

          преимущества "программиста" как потенциала человеческой синергии куда больше чем многие себе представляют и понимают, а если тебе нужны только деньги, иди в манагеры или банкиры

          для меня большая проблема это мобильная (могильная) разработка, и ассемблер, я отпихиваюсь си шарпом и веб вайв (а ассемблер просто тяжело, не хочу думать), но мне рано или поздно все равно придется овладеть обоими


        1. HemulGM
          11.12.2023 05:35

          Затем же, зачем становиться шарпистом или плюсовиком - разработка ПО.


      1. dyadyaSerezha
        11.12.2023 05:35

        Я знаю, для чего был создан Паскаль

        Не нужен сейчас, а именно был создан. И я писал на нем и на Delphi, когда ты еще под стол пешком ходил, в лучшем случае. Но все это совершенно не отменяет моего вопроса, который чёткий и ясный. И главное, актуальный.


        1. andreykorol
          11.12.2023 05:35

          Потому, что человек так захотел.
          Видимо ваш вопрос не понимают, если его приходится три раза повторить. Нет смысла ничего не меня его повторять. Перефразируйте, может будет полегче.


          1. dyadyaSerezha
            11.12.2023 05:35

            Да вот пока не видно ни одного человека, который, прочитав эту статью, захотел бы с нуля стать Delphi-программистом ????


            1. andreykorol
              11.12.2023 05:35

              Скорее всего нулевые программисты тут не ходят, про какой бы язык не шла речь.
              И уж точно врядли имеют возможность и причину тут об этом заявлять. Вы ждали под этой статьей комментария: "спасибо, теперь я знаю кем стану"?


              1. dyadyaSerezha
                11.12.2023 05:35

                Тогда что же имел ввиду автор под фразой "для самых маленьких" в заголовке и под первой фразой статьи "Принято считать, что программирование это сложно, но это миф"??

                Или я чего-то не понял?


                1. andreykorol
                  11.12.2023 05:35

                  А вот тут то вы его и поймали :) Тут я согласен с вами. Сегодня казним его или оставим на новый год?


                  1. dyadyaSerezha
                    11.12.2023 05:35

                    Под новый год лучше, на оливье)


        1. HemulGM
          11.12.2023 05:35

          Язык не завис в 2005 и развивается постоянно. Так что он не менее актуален, чем C# или C++. Гуглим, удивляемся.


          1. dyadyaSerezha
            11.12.2023 05:35

            Гугльнул, удивился.

            https://www.tadviser.ru/index.php/Статья:Рейтинг_востребованности_языков_программирования

            - не вошёл в десятку самых востребованных и вообще никуда не вошёл.

            https://habr.com/ru/articles/651585/

            - не вошёл в двадцатку.


            1. HemulGM
              11.12.2023 05:35

              А я и не сказал, что он "очень популярный". Он рабочий и актуальный. И статус "мертвого" языка он не заслужил.


      1. aamonster
        11.12.2023 05:35

        У меня есть коммерческий опыт разработки на Паскале и Дельфи (Дельфи прекрасен, на тот момент и ещё долго после afaik ничего сопоставимого уровня для создания GUI просто не было... MFC – боль), но я задаюсь тем же вопросом.

        К сожалению, это по сути мёртвый язык/среда, возможностей применения (кроме как чисто для себя) практически нет :-(.

        ЗЫ: Также цепанула фраза в начале статьи – мол, Objective Pascal ничем не отличается от C++. Это верно, лишь если ограничиваться "C с классами".

        ЗЫ2: На всякий случай плюсанул в карму, даже если не согласен насчёт полезности и т.п. – сама тема достаточно интересна для обсуждения, а знание практик Паскаля/Дельфи даст выигрыш и при последующем программировании на других языках.


        1. HemulGM
          11.12.2023 05:35

          возможностей применения (кроме как чисто для себя) практически нет

          Чем он не подходит для решения "современных" проблем? Этот язык мертвый именно для вас, ведь вы не интересуетесь его развитием, а оно далеко не нулевое.


          1. aamonster
            11.12.2023 05:35

            В основном малым количеством вакансий.


            1. HemulGM
              11.12.2023 05:35

              Это как-то не вяжется с "возможностей применения ... практически нет"


              1. aamonster
                11.12.2023 05:35

                Вяжется. Увы, это некая воронка угасания языка: нет вакансий – люди не учат язык – нет специалистов – на новых проектах выбирают другой язык, чтобы было легче найти специалистов – нет вакансий...

                Паскаль – прекрасный язык, Дельфи – замечательная среда, но, увы, некогда они проиграли C++.


                1. LAutour
                  11.12.2023 05:35

                  Для прикладных целей: писать утилитки для себя и для работы delphi\freepascal вполне удобны.


                1. HemulGM
                  11.12.2023 05:35

                  Делфи не проигрывал плюсам, Делфи проиграл Шарпу, потому что МС не мало палок в колеса понаставила. Перекупила себе родоначальника Делфи, который сейчас и занимается Шарпом (он же и TypeScript создал). Перетащила в Шарп почти все фишки Делфи и идеи среды разработки.

                  Однако у Делфи до сих пор есть не мало преимуществ перед Шарпом.

                  1. Независимость исполнительного файла

                  2. Скорость сборки проекта и развертывания

                  3. Производительность

                  4. Удобство создания GUI и возможности GUI (даже не смотря на WPF)

                  5. Простота создания собственных контролов и интеграция в среду

                  6. Открытость кода, не смотря на проприетарность языка


                  1. aamonster
                    11.12.2023 05:35

                    Я, видимо, постарше вас и успел увидеть именно как Дельфи проиграл плюсам). Это уже потом у плюсов часть поляны отжали новые языки. А потом появились ещё более новые, впитавшие в себя то, что было в паскале, но чего не хватало в плюсах – к примеру, в котлине и свифте есть нормальный switch (даже лучше паскалевского).

                    ЗЫ: и я прекрасно знаю преимущества Дельфи. Я ж говорю – имею опыт работы на нём, не для себя – для заказчика. Было очень удобно.


                  1. DMGarikk
                    11.12.2023 05:35

                    Все что вы описываете. это по нынешним временам уже довольно узкая сфера разработки десктопных приложений

                    независимость файла? - это уже лет 10 как никого не волнует

                    скорость сборки? - это крайне несущественный показатель выбора инструмента (ну разве что он не трое суток собирается)

                    производительность? - возможно соглашусь, мне не с чем сравнить

                    собственные контролы и интеграция - опятьже это применимо сугубо в нише десктопной разработки

                    открытость кода? всмысле исходник компилятора доступен?

                    пока это выглядит как "нужно быстрое приложение на десктоп но в си у нас никто не умеет, а C# как и Java тормозят насколько мы слышали"


                    1. HemulGM
                      11.12.2023 05:35

                      Речь не только о десктоп разработке. Делфи давно не только Десктоп и тем более, не только под Винду.

                      Клиент ChatGPT

                      На скрине не хватает только МакОС и иОС сборки, но она тут имеется

                      Собственные контролы - это про любую платформу. Суть здесь в том, что создавать собственные наборы контролов и компонент в Делфи проще, чем где-либо (потом можно опубликовать в штатный менеджер пакетов). И всё это будет доступно визуально другим разработчикам, которые не будут тратить время вообще ни на что, просто кинув компонент на форму и настроив его.

                      Например, тот же ChatGPT. Я создал невизуальный компонент, который достаточно кинуть на форму, вписать токен и название модели. А дальше в событии выбрать куда выводить текст (или сложное содержимое), функции и по кнопке вызвать метод с промптом. Т.е. на полноценный чат уйдет не больше 5 минут (с учетом открытия среды).

                      Hidden text


                      1. Albert2009Zi
                        11.12.2023 05:35

                        Просто ради моей собственной эрудиции, а возможно и будущего мастхава - есть Delphi под Linux и ARM? Т.е. есть уже дельфовая альтернатива Qt? Или?


                      1. HemulGM
                        11.12.2023 05:35

                        Под Linux (x64), как видно из скрина, - есть. Под АРМ, точно знаю, что под Андроид собирает, а Линукс и АРМ - не пробовал.


                      1. DMGarikk
                        11.12.2023 05:35

                        Делфи давно не только Десктоп и тем более, не только под Винду.

                        а я про Винду ни слова и не сказал

                        сейчас всё gui смещается в веб, из-за чего такие извраты как электрон стали нормой... и я теперь понимаю почему, не надо держать отдельного программиста для gui для каждой платформы, берешь фронтовика и он тебе интерфейс и на андройде и на десктопе и в вебе делает, потому что код и принципы одинаковые

                        достаточно кинуть на форму,

                        на какую форму? вы опять про десктоп приложения?

                        или предложите писать веб сервисы на делфи с серверным рендерингом в 23 году?


                      1. HemulGM
                        11.12.2023 05:35

                        Погугли TMS Web Core и UniGUI


                      1. DMGarikk
                        11.12.2023 05:35

                        а что тут гуглить, в 23 году фронтом должен заниматся фронт, а не фуллстек на беке

                        я вот не представляю как вы будете чинить проблему "открываю ваш сервис на ios, а у меня разметка съезжает, а на андройде норм"


                      1. HemulGM
                        11.12.2023 05:35

                        Разные подходы. Например, тот же электрон - это тоже фуллстек. Так и другие веб приложения.


                      1. DMGarikk
                        11.12.2023 05:35

                        это тоже фуллстек

                        И это прискорбно, бек написанный фронтом и фронт написанный беком - это кошмар и ужас в одном флаконе


                      1. simenoff
                        11.12.2023 05:35

                        У Вас Delphi 11 купленная?


                      1. HemulGM
                        11.12.2023 05:35

                        На работе - да. Дома Delphi 11 CE


                      1. simenoff
                        11.12.2023 05:35

                        Для 11 версии есть книга аналогичная "Руководство по Object Pascal для Delphi 10.4 Sydney"?



                      1. simenoff
                        11.12.2023 05:35

                        Ещё бы на русском..


                      1. kalapanga
                        11.12.2023 05:35

                        Так "Руководство по Object Pascal для Delphi 10.4 Sydney" на русском - это же вроде какой-то самиздат, да ещё и невычитанный машинный перевод. На кой такое счастье нужно? Ценность как у этой статьи...

                        А качественный перевод делать дорого и долго. К моменту выхода опять актуальность потеряется.


                      1. simenoff
                        11.12.2023 05:35

                        Хз кто переводил, но ссылку на книгу присылала Embarcadero


                      1. kalapanga
                        11.12.2023 05:35

                        И по ссылке русский перевод? Ну тогда нормально. А то по сети под этим названием какая-то шняга гуляет.



                    1. aamonster
                      11.12.2023 05:35

                      Скорость сборки важна. xkcd#303.

                      А вот ваш последний абзац – это аккурат то, что сейчас больше всего играет против дельфи. Ну нет смысла затевать новый проект на языке, для которого на рынке в 10 раз меньше программистов.


      1. Palesandr
        11.12.2023 05:35

        я был программистом делфи + MSSQL.
        а потом встретил c# :)
        даже не знаю, где используют делфи, разве только для поддержки старых проектов


        1. HemulGM
          11.12.2023 05:35

          Где угодно используется. Десктоп, веб, мобилки, бэк. Никаких проблем и сложностей. А старые проекты есть на всех языках.


    1. AndreyDmitriev
      11.12.2023 05:35

      А, кстати, несколько лет назад мне по работе потребовалось наваять несложное приложение для планшета на Андроиде. Я вроде всё по учебнику делал, но процесс с Андроид студей был весьма тернист, что-то там компилялось с ошибкой, в общем я и так и сяк, убил на это дело пару дней и уже был готов взять MIT App Inventor, но наткнулся на Embarcadero, а поскольку я довольно много программировал на Дельфи четверть века назад, то приложение на удивление легко набросалось буквально за вечер и всё заработало сразу и без проблем. Там "планка вхождения" реально ниже. Надо будет Delphi 12 Athens на досуге глянуть.


      1. dyadyaSerezha
        11.12.2023 05:35

        Да что ж такое. Я не спрашивал, для чего Delphi может пригодиться программисту по жизни. Может и ассемблер пригодиться, и даже какой-нибудь PL/1 - ну мало чего новый проект потребует. Я спросил совершенно другое.


        1. AndreyDmitriev
          11.12.2023 05:35

          Если вы про востребованность на рынке, то она есть, небольшая конечно, но есть. По немецкому рынку вакансий - зайдите скажем на monster.de, вбейте там Delphi и вы их увидите. У нас до сих пор старые проекты живы. Ну и как язык для обучения вполне норм. Опять же обычно единственным языком сейчас не ограничиваются, как второй-третий язык почему бы и нет. Кокуренция к тому же невелика.


          1. dyadyaSerezha
            11.12.2023 05:35

            Рынок Германии это все же рынок Германии. И зачем обучаться программированию на очень маловостребованном языке, если можно на очень востребованном?


    1. nronnie
      11.12.2023 05:35

      Только один вопрос: а зачем становиться Delphi-программистом?


    1. Offnull
      11.12.2023 05:35

      Там конкуренция меньше чем у других ЯП , и зп высокие даже у джуна на фоне других языков


      1. dyadyaSerezha
        11.12.2023 05:35

        Можно сюда или в личку кинуть хотя бы пять открытых позиций по Delphi с высокими зарплатами?


        1. Offnull
          11.12.2023 05:35

          Хх ру вам на помощь, у джуна на старте зп в среднем 100к, где вы видели такое на других ЯП, не считая c++ с минимум конкуренции?


          1. DMGarikk
            11.12.2023 05:35

            а реально сеньором потом стать с 350к+? и работу через 10 лет найти?


            1. Offnull
              11.12.2023 05:35

              Какова вероятность, что вы на других языках будете 350 получать без знания английского , в России не так уж и много таких вакансий скажу вам, если смотреть язык python , другими не интересуюсь, т.к разрабатываю на питоне???

              Работа будет также и через 10 лет, т.к легаси системы у крупных корпоратов никуда не денутся а разгребать это кому-то надо...


              1. DMGarikk
                11.12.2023 05:35

                Какова вероятность, что вы на других языках будете 350 получать без знания английского

                ну не маленькая вероятность, я больше получаю, английский у меня правда B1 но он на нынешней работе мне не нужен


                1. Offnull
                  11.12.2023 05:35

                  Ну вы скорее исключение из правила, т.к большинство получают до 200 т.р в среднем, исходя из вакансий на хх.ру и даже 200 уже выше среднего как по мне..

                  А тут без конкуренции, человек с ходу получать будет 100+, к тому же потом ему ничего не мешает изучить другие направления и поднять свое зп ещё выше

                  Уверен раз у вас оплата 350+, то и знаете вы не один ЯП, что также не мешает другим быть также


                  1. DMGarikk
                    11.12.2023 05:35

                    я не думаю что я прям исключение из сеньоров, разве что меня в менеджмент тянет, все мои коллеги с кем я работал (сеньорских грейдов) получают 300+ которые из РФ не уехали

                    Это еще при том что я например не смогу пройти собес в яндекс или в гугл

                    по вакансиям на хх такое себе оценивать рынок зарплат потому что там большинство вакансий с высокими грейдами без вилок


                    1. Offnull
                      11.12.2023 05:35

                      Но и моя логика тоже имеет обоснование, синьоров не так уж и много, по сравнению с джунами и мидлами, тут просто момент такой, что не каждый хочет быть синьором, но вот что точно, так это каждый хочет зарабатывать с ходу хорошо, и людям семейным с детьми , устраиваться на позицию джуна с зп менее 100к не каждый решиться в том числе конкуренцию побороть не каждый осилит, поэтому изучить делфи и найти работу, думаю будет проще и выгоднее на старте, а уже потом можно и другие варианты искать по увеличению зарплатной вилки , изучив другие ЯП уже получая относительно больше других


  1. SpiderEkb
    11.12.2023 05:35

    К примеру, богатая палитре Com объектов (компонентов, или готовых шаблонов для кнопок, полей ввода текста, картинок, и тд, кароч не надо изобретать велосипеды).

    Полный бред. К Паскалю это не имеет никакого отношения. Это библиотека VCL, основанная на стандартных Windows Common Controls (ComCtl).

    И, кстати, COM объекты это совсем про другое.

    И та же самая библиотека может использоваться в Borland C++ Builder. Который фактически тот же Delphi, но не на Паскале, а на С++

    При этом для C++ есть и другие фреймворки - Qt, wxWidgets, MFC тот же... Которые точно также все это реализуют.

    Короче, очередной бред "мамкиного погромиста".


    1. IvanPetrof
      11.12.2023 05:35

      Моё мнение - если и писать под vcl (ну вдруг так получилось), то уж лучше на c++ чем на pascal.

      Знание c++ хоть где-то потом может пригодиться (хоть оно в билдере и со своими приколами), а знание паскаля, это.. ну примерно - как 1С (в смысле - очень узкая ниша).

      Хотя, наверное, паскаль лучше приспособлен для обучения. Я тоже когда-то с него начинал.


      1. SpiderEkb
        11.12.2023 05:35

        На билдере в своей время немало писал. Из ну вот совсем специфического - разве что property (на мой взгляд весьма удобная штука) и реальная поддержка борландовским компилятором типа long double (80 бит, для остальных компиляторов long double == double).

        Но с современными версиями стандартов там совсем никак. Даже не знаю - живо оно еще или нет.

        Так что сейчас если и писать, то использовать кроссплатформенные gcc + Qt (правда, там с лицензией какие-то непонятки были вроде бы) или wxWidgets (OpenSource).


        1. HemulGM
          11.12.2023 05:35

          Статья отвратительная. С этим не поспоришь. Но, на самом деле, Delphi не стоит на месте. Там тоже есть другие фреймворки, в частности штатный кроссплатформенный (Билдер, кстати его тоже частично поддерживает) - FMX (FireMonkey). Легко посоперничает с Qt и WPF.


          1. SpiderEkb
            11.12.2023 05:35

            Я про Делфи (или Паскаль) вообще ничего не говорил плохого. Судя по текущему состоянию дел, для десктоп разработки под Вин или Линукс вполне себе подходит. И прекратившим развитие ее тоже не назовешь. Значит, кому-то это нужно и кто-то этим пользуется.


    1. nronnie
      11.12.2023 05:35

      Короче, очередной бред "мамкиного погромиста".

      Да автор своим циклом статей откровенно стебется :) Как бы ему только до бана случайно не достебаться :))

      С нетерпением жду статью про C#, т.к. я спец именно в нем.


    1. LAutour
      11.12.2023 05:35

      При этом для C++ есть и другие фреймворки - Qt, wxWidgets, MFC тот же... Которые точно также все это реализуют.

      Не совсем - в отличии от VCL они требуют приложения своих библиотек к исполняемому файлу.


      1. SpiderEkb
        11.12.2023 05:35

        Ну, строго говоря (по крайней мере для билдера) VCL можно было как статиком линковать, так и динамиком (с дополнительынми DLL).

        С Qt не приходилось работать много, а wxWidgets точно также можно собирать как статическими библиотеками, так и динамическими и линковать соответственно.

        Так что тут нет каких-то радикальных отличий.


        1. Arkasha
          11.12.2023 05:35

          Qt тоже можно линковать статически


          1. AMajor-C
            11.12.2023 05:35

            Бесплатно - нет. Ну, точнее, только в нарушение лицензии.


  1. lhomme
    11.12.2023 05:35

    Тонко, очень тонко)


  1. d_ilyich
    11.12.2023 05:35

    Особенности концепции языка предполагают создание новых переменных только в заголовках

    Поскольку речь всё-таки о Delphi, то это уже не так: Inline Variable Declaration


  1. bert2000
    11.12.2023 05:35

    Любите шарпы, но пишете на пасквиле?

    Писаки на си называются насильниками если что


  1. leremin
    11.12.2023 05:35

    А язык не Delphi называется? Объектным Паскалем он был до Delphi 6.


    1. LAutour
      11.12.2023 05:35

      Если так придираться, то при упоминании C++ нужно всегда уточнять чья версия с отклонениями от стандарта имеется ввиду (microsoft, borland, gnu).


  1. LAutour
    11.12.2023 05:35

    Еще у паскаля есть одна уникальная причуда, это процедуры (на ровне с функциями), так как это высокоуровневый язык программирования (спроектированный под концепцию ооп) работа предполагается со сложно составными объектами (с классами), и, специально для свойств внутри этих классов (для переменных внутри класса, класс — это пользовательский тип данных) были созданы процедуры (для изменения содержимого, которое ассоциировано со свойством).

    Извините, но что это за бред про процедуры?


    1. SpiderEkb
      11.12.2023 05:35

      Только про процедуры? А

      высокоуровневый язык программирования (спроектированный под концепцию ооп)

      применительно к Паскалю не смущает?


      1. LAutour
        11.12.2023 05:35

        Учитывая, что говорится об Object Pascal - не очень.


        1. SpiderEkb
          11.12.2023 05:35

          Ну так С++ тоже "специально под ООП спроектирован".


  1. DMGarikk
    11.12.2023 05:35

    Почитал статью как в начало нулевых вернулся ;))

    А COM разве не считается устаревшим стандартом?


    1. nronnie
      11.12.2023 05:35

      Да тут тема главная еще в том, что компоненты Delphi никакого отношения к COM вообще не имеют :)


      1. SpiderEkb
        11.12.2023 05:35

        Товарищ явно путает COM (Component Object Model) в винде и Common Controls (CommCtl) там же. И на все это накладывается термин "компонента" из VCL.

        И да. Ни то, ни другое к дельфям не относится. Это чисто виндовые вещи для которых в VCL (и других аналогичных фреймворках) есть классы-обертки


    1. mayorovp
      11.12.2023 05:35

      Считается, хотя лучшего для интеграции объектно-ориентированных библиотек на разных языках ещё не придумали.

      Но у автора ни слова про интеграцию, как и про сам COM...


  1. deafcafe
    11.12.2023 05:35

    PascalABC - когда нужно что-либо быстро запрограммировать. Можно использовать в качестве калькулятора.


    1. aamonster
      11.12.2023 05:35

      В качестве калькулятора удобно использовать адресную строку Chrome.


      1. LAutour
        11.12.2023 05:35

        А если без интернета?


        1. aamonster
          11.12.2023 05:35

          Хм, проверил – без интернета не считает (это показывает, как часто я бываю без интернета). Чаще я бываю без десктопа.

          Ну, тогда любой привычный язык с REPL. Сейчас для меня это, скорей всего, будет javascript. Как вы понимаете, опять же в браузере, только уже в девелоперской консоли).


        1. mayorovp
          11.12.2023 05:35

          Консоль инструментов разработчика Хрома (та, что открывается по F12)


  1. d_ilyich
    11.12.2023 05:35

    Интересно, кто в Вашем понимании "начинающий программист" (НП)? Вот у меня, например, по-прежнему вызывают временный паралич умственной деятельности некоторые словосочетания типа "парадигма программирования". Вы с самого начала закидываете непонятными терминами типа "биос", "драйвер", "пиксель". Это для "самых маленьких"?

    Потом сразу запускаете Lazarus. Где его взять, как, чего и т.д.? В первом листинге присутствуют, в частности, кнопка и поле ввода, но перед этим ни слова, что сначала надо их добавить на форму. Листинг огромен! Да, большая часть - это комментарии, но НП может об этом не подозревать. Пытаюсь представить себя в роли этого НП: я бы, наверное, пал духом при виде такого.

    Мне в роли НП (да даже не обязательно в программировании, просто в роли новичка) хотелось бы сразу увидеть некий положительный результат: Ух, ты! Работает! Классно! Применительно к программированию - тот самый "привет, мир!"; "меня зовут {имя}, мне {n} лет"; уравнения простенькие, может быть. Если б я был "самым маленьким", то не уверен, что с помощью этой статьи за час смог бы хоть небольшого успеха достичь.

    И ещё. Если Вы стремитесь своими статьями пробудить интерес к программированию у новичков, то, думаю, не стоит использовать в примерах слова типа "быдлокодер". Как-то не очень воодушевляет.


    1. SpiderEkb
      11.12.2023 05:35

      Не воспринимайте всерьез все это. Просто галоперидол не успели кому-то вовремя подвезти.


  1. DevlabStudio
    11.12.2023 05:35

    Аж ностальгию словил, мой первый язык =)


  1. yugo_fx
    11.12.2023 05:35

    Чего автору не занимать, так это упорства в продвижении бреда! Секты примерно так и самоогранизуются, удачи вам и всех благ!


  1. JordanCpp
    11.12.2023 05:35

    Как стать Delphi-программистом за час «для самых маленьких»


  1. JordanCpp
    11.12.2023 05:35

    Автор вы юзаете Lazarus?

    Ведь Lazarus верно?


  1. ValdikSS
    11.12.2023 05:35

    Час? Как-то долговато.


  1. sdramare
    11.12.2023 05:35

    То, что мертво, должно оставаться среди мертвых, ему ничего делать в мире живых.


    1. HemulGM
      11.12.2023 05:35

      Последняя версия Delphi (и спецификации языка и версия среды) вышли в прошлом месяце. Предыдущая версия вышла пол года назад. Продукт, который стоит не малых денег с регулярным обновлением и поддержкой - глупо называть "мертвым".


      1. sdramare
        11.12.2023 05:35

        Пока существуют легаси продукты авторы делфи будут доить этот рынок, выпуская новые версии среды программирования мышкой, в этом и не приходится сомневаться. Но если одно только наличие работающих легаси систем является доказательством "не мертвости", то тогда и кобол живее всех живых.


        1. HemulGM
          11.12.2023 05:35

          По-моему я сказал, что язык развивают, а не что на него есть рабочие места. Именно наличие развития говорит о том, что язык НЕ мертв. Или вы этот текст просто пропускаете?

          Софт пишется на Делфи в том числе и даже больше новый. С нуля. А не только участвуют в поддержании легаси. Я сейчас занимаюсь исключительно новыми разработками. В разных местах. И люди, с которыми общаюсь, пишут в основном новый софт, а не допиливают старый. А с учетом того, что я больше осведомлен о разработках на Делфи, то мой аргумент весомее, нежели ваши сомнения.


          1. sdramare
            11.12.2023 05:35

            Давайте мы будем ориентироваться не на ваш субъективный информационный пузырь ("я делфи разработчик и в моей компании, где все пишут на делфи, новые проекты мы тоже делаем на делфи"), а на объективную информацию. Вот, например, статистика по доли языка в открытых вакансиях по миру: лидер JavaScript с 53%, C# имеет 28%, C++ 23%, а делфи занимает аж 1% рынка, проигрывая F# и едва обходя хаскелл. Да, живее всех живых, что уж тут скажешь.


            1. HemulGM
              11.12.2023 05:35

              я делфи разработчик и в моей компании, где все пишут на делфи, новые проекты мы тоже делаем на делфи

              Это вы для себя сами придумали, дабы было удобно ответить.

              Я создаю проекты не только в своей компании, где работаю, но и участвую в разработке сторонних проектов совершенно сторонних людей. Я общаюсь с разными людьми, и не только в РУ сегменте.

              А ваша статистика не основана ни на чем и будет справедлива только для тех языков, проекты на которых доступны всем (или ими пользуются в публичном доступе и/или они в опенсорсе).

              На Делфи как правило создаю коммерческие продукты, которые нацелены на конкретных пользователей, а не ширпотреб, очень много софта создано для внутреннего использования.

              Помимо всего этого, несмотря на то, что я специально заметил, что речь НЕ О РАБОЧИХ МЕСТАХ, вы снова приводите статистику рабочих мест. Т.е. вы вообще не читаете то, что вам пишут?

              Его используют в банках (А Сбер недавно выпустил публичный софт на Делфи для пользователей)

              Скрин

              Altium Designer - софт для электронщиков по работе с платами

              FL Studio - софт для создания музыки

              Ceramic3D - софт для дизайна интерьера и рендера

              Toad for Oracle - менеджер СУБД для Oracle

              Game Maker Studio - софт для создания игр

              HeidiSQL - менеджер СУБД для MySQL и иже с ним

              Everest - софт для сбора и мониторинга информации о ПК

              Почти весь софт Auslogics

              Inno Setup - мастер создания установщиков

              Я могу так долго продолжать


              1. DMGarikk
                11.12.2023 05:35

                Я могу так долго продолжать

                вы пишите в каком году софт то этот был написан

                Toad писался в 98 году, и не Ораклом

                FL Studio - 97 год

                HeidiSQL - 06 год

                Game Maker Studio

                на делфи только первые версии были, сейчас уже шарп

                еще пара примеров - какието нишевые софтины судя по всему написанные одним-двумя человеками

                Его используют в банках (А Сбер недавно выпустил публичный софт на Делфи для пользователей)

                Его не используют специально. это зачастую сторонний софт который случайно туда попал по историческим причинам

                Есть например довольно известный внутри процессинговой отрасли софт, для управления банкоматами, написанный на делфи в начале нулевых

                довольно корявое поделие сделанное на коленке двумя программистами, один из которых на тот момент когда я с ним сталкивался был уже в пенсионном возрасте

                есть некая вероятность что сбер купил эту контору вместе с софтом


                1. HemulGM
                  11.12.2023 05:35

                  Софт Сбер на скрине - это софт на современном фреймворке (FMX) и современном компиляторе, который не совместим с тем, что был с самого начала (VCL). Это софт, которого раньше не было. Максимальный возраст проекта может быть где-то лет 5. Но я сильно в этом сомневаюсь, потому что тогда FMX ещё не был так стабилен, чтоб на нём писать публичный софт


  1. CAM_devs
    11.12.2023 05:35

    Так сложилось, что свой продукт мы начали писать в 1996. Сейчас имеем 3млн строк на Delphi. Продукт из категории САПР отлично продается за рубежом и входит в топ 20 среди аналогичного софта. В 2022 все наши конкуренты дружно встали и ушли из России, после чего мы стали здесь практически монополистами. Госкомпании дружно заливают нас деньгами и требуют перехода на Linux. Поэтому стек Microsoft, включая C#, который "всего" в 2 раза медленнее нативного Delphi не подходит. Миграция на "плюсы" потребует кучи времени и не приведет к росту функциональности системы. Какая у нас альтернатива Delphi? Требуются программисты на Delphi, з/п выше средней по отрасли. Специфика продукта: расчеты, графика, геометрия, практически не используем базы данных.


    1. KongEnGe
      11.12.2023 05:35

      3 млн за четверть века -- это даже мало :) Либо у вас очень эффективная кодовая база с погашенными техдолгами.


      1. HemulGM
        11.12.2023 05:35

        В Delphi - это нормальная практика, т.к. более половины всего кода, который был бы на плюсах, является автогенерацией (dfm + определения в модуле связанном с этой dfm)


    1. egr0proxy
      11.12.2023 05:35

      А что за САПР,если не секрет?


      1. CAM_devs
        11.12.2023 05:35

        SprutCAM


    1. LittleAlien
      11.12.2023 05:35

      включая C#, который "всего" в 2 раза медленнее нативного Delphi

      Навскидку на этом:
      https://github.com/Mark-Kovalyov/CardRaytracerBenchmark
      получаю С# x64 - 9.4, Delphi x64 - 16.8 секунды (однопоток, консольный вывод в Дельфи отключен). Меньше - лучше, то есть С# быстрее почти в 2 раза.
      Почему? Ну, JIT C# основан вероятно на C++, а кодогенерация в плюсовых компиляторах со временем улучшается. У Дельфи она застряла на уровне 2000-х по причине неустроенности (перепродажи) и нехватки ресурсов на разработку.
      Я понимаю, почему вы держитесь за написанные и отлаженные млн. строк, просто слегка просвещаю насчёт современного соотношения сил.


      1. aamonster
        11.12.2023 05:35

        Думаю, у них всё упирается в затраты на выделение/освобождение памяти (когда платишь за удобство GC быстродействием), кодогенератор-то понятно, какой лучший код выдаст.


        1. sdramare
          11.12.2023 05:35

          Ничто не мешает писать на C# код минимизирующий использование GC - value-type, Span, ArrayPool/ObjectPool, ref, поинтеры и т.д. Скорее у них все упирается в то, что называют "Skill Issue"


          1. aamonster
            11.12.2023 05:35

            Можно, но это изрядно убьёт удобство C# и для получения легко поддерживаемого кода потребует довольно высоких навыков.


            1. sdramare
              11.12.2023 05:35

              На любом языке программирования, хоть Делфи, хоть C# хоть JS или Python нужные профессиональные навыки чтобы писать хороший и поддерживаемый код. Я не знаю такого языка программирования, который можно дать команде безграммотных "индусов" и они напишут идеально поддерживаемое приложение просто потому что это такой волшебный язык. Опять же, оптимизация работы с памятью делается в тех местах, где она нужна, какой-нибудь простой обработчик нажатия кнопки можно писать максимально удобно и просто, с LINQ и прочим, так как это не hot path.


              1. aamonster
                11.12.2023 05:35

                Offtopic: словосочетание «безграммотных "индусов"» сделало мой день :-)

                Насчёт оптимизации – всё так. Но всё же не зная конкретных задач – трудно сказать, что в них можно выжать из разных языков в плане оптимизации и в плане удобства поддержки кода. Да плюс ещё могут вылезать какие-то менее очевидные вещи – например, Apple в своё время отказалась от использования GC в пользу reference counting, довольно любопытная история.


                1. sdramare
                  11.12.2023 05:35

                  Ну эппл отказалась, а гугл наоборот использует java c GC в андроид - видим ли мы какую-то категорическую качественную разницу в приложениях? Я бы не сказал.


                  1. aamonster
                    11.12.2023 05:35

                    А вы полюбопытствуйте, почему именно отказались (они не просто отказались, не попробовав: несколько лет у них поддержка GC была), чем за это заплатили, что получили.
                    Это вопрос компромиссов, Apple предпочёл один компромисс (учитывающий их специфику – высокие требования к плавности и отзывчивости интерфейса), Google другой.


        1. mayorovp
          11.12.2023 05:35

          Конкретно в CardRaytracerBenchmark нет никаких затрат на выделение/освобождение памяти, там только куча математики.


      1. HemulGM
        11.12.2023 05:35

        Я не уверен в оптимальности тамошнего кода. Я добавил inline модификаторы и с 19сек, на моей машине, я уже получил 14сек. Так что хорошо бы взять того, кто сначала нормально напишет код, а потом уже сверять.

        Компилятор Делфи не застрял в 2000-х, вы заблуждаетесь. Да, он не такой оптимальный, как некоторые для С++, но в конечных задачах на C#, где как правильно обычный код, как и на Делфи - и Делфи выигрывает в производительности конечной программы, если не заниматься в C# сильной оптимизацией.

        Так же, замечу, что хоть Дельфовый компилятор и развивается, но не так быстро, как хотелось бы. В нем до сих пор мало интринсиков. И поддерживается не так много новых инструкций процессоров (в частности для векторов).

        И ещё, хочу обратить внимание, что люди держаться за Делфи не потому что на нём млн.ы строк написаны, не потому что Легаси надо как-то поддерживать. На данный момент нового софта пишут не меньше, чем раньше.


        1. LittleAlien
          11.12.2023 05:35

          Компилятор Делфи не застрял в 2000-х, вы заблуждаетесь.

          У меня есть проект, который собирается разными версиями Дельфи начиная с D5/1999, недавно протестировал его на D12/2023.
          И какая же разница в скорости исполняемого кода за 24 года?
          Никакой! Ну может 1%, на уровне погрешности.
          Потому что там в основном целочисленные расчёты, и единственное заметное улучшение компилятора (плавающая точка на SSE в x64) не влияет.
          Так вот и получается, что для моих целей прогресса в компиляторе нет, и он застрял даже можно сказать в 90-х.
          Андроиды и прочие платформы не особо интересны, разве что Линукс... впрочем, по сообщениям там ещё хуже со скоростью, потому что это криво (с отключенной оптимизацией) прикрученный LLVM. Кто-то может проверить кардтрейсер на Дельфи/Линуксе?

          На Си у меня нет проекта в точности аналогичного дельфийскому, но тот же кардтрейсер на gcc версий 4.9 и 12 (между ними 8 лет) показывает на разных ф-ях ускорение 10-20%, а иногда 2+ раза, если новая версия векторизовала, а старая нет. С компилятором 1999 года разница должна быть ещё больше хотя бы из-за поддерживаемого набора инструкций.


      1. HemulGM
        11.12.2023 05:35

        А вот тест бенчмарка C# на моей машине

        х32 C# примерно равен скорости исполнения x64 Delphi

        x64 C# медленнее чем x64 Delphi на 1.3сек


        1. sdramare
          11.12.2023 05:35

          На вашем же скриншоте написана ошибка запуска. А происходит она потому что первый тест это запуск с версией .net core, которая у вас не собралась. https://github.com/Mark-Kovalyov/CardRaytracerBenchmark/blob/master/c-sharp/run.cmd В результате вы смотрите только бенчмарк для .NET Framework, оптимизацией и развитием которого MS уже много лет не занимается.


          1. HemulGM
            11.12.2023 05:35

            Версия MSBuild 17.7.4+3ebbd7c49 для .NET
              Определение проектов для восстановления...
              Все проекты обновлены для восстановления.
            CSC : error CS5001: Программа не содержит статического метода "Main", подходящего для точки входа. [D:\Projects\#Fork\C
            ardRaytracerBenchmark\c-sharp\card-raytracer.csproj]


            1. mayorovp
              11.12.2023 05:35

              Это из-за того, что папка с исходниками совпадает с выходной. Новые SDK в этой ситуации отказываются автоматически включать исходники в проект.

              Замените <Compile Remove="card-raytracer-mt.cs" />в проекте на <Compile Include="card-raytracer.cs" />

              Да и netcopreapp2.1 надо заменить на что по-свежее, net7.0 там или net8.0


              1. HemulGM
                11.12.2023 05:35

                Спасибо, помогло. Но ошибка какая-то не информативная.


          1. HemulGM
            11.12.2023 05:35

            Ну в общем вот. Быстрее где-то на 1.2сек. Но повторяю, что стоит написать на Делфи более актуальный код. Я бы занялся, но времени хватает, только что на Хабре языком чесать)

            Тут на Делфи х64


            1. sdramare
              11.12.2023 05:35

              Просто напомню, что началось все с утверждения "C#, который "всего" в 2 раза медленнее нативного Delphi". А касательно оптимизации - .net версия там так же без особых мыслей сделана, те же хинты для инлайнинга в C# тоже можно было бы расставить и использовать MathF вместо Math. Да и, к примеру, не удивлюсь если вот этот кусок побайтовой записи в файл занимает больше времени чем весь остальной код

              res.WriteByte((Byte)p.x);
              res.WriteByte((Byte)p.y);
              res.WriteByte((Byte)p.z);


            1. LittleAlien
              11.12.2023 05:35

              Ну что касается "написать правильно", то например C++ можно относительно небольшими правками разогнать в разы, я про это целую статью писал:
              https://habr.com/ru/articles/685228/
              Дельфи от этих правок ускоряется гораздо меньше, потому что векторизацию компилятор не умеет совсем. Хотите SIMD - только хардкор, только ассемблерные простыни вручную.


      1. LAutour
        11.12.2023 05:35

         кодогенерация в плюсовых компиляторах со временем улучшается

        Вот только при этом системные требования к откомпилированным программам все растут и растут.


    1. aamonster
      11.12.2023 05:35

      Это вы красиво зашли :-). Сейчас ностальгирующие по Delphi деды вроде меня вас запомнят, и потом вам будет, где искать разработчиков. Вероятно, даже не таких плохих, как обычно видишь на собесах.


      1. CAM_devs
        11.12.2023 05:35

        Если серьезно ищете работу, пишите пообщаемся. Продукт SprutCAM, контакты в сети.


    1. sdramare
      11.12.2023 05:35

      Поэтому стек Microsoft, включая C#, который «всего» в 2 раза медленнее нативного Delphi не подходит.

      С учетом что последняя версия .net показывает в большинстве бенчамарков производительность сопоставимую с С++, то либо делфи обладает какой-то невероятной скоростью работы, в разы быстрее С++, во что крайне сложно поверить, либо, что более вероятно, вы просто заблуждаетесь.

      https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/csharpcore-gpp.html


  1. kkuznetzov
    11.12.2023 05:35

    Программист некромант


  1. HemulGM
    11.12.2023 05:35

    Особенности концепции языка предполагают создание новых переменных только в заголовках

    Неужели?

    program Test;
    begin
      var MyVar := '123'; //string
      writeln(MyVar);
    end.

    Еще у паскаля есть одна уникальная причуда, это процедуры (на ровне с функциями), так как это высокоуровневый язык программирования (спроектированный под концепцию ооп) работа предполагается со сложно составными объектами (с классами), и, специально для свойств внутри этих классов (для переменных внутри класса, класс — это пользовательский тип данных) были созданы процедуры (для изменения содержимого, которое ассоциировано со свойством).

    Этот бред мы просто пропустим. И да, язык не "спроектирован под концепцию ООП". Язык мультипарадигменный. Хочешь - используй ООП, хочешь ФП.

    Не в обиду разработчикам с++ и с (которые работали всю жизнь только с С, С++, «сибразины»), но у паскаля есть множество неоспоримых плюсов перед с++ (хе‑хе ну вы поняли с++ и плюсы), просто мало кто о них знает в меру собственных знаний.

    К примеру, богатая палитра Com объектов (компонентов, или готовых шаблонов для кнопок, полей ввода текста, картинок, и тд, кароч не надо изобретать велосипеды).

    Как это вообще относится к языку? Это никак к нему не относится. Это VCL - GUI фреймворк. И да, язык можно использовать БЕЗ VCL и даже для создания сложных программ с GUI.

    Lazarus - это НЕ ПРО Delphi. Это про FPC! Это разные языки и с каждым кодом всё больше и больше между ними разница.

    PUBLISHED ничем не отличается от PUBLIC. Это специальный модификатор, который используется при регистрации класса в среде разработки для работы в DesignTime!

    Вы, к слову, прекрасный представитель "БЫДЛО кодера" на Паскале.

    Модификаторы доступа НЕ пишутся на каждую строчку и не относятся к конкретной строчке! Модификатор доступ - это СЕКЦИЯ!

    По этому, когда вы напишите следующее

    ... class
    PRIVATE MyField: integer;
    MyString: string;
    end;

    MyString - ТОЖЕ private! Потому что следует писать вот так:

    ... class
    private
      MyField: integer;        //private
      MyAnotherField: string;  //private
    public
      MyString: string;        //public
      MyInt: integer;          //public
    end;

    Несмотря на то, что я люблю Delphi ваша статья заслуженно получает минус от меня. Причины:

    1. Вы учите плохому. Подходы не верные. Используете антипаттерны и, хоть вы и пишите, что в Делфи можно избавиться от низкоуровневого программирования, вы используете постоянно символ "@" - который позволяет получить прямой адрес. Это делать, без необходимости вообще не надо. А я уже и не помню, когда подобное писал.

    2. Очень много синтаксических ошибок и много не верной (не актуальной) информации. Когда говорят о COM объектах - подразумевают не контролы VCL, которые технически ими являются, но обернуты очень глубоко фреймворком. И к самому языку они никак не относятся!

    3. У вас очень плохой багаж знаний современного Delphi. А помимо всего этого, вы вроде как говорите о Delphi, но используете FPC и среду Lazarus, которые никак не связаны с Delphi!

    Современный Delphi сильно вырос по сравнению с FPC и среда разработки RAD Studio на порядок превосходит Lazarus.


  1. simenoff
    11.12.2023 05:35

    AIMP, кстати, на Delphi написан, мой любимый аудиопроигрыватель с момента появления


  1. simenoff
    11.12.2023 05:35

    1. HemulGM
      11.12.2023 05:35

      Вакансий на HH: 
      Delphi:       265 (-7)     ~90k  (22-270)
      Pascal:       83 (-3)      ~90k  (30-180)
      Python:       3697 (-32)   ~60k  (8-500)
      C#:           2088 (-33)   ~50k  (15-275)
      C++:          2595 (-34)   ~100k (25-450)
      Swift:        455 (-16)    ~100k (30-350)
      Java:         3413 (-37)   ~75k  (15-200)
      Visual Basic: 97 (-5)      ~90k  (20-200)
      Go:           1118 (-1)    ~90k  (25-400)
      Ruby:         173 (-3)     ~130k (25-350)
      Kotlin:       1065 (-22)   ~100k (15-450)
      Rust:         105 (-1)     ~150k (50-400)
      Fortran:      6 (0)        ~180k (180-180)
      Dart:         134 (0)      ~140k (30-300)
      
      Flutter:      227 (-3)     ~80k  (30-300)
      FireMonkey:   1 (0)        ~65k  (65-65)
      Electron:     93 (-2)      ~175k (70-350)
      Lazarus:      12 (-1)      ~100k (20-120)
      React Native: 274 (-6)     ~80k  (30-320)
      PostgreSQL:   4877 (-68)   ~70k  (15-250)

      Вот такую статистику я в боте вывожу. Здесь запрос на HH на 100 свежих позиций. Ну и общее кол-во вакансий тоже показывается.
      1 число - это всего вакансий (в скобках - разница с предыдущим значением). 2 - медианная зп (на последних 100 вакансий), 3 - вилка


  1. simenoff
    11.12.2023 05:35

    Свежие книги по Delphi выходили какие-нибудь?


    1. HemulGM
      11.12.2023 05:35

      Выходили


  1. Eremite_b
    11.12.2023 05:35

    Для меня Паскаль стал хорош в обучении тем, что строго следил и говорил мне, что я должен был описать каждую переменную, которую хочу использовать.


  1. Albert2009Zi
    11.12.2023 05:35

    Вставлю свои пять копеек. А чего это Вы какую-то страшную IDE используете? Есть же Embarcadero RAD Studio Community 10.xx бесплатная, со всеми подсветками, переходами по имплементации и т.п. фишками нормальной IDE. По мне, так полная (могу ошибаться) копия Visual Studio в плане функционала.


    1. HemulGM
      11.12.2023 05:35

      Visual Studio - это копия RAD Studio =)


      1. Albert2009Zi
        11.12.2023 05:35

        Этот холивар не ко мне, я слишком стар для этого... Я больше наслаждаюсь качеством и "аусштаттунгом" изделий.


    1. kalapanga
      11.12.2023 05:35

      В последней версии Community Edition Embarcadero опять учудили - удалили компилятор командной строки! Вы по прежнему можете делать всё, но некоторые вещи теперь должны делать через Ж или опять слегка пиратить. Конечно дарёному (бесплатному) коню в зубы не смотрят. Но при всей моей привязанности к Дельфи политика Embarcadero иногда, мягко говоря, своеобразная.


      1. Albert2009Zi
        11.12.2023 05:35

        Я не качал последней версии, у меня на домашнем компе стоит, скачанная больше года назад 10ть - точка какая-то версия. На лэптопе с работы стоит полноценная лицензионная 11ая.
        Я писал сразу GUI для измерительной программы и командная строка нужна была больше для проверки очень ограниченной части функционала отдельных кусков и прогона некоторых идей. Командная строка работала отлично.
        Все подобные баги - это ведь извечная проблема всего бесплатного :(


  1. kalapanga
    11.12.2023 05:35

    Интересно, 24 людям (на моменть написания этого комментария), которые поставили плюс этой статье, что именно в ней понравилось?


  1. idmelnik
    11.12.2023 05:35

    Многоэтажную конструкцию:

      StringGrid1.Cells[0,0]:='б';  
      StringGrid1.Cells[1,0]:='ы';
      StringGrid1.Cells[2,0]:='д';
      StringGrid1.Cells[3,0]:='л';
      StringGrid1.Cells[4,0]:='о';
      StringGrid1.Cells[5,0]:='к';
      StringGrid1.Cells[6,0]:='о';
      StringGrid1.Cells[7,0]:='д';
      StringGrid1.Cells[8,0]:='е';
      StringGrid1.Cells[9,0]:='РРР';

    можно было заменить всего на одну строчку:

    StringGrid1.Rows[0].DelimitedText := 'б ы д л о к о д е ррр'

    Результат будет тот же! )))


    1. d_ilyich
      11.12.2023 05:35

      А если б текст ёлочкой был, лесенкой или по спирали? Я вот когда читаю книжку, то не тупо копирую/вставляю примеры, а пытаюсь что-то поменять, поэкспериментировать. В данном случае считаю "многоэтажность" вполне оправданной. А к оптимизации можно последовательно идти.