What is the component a popup menu click originated from - delphi

Having a popup menu attached to several components on a form (buttons, but also things like TCharts), I would like to know which component was right clicked to start the popup menu in the first place.
The Sender parameter of the click method just points to the TMenuItem, its parent to the popup menu (or the parenting menu item).
How do I get the originating component?

Did you mean PopupMenu1.PopupComponent ?

You can get the caller component within the click event of the TMenuItem of a PopupMenu by
Caller := ((Sender as TMenuItem).GetParentMenu as TPopupMenu).PopupComponent;
An Example of a PopupMenu which is assigned to several list boxes and solves the export to file functionality:
procedure TForm1.mniExportFileClick(Sender: TObject);
var Caller: TObject;
begin
if SaveTextFileDialog1.Execute then
begin
Caller := ((Sender as TMenuItem).GetParentMenu as TPopupMenu).PopupComponent;
(Caller as TListBox).Items.
SaveToFile(SaveTextFileDialog1.FileName,
StandardEncodingFromName(
SaveTextFileDialog1.Encodings[SaveTextFileDialog1.EncodingIndex]));
end;
end;

As a last resort you can use Mouse.CursorPos in TPopupMenu.OnPopup to find this component on a form. But there is probably a better/easier way.

PopUpMenu.PopupComponent indicates the component that last displayed the popup menu in response to the right mouse click

