Creating applications is like cooking: it requires fresh ingredients (customer requirements), quality equipment (development environment) and dexterity. Some projects can be done in two hours, but there are others that take weeks, months, or even years to prepare.

One of the difficulties that arises is the loss of relevant information about the code or visual forms. And this becomes a problem if the number of forms exceeds a hundred. Of course, with good design documentation this is easy to handle, but in practice I would like to have a tool that would help determine the name of the application form right during its execution. To implement this functionality, a hotkey system is useful.

But first, a little modification will be required: the ability to perform an arbitrary procedure. Let me remind you that in the current version of this system there are two options available: pressing a button and selecting a menu item.

The required functionality must be added to the Hotkey_OnKeyDownST() procedure. To make this possible, when analyzing the name we will use the object naming convention. The first three characters will tell us which action category to select.

const
  T_BUTTON = 'btn'; 
  T_MENU_ITEM = 'mni'; 

procedure Hotkey_OnKeyDownST(Sender: TObject; var Key: Word; ShiftState: TShiftState);
// processing hotkeys - according to the Delphi standard
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
    // match found
    if (Key = HotKey_Code[i]) and (ShiftState = HotKey_ShiftState[i]) then
    begin
      tmpName := HotKey_Command[i];
      case GetClassName(tmpName) of // in the prefix indicates what needs to be clicked/executed
      T_BUTTON: begin // look for a button
        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 // look for a menu item
        FindC(tmpForm, tmpName, tmpComponent, False);
        if tmpComponent <> nil then
        begin
          if tmpComponent is TMenuItem then
            TMenuItem(tmpComponent).Click
        end;
      end;
      else begin // execute the procedure by name
        ExecProc(tmpName,tmpForm.Name);
      end;
      end; // case
      break;
    end;
  end;
end;Code language: Delphi (delphi)

In My Visual Datavase, you cannot convert a string into a procedure call, but you can assign an OnClick event handler and click the button by calling the Click method. The main condition is that the input parameters of the procedure must match the input parameters of the button click handler. And in case we need to pass something as a parameter, we use the TagString property of the button as a storage chamber.

procedure ExecProc( AProcName:string; AParamStr:string='' );
// execution of the procedure
// AProcName - name of the procedure being executed
// AParamStr - a string parameter that can be passed to the button (procedure)
var
  tmpButton :TdbButton;
begin
  try
    FindC(MainForm,'btnExecProc',tmpButton, False);
    if tmpButton = nil then
      tmpButton := TdbButton.Create(MainForm);
    tmpButton.Name := 'btnExecProc';
    tmpButton.OnClick := AProcName; // name of the procedure being executed
    tmpButton.TagString := AParamStr; // pass the parameter
    tmpButton.Click; // BClick;
  except
    RaiseException('ExecProc('''+AProcName+''') - '+ExceptionMessage);
  end;
end;Code language: Delphi (delphi)

Technical information about the form will for now include the name of the form. But in the future, knowing the name, you can get more information about the form itself and the components that are on it:

procedure FormSysInfo( sender:TObject; ACancel:boolean );
// system information about the active form
var
  tmpFormName: string;
  tmpForm:TForm;
begin
  tmpFormName := TdbButton(Sender).TagString;
  ShowMessage( tmpFormName );
end;Code language: JavaScript (javascript)

A little modification was also required for the Hotkey_Init() procedure. Instead of a fixed size of arrays, their size is now dynamically increased when adding each new combination.

var
  HotKey_Code: array of byte; // virtual code
  HotKey_ShiftState: array of TShiftState; // click flags
  HotKey_Command: array of string; // command to be executed: name of a button, menu item or procedure

procedure Hotkey_Init(Sender: TObject);
// connection to the form
// Sender - the form for which the hotkey system is connected
var
  i:integer;
  //
  procedure AddHotKey(ACode: byte; AShiftState: TShiftState; ACommend: string);
  var
    tmpLength:integer;
  begin
    inc(i);
    // increase the size of the arrays
    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() - parameter is not a form');
      exit;
    end;
    //
    TForm(Sender).KeyPreview := True;
    TForm(Sender).OnKeyDown := 'Hotkey_OnKeyDownSt';
    //
    // setting up hot keys
    AddHotKey(VK_F1, 0, 'btnHelp'); // show help
    AddHotKey(VK_F2, 0, 'btnNew'); // Add a note
    AddHotKey(VK_F4, 0, 'btnEdit'); // edit entry
    AddHotKey(VK_F8, 0, 'btnDelete'); // delete entry
    AddHotKey(VK_F11, 0, 'mniAboutEx'); // show the "About" window
    AddHotKey(VK_F12, 0, 'FormSysInfo'); // system information about the form
  except
    RaiseException(ExceptionMessage);
  end;
  //
end;Code language: Delphi (delphi)

Indirect initialization of hotkeys through help initialization – Help_Init()

procedure MainForm_OnShow(Sender: TObject; Action: string);
// display the main form
var
  tmpForm: TForm;
  tmpStartTime: TTime;
  tmpSleepTime: integer;
begin
  //
  tmpForm := Splash_Create;
  tmpForm.Show;
  Application.ProcessMessages;
  tmpStartTime := Time();
  //
  // there must be all sorts of initialization, which can take a long time
  App_InitSystemVar; // initialization of system variables
  DTF_Init(frmMain.tgrStyle);
  // after initializing system variables; you need to specify any real table in order to pull colors for the style from it
  Resource_Init();
  Resource_CreateMenu(frmMain);
  Images_Init; // initializing the image loading subsystem
  // unicode_Init;
  Style_Init; // style activation
  // Style_CreateMenu(frmMain); // add styles to the menu
  StyleView_AddToMenu(frmMain); // add a call to the style manager to the menu
  UserApp_InitForm; // create forms
  UserApp_InitVar; // set up variables
  // initialization that comes after setting variables
  // CE_Init(MainForm); // the main menu is on the main form, but is displayed where needed
  Hotkey_Init(MainForm); // enable hotkeys
  Help_Init( APP_FORM_ALL, SPLASH_FORM_NAME ); // connect hotkeys to all forms - enable the help system
  UserApp_InitBase; // initialize the database
  //
  // guaranteed delay, but not more than specified in APP_SPLASH_DELAY
  tmpSleepTime := SPLASH_DELAY_MIN - Trunc((Time() - tmpStartTime) * 24 * 60 * 60 * 1000);
  if tmpSleepTime > 0 then
    Sleep(tmpSleepTime);
  tmpForm.Close;
  tmpForm.Free;
  //
  // display the name and version of the program in the header of the main form
  frmMain.Caption := R('APP_NAME', APP_NAME) + ' ' + License_GetVersion;
  Form_RestorePosSize(frmMain);
  Form_AddColWidthMenuAll();
end;Code language: JavaScript (javascript)

Result

Press F12 and receive a message with the name of the form – a lightweight version of Component Explorer.

There are limitations to using ExecProc(). A feature of script processing does not allow recursive calling of handlers in combination with modal windows. In our case, this means that if a hotkey was used to call a form in modal mode, then until this form is closed, it will not be possible to use this subsystem again.

Leave a Reply

Your email address will not be published. Required fields are marked *