我有一个复合视觉控件,它由编辑框和下拉按钮组成。下拉按钮不是窗口控件,而是通过编辑框绘制的。我通过以下调用限制编辑的宽度:
SendMessage(Handle, EM_SETMARGINS, EC_RIGHTMARGIN,
(DropDownButtonWidth + 2) shl 16);
它在Windows XP下运行正常但在Windows 7下无效。在后一种情况下,当聚焦编辑框重叠下拉按钮并删除其图像时。
在两个操作系统下限制编辑框rect的正确方法是什么?
PS:我还尝试了另一种方法:
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));
但它也不适用于Windows 7。
答案 0 :(得分:2)
设置边距的第一个代码是正确的。
事情变得棘手但是由于VCL的工作方式,可以重新创建为给定VCL控件创建的基础窗口,以响应在运行时对VCL属性所做的更改(某些属性更改只能在Windows API级别应用)通过摧毁和重建窗口)。尽管在不同的Windows版本中(通常)不会更改消息的顺序,但可能会引入其他消息,其中一些消息可能会改变围绕这些窗口的VCL代码可能会触发的顺序,或者会干扰该代码的行为在VCL无法满足的基础Windows API窗口中也可能引入了一种行为(同样,在混合低级API调用时最常发生这种行为,如本例所示)。
在将VCL行为与较低级别的直接API调用混合时尤其如此 - 就像在这种情况下一样。
还有一些其他因素可能会在应用后干扰某些设置,这需要您自己销毁并重新创建窗口并重新应用自己的设置。
我在不同版本的XP上看到了其他相关代码(不是Delphi)的问题报告 - 似乎SP2中引入了一些在这方面有一些影响的变化。
在 EM_SETMARGINS 的情况下,我遇到了同样的问题并通过查看 TButtonEdit 控件如何设置应用所需的边距来修复它(这是有效的至少在我的Windows 7安装上。)
由于我正在实现自己的自定义控件,而不是尝试将边距应用于某些现有的编辑控件,因此对我来说可能更容易。在下面的代码段中, TCustomPickEdit 是我的自定义控件类,它包含一个 fButton 对象,该对象包含与选择器按钮相关的所有设置。您需要进行适当的调整以在特定情况下应用此代码。
我发现以下内容:
需要在至少3个位置应用边距。首先,每当可能影响边距的设置被更改时,无论何时创建编辑控件窗口句柄,最后每当编辑控件上的字体发生更改时,
即使正确设置了边距,也需要调整控件的剪切矩形以确保正确绘制。这需要覆盖编辑控件的 WndProc 并拦截一些消息。此 WndProc 还需要响应字体更改通知,以便在更改编辑控件字体时重新应用边距。
在我的案例中处理这些问题的代码如下所示:
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;
答案 1 :(得分:1)
我怀疑您可能需要进一步阅读the documentation on EM_SETMARGINS
。它声明:
HIWORD指定新的宽度 右边距,以像素为单位。这个 如果wParam没有,则忽略该值 包括EC_RIGHTMARGIN。
编辑控件和Rich Edit 3.0和 后来:HIWORD可以指定 EC_USEFONTINFO值设置正确 边距到计算的窄宽度 使用的文本指标 控件的当前字体。如果没有字体 已设置为控制,保证金 设置为零。
请注意有关EC_USEFONTINFO的第二段设置窄宽度。这可能意味着这是设置窄宽度的唯一方法。我不确定,因为我没有尝试过,但它可能有所帮助。
另请注意,Rich Edit控件和常规编辑框具有不同的行为,因此请检查您正在使用哪一个。