I have a bunch of panels and I want to let the user right click any of those panels and perform a "delete file" action.
So, I have a single pop-up menu associated with all those panels.
This is how I find out which panel was right clicked:
(Note: I put lots of comments to clearly explain how it works. But if you don't like it, you can compactify the code to 2 lines (see the second procedure)).
So, if you have actions assigned to that pop-up menu:
procedure Tfrm.actDelExecute(Sender: TObject);
VAR
PopMenu: TPopupMenu;
MenuItem: TMenuItem;
PopupComponent: TComponent;
begin
{ Find the menuitem associated to this action }
MenuItem:= TAction(Sender).ActionComponent as TMenuItem; { This will crash and burn if we call this from a pop-up menu, not from an action! But we always use actions, so.... }
{ Was this action called by keyboard shortcut? Note: in theory there should be no keyboard shortcuts for this action if the action can be applyed to multiple panels. We can call this action ONLY by selecting (right click) a panel! }
if MenuItem = NIL then
begin
MsgError('This action should not be called by keyboard shortcuts!');
EXIT;
end;
{ Find to which pop-up menu this menuitem belongs to }
PopMenu:= (MenuItem.GetParentMenu as TPopupMenu);
{ Find on which component the user right clicks }
PopupComponent := PopMenu.PopupComponent;
{ Finally, access that component }
(PopupComponent as TMonFrame).Delete(FALSE);
end;
If you only have a simple pop-up menu (no actions assigned):
procedure Tfrm.actDelHddExecute(Sender: TObject);
VAR PopupComponent: TComponent;
begin
PopupComponent := ((Sender as TMenuItem).GetParentMenu as TPopupMenu).PopupComponent;
(PopupComponent as TMonFrame).Delete(TRUE);
end;
You can put all that code in a single function that returns a TPanel and call it like this:
procedure Tfrm.actDelWallExecute(Sender: TObject);
begin
if GetPanelFromPopUp(Sender) <> NIL
then GetPanelFromPopUp(Sender).Delete(FALSE);
end;

Related

TEdit with clear button [duplicate]

When use TEdit control on the right side stay small icon 'x'. How after click on icon clear TEdit box.
Tnx all!
Delphi provide TClearEditButton to clear the TEdit content. It can be added by right clicking and selecting AddItem - TClearEditButton from the popup menu. It also has a Click procedure overriden in FMX.Edit unit like:
procedure TClearEditButton.Click;
var
EditTmp: TCustomEdit;
begin
inherited Click;
EditTmp := GetEdit;
if EditTmp <> nil then
begin
if EditTmp.Observers.IsObserving(TObserverMapping.EditLinkID) then
if not TLinkObservers.EditLinkEdit(EditTmp.Observers) then
Exit; // Can't change
EditTmp.Text := string.Empty;
if EditTmp.Observers.IsObserving(TObserverMapping.EditLinkID) then
TLinkObservers.EditLinkModified(EditTmp.Observers);
if EditTmp.Observers.IsObserving(TObserverMapping.ControlValueID) then
TLinkObservers.ControlValueModified(EditTmp.Observers);
end;
end;
Which make you don't need to write OnClick event handler for the TClearEditButton unless you want to do some other job along side with clearing the edit.
If you are using a TEditButton then you should write the OnClick event handler like:
procedure TForm1.EditButton1Click(Sender: TObject);
begin
Edit1.Text:= EmptyStr;
end;

get categorybuttons items caption under mouse in delphi

how can I get caption of an item or a category when mouse is entering on them?
how can I get the current caption of an item or a category when right clicking on them?
I assigned a popup menu to categorybuttons. Now I need to obtain the current item or category captions and save them in variable. Because my popup menu has an item that by clicking on it it opens a new form so I want to use this variables values here.
Something like this works at click event :
Current_Items, Current_Category: String
procedure TForm1.CategoryButtons1Click(Sender: TObject);
begin
Current_Items := CategoryButtons1.CurrentCategory.Items
[CategoryButtons1.SelectedItem.Index].Caption;
Current_Category := CategoryButtons1.CurrentCategory.Caption;
end;
But I need to obtain them when right click.
Can someone helps me to do this?
Thank you...
Edit:
Use the OnHotButton event to prepare the Current_Item variable. That gives you the Item on which the mouse right button is clicked, but not the category.
Just note however that this does not select (activate) that particular button.
var
Current_Items, Current_Category: String;
procedure TForm17.CategoryButtons1HotButton(Sender: TObject;
const Button: TButtonItem);
begin
if Button <> nil then
Current_Items := Button.Caption;
end;
Then use Current_Items to identify which button is hot when you popup the menu.

Main Menu in toolbar not working as expected

I create a VCL forms application, add a main menu and insert the "MDI Frame Menu" from the menu templates. I run the programme and use the acceleration keys. Everything works as expected.
I now add a toolbar, disconnect the main menu from the form and link it to the toolbar. I run the programme . Now the menu items activate by just pressing the appropriate key without pressing Alt (e.g. pressing "W" opens the Windows menu item.
How can I get the menu on the toolbar to behave like the main menu without it?
I created one answer to my question (there might be simpler and more elegant ones). Steps to make a TMainMenu in a toolbar behave the same as a TMainMenu on a form are:
Put a TMainMenu on MainForm
Populate the MainMenu as needed
Put an ActionList on the form
Make sure all the menu items act via the ActionList
Clear the menu property of the MainForm
Put a TToolbar on the form
Assign the MainMenu to the Toolbar
Write the procedure DeleteHotKeysOfToolbarMenu(Sender: TObject); (see code snippet below)
Write code for the ActionList.OnExecute event as shown below
Set the KeyPreview property of the MainForm to true
Write the MainForm.OnKeyPress event as shown below
In the Create procedure of the MainForm call DeleteHotKeysOfToolbarMenu to start the programme without any visible hot keys
That is it
Below are the code snippets:
procedure TMainForm.DeleteHotKeysOfToolbarMenu(Sender: TObject);
var
m: integer;
begin
for m := 0 to Toolbar.ButtonCount-1 do
Toolbar.Buttons[m].Caption := StripHotKey(Toolbar.Buttons[m].Caption);
end;
procedure TMainForm.ActionListExecute(Action: TBasicAction; var Handled: Boolean);
begin
if Action.ActionComponent.ClassType = TMenuItem then
DeleteHotKeysOfToolbarMenu(Self);
end;
TMainForm.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if (ssAlt in Shift) or (Key = VK_F10) then
begin
Toolbar.Menu := nil;
Toolbar.Menu := MainMenu;
end;
if Key = VK_Escape then DeleteHotKeysOfToolbarMenu(Self);
end;

Calling a Form2 button Click event from Form1 Button Click event

I use D7 how can I call button click event of Form2 from Form1 Button click event ..
procedure TForm1.Button1Click(Sender: TObject);
begin
//-- here should go calling button click event of Form2
Form2.show;
end;
Like this:
Form2.Button1.Click;
Note however, that it is often indicative of poor design for code in one form to poke at the GUI objects of another form. It might be better for the other form to offer a public method that can be called to perform whatever action is required.
If procedure is declared as public at Form2 you can call it.

How to detect popup of a sub-menu of a popup menu (and how to populate it dynamically)?

I have a popup menu which contains several menu items and one of them can have child items. This entry has a little arrow on the right and when you hover your mouse over it, a sub-menu will open (without clicking). Now I want to populate this sub-menu at runtime, but only if the user actually opens it. If the user never opens the sub-menu, it will be empty (maybe contain a placeholder). How could I accomplish this? Is it even possible to modify a popup-menu when it is already visible?
Thanks for your help!
There is no difference between submenus in standard menus or context (popup) menus: If a menu item has a submenu attached, then its OnClick event will fire just before the submenu is shown (note that you don't need to click for it to show up), and in that event handler you can modify the submenu (either set properties of existing items, or add new items / delete existing items).
Some demo code about dynamically adding and removing items:
procedure TForm1.FormCreate(Sender: TObject);
var
Popup: TPopupMenu;
Item, SubItem: TMenuItem;
begin
Popup := TPopupMenu.Create(Self);
PopupMenu := Popup;
Item := TMenuItem.Create(Popup);
Item.Caption := 'Test submenu';
Item.OnClick := PopupClick;
Popup.Items.Add(Item);
SubItem := TMenuItem.Create(Item);
SubItem.Caption := 'dummy';
Item.Add(SubItem);
end;
procedure TForm1.PopupClick(Sender: TObject);
var
SubmenuItem, Item: TMenuItem;
begin
SubmenuItem := Sender as TMenuItem;
// delete old items (leave at least one to keep the submenu)
while SubmenuItem.Count > 1 do
SubmenuItem.Items[SubmenuItem.Count - 1].Free;
// create new items
while SubmenuItem.Count < 3 do begin
Item := TMenuItem.Create(SubmenuItem);
Item.Caption := Format('new item created %d', [GetTickCount]);
SubmenuItem.Add(Item);
end;
end;

Resources