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

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

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

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

const
  T_BUTTON = 'btn'; // кнопка
  T_MENU_ITEM = 'mni'; // элемент меню

procedure Hotkey_OnKeyDownST(Sender: TObject; var Key: Word; ShiftState: TShiftState);
// обработка горячих клавиш - по стандарту Delphi
var
  tmpForm: TForm;
  tmpButton: TdbButton;
  tmpName: string;
  tmpComponent: TComponent;
  i: integer;
  tmpLength:integer;

begin
  tmpForm := TForm(Sender);
  tmpName := '';
  tmpLength :=  Length(HotKey_Code) - 1;
  for i := 0 to tmpLength do
  begin
    // найдено совпадение
    if (Key = HotKey_Code[i]) and (ShiftState = HotKey_ShiftState[i]) then
    begin
      tmpName := HotKey_Command[i];
      case GetClassName(tmpName) of // в префиксе указания, что нужно нажать/выполнить
      T_BUTTON: begin // ищем кнопку
        FindC(tmpForm, tmpName, tmpComponent, False);
        if tmpComponent <> nil then
        begin
          if tmpComponent is TdbButton then
          begin
            TdbButton(tmpComponent).Click;
            Key := 0;
          end
          else if tmpComponent is TMenuItem then
          begin
            TMenuItem(tmpComponent).Click;
            Key := 0;
          end
        end;
      end;
      T_MENU_ITEM: begin // ищем пункт меню
        FindC(tmpForm, tmpName, tmpComponent, False);
        if tmpComponent <> nil then
        begin
          if tmpComponent is TMenuItem then
            TMenuItem(tmpComponent).Click
        end;
      end;
      else begin // выполняем процедуру по имени
        ExecProc(tmpName,tmpForm.Name);
      end;
      end; // case
      break;
    end;
  end;
end;Code language: Delphi (delphi)

В My Visual Datavase нельзя преобразовать строку в вызов процедуры, но можно присвоить обработчик события OnClick и нажать кнопку, вызвав метод Click. Главное условие – входные параметры процедуры должны соответствовать входным параметрам обработчика нажатия кнопки. А на случай, если понадобиться что-то передать в качестве параметра, используем свойство кнопки TagString в качестве камеры хранения.

procedure ExecProc( AProcName:string; AParamStr:string='' );
// выполнение процедуры
// AProcName - имя выполняемой процедуры
// AParamStr - строковый параметр, который можно передать в кнопку (процедуру)
var
  tmpButton :TdbButton;
begin
  try
    FindC(MainForm,'btnExecProc',tmpButton, False);
    if tmpButton = nil then
      tmpButton := TdbButton.Create(MainForm);
    tmpButton.Name := 'btnExecProc';
    tmpButton.OnClick := AProcName; // имя выполняемой процедуры
    tmpButton.TagString := AParamStr; // передаём параметр
    tmpButton.Click; // BClick;
  except
    RaiseException('ExecProc('''+AProcName+''') - '+ExceptionMessage);
  end;
end;Code language: Delphi (delphi)

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

procedure FormSysInfo( sender:TObject; ACancel:boolean );
// системная информация об активной форме
var
  tmpFormName: string;
  tmpForm:TForm;
begin
  tmpFormName := TdbButton(Sender).TagString;
  ShowMessage( tmpFormName );
end;Code language: JavaScript (javascript)

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

var
  HotKey_Code: array of byte; // виртуальный код
  HotKey_ShiftState: array of TShiftState; // флаги нажатия
  HotKey_Command: array of string; // выполняемая команда: название кнопки, пункта меню или процедуры

procedure Hotkey_Init(Sender: TObject);
// подключение к форме
// Sender - форма, для которой подключается система горячих клавиш
var
  i: integer;
  //
  procedure AddHotKey(ACode: byte; AShiftState: TShiftState; ACommend: string);
  var
    tmpLength:integer;
  begin
    inc(i);
    // увеличить размер массивов
    tmpLength :=  Length(HotKey_Code)+1;
    SetLength(HotKey_Code, tmpLength);
    SetLength(HotKey_ShiftState, tmpLength);
    SetLength(HotKey_Command, tmpLength);
    HotKey_Code[i] := ACode;
    HotKey_ShiftState[i] := AShiftState;
    HotKey_Command[i] := ACommend;
  end;

begin
  try
    if not(Sender is TForm) then
    begin
      RaiseException('Hotkey_Init() - параметр не является формой');
      exit;
    end;
    //
    TForm(Sender).KeyPreview := True;
    TForm(Sender).OnKeyDown := 'Hotkey_OnKeyDownSt';
    //
    // настройка горячих клавиш
    AddHotKey(VK_F1, 0, 'btnHelp'); // показать помощь
    AddHotKey(VK_F2, 0, 'btnNew'); // добавить запись
    AddHotKey(VK_F4, 0, 'btnEdit'); // редактировать запись
    AddHotKey(VK_F8, 0, 'btnDelete'); // удалить запись
    AddHotKey(VK_F11, 0, 'mniAboutEx'); // показать окно "О программе"
    AddHotKey(VK_F12, 0, 'FormSysInfo'); // системная информация о форме
  except
    RaiseException(ExceptionMessage);
  end;
  //
end;Code language: Delphi (delphi)

Опосредованная инициализация горячих клавиш через инициализацию помощи – Help_Init()

procedure MainForm_OnShow(Sender: TObject; Action: string);
// отображение главной формы
var
  tmpForm: TForm;
  tmpStartTime: TTime;
  tmpSleepTime: integer;
begin
  //
  tmpForm := Splash_Create;
  tmpForm.Show;
  Application.ProcessMessages;
  tmpStartTime := Time();
  //
  // тут должна быть всяческая инициализация, которая может занять продолжительное время
  App_InitSystemVar; // инициализация системных переменных
  DTF_Init(frmMain.tgrStyle);
  // после инициации системных переменных; нужно указать любую реальную таблицу, чтобы с неё тянуть цвета для стиля
  Resource_Init();
  Resource_CreateMenu(frmMain);
  Images_Init; // инициализация подcистемы загрузки картинок
  // unicode_Init;
  Style_Init; // активация стиля
  // Style_CreateMenu(frmMain); // добавить стили в меню
  StyleView_AddToMenu(frmMain); // добавить в меню вызов менеджера стилей
  UserApp_InitForm; // создать формы
  UserApp_InitVar; // настроить переменные
  // инициализация, которая идет после настройки переменных
  // CE_Init(MainForm); // главное меню находится на главной форме, но отображается там, где нужно
  Hotkey_Init(MainForm); // подключить горячие клавиши
  Help_Init( APP_FORM_ALL, SPLASH_FORM_NAME ); // подключить горячие клавиши на все формы - включить систему помощи
  UserApp_InitBase; // инициализация базы данных
  //
  // гарантированная задержка, но не более указанной в APP_SPLASH_DELAY
  tmpSleepTime := SPLASH_DELAY_MIN - Trunc((Time() - tmpStartTime) * 24 * 60 * 60 * 1000);
  if tmpSleepTime > 0 then
    Sleep(tmpSleepTime);
  tmpForm.Close;
  tmpForm.Free;
  //
  // отобразить в заголовке главной формы название и версию программы
  frmMain.Caption := R('APP_NAME', APP_NAME) + ' ' + License_GetVersion;
  Form_RestorePosSize(frmMain);
  Form_AddColWidthMenuAll();
end;Code language: JavaScript (javascript)

Результат

Нажимаем F12 и получаем сообщение с название формы – облегченная версия Component Explorer.

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

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

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