代码之家  ›  专栏  ›  技术社区  ›  Andrej KirejeÅ­

为什么em_SetMargins在Windows7下不工作?

  •  3
  • Andrej KirejeÅ­  · 技术社区  · 14 年前

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

    SendMessage(Handle, EM_SETMARGINS, EC_RIGHTMARGIN, 
      (DropDownButtonWidth + 2) shl 16);
    

    它在Windows XP下工作正常,但在Windows 7下不工作。在后一种情况下,当聚焦编辑框重叠下拉按钮并擦除其图像时。

    在两种操作系统下,限制编辑框矩形的正确方法是什么?

    附言:我还尝试了另一种方法:

      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));
    

    但它也不适用于Windows7。

    2 回复  |  直到 12 年前
        1
  •  2
  •   Deltics    12 年前

    第一个设置页边距的代码是正确的。

    但是,由于VCL的工作方式,为给定VCL控件创建的基础窗口可能会根据运行时对VCL属性所做的更改而重新创建(某些属性更改只能通过销毁和重新创建窗口在Windows API级别应用)。虽然消息的顺序(通常)在不同的Windows版本中没有更改,但可能会引入其他消息,其中一些消息可能会更改缠绕在这些窗口上的VCL代码可能触发的顺序,或干扰该代码的行为。

    在VCL所不满足的基础Windows API窗口中也可能引入了一种行为(同样,在混合低级API调用时最有可能发生这种情况)。

    尤其是当VCL行为与较低级别的直接API调用混合时,这种情况尤其如此——在本例中就是这样。

    还有其他一些事情一旦应用,可能会干扰某些设置,这要求您自己销毁并重新创建窗口,然后重新应用自己的设置。

    我看到过其他关于这个领域的问题的报告,在不同版本的xp上使用相同的代码(而不是delphi),在sp2中引入了一个变化,在这个领域产生了一些影响。

    如果是 新兴市场利润率 我和你有同样的问题,通过观察 t按钮编辑 控件已成功应用所需的页边距(至少在我的Windows 7安装中有效)。

    由于我正在实现自己的自定义控件,而不是试图将页边距应用于某个现有的编辑控件,这可能使事情变得更简单。在下面的代码片段中, t自定义文档 是我的自定义控件类,它包含 F按钮 对象,它保存与选取器按钮相关的所有设置。您需要进行适当的调整,以便在特定情况下应用此代码。

    我发现如下:

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

    2. 即使正确设置了页边距,也需要调整控件的剪切矩形以确保正确的绘图。这需要覆盖 窗口过程 编辑控件和截取一些消息。这个 窗口过程 还需要响应字体更改通知,以便在编辑控件字体更改时重新应用边距。

    在我的例子中,处理这些问题的代码如下所示:

      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;
    
        2
  •  1
  •   Jeff Yates    14 年前

    我想你可能需要进一步了解 the documentation on EM_SETMARGINS . 它指出:

    hiword指定 右边距,以像素为单位。这个 如果wParam不忽略值 包括欧共体右边距。

    编辑控件和Rich Edit 3.0和 稍后:hiword可以指定 EC使用fontinfo值设置右侧 计算出窄宽度的边距 使用 控件的当前字体。如果没有字体 已为控件设置,页边距 设置为零。

    请注意第二段中有关ec_sefontinfo的内容,以设置窄宽度。这可能意味着这是设置窄宽度的唯一方法。我不确定,因为我还没试过,但可能会有帮助。

    还要注意,富编辑控件和常规编辑框具有不同的行为,因此请检查您使用的是哪种行为。