How can I make a menu stay visible after it's clicked? - delphi

I'm using Delphi. I have my popup menu ready, and in a submenu I want to click, but I don't want the popup menu to disappear. I want to click and make it stay.

Easy one, disable the item. < g >
Joke aside, not an easy task.
If you want the popup menu to act like a top-most form (that is you can both interact with the items and with controls on your form without deactivating the menu), forget it, it cannot be done with a standard menu.
But if your requirement is as exactly as stated in your question (click an item, and the menu is not closed - click outside and it is closed), with some work, it would be possible.
Your aim would be to subclass the window that your submenu will reside in to override some message handling. First, derive a new class from 'TPopupList' and override its 'WndProc'. Here is an example doing this.
If you intend to prevent the closing of the menu by selecting root items then in PopupList's WndProc you'd handle WM_ENTERIDLE and get the popup menu's window handle from the message's lParam and subclass the popup menu's window.
If you only intend to prevent the closing of the menu by selecting submenu items, then in PopupList's WndProc you'd watch for WM_INITMENUPOPUP messages where the wParam is "not" the handle of the PopupMenu itself, that would mean a submenu is about to be shown. Only then you'd handle WM_ENTERIDLE and get the window handle that the submenu resides in and subclass that window.
After subclassing the window that the popup menu or the popup submenu resides in, you'd intercept an undocumented 'MN_BUTTONDOWN' ($01ED) message and prevent further handling (not call the original window procedure). Probably you'd also want to prevent closing of the menu with the keyboard; you'd watch for WM_KEYDOWN (Enter) and WM_CHAR (accelerator) messages.
Well, would take some work I guess.

I don't know how can you do that but TAdvStickyPopupMenu component (TMS software) can do this.

Related

Get the calling component of TPopupMenu

I have a TStringGrid, that has a TPopupMenu connected.
By clicking one event of the popup menu, I would like to get the calling component. Is that possible?
Background:
It is a bigger project, every form has a "BasicForm" I can inherited from. So I would like to provide a "default popup menu" for grids that have stuff like Copy, Select, and so on in it. In the inherited form I only match the grid (if exists) with that popup and I'm done.
Seems you are looking for the PopupComponent property of TPopupMenu:
Vcl.Menus.TPopupMenu.PopupComponent
Indicates the component that last displayed the popup menu in response
to a right mouse click.
Read PopupComponent to determine which control is currently using the
popup menu. In applications where multiple controls share the same
pop-up menu, use PopupComponent to determine which of them displayed
the menu.
Set PopupComponent to associate a control with the menu before calling
the Popup method programmatically to bring up the pop-up menu.

Make popup window close when releasing mouse button on an item on the fly

When clicking on a button I open a popup menu, e.g. using popupMenu.popup().
To select an item I must first release the mouse button and then click on a menu item to execute it.
This is "normal", but what I want is the behavior that I won't have to do an extra click on the menu item. I would like to be able to click on the button, move over a menu item (still holding the button) and execute it immediately after releasing the mouse button.
This is similar to how cascaded sub menus work.
I tried the way using TrackPopupMenu to hook into the messages and execute the item when the button is released. This works, but...
When using images in the popup menu (either bitmap or imagelist items) together with TrackPopupMenu then the menu does not show any entry. Every entry is some pixels wide and empty. You can use them blindly, so they work somehow but the drawing is not done correctly.
I'm using Delphi XE2 Pro.
I also tried to find general articles to hook into menu messages but did not find anything that works without using TrackPopupMenu. Maybe there is a way to have TrackPopupMenu displaying menus with images?
Any help is much appreciated.
You are routing menu messages to the wrong window procedure, you are passing the handle of your form to TrackPopupMenu (you should post your code, then there would be no need to guess what you're doing wrong. And you'd probably receive a much quicker reply).
Forms have menu support for window menus. When a form window procedure receives a, say WM_DRAWITEM, it only draws the item if it belongs to the window menu. For popup menus, VCL uses a utility window which is accessible through the global PopupList. See below example.
var
Pt: TPoint;
begin
Pt := Button1.ClientToScreen(Point(0, Button1.Height));
TrackPopupMenu(PopupMenu1.Handle, TPM_LEFTBUTTON, Pt.X, Pt.Y, 0,
PopupList.Window, nil);

Avoid click propagation on Page that is under the current page on a TPageControl

I have a TPageControl that contains five pages and the page shown is alternated setting the ActivePageIndex property in this way:
PageControl1.ActivePageIndex := 4;
the problem is that the page below covered by the page currently shown get click on his buttons while the mouse is pressed on the above page, how can I avoid this behaviour ? How can I avoid the propagation of the click on Pages below the currently shown (that is also the current index)?
The application uses CLX as Graphics library instead of VCL.
Delphi does not do click Propagation.
I would check if the button that gets click are placed on the TabSheet and not on the parent control. Find the button you want in the drop down list of object inspector and press - the selected item will be the parent of the button. Is it a TabSheet?
Or you can add this code as a first line of your button-click-function
ShowMessage(TButton(Sender).Parent.Name);

How to avoid the "Open IME" popup in a StringGrid?

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?

Mimic outside click on a popup menu

You know how in a popup menu if you click outside of the menu the popup disappears? Well I would like to reproduce that.
Currently I am having a panel created with some components on it when a button is clicked. The panel and sub components go away when you click a certain button on the panel. However I want it to go away if you click anywhere outside of the panel.
I think you would need to install and application-wide mouse message hook, and if your panel is visible and the coordinates of the mouse event are outside of your panel bounds, then hide the panel. Also handle the WM_ACTIVATE message in your form.
[Edited: removed answer involving SetCaptureControl() because the bahaviour is not appropriate in this circumstance]

Resources