Продолжаем работу над пилотным проектом 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, которые зачем-то называют Искусственным Интеллектом.

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

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *