zoukankan      html  css  js  c++  java
  • 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;

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

  • 相关阅读:
    阿里DatatX mysql8往 Elasticsearch 7 插入时间数据 时区引发的问题
    通俗易懂 k8s (3):kubernetes 服务的注册与发现
    ReplicaSet 和 ReplicationController 的区别
    使用Go module导入本地包
    k8s之statefulset控制器
    终于成功部署 Kubernetes HPA 基于 QPS 进行自动伸缩
    Atitit drmmr outline org stat vb u33.docx Atitit drmmr outline org stat v0 taf.docx Atitit drmmr out
    Atitit all diary index va u33 #alldiary.docx Atitit alldiaryindex v1 t717 目录 1. Fix 1 2. Diary deta
    Atitit path query 路径查询语言 数据检索语言 目录 1.1. List map >> spel 1 1.2. Html数据 》》Css选择符 1 1.3. Json 》map》
    Atitit prgrmlan topic--express lan QL query lan表达式语言 目录 1. 通用表达语言(CEL) 1 1.1. 8.2 功能概述 1 1.2. Ongl
  • 原文地址:https://www.cnblogs.com/findumars/p/4761148.html
Copyright © 2011-2022 走看看