为什么EM_SETMARGINS在Windows 7下不起作用?

时间:2010-11-18 17:31:28

标签: windows delphi winapi user-interface windows-7

我有一个复合视觉控件,它由编辑框和下拉按钮组成。下拉按钮不是窗口控件,而是通过编辑框绘制的。我通过以下调用限制编辑的宽度:

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。

2 个答案:

答案 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 对象,该对象包含与选择器按钮相关的所有设置。您需要进行适当的调整以在特定情况下应用此代码。

我发现以下内容:

  1. 需要在至少3个位置应用边距。首先,每当可能影响边距的设置被更改时,无论何时创建编辑控件窗口句柄,最后每当编辑控件上的字体发生更改时,

  2. 即使正确设置了边距,也需要调整控件的剪切矩形以确保正确绘制。这需要覆盖编辑控件的 WndProc 并拦截一些消息。此 WndProc 还需要响应字体更改通知,以便在更改编辑控件字体时重新应用边距。

  3. 在我的案例中处理这些问题的代码如下所示:

      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控件和常规编辑框具有不同的行为,因此请检查您正在使用哪一个。