• Delphi控件的显示内容与显示边框是两回事


    没有内容,不代表没有边框。比如设计期一个空的TImage仍是有边框的。

    if (csOpaque in image1.ControlStyle) then ShowMessage('不透明')
    else ShowMessage('透明') // image1没有内容的时候,就是透明;有内容的时候,就是不透明

    再比如:

    procedure TWinControl.PaintControls(DC: HDC; First: TControl);
    var
      I, Count, SaveIndex: Integer;                                    
      FrameBrush: HBRUSH;
    begin
      // 这个DC其实是父Win控件的句柄
      // 一共有2处调用此函数。分别是TControl.Repaint和TWinControl.PaintHandler,分别用来重绘图形控件和Win控件(后者包括了图形子控件,也正因为这个才需要执行这个函数)
      if DockSite and UseDockManager and (DockManager <> nil) then
        DockManager.PaintSite(DC);
      // 重画所有子控件(图形和句柄控件)
      // FControls和FWinControls在TControl.SetParent里调用TWinControl.Insert里增加元素
      if FControls <> nil then // 专指图形控件,不包含windows控件
      begin
        I := 0;
        if First <> nil then
        begin
          I := FControls.IndexOf(First);
          if I < 0 then I := 0;
        end;
        Count := FControls.Count;
        while I < Count do
        begin
          with TControl(FControls[I]) do
            if (Visible or (csDesigning in ComponentState) and not (csNoDesignVisible in ControlStyle)) and
              RectVisible(DC, Rect(Left, Top, Left + Width, Top + Height)) then // API
            begin
              if csPaintCopy in Self.ControlState then Include(FControlState, csPaintCopy);
              SaveIndex := SaveDC(DC);      // API,重画前,保存父控件的DC
              MoveWindowOrg(DC, Left, Top); // 调用2个API
              IntersectClipRect(DC, 0, 0, Width, Height); // API,新建一个完全的区域
              // 原本图形控件不能接受Windows消息的,现在也接受了。注意传递了父控件的DC
              Perform(WM_PAINT, DC, 0);     // important7,图形控件已经把WM_PAINT消息内容已经填好,就等程序员填写Paint函数加上真正要执行的内容。
              RestoreDC(DC, SaveIndex);     // API,恢复父控件的DC
              Exclude(FControlState, csPaintCopy); // 画完之后,去除标记
            end;
          Inc(I);
        end;
      end;
      // 除此以外,还要给Windows子控件额外画边框(因为实体已经画好了)(注意不是给自己画边框)
      if FWinControls <> nil then // 专指windows控件,不包含图形控件
        for I := 0 to FWinControls.Count - 1 do
          with TWinControl(FWinControls[I]) do
            if FCtl3D and (csFramed in ControlStyle) and
              (Visible or (csDesigning in ComponentState) and not (csNoDesignVisible in ControlStyle)) then
            begin
              // fixme 可以试试屏蔽这里的语句,看看效果
              FrameBrush := CreateSolidBrush(ColorToRGB(clBtnShadow)); // API
              FrameRect(DC, Rect(Left - 1, Top - 1, Left + Width, Top + Height), FrameBrush); // API 画矩形边框
              DeleteObject(FrameBrush); // API
              FrameBrush := CreateSolidBrush(ColorToRGB(clBtnHighlight));
              FrameRect(DC, Rect(Left, Top, Left + Width + 1, Top + Height + 1), FrameBrush); // 画两条线
              DeleteObject(FrameBrush); // API
            end;
    end;

    又看到一个函数:

    procedure TWinControl.WMWindowPosChanged(var Message: TWMWindowPosChanged);
    var
      Framed, Moved, Sized: Boolean;
    begin
      // 三明治手法,这里使边框失效
      // 判断是否有边框,是否移动了,是否改变了尺寸
      Framed := FCtl3D and (csFramed in ControlStyle) and (Parent <> nil) and (Message.WindowPos^.flags and SWP_NOREDRAW = 0);
      Moved := (Message.WindowPos^.flags and SWP_NOMOVE = 0) and IsWindowVisible(FHandle); // API
      Sized := (Message.WindowPos^.flags and SWP_NOSIZE = 0) and IsWindowVisible(FHandle);
      // 如果有边框,并且已经移动或者改变了尺寸,那么使边框无效
      if Framed and (Moved or Sized) then InvalidateFrame;  // 类函数 fixme 这不是重复了吗?
      // 仅仅调整边框不够,更主要是调整控件自己的位置
      if not (csDestroyingHandle in ControlState) then UpdateBounds; // 类函数,使用API调整控件在屏幕上的位置
    
      inherited; // super 三明治手法,调用程序员潜在的消息函数,并重新计算最大化最小化的限制和坞里的尺寸
    
      // fixme 根据消息的内容,再次使边框无效(如果有显示或隐藏标记的话)
      if Framed and ((Moved or Sized) or (Message.WindowPos^.flags and (SWP_SHOWWINDOW or SWP_HIDEWINDOW) <> 0)) then
        InvalidateFrame; // 类函数,简单调用API
    end;
    procedure TWinControl.InvalidateFrame;
    var
      R: TRect;
    begin
      R := BoundsRect; // 类属性,调用方法,简单计算
      InflateRect(R, 1, 1); // API
      InvalidateRect(Parent.FHandle, @R, True); // API
    end;

    留个爪,以后再详细研究~

  • 相关阅读:
    MyEclipse使用总结——MyEclipse10安装SVN插件
    SVN的安装和配置
    Git
    myeclipse 怎么安装与激活
    jQuery
    sql server 2008
    原问题:身份证为什么只有15位
    QTP10破解方法及mgn-mqt82.exe下载
    WARNING [Project: :app] To shrink resources you must also enable ProGuard
    your local changes would be overwritten by merge. commit stash or revert them to proceed. view them
  • 原文地址:https://www.cnblogs.com/findumars/p/4761148.html
Copyright © 2020-2023  润新知