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?
Related
In delphi:
How can you respond to a key press when the current focus is on a radiogroup which does not have an onkeypress event. I was hoping to use the forms onkeypress event but it doesnt see to fire.
You can make this possible by setting the form's KeyPreview property to True.
However, I'm not sure you are actually doing things right, since this is a fairly uncommon problem.
You didn't write what keyboard shortcut you want to respond to. But please remember that
Letters are used to navigate the GUI. For instance, pressing A might select the &All radio button or click the &Add push button. Similarly, Alt+A does the same if the current control allows character input, allows you to open the &Add-ons menu item, etc.
If you want to add a proper shortcut like Ctrl+O, it is much better to use a TActionList with an action having this shortcut. This action can be mapped to menu items, buttons, etc., or simply exist in the background not being attached to any visual control. In very simple applications, you might want to use a stand-alone menu item with such a shortcut instead.
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);
How can I disable popup of a popup menu?
My problem is that I have a nice context menu for my listbox but if I shift-rightclick an item, I execute some code, and I don't want the popup menu popping up afterwards.
But if it is a normal rightclick on the listbox, then of course I want the popup menu.
There's no "OnContextPopup" in Delphi, and no "Handled" parameter either. One way of doing this in Delphi is as follows:
Locate the PopupMenu on your form, click it, go to the events tab of the object inspector, double-click the cell to the right of "OnPopup" and insert the following code (the line right after begin):
PROCEDURE TForm1.PopupMenu1Popup(Sender : TObject);
BEGIN
IF GetKeyState(VK_SHIFT) AND $8000<>0 THEN Abort
END;
this will suppress the popup menu, if any of the two SHIFT keys are pressed when the menu is about to pop up...
Another way (spurred by TLama's comment above) is to locate the OnContextPopup event for the control you want to suppress the popup for (in this case your ListBox), double click it (to create/jump to the event handler) and insert the following code:
PROCEDURE TForm1.ListBox1ContextPopup(Sender : TObject ; Point : TPoint ; VAR Handled : BOOLEAN);
BEGIN
Handled:=(GetKeyState(VK_SHIFT) AND $8000<>0)
END;
The main difference between these two methods is that the first one suppresses the popup, no matter which control the popup menu is attempting to pop up over, whereas the second method allows you to only suppress the popup for specific controls (as you can assign the same popup menu to several controls).
I have a Delphi 6 application that has a TJvListView control. I have a popup menu tied to that control via the control's PopupMenu property. What I would like to do is show a different popup menu based on which column the user had the mouse over when they right clicked, with the additional option to not show a popup menu at all if the current column does not need one. How can I do this?
Thanks to this detailed sample by Remy Lebeau on in-place editing in a TListView I know what row and column the mouse is over except for one wrinkle. The mouse down event where I determine the current row and column occurs after the popup menu is exited.
I now need to know two things. First, how can I get some event to fire before the popup menu shows after a right mouse click so I can record the current list view row and column and suppress the popup menu if I want to, and second, how I can show a different popup based on the current column. I am hoping to avoid having to write a bunch of mini-forms instead of using the TListView PopupMenu property and supporting code. Is there a simple solution, perhaps some fancy footwork in a sub-class I should create around TJvListView?
You could perform the detection in mousemove instead of mousedown/Click and change the popupmenu depending.
You also could remove any popupmenu and call the wished via p.pupup in mousedown as you desire.
I'm building a custom control which is to have multiple focus points. For example, within 1 control, let's say there's 3 regions (could be defined as a rect on the canvas) which are to be able to have focus. Depending on which one has focus, I don't want the default Windows dotted line around it, but some special handling. I know nothing about how to even give 1 custom control its own focus.
The original project was a single TPanel with a few VCL controls on it, each of course being its own window, thus having its own focus. But now I'm putting it into a custom class of its own, which these 3 controls will no longer exist (they were only there in version 1 as a prototype) and I need to now somehow mimic the focus in these different regions.
I guess similar to something as simple as a TListBox, where certain items within that control get the focus instead of the entire control its self.
Here's a picture to help demonstrate what I'm making...
The one on the top is the original with the buttons. But the one on the bottom is the new one I'm building which is all custom drawn.
To elaborate, I'd like to see if Windows already has special handling for this type of scenario before I go and re-invent the wheel.
I'm not looking for the "Easiest" way to accomplish this. And I also do not want recommendations to revert back to how I had it before, because there's many reasons I don't want 1 control with multiple other controls within. I just need a yes or no, with an explanation.
More
I just realized the main concern is the use of the tab key. The control has to first get the focus, start the focus on whichever sub-item it's supposed to, then respond to tab on my command until it reaches the end, then pass the tabbing over to the next control. Then it also needs shift+tab as well. How on earth would I implement this tabbing? That's where I got stuck, but it just struck me that this is the main reason I'm asking.
About the handling of the TAB key - it should be something like this: you handle the WM_GETDLGCODE message to indicate that you want to proccess the TAB key, ie
TMyControl = ...
protected
procedure WMGetDlgCode(var Msg: TMessage); message WM_GETDLGCODE;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
...
procedure TMyControl.WMGetDlgCode(var Msg: TMessage);
begin
inherited;
Msg.Result:= Msg.Result or DLGC_WANTTAB;
end;
and the in the overriden KeyDown method you decide what to do in response of it, something like
procedure TMyControl.KeyDown(var Key: Word; Shift: TShiftState);
begin
if(Key = VK_TAB)then begin
if(ssShift in Shift)then begin
if(first subcontrol is focused) set focus to previous control on parent
else set focus to previous child area
end else begin
if(last subcontrol is focused) set focus to next control on parent
else set focus to next child area
end;
end else inherited;
end;
No you can't get windows to recognize multiple points of keyboard focus inside the same window handle, since each control with a window handle either has, or does not have, keyboard focus. The "inner focus" between multiple controls is up to you to sort out.
As you already knew, the most simple way to accomplish this is to have multiple sub-controls with their own window-handles, which is what you said you are doing:
TMyThreeEditControls = class(TControl) // parent has no window handle!!!!
protected
FEdit1:TEdit;
FEdit2:TEdit;
FEdit3:TEdit;
...
end
In the situation above, the parent control is a TControl, it creates several sub controls, in my example above, all three have their own window handles, and thus Windows can display keyboard focus when you hit tab, and handle mouse focus as part of Windows's common controls library's functionality.
In short, the "composite" approach where you include sub-objects (other controls) in your main control, which you are trying to move away from is in fact, the only way to let Windows do most of the work.
On the other hand, what you might be looking for is not a way to have a control paint itself, but some code to make something look like it is focused, in your own custom painting routines, if that is what you are looking for, you should look into the VCL source code or this link on about.com for examples on how to tell Windows to draw a focus rectangle, etc. The about.com link is an imitation and does not use real windows code to draw focus in a Windows-theme aware way.
Update: it is possible that what you are also looking for is the way to determine if mouse co-ordinates are within a specified rectangle (the rectangle represents a button in your case) and if so, to draw a "hot state" for the button. There are more sub-tasks than this to accomplish if you wish to build a control yourself, I recommend you study existing controls such as TStringGrid and TCategoryButtons in the VCL source code, to see the MouseMove, MouseDown, and MouseUp handling code you will need to do the things you are trying to do. In particular, StringGrid source code is the way to see how the "tab key" can be used within a single control with a single window handle, because in that control the tab key can be used (if the right options are turned on) to navigate among all the cells inside the string grid, as if each one was a separate control, even though it is all one control.
Another way to achieve this is to use one edit box that you re-use for each region that you want to have "focused". This is essentially how Delphi's grids work.
When the user clicks in that area (or hits the tab key into your control) you set the edit controls text to the data in that area, set the edit controls bounds to the area and make it visible. When the user exits the control (by clicking out of it or tabbing) you hide the edit control. If you make your control accept the tab key, you can make it "edit" the next area when they hit tab and exit it when they are in the last area.
Then it's just house keeping to make sure you store the entered data in the right spot in your component.