My question is how to catch which menu item was pressed in some form? For an example :
I have a form with a button. When I pressed the button the menu of the application will be on focus and the child form wait to choose a menu item. After I choose one the child form show a message with the name of the menu item which I pressed.
Can anyone tell me how to do this?
Thanks in advance!
Something like this is a direct answer to your question:
procedure TMyForm.MenuItemClick(Sender: TObject);
begin
ShowMessage((Sender as TMenuItem).Caption);
end;
This event handler should be connected to each menu item that you wish to behave this way.
It seems that you want some centralised logging or monitoring of the execution of menu items. If you use actions and associate these with your menu items then you can get an application wide notification that an action has been executed. Drop a TApplicationEvents object onto your main form and handle its OnActionExecute event. Like this:
procedure TMyForm.ApplicationEvents1ActionExecute(Action: TBasicAction; var Handled: Boolean);
begin
ShowMessage((Action as TAction).Caption);
end;
This will fire whenever any event in your app is executed.
1/ By default you set all the TMenuItem OnClick event handler to Nil.
2/ When you click the form button you assign an event to each TMenuItem, this event will be only called once, and will record the 'trigger'.
3/ When the event is called you reset all the TMenuitem.OnClick to Nil
4/ To make this easyer, you store all your MenuItems in a TList.
example:
global variables (private declaration in TMyForm):
MyTriggerItem: TMenuItem; // used as pointer
MyMenuItemList: TList; // used to store all TMenuItem which are 'listened to'
your TButton handler:
Procedure TMyForm.ButtonClick(Sender: TObject);
Var
i: Integer;
Begin
For i:= 0 To Pred(MyMenuItemList.Count) Do TMenuItem(MyMenuItemList[i]).OnCLick := CommonMenuItemClick;
End;
your TMenuItem event handler:
Procedure TMyForm.CommonMenuItemClick(Sender: TObject);
Var
i: Integer;
Begin
MyTriggerItem := TMenuItem(Sender);
For i:= 0 To Pred(MyMenuItemList.Count) Do TMenuItem(MyMenuItemList[i]).OnCLick := Nil;
End;
Related
I need that "x" button on any form would not close the form but instead open another 3 random forms on delphi, i have no idea how to do that, please help
Just use the form's OnCloseQuery event to detect the user's trying to close your form (by clicking the close button in the top-right corner, by double-clicking the form's title bar icon, by selecting the Close system menu item, by pressing Alt+F4, etc.).
Then set CanClose to False and instead open your three new forms:
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
CanClose := False;
Form2.Show;
Form3.Show;
Form4.Show;
end;
As suggested by #AndreasRejbrand's answer, you could use the Form's OnCloseQuery event. But, the problem with that approach is that the event is also triggered during system reboot/shutdown, and you don't want to block that. If OnCloseQuery returns CanClose=False during a system shutdown, the shutdown is canceled.
Another option is to use the Form's OnClose event instead, setting its Action parameter to caNone, eg:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caNone;
Form2.Show;
Form3.Show;
Form4.Show;
end;
However, the best option would to be to handle only user-initiated closures (the X button, ALT-F4, etc) by having the Form handle the WM_SYSCOMMAND message looking for SC_CLOSE notifications, eg:
procedure TForm1.WndProc(var Message: TMessage);
begin
if (Message.Msg = WM_SYSCOMMAND) and (Message.WParam and $FFF0 = SC_CLOSE) then
begin
Message.Result := 0;
Form2.Show;
Form3.Show;
Form4.Show;
end
else
inherited;
end;
This way, system-initiated closures are unhindered.
Hi guys I am a Delphi beginner and I have a simple question because finding something online for Delphi seems to be hard.
I have a CheckListBox and when I click on the checkbox of an Item I want to pass it to another form lets say form2 gets created. There I have 2 buttons:
Delete - it should delete the selected Item so the item where the form spawned on. How do I delete the selected Item?
Edit Entry - I need to pass the checked Item values to another form where I can edit the values and save it as a new one. How do I pass the values from the selected Item to another form?
Ty Faded.
Here's a better approach:
Create a new VCL application.
Add a TCheckListBox control with a few items on it:
Drop a TActionList component on the form.
Create two actions: aDelete and aRename. Sets their captions to Delete... and Rename... and their hints to Removes the selected item from the list. and Renames the selected item in the list..
Add the following code to their OnExecute handlers:
procedure TForm1.aDeleteExecute(Sender: TObject);
begin
if CheckListBox1.ItemIndex = -1 then
Exit;
if MessageBox(Handle, 'Do you want to delete the selected item?',
'Delete', MB_ICONQUESTION or MB_YESNO) <> IDYES then
Exit;
CheckListBox1.DeleteSelected;
end;
procedure TForm1.aRenameExecute(Sender: TObject);
var
S: string;
begin
if CheckListBox1.ItemIndex = -1 then
Exit;
S := CheckListBox1.Items[CheckListBox1.ItemIndex];
if InputQuery('Rename', 'Please enter the new name:', S) then
CheckListBox1.Items[CheckListBox1.ItemIndex] := S;
end;
Add the following code to their OnUpdate handlers:
procedure TForm1.aDeleteUpdate(Sender: TObject);
begin
aDelete.Enabled := CheckListBox1.ItemIndex <> -1;
end;
procedure TForm1.aRenameUpdate(Sender: TObject);
begin
aRename.Enabled := CheckListBox1.ItemIndex <> -1;
end;
Drop a TPopupMenu on the form. Name it pmList. Add two menu items. Set their Action properties to aDelete and aRename, respectively. This will automatically give the items the caption, hint, and hotkeys of the actions:
Now assign pmList to the check list box control's PopupMenu property.
Test the application. Notice that the context menu items are enabled only if an item is selected; otherwise, they are both disabled. (This is thanks to the OnUpdate handlers. It would be very sloppy of us to skip these. But notice that we still verify that an item is selected in the OnExceute handlers. In quality software, you always use both belt and braces.)
Of course, we must map the Del and F2 keys to the delete and rename actions. We could use the ShortCut properties of the actions, but that would make these keys delete and rename in this list even if another GUI control has focus, and that's very bad. Instead, we add an OnKeyDown handler to the check list box control itself:
procedure TForm1.CheckListBox1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
case Key of
VK_DELETE:
aDelete.Execute;
VK_F2:
aRename.Execute;
end;
end;
Is it possible to change the Multiselect behaviour with a standard TListBox?
I would like items to only be multiselected by holding the Ctrl key, not the Shift key.
I have TActions which update depending on items selected, eg:
TAction(Sender).Enabled := ListBox1.ItemIndex <> -1;
The controls assigned to the action flicker when a listbox item is selected when holding shift to multiselect, this does not happen by holding ctrl key only.
So I would like to use only Ctrl key to multiselect.
Simply put, how can I:
Multiselect TListBox
Use Ctrl to multiselect
Shift has no effect
Thanks :)
Item selection is processed by the default window procedure of the underlying list box api control. Because of this there's no VCL property that would do this. Nevertheless, users might not like this, but you can change the behavior by handling WM_LBUTTONDOWN message that is post the the control which triggers item selection. Subclass the control in any way you like. Or, since WM_LBUTTONDOWN is posted, you can use OnMessage event of an ApplicationEvents component. Or, just as one example below, if the control is immediately parented by the form, you can use the notification sent to the parent:
type
TForm1 = class(TForm)
..
private
procedure WMParentNotify(var Msg: TWMParentNotify); message WM_PARENTNOTIFY;
..
procedure TForm1.WMParentNotify(var Msg: TWMParentNotify);
var
Pt: TPoint;
State: TKeyboardState;
begin
if (Msg.Event = WM_LBUTTONDOWN) then begin
Pt := SmallPointToPoint(SmallPoint(Msg.XPos, Msg.YPos));
MapWindowPoints(Handle, ListBox1.Handle, Pt, 1);
if PtInRect(ListBox1.ClientRect, Pt) then begin
GetKeyboardState(State);
State[VK_SHIFT] := 0;
SetKeyboardState(State);
end;
end;
inherited;
end;
I want to have a shortcut key combination (like Ctrl+Alt+D) in my app to invoke a function, but I don't want the shortcut to appear on any menu. Is it possible to have a shortcut available in your app that is otherwise invisible?
you can use the OnShortCut event of the TApplicationEvents component to this task
check this code
procedure TForm1.ApplicationEvents1ShortCut(var Msg: TWMKey;
var Handled: Boolean);
begin
if (Msg.CharCode = Ord('D')) and (HiWord(Msg.KeyData) and KF_ALTDOWN <> 0) and (GetKeyState(VK_CONTROL) < 0) then
begin
ShowMessage('Ctrl+Alt+D Pressed') ;
Handled := true;
end;
end;
Yes it's possible. You must add an Object of class TAction to your form.
You can specify a keyboard shortcut for the Taction and then put your code in event OnExecute of the TAction.
Note that you cannot add a Taction directly to your form, you must put a TactionList on your form and then you can add a Taction to your TActionList.
Please assist me: How to assign an up arrow keyboard shortcut to action or menu item, and keep it actual for navigating the list control (e.g. ListBox/Virtual Treeview/other) at the same time?
Thanks!
You comment:
And how about the Winamp player? It has Volume Up/Volume Down features assigned to the up arrow key and down arrow key correspondingly.. Okay, if that impossible in Delphi, then ...
but it certainly is possible, it just isn't a good idea to do it, and against the Windows User Experience Interaction Guidelines.
But if you're set on implementing it, here's how. Override the following method in your form class that contains the action components:
function IsShortCut(var Message: TWMKey): Boolean; override;
and in it you can prevent the Up and Down key from triggering the actions they are shortcuts for:
function TWeirdForm.IsShortCut(var Message: TWMKey): Boolean;
begin
if (Message.CharCode in [VK_UP, VK_DOWN])
// insert test whether message needs to go to the focused control instead
and (...)
then begin
// insert calls to code that should be executed instead
Result := False;
exit;
end;
inherited;
end;
Note that you should test for the correct shift state too, and check that your code doesn't break any other window behaviour users expect, like moving of the window with the arrow keys.
On the form properties set KeyPreview := true
then on KeyUp event of the form write event to check if you Up key is pressed and make it call the menu item (on this case menu item called Action1):
procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if (Key = VK_UP) and (ActiveControl = ListBox1)then
Action11.Click;
end;
procedure TForm1.Action11Click(Sender: TObject);
begin
if ListBox1.ItemIndex >=0 then
ShowMessage(ListBox1.Items[ListBox1.ItemIndex]);
end;
If you need the Action1 to be executed even if they Current Control isn't the listbox, remove the and part of the IF statement