|
|
|
ЧАСТЬ 1. AL-IV: Как начать программировать |
Ссылка на загрузку компиляторов и
базовых примеров кода: |
||
Дата последнего изменения:
Апрель 2021 |
||
Выбор компилятора и целевой платформы |
||
|
||
|
||
Настройка параметров для компилятора |
||
|
||
|
||
|
||
Подготовка исходного кода |
||
Соблюдайте эти правила, и вы получите значительно более понятный, структурированный, и соответственно - читабельный и легко поддерживаемый код. |
||
Запуск компилятора, анализ ошибок |
||
|
||
П.С. В ПРИЛОЖЕНИИ (в конце этого описания) приводится подробный разбор настроек командного и конфигурационного файлов для компиляции конкретного примера.
|
||
Если не хватает библиотечных функций ... |
||
|
||
Отладка кода |
||
|
ЧАСТЬ 2. AL-IV: Создание программ с графическим пользовательским интерфейсом |
Предисловие. Программирование приложений с визуальным интерфейсом в AL-IV построено таким образом, чтобы возможно было написать один рабочий код для всех платформ, и в зависимости от выбранного компилятора и набора библиотек, получить программу для соответствующей платформы. Независимо от платформы, результирующая программа будет состоять из тех же самых, почти равных по возможностям визуальных и не визуальных элементов, которые всюду работают по одному и тому же алгоритму.
Разумеется, небольшие различия возможны. В одних средах для разделения директорий в пути к файлу используются символы прямой дроби, в других - обратной. В одних случаях пользователь будет использовать клик правой клавиши мыши, в других - двойной клик правой клавиши, чтобы вызвать меню. Может отличаться внешний вид формы и даже расположение элементов на форме.
Т.е., мы разрабатываете программу в удобной для разработчика среде, а затем указываем, в какую платформу компилировать, и получаем исходный код для требуемой целевой платформы. А возможно, и сразу исполнимое приложение, если это возможно. И при этом не требуется изменять исходный код для адаптации к другой платформе.
К сожалению, при таком подходе, помимо преимуществ, появляются и недостатки:
|
2.1. Дерево визуальных и невизуальных компонентов для разработки |
Все стандартные визуальные управляющие
элементы являются прямыми наследниками класса |
||||||||||||||||||||||||||||||||||||||||||||
|
Особенности визуальных управляющих
элементов часто следуют из возможности реализации их функциональности
через соответствующие "зеркальные" компоненты целевых платформ.
Ограничения на функциональность элемента зачатую появляются вследствие
того, что зеркальный компонент на одной из платформ содержит такое
ограничение. Проще сразу ограничить функциональность соответствующего
элемента в библиотеке для AL-IV, нежели
пытаться преодолеть такое ограничение на конкретной платформе. И это
всё-таки лучше, чем допустить существенно различное поведение элемента в
зависимости от платформы, на которой исполняется приложение. В правых колонках, соответствующих целевым платформам, при наличии
особенностей реализации, имеются комментарии. Например, для |
Невизуальные управляющие
элементы ( |
2.2. Компоновка формы. Колонки. |
Компоновка формы формально двухуровневая [см. дополнение в следующем пункте]: на плоскости формы размещаются колонки, внутри которых располагаются визуальные элементы (кнопки, метки, поля ввода, выбора и т.д.). Фактически, при реализации, уровней может быть больше, т.к. для обеспечения прокрутки области, в которой размещается слишком много элементов, сама форма содержит в себе скроллируемую (по горизонтали) панель, а уже на ней размещаются колонки. (В случае мобильного приложения сами формы представляются панелями, лежащими на родительской форме). И так же для колонок - для обеспечения их прокрутки при необходимости, они представляются нативными панелями с вертикальной прокруткой, на которых уже размещается панель с вложенными элементами. Но с точки зрения программирования, модель остаётся двухуровневой, т.к. управлению подлежат колонки формы и сама форма как объект, а не зеркальные представления этих сущностей.
|
Более того, сами колонки не имеют соответствующего класса или объекта, доступного для управления, и управление колонками осуществляется через методы формы. Собственно, какое-либо особо сложное управление для колонок и не требуется: выравнивание колонки задаётся только в момент её создания. Важно помнить, что в некоторых
целевых системах фактическое расположение колонок может отличаться от
предполагавшегося при разработке формы. Например, на ограниченном
размерами экране смартфона, одномоментно могут быть не видны сразу все
колонки, а выровненные
|
Если в конструкторе формы
начать создавать визуальные элементы, не создавая колонку, то
автоматически создаётся первая безымянная колонка, с выравниванием
Если создавать несколько колонок с выравниванием 'CLIENT', то отображаться будет единовременно только одна - первая, для которой в событии формы column_hidden было возвращено FALSE. |
Дополнительно, допускается создание "вложенных" перпендикулярных колонок с выравниванием 'LEFT'/'TOP', 'RIGHT'/'BOTTOM'. При создании для таких колонок должна указываться текстовая метка "родительской" колонки, выравнивание которой не должно быть параллельно выравниванию вложенной (т.е. если вложенная колонка имеет выравнивание 'LEFT'/'RIGHT', то "родительская" не может быть выровнена ни 'LEFT', ни 'RIGHT'). Слова "вложенная", "родительская" приведены в кавычках, так как никакого дополнительного уровня вложенности не создается: "родительская" колонка используется только как "якорь", или "базис", от прямоугольника которой в заданном выравниванием направлении откусывается прямоугольник для "вложенной" колонки в процессе ее размещения. Следует учесть, что на некоторых платформах вложенные колонки таковыми не становятся, и отображаются как обычные колонки с соответствующим выравниванием (Android). |
При автоматическом размещении элементов:
Для колонок, выровненных влево, вправо или по клиенту, реализуется автоматическое размещение визуальных элементов сверху вниз по умолчанию (имеется возможность указать явно выстраивание контролов в колонке сверху вниз и для горизонтальных колонок). При этом горизонтальные размеры элементов рассчитываются автоматически, так, чтобы либо элемент целиком занял один ряд, либо он был размещён в ряду вместе с его меткой, если позволяют размеры метки. (А если сразу за элементом создается {Paint_turtle}, то он так же занимает место в том же ряду, справа от предыдущего контрола).
|
Параметром "ширина метки" при создании колонки определяется максимальный размер метки (в "поинтах" - точках), при котором метка размещается рядом с соседним по отношению к ней элементом. Если ширина метки оказывается больше, она занимает отдельный ряд, и следующий элемент размещается ниже, так же занимая целый ряд во всю ширину.
Только одному элементу в колонке разрешается
автоматическое изменение высоты вместе с изменением высоты колонки. И не
все классы визуальных элементов могут автоматически изменять свою
высоту. Это свойство относится только к |
Для колонок, выровненных вверх
( Пример колонки с выравниванием вверх/вниз (схема):
|
Для таких горизонтальных колонок может задаваться так же свойство размещения контролов методом Set_controls_layout({controls_layout}) или в дизайнере формы. Возможные варианты: 'CONTROLS_LEFT' - все визуальные элементы размещаются слева направо. Если последний элемент класса {Edit}, {Combo}, {Paintbox} (и его наследники) имеет флажок "Расширение вправо/вниз", то он занимает остаток ширины колонки; 'CONTROLS_RIGHT' - все элементы прижаты к правому краю; 'CONTROLS_CENTER' - Элементы равномерно распределены, с одинаковыми расстояниями между ними и краями колонки (если есть место, иначе как для 'CONTROLS_LEFT'); 'CONTROLS_JUSTIFY' - аналогично предыдущему, но левый и правый элемент прижаты к краям колонки; 'CONTROLS_LEFT_LAST_RIGHT' - аналогично 'CONTROLS_LEFT', но последний элемент прижимается к правому краю (если есть место); 'CONTROLS_TOP_TO_BOTTOM' - для горизонтальной колонки указывается, что контролы будут размещаться как для вертикальной, сверху вниз. Вероятно, при этом следует задать колонке увеличенную высоту, чтобы элементы в этой колонке были видимы; 'CONTROLS_VERTICAL_2|_COLUMNS' - работает и для вертикальных, и для горизонтальных колонок, элементы размещаются в 2 колонки, занимая сначала левую половину колонки, затем, начиная с контрола с индексом N/2 (где N= число контролов в колонке), правую половину. |
Существует так же возможность
для любых типов колонок отказаться от автоматического размещения элементов в колонках вызовом |
2.3. Обработка событий |
В AL-IV
нет указателей на функции. Делегаты, как в C#,
или "слушатели" (listeners), как в
Java - это слишком громоздкий способ
обрабатывать события. В AL-IV - единственная
возможность обработать события визуальных элементов формы, это
переопределить в своей форме соответствующие методы формы, например,
Для случаев наследования контрольных элементов, некоторые события вызываются в самих контрольных элементах (например, движения мыши). |
Как и все методы, начинающиеся
со строчной буквы, эти методы являются защищёнными. Они так же помечены
маркером |
Если предполагается
обрабатывать похожие события от нескольких элементов на форме, то в
соответствующем обработчике следует анализировать параметр
|
Рекомендуется сколько-нибудь сложную обработку выносить в отдельные методы, оставляя в основном обработчике только действия, не требующие больше пары-другой строк кода. |
В случае, если есть необходимость свести в одно место обработку одного события от нескольких источников (кнопок, меню, клавиатуры), можно использовать для этого обработчик событий меню, вызывая его из всех альтернативных методов. (Чтобы компилятор не возмущался по поводу неправомерного использования CALLBACK-метода menu, следует выделить код в свой метод, например, operation, и вызывать его из обработчиков menu, click и других, передавая необходимый параметр). |
Можно значительно упростить разработку, если
вместо классов |
2.5. Всплывающее меню |
В AL-IV
предлагается использовать только всплывающее меню. Для имитации
главного меню возможно использовать колонку с кнопками, выровненную
по верхнему краю формы ( |
||
Меню
создаётся на основе набора строк, разделённых символами конца строки
|
||
Строки, задающие меню, обычно состоят из имени пункта меню, и собственно текста меню. Имя и текст разделены символом двоеточия. Если такого символа нет, то именем пункта меню считается сам текст меню (рекомендуется так не делать, с учётом возможной языковой адаптации строк, представляющих собой текст пунктов меню). Дополнительные атрибуты пунктов меню, если они есть, записываются через запятую после синонима пункта меню (до двоеточия). На данный момент возможны два дополнительных атрибута - disabled и checked. Например, вызов традиционного файлового меню для кнопки Файл (в
"главном меню" из кнопок): |
||
|
Строка, формирующая меню,
передаётся функции |
|
В обработчике событий меню
следует проанализировать имя сработавшего пункта меню (используя
|
|
Для удобства использования визуального редактора меню (входит в состав визуального Дизайнера формы), для формирования меню предлагается использовать ряд функций класса {Menu|_create}. Приведенный выше код меню с использованием этих функций будет выглядеть, например, так: |
|
|
Дополнительное преимущество использования дизайнера меню: меню, составленные с его использованием, отображаются в схеме формы (в нижней части), позволяя двойным кликом по элементу выполнить переход к обработчику соответствующего пункта меню. |
ЧАСТЬ 3. Среда разработки: редактор IDE AL4 |
ПРИЛОЖЕНИЕ 1. AL-IV: Магия командных файлов для запуска компилятора |
ПРИЛОЖЕНИЕ 2. Постепенный переход на AL-IV в существующем проекте |
(в процессе) |
Постановка задачи по миграции кода в AL-IV |
Предположим, у нас имеется некое приложение, разработанное на Delphi + VCL или Delphi + KOL, с большим количеством форм, и привязанного к ним кода. И по каким-то причинам нам, к примеру, желательно перейти к AL-IV (например, предполагается возможность запуска на платформе Linux, или требуется уйти от неподдерживаемой версии компилятора Delphi, или по другим причинам). Но перевести в AL-IV сразу все 10 или больше форм приложения не представляется возможным. Поступаем следующим образом. |
Решение: изменить синтаксис AL-IV - программ на Pascal-подобный |
Начиная с версии 1.3.0, в AL-IV
имеется поддержка синтаксиса Pascal. А именно,
компилятор воспринимает классы, написанные как бы на языке
Pascal (несколько урезанном). Для этого в
начале класса размещается 5 строк: |
После чего размещается код на языке Pascal, начиная с директивы unit, имени модуля - как обычно в Паскале - и заканчивая директивой end с точкой. Более того, не запрещено просто добавить вышеозначенный комментарий с указанием синтаксиса "PASCAL" в уже существующий модуль и попробовать подать его на вход AL-IV-компилятора. |
Неподдерживаемые конструкции |
В большинстве случаев с первой попытки ничего не выйдет, так как AL-IV воспринимает далеко не все конструкции Delphi/Free Pascal, и даже не все конструкции стандартного языка Pascal. Например, не поддерживаются: |
- оператор do ... while; - оператор with ... do; - массивы массивов; - переопределение типов данных на основе
других типов - глобальные переменные; - параметры конструкторов (игнорируются с выдачей предупреждения); - определение дополнительных классов с методами (или унаследованных от других классов), кроме единственного класса в модуле [т.к. в AL-IV модуль - это и есть класс, и дополнительные структуры не могут быть полноценными классами]; - необязательные параметры и параметры со значениями по умолчанию; - массивы, создаваемые "на лету" путем заключения в квадратные скобки списка произвольных выражений; - индексы в константном массиве должны быть целыми числами начинаться с нуля (в Pascal - с произвольного целого числа, или вообще использоваться другой тип, например, перечисление или Boolean); - нет свойств (property) с несколькими индексами; |
Строгие правила AL-IV в коде Pascal |
Так же, продолжают действовать некоторые строгие правила AL-IV по оформлению кода (хотя большая часть все-таки смягчена). А именно: - длина строки кода, не считая комментариев, не должна превышать 80 символов; - линейный блок кода не может содержать
более 7 простых операторов и более 7 блочных операторов, либо блок
должен быть разделен на части операторным комментарием (в синтаксисе
Pascal он записывается в форме - в AL-IV нет var-параметров, и все прочие параметры должны использоваться как константы (код, который не удовлетворяет этим требованиям, должен быть модифицирован); - имена полей, функций, констант не должны
быть менее 8 символов, или должны быть дополнены в форме: |
Смягченные правила AL-IV в коде Pascal |
Для синтаксиса а-ля-Паскаль в язык введены смягчающие правила, позволяющие использовать особенности языка Pascal с минимальным числом переделок в коде: - регистронезависимость имен функций, переменных, типов и т.д. - снято ограничение на глубину вложенности операторов (if/case, for/while); - разрешено не указывать квадратные скобки при использовании массивов как самостоятельных объектов (например, как параметров функций); - не требуется указывать Clone/Dismiss при копировании структур (всегда используется "клонирование"); - разрешено присваивать значения полям и "методам", для которых определен SETTER (т.е., аналог присваивания значения свойствам); |
Автоматическое и ручное преобразование кода Pascal в AL-IV |
В процессе механистической предварительной конверсии кода Паскаль в AL-IV проводятся некоторые преобразования в коде, позволяющие упростить перевод существующего кода. Например, тип TStringList превращается в массив строк, так же как и array of String; Но для типа TList необходимо указывать, в массив каких элементов он переводится: {@Integer[]} или {@TBitmap[]} - сразу вслед за типом в декларации переменной/параметра/поля. Так же, некоторые операции механически не воспринимаются. Например, после AND и OR следует указывать уточняющие {@&} и {@|}, если речь идет именно о побитовых операциях. То же касается и NOT {@~}. |
Для преобразования кода следует включить в uses модуль Delphi_to_al4, который содержит ряд определений функций, констант, перечислений, позволяющих более плавно перейти к работе с компилятором AL-IV. Часть этих функций - только для AL-IV, чтобы он начал понимать, как следует работать с часто употребляемымb в коде Pascal функциями (например, Rect, Point). А часть - для обеих "сторон", и предполагает небольшой рефакторинг кода с тем, чтобы обратиться в паскаль-коде к этим функциям взамен обычных. Например, NewBitmap, AsInt, SetBrush и т.п. |
Для автоматического преобразования имен модулей из списка директивы uses в классы AL-IV используются файлы с именем Delphi_units_to_al4.convert (причем, используются все такие файлы, найденные по всем указанным в опциях проекта путям для поиска модулей - так что, всегда можно добавить свои такие файлы, специфичные для конкретного трансформируемого Delphi проекта). Аналогично, для автоматического преобразования используемых в коде типов данных служат файлы с именем Delphi_types_to_al4.convert. |
Для перевода форм Delphi в формы AL-IV, используется специально для этих целей унаследованный от {Form} класс {Form_delphi}. Ряд функций, облегчающих миграцию проектов Delphi в AL-IV, размещены в этом модуле (например, SetControlVisible, ShowMessage). |
Примерно так же и класс {Screen_delphi}, унаследованный от {Screen}, упрощает перевод самого проекта в AL-IV. И он содержит функции, эквивалентные глобальным - общим для всех форм. Например, GetRandSeed, SetRandSeed, Random(N), GetTickCount. |
![]() |
Ручное преобразование кода Pascal в AL-IV: условная компиляция |
Иногда возникает необходимость писать два варианта кода - для обычной компиляции с Delphi или Free Pascal, другой - для AL-IV. Причем, в случае AL-IV может понадобится возможность написать код именно на AL-IV, а не в виде Pascal-кода.
Для случая кода AL-IV, используется
конструкция |
Для случая особого варианта Pascal-кода
(или когда код вообще не нужен в случае AL-IV): |
Замечания:
|
Ручное преобразование кода Pascal в AL-IV: трансформация формы |
|
Программирование в Delphi во многом перпендикулярно программированию в AL-IV (и не только в Delphi), и в случае визуального программирования ситуацию, на первый взгляд, еще хуже: нет ничего, кроме минимального набора контролов, нет возможности как попало размещать эти контролы на формы, иначе происходит обработка событий. Но все (или многое) решаемо. |
|
Во-первых, вам не понадобятся панели: колонки AL-IV не являются их прямой заменой. Поэтому все панели в декларации формы лучше всего скрыть от AL-IV компилятора директивами (*$ifdef al4*), поместив в часть (*$else*). Далее, необходимо сформировать конструктор формы, если он еще не создан, и в нем в директиве (*$ifdef al4code*) прописать создание нужных контролов и колонок, используя синтаксис AL-IV. Разумеется, для всех контролов необходимо найти ближайшие замены, а если таких нет, то придется переделать Delphi код так, чтобы использовать контролы, имеющие аналоги. Например, в проекте ниже (Глазомер) использовалось 5 компонентов TShape на панели, чтобы пользователь кликом по ним делал выбор. Эта часть кода была переписана на использование TPaintbox, а список TShape успешно был заменен на массив прямоугольников TRect. |
|
События в форме Delphi обычно пишутся для
каждого контрола и для каждого вида события в отдельных
процедурах-обработчиках, тогда как в AL-IV
имеется один обработчик каждого вида - один на все контролы (после чего,
разумеется, можно в зависимости от отправителя, перенаправить обработку
на свою функцию). Соответственно, имеет смысл выделить блок кода,
защищенный директивой (*$ifdef al4code*), и
разместить в нем обработчики формы AL-IV,
перенаправляющие обработку на соответствующие обработчики,
написанные изначально на Pascal. Например: |
|
|
|
При наличии процедур рисования на канве следует учитывать, что в Delphi единицей измерения является пиксель, тогда как в AL-IV - обычно point, но может выполняться переключение и на другие единицы измерения, в том числе на пиксели. При рисовании на канве TPaintbox-контрола, код AL-IV автоматически переходит в "естественную" дл Delphi единицу измерения, но в случае рисования на других полотнах, отслеживайте эту ситуацию сами. То же самое касается и событий мыши: Delphi-процедуры хотят работать с пикселями, а в AL-IV события мыши хранят координаты в point'ах, причем не относительно контрола, на котором произошло событие, а относительно всей формы. Поскольку работы с координатами мыши не является обычной в каждой форме Delphi (и требуется далеко не в каждом приложении Delphi), конверсию поинтов в пиксели вы тоже сделаете сами, вызвав соответствующие функции из модуля Delphi2AL4.pas. |
Ручное преобразование кода Pascal в AL-IV: глобальные переменные |
В AL-IV нет глобальных переменных, и конструкция var на уровне модуля языка Pascal вызывает ошибку конвертации. Чтобы работать с этими переменными в обоих вариантах - и в прежнем Delphi-проекте, следует переместить все глобальные переменные в главную форму. При этом сама главная форма должна быть доступна как в Delphi-проекте, так и в AL-IV - после трансформации. Предположим, переменная главной формы называется fmMain. В этом случае в проекте Delphi все обращения к глобальным переменным превращаются в fmMain.SomeVar. В частности, если речь идет о глобальной переменной некоторой дочерней формы fmChild1, то обращение к ней должно перейти в fmMain.fmChild1. Чтобы в контексте методов всех форм, кроме главной, идентификатор fmMain распознавался как ссылка на объект главной формы, и при этом не пришлось идти по длинному пути (* - см. ниже), лучше всего выполнить следующее: В модуле главной формы прописать функцию, имя которой совпадает с именем главной формы (в нашем конкретном примере это fmMain). Это должна быть именно функция, а не метод (догадайтесь, почему). Чтобы не создавать для каждого возможного целевого фреймворка/языка программирования собственный вариант нативного модуля, который "добывает" ссылку на главную форму, прописываем в теле этой функции обращение к уже готовой функции Get_main_form, и приводим полученный результат к типу главной формы. В случае AL-IV кода: В случае Pascal-кода: |
(*) Длинный путь заключался бы в том, чтобы в каждой дочерней формы создать переменную fmMain_ типа TfmMain, и функцию fmMain, которая возвращает эту переменную. И прописать в точках создания всех дочерних форм присваивания значения (объекта главной формы) этим внутренним переменным fmMain_ всех этих дочерних форм. Причем, путь этот не только длинный, но и может вызывать потенциальные ошибки (если не были найдены и откорректированы все точки создания дочерних форм). |
Пример конверсии: Glazomer |
|
В прилагаемом архиве приведен пример конверсии несложного Delphi-приложения, выполненного студентом на Delphi/VCL. В конверсии мультимедийные функции заменены заглушками (в файле Mediaplayer.al4), если их реализовать, то звук тоже должен работать. Но для демонстрации возможностей это не принципиально. Архив для загрузки: Glazomer_to_al4.zip (470 Кб)
|
|
![]() |
Содержание |
ЧАСТЬ 1. AL-IV: Как начать программировать
ЧАСТЬ 2. AL-IV: Создание программ с графическим пользовательским интерфейсом
ЧАСТЬ 3. Среда разработки: редактор IDE AL4
ПРИЛОЖЕНИЕ 1. AL-IV: Магия командных файлов для запуска компилятора
ПРИЛОЖЕНИЕ 2. Постепенный переход на AL-IV в существующем проекте
В
начало
|