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.
![](https://k245.ru/wp-content/uploads/2024/05/informatsiya-o-forme.jpg)
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.