We know that if we set a shortcut (for example, Ctrl + F2) to a TMenuItem, the menu item will be executed automatically once the shortcut specified is pressed, and the shortcut description will be also shown when the menu is displayed.
But is there a way to have the shortcut descriptions visible on the menu items but make the menu don't respond to the shortcuts automatically?
You might ask me why I want this, here is the situation:
In a multiple document (like firefox's multiple tabs) program, there are multiple instances of TPopupMenu thus multiple TMenuItem objects have the same shortcuts, but I only want the menuitems in the active document window respond to the shortcuts.
Edit 1: Sorry, I wanted to simplify my question and I described it wrongly - actually, I use TActionList and link the actions to menu items.
Edit 2: Just found: I think I can use TApplicationEvents.OnShortCut Event to intercept the shortcuts before they are being dispatched to the menus/actions... I'll try and will update my questions when I get a result.
Use the tab (#9) character to indicate the shorcut part of the text in standard menus. You can set the Caption property of the menu item or the action component that the menu item is bound to by either editing the 'dfm' or at run-time to include the tab character:
procedure TForm1.FormCreate(Sender: TObject);
begin
Action1.Caption :=
Action1.Caption + #9 + ShortCutToText(ShortCut(VK_F2, [ssCtrl]));
Unless you also assign to the ShortCut property itself of the menu item or the action, the click/execute event will not be fired.
Related
In an MDI VCL application, when I have a non-modal Form showing, keyboard shortcuts for the MainForm's menu will switch focus to the MainForm and perform menu item actions - which is never what I want.
In earlier versions of Delphi, one could override the MainForm's IsShortCut() method (as answered here), but this no longer works in Delphi 10.4.2.
I have tried various permutations of using OnShortCut and IsShortCut() from TApplication and TForm without success.
Overriding IsShortCut() of a non-MainForm to return true for Alt+ keyboard combinations does work to block the MainForm menus, but it also blocks local hotkeys in the action form, so is not very helpful.
Is there now a better (or any!) way to do this?
I found that when the shortcut is invoked, the main form (or active MDI form) calls the container menu item's OnClick before testing for assignments of the shortcuts. So what works for me is enabling the menu item in the menu item's container menu's OnClick handler (e.g. for an item on the File menu, set the OnClick event for the File menu item itself). E.g. like this
procedure TMyForm.FileMenuClick(Sender: TObject);
begin
MyMenu.Enabled := Screen.ActiveForm = self;
end;
The corresponding shortcut for MyMenu is then not processed by the form, and can be correctly used by the active window.
I have Two listboxes and both with Multiselect:=True. I have a popup menu that Copy/Paste to/from the Clipboard for the selected items. All works as intended.
I wanted to add keyboard CtrlC (Copy) and Ctrl+V (Paste) but after selecting items, then using Ctrl-C, the Selected items all lose selection and the first item in the list is selected and it gets copied to the Clipboard.
I am using the KeyPreview and main form OnKeyUp
if (ssCtrl in Shift) then
begin
case Char(Key) of
'c','C' : puCopyClick(Sender);
'v','V' : puPasteClick(Sender);
end;
Exit;
end;
case Key of
VK_Delete : puDeleteClick(Self);
end;
Exit;
How can I make the Ctrl+C etc work as the popup does?
Thanks
The best way to handle shortcut keys is to let the menu items handle them. You say that you have a popup menu that has these actions. Use the Shortcut property of the menu item to associate that menu item with the shortcut key.
That allows you to remove all the manual keyboard event handling and let the framework do it for you. That has many benefits. Not least of which is that the event will fire when the key goes down rather than when it goes up as you currently have it.
Even better would be to use actions which if I recall correctly do exist in Delphi 5. These allow you to associate a single action, for example copy to clipboard with multiple independent UI elements. For example that action can be associated with a main menu, a popup menu, and a shortcut key.
In a StringGrid, sometimes I get the unwanted menu below when I right-click. Is this a Windows popup?
How to I prevent this popup from appearing rather than my own?
I have goAlwaysShowEditor in my Options.
I have set StringGrid.PopupMenu to my popup.
I've set StringGrid.OnMouseDown to show my popup if it's a right click.
You can override the virtual CreateEditor method like this way (not a good solution though, I know :-):
type
TStringGrid = class(Grids.TStringGrid)
protected
function CreateEditor: TInplaceEdit; override;
end;
implementation
function TStringGrid.CreateEditor: TInplaceEdit;
begin
Result := inherited CreateEditor;
TMaskEdit(Result).PopupMenu := Form1.PopupMenu1;
end;
That is the popup menu found in every Windows EDIT control. Possible the world's most known menu (the only competition comes from the system menu). You want it, because your user's expect it (and need it). When you edit the text in a cell, the TStringGrid control actually creates a standard Windows EDIT control, which is great. And thus you get its popup menu.
In addition, to show your own popup menu (when you are not editing a cell), you don't need to set the OnMouseDown handler. It is enough to set the PopupMenu property. In fact, it is very bad to use the OnMouseDown handler to trigger a popup menu, because then the menu will only be shown when the user right-clicks the control (and not, for instance, when he presses the "context" button on his keyboard).
If you really want your own popup menu to show, even when the user is editing a cell, you really have to give him his usual options for undo, copy, cut, paste, Unicode stuff, etc., manually. Surely you don't want that?
I've got a TMemo with an associated TPopupMenu on a FireMonkey form.
When I rightclick on the memo, I get my own popup menu, but after my popup disappears I still get the default popup (the one that says cut, copy, paste, select all).
How do I disable the default menu, or can I add my own items to the default menu perhaps?
I can't reproduce this behavior. Here's what I tried:
File->New->FireMonkey HD Application
Drop a TMemo and TPopupMenu on the form
Assign PopupMenu to Memo1.PopupMenu in the Object Inspector
Create two menu items in the PopupMenu, and assign them both the same OnClick event (generated in the Object Inspector). I left the default caption of MenuItem1 and MenuItem2 in the Caption of both items.
Wrote a simple MessageDlg that displays TMenuItem(Sender).Caption with a single Ok button in the OnClick handler.
Run the application, right-click Memo1, and choose either menu item
I get a single menu displayed with my two items (MenuItem1 and MenuItem2). Choosing either item displays the appropriate Caption in a message dialog, and clicking Ok in that dialog. There is no default popup menu displayed.
EDIT: Found it for you. This is a bug fixed in Update 3 - see the list of bug fixes in Update 3, and search for 98705, or scroll through until you reach the section on FireMonkey\Components (it's the second or third entry under that section).
Each TTabSheet on my TPageControl has a TToolBar on it. Each tool bar has a TToolButton that should respond to the same keyboard shortcut. How do I provide hotkeys so that the right button is invoked for the current page?
On the first tab sheet, Ctrl+T should make something happen, but upon switching to the second tab, Ctrl+T should make something else happen instead.
Is this a time to toggle TActionList.State between asNormal and asSuspended when tab sheets are shown or hidden?
If you want Ctrl+T simply to flip between active TabSheets on a PageControl, then create a single Action, with a Ctrl+T shortcut, and flip between pages as required:
procedure TForm1.actNextPageExecute(Sender: TObject)
var
nextPageIndex: Integer;
begin
nextPageIndex := PageControl1.ActivePageIndex+1;
if (nextPageIndex > PageControl1.Pages.Count-1) then
nextPageIndex := 0;
PageControl1.ActivePageIndex := nextPageIndex;
end;
If you want one TAction to do different things depending on what control initiated it, just look at the action's ActionComponent property. Hook all the controls to the same action.
An alternative would be to have multiple actions with the same shortcut and enable or disable them in the Update event based on what is visible or focused.