Продолжаем работу над пилотным проектом Data Keeper, который в дальнейшем должен заменить My Visual Database (MVDB). Добавляем новый тип хранимых данных – логический. А для визуализации – новый тип компонента пользовательского интерфейса, так как имеющийся в MVDB TdbCheckBox в Windows 10 выглядит не очень презентабельно.

Переключатель состоит из панели TdbPanel (1), на которой находятся три изображения TdbImage (2), каждое из которых отвечает за одно из трёх состояний переключателя:
- On – включен; отображается, если значение свойства = ‘Да’
- Off – выключен; отображается, если значение свойства = ‘Нет’
- Null – не определен; отображается, если значение свойства = NULL
При использовании переключателя размеры текстового поля уменьшаются и поверх него отображается панель переключателя. Ниже приводится фрагмент процедуры efmObject_OnShow(), в котором создаётся/активируется переключатель:
// переключатель
if tmpControlID = 7 then
begin
tmpEdit.Width := 32;
FindC(tmpForm,'panData_'+intToStr(tmpCount),tmpPanel,False);
if tmpPanel = nil then
tmpPanel := TdbPanel.Create(tmpForm);
with tmpPanel do
begin
parent := tmpParent;
name := 'panData_'+intToStr(tmpCount);
caption := '';
top := tmpEdit.Top;
left := tmpEdit.Left;
width := tmpEdit.width;
height := tmpEdit.height;
bevelWidth := 0;
color := tmpParent.color;
visible := True;
end;
//
FindC(tmpForm,'imgDataOn_'+intToStr(tmpCount),tmpImageOn,False);
if tmpImageOn = nil then
tmpImageOn := TdbImage.Create(tmpForm);
with tmpImageOn do
begin
parent := tmpPanel;
name := 'imgDataOn_'+intToStr(tmpCount);
align := alClient;
center := True;
picture.LoadFromFile( ExtractFilePath(Application.ExeName) + 'images\toggle\toggle_on.png' );
onClick := 'Toggle_Off';
end;
//
FindC(tmpForm,'imgDataOff_'+intToStr(tmpCount),tmpImageOff,False);
if tmpImageOff = nil then
tmpImageOff := TdbImage.Create(tmpForm);
with tmpImageOff do
begin
parent := tmpPanel;
name := 'imgDataOff_'+intToStr(tmpCount);
align := alClient;
center := True;
picture.LoadFromFile( ExtractFilePath(Application.ExeName) + 'images\toggle\toggle_off.png' );
onClick := 'Toggle_On';
end;
//
FindC(tmpForm,'imgDataNull_'+intToStr(tmpCount),tmpImageNull,False);
if tmpImageNull = nil then
tmpImageNull := TdbImage.Create(tmpForm);
with tmpImageNull do
begin
parent := tmpPanel;
name := 'imgDataNull_'+intToStr(tmpCount);
align := alClient;
center := True;
picture.LoadFromFile( ExtractFilePath(Application.ExeName) + 'images\toggle\toggle_indeterminate.png' );
onClick := 'Toggle_On';
end;
case VarToStr( SQLExecute('SELECT value_s FROM oproperty WHERE id_object = '+IntToStr( efmObject.btnSave.dbGeneralTableId )+' AND id_cproperty = '+tmpDataSet.FieldByName('id').asString +' AND orderNum is NULL' ) ) of
'Да':
begin
tmpImageNull.Visible := False;
tmpImageOff.Visible := False;
tmpImageOn.Visible := True;
end;
'Нет':
begin
tmpImageNull.Visible := False;
tmpImageOff.Visible := True;
tmpImageOn.Visible := False;
end;
else
begin
tmpImageNull.Visible := True;
tmpImageOff.Visible := False;
tmpImageOn.Visible := False;
end;
end;
end;
Code language: PHP (php)
Обработчики кликов по изображениям не только меняют видимость картинок, но и записывают необходимые данные в поле редактирования:
procedure Toggle_On(Sender: TObject);
var
tmpForm: TForm;
tmpImageOn: TdbImage;
tmpImageOff: TdbImage;
tmpImageNull: TdbImage;
tmpEdit: TdbEdit;
begin
CForm(Sender,tmpForm);
FindC(tmpForm,'imgDataOn_'+GetSuffix(TdbImage(Sender).Name),tmpImageOn);
FindC(tmpForm,'imgDataOff_'+GetSuffix(TdbImage(Sender).Name),tmpImageOff);
FindC(tmpForm,'imgDataNull_'+GetSuffix(TdbImage(Sender).Name),tmpImageNull);
FindC(tmpForm,'edtData_'+GetSuffix(TdbImage(Sender).Name),tmpEdit);
tmpImageOff.Visible := False;
tmpImageNull.Visible := False;
tmpImageOn.Visible := True;
tmpEdit.Text := 'Да';
end;
procedure Toggle_Off(Sender: TObject);
var
tmpForm: TForm;
tmpImageOn: TdbImage;
tmpImageOff: TdbImage;
tmpEdit: TdbEdit;
tmpImageNull: TdbImage;
begin
CForm(Sender,tmpForm);
FindC(tmpForm,'imgDataOff_'+GetSuffix(TdbImage(Sender).Name),tmpImageOff);
FindC(tmpForm,'imgDataOn_'+GetSuffix(TdbImage(Sender).Name),tmpImageOn);
FindC(tmpForm,'imgDataNull_'+GetSuffix(TdbImage(Sender).Name),tmpImageNull);
FindC(tmpForm,'edtData_'+GetSuffix(TdbImage(Sender).Name),tmpEdit);
tmpImageOff.Visible := True;
tmpImageOn.Visible := False;
tmpImageNull.Visible := False;
tmpEdit.Text := 'Нет';
end;
Code language: PHP (php)
Обработчиков все два, так как диаграмма состояний переключателя не является круговой:

Настройка
Регистрируем новый элемент в справочнике компонентов UI

Добавляем новый класс хранимых значений

Теперь его можно использовать при описании свойств объектов

Результат

В табличном представлении отображаются привычные значения “Да” или “Нет” (2), а на форме редактирования красуется современный переключатель (1) в стиле Windows 10.
К сожалению, MVDB не имеет возможности с помощью кода менять цвет изображений в формате PNG, поэтому такой переключатель будет хорошо смотреться не со всеми стилями. Это можно решить несколькими способами:
- для каждого стиля хранить свои изображения переключателей
- использовать формат изображений BMP и менять его с помощью скрипта
- рисовать переключатель на канве панели
- использовать для отображения переключателя компоненты TShape
Последний вариант мне кажется самым перспективным, но в рамках проекта Data Keeper нет надобности улучшать внешний вид программы, так как основная цель – отработка принципа работы и основных алгоритмов генерации форм на основании структуры данных.
А в этом деле прогресс налицо: вместо проектирования таблиц для реляционных БД Data Keeper предлагает, как мне кажется, более понятную систему описания классов объектов. Впрочем, пока я не получил ни одного комментария и, возможно, пользователи ожидают ещё более простые варианты конструкторов. Например, интеграцию с голосовыми помощниками или модными интеллектуальными системами вроде ChatGPT, которые зачем-то называют Искусственным Интеллектом.

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

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