Reputation: 5481
I have a compound visual control which consists of edit box and a drop down button. The drop down button is not a windowed control and is drawn over edit box. I limit edit's width with following call:
SendMessage(Handle, EM_SETMARGINS, EC_RIGHTMARGIN,
(DropDownButtonWidth + 2) shl 16);
It works fine under Windows XP but doesn't work under Windows 7. In latter case, when focused edit box overlap dropdown button and erases its image.
What would be correct way of limiting edit box rect under both operation systems?
PS: I also tried another approach:
SendMessage(Handle, EM_GETRECT, 0, LongInt(@Loc));
Loc.Bottom := ClientHeight + 1;
Loc.Right := ClientWidth - FButton.Width - 2;
Loc.Top := 0;
Loc.Left := 0;
SendMessage(Handle, EM_SETRECTNP, 0, LongInt(@Loc));
But it doesn't work for Windows 7 either.
Upvotes: 4
Views: 3587
Reputation: 23046
Your first code to set the margins is correct.
Things get tricky however because of the way the VCL works, the underlying window created for a given VCL control may be recreated in response to changes made to VCL properties at runtime (some property changes can only be applied at the Windows API level by destroying and recreating the window). Although the order of messages is (usually) not changed in different Windows versions, there can be additional messages introduced, some of which may alter the order in which the VCL code wrapped around those windows may fire, or interfere with the behaviour of that code.
It is also possible that a behaviour was introduced in the underlying Windows API windows that the VCL does not cater for (again, most likely to occur when mixing low level API calls as in this case).
This is especially the case when mixing VCL behaviours with lower level, direct API calls - as in this case.
There are also other things that can interfere with certain settings once applied, which require that you yourself destroy and recreate the window and re-apply your own settings.
I have seen other reports of problems in this area with the same code (not Delphi) on different versions of XP - there seems to have been a change introduced in SP2 that had some impact in this area.
In the case of EM_SETMARGINS I had the same problem you did and fixed it by looking at how the TButtonEdit control managed to apply the margins it required (which was working at least on my Windows 7 installation).
Things were perhaps made easier for me by the fact that I was implementing a custom control of my own, rather than trying to apply margins to some existing edit control. In the code snippets below, TCustomPickEdit is my custom control class, which incorporates an fButton object which holds all the settings relevant to the picker button. You will need to make suitable adjustments to apply this code in your particular situation.
What I found was the following:
Margins needed to be applied in at least 3 places. First, whenever the settings that might affect the margin were changed, second whenever the edit control window handle was created, and finally whenever the font on the edit control is changed:
Even with margins correctly set, the clipping rectangle of the control needed to be adjusted to ensure correct drawing. This required overriding the WndProc of the edit control and intercepting a couple of messages. This WndProc also needed to respond to a font change notification to reapply the margins in the event that the edit control font was changed.
The code for dealing with each of these in my case is shown below:
procedure TCustomPickEdit.ConfigureButton;
// 1. Apply margins when button settings are changed
begin
fButton.Caption := Button.Caption;
fButton.Flat := Button.Flat;
fButton.Glyph := Button.Glyph;
fButton.NumGlyphs := Button.NumGlyphs;
fButton.Visible := Button.Visible;
ApplyMargins;
end;
procedure TCustomPickEdit.CreateHandle;
// 2. Apply margins when underlying window handle is created
begin
inherited;
ApplyMargins;
end;
procedure TCustomPickEdit.WndProc(var aMessage: TMessage);
// 3. Adjust clipping rectangle for correct drawing
// 4. Apply margins when font is changed
var
top: Integer;
begin
case aMessage.Msg of
CN_CTLCOLORSTATIC,
CN_CTLCOLOREDIT : if Button.Visible then
begin
top := fButton.Top;
if ThemeServices.ThemesEnabled and Ctl3D then
Inc(top);
ExcludeClipRect(aMessage.WParam, fButton.Left,
top + 1,
fButton.Left + fButton.Width,
fButton.Height);
end;
end;
inherited;
case aMessage.Msg of
CM_FONTCHANGED : if NOT (csLoading in ComponentState) then
ApplyMargins;
end;
end;
Upvotes: 3
Reputation: 62387
I suspect you may need to read further into the documentation on EM_SETMARGINS
. It states:
The HIWORD specifies the new width of the right margin, in pixels. This value is ignored if wParam does not include EC_RIGHTMARGIN.
Edit controls and Rich Edit 3.0 and later: The HIWORD can specify the EC_USEFONTINFO value to set the right margin to a narrow width calculated using the text metrics of the control's current font. If no font has been set for the control, the margin is set to zero.
Note the second paragraph regarding EC_USEFONTINFO to set a narrow width. This may be implying that this is the ONLY way to set a narrow width. I don't know for sure as I haven't tried it, but it may help.
Note also that Rich Edit Controls and regular Edit Boxes have different behaviour, so check which one you're using.
Upvotes: 1