zoukankan      html  css  js  c++  java
  • 五种情况下会刷新控件状态(刷新所有子FWinControls的显示)——从DFM读取数据时、新增加子控件时、重新创建当前控件的句柄时、设置父控件时、显示状态被改变时

    五种情况下会刷新控件状态(刷新控件状态才能刷新所有子FWinControls的显示):

    在TWinControls.PaintControls中,对所有FWinControls只是重绘了边框,而没有整个重绘这些FWinControl子控件。那么什么时候才整个重绘全部FWinControls呢?这时候,就不是一个单纯的WM_PAINT来解决控件重绘的问题了,而是这个TWinControl.UpdateShowing函数:

    procedure TWinControl.UpdateShowing;
    var
      ShowControl: Boolean;
      I: Integer;
    begin
      ShowControl := (FVisible or (csDesigning in ComponentState) and
        not (csNoDesignVisible in ControlStyle)) and
        not (csReadingState in ControlState);
      if ShowControl then
      begin
        if FHandle = 0 then CreateHandle;
        if FWinControls <> nil then
          for I := 0 to FWinControls.Count - 1 do
            TWinControl(FWinControls[I]).UpdateShowing;
      end;
      if FHandle <> 0 then
        if FShowing <> ShowControl then
        begin
          FShowing := ShowControl;
          try
            Perform(CM_SHOWINGCHANGED, 0, 0);
          except
            FShowing := not ShowControl;
            raise;
          end;
        end;
    end;

    那么什么时候才会调用TWinControl.UpdateShowing;呢?回答是,就一种情况下:当控件状态改变的时候:

    procedure TWinControl.UpdateControlState;
    var
      Control: TWinControl;
    begin
      Control := Self;
      while Control.Parent <> nil do
      begin
        Control := Control.Parent;
        if not Control.Showing then Exit;
      end;
      if (Control is TCustomForm) or (Control.FParentWindow <> 0) then UpdateShowing; // 必须有父窗口,才给显示。TCustomForm那已经是顶级窗口
    end;

    那么什么时候算控件状态改变?回答是,一共五种情况:从DFM读取数据时、新增加子控件时、重新创建当前控件的句柄时、设置父控件时、显示状态被改变时:

    // 情况一:
    procedure TWinControl.ReadState(Reader: TReader);
    begin
      DisableAlign;
      try
        inherited ReadState(Reader);
      finally
        EnableAlign;
      end;
      FixupTabList;
      if FParent <> nil then Perform(CM_PARENTCTL3DCHANGED, 0, 0);
      UpdateControlState;
    end;
    
    // 情况二:
    procedure TWinControl.InsertControl(AControl: TControl);
    begin
      AControl.ValidateContainer(Self);
      Perform(CM_CONTROLLISTCHANGE, Integer(AControl), Integer(True));
      Insert(AControl);
      if not (csReading in AControl.ComponentState) then
      begin
        AControl.Perform(CM_PARENTCOLORCHANGED, 0, 0);
        AControl.Perform(CM_PARENTFONTCHANGED, 0, 0);
        AControl.Perform(CM_PARENTSHOWHINTCHANGED, 0, 0);
        AControl.Perform(CM_PARENTBIDIMODECHANGED, 0, 0);
        if AControl is TWinControl then
        begin
          AControl.Perform(CM_PARENTCTL3DCHANGED, 0, 0);
          UpdateControlState;
        end else
          if HandleAllocated then AControl.Invalidate;
        AlignControl(AControl);
      end;
      Perform(CM_CONTROLCHANGE, Integer(AControl), Integer(True));
    end;
    
    // 情况三:
    procedure TWinControl.CMRecreateWnd(var Message: TMessage);
    var
      WasFocused: Boolean;
    begin
      WasFocused := Focused;
      DestroyHandle;
      UpdateControlState;
      if WasFocused and (FHandle <> 0) then Windows.SetFocus(FHandle);
    end;
    
    // 情况四:
    procedure TWinControl.SetParentWindow(Value: HWnd); 
    begin
      if (FParent = nil) and (FParentWindow <> Value) then
      begin
        if (FHandle <> 0) and (FParentWindow <> 0) and (Value <> 0) then
        begin
          FParentWindow := Value;
          Windows.SetParent(FHandle, Value);
          if (Win32MajorVersion >= 5) and (Win32Platform = VER_PLATFORM_WIN32_NT) then
            Perform(WM_CHANGEUISTATE, MakeWParam(UIS_INITIALIZE, UISF_HIDEACCEL or UISF_HIDEFOCUS), 0);
        end else
        begin
          DestroyHandle;
          FParentWindow := Value;
        end;
        UpdateControlState;
      end;
    end;
    
    // 情况五:
    procedure TWinControl.CMVisibleChanged(var Message: TMessage);
    begin
      if not FVisible and (Parent <> nil) then RemoveFocus(False);
      if not (csDesigning in ComponentState) or
        (csNoDesignVisible in ControlStyle) then UpdateControlState;
    end;

    但是还是有个问题,在TWinControl.UpdateShowing里执行了CM_SHOWINGCHANGED消息,也就是:

    procedure TWinControl.CMShowingChanged(var Message: TMessage);
    const
      ShowFlags: array[Boolean] of Word = (
        SWP_NOSIZE + SWP_NOMOVE + SWP_NOZORDER + SWP_NOACTIVATE + SWP_HIDEWINDOW,
        SWP_NOSIZE + SWP_NOMOVE + SWP_NOZORDER + SWP_NOACTIVATE + SWP_SHOWWINDOW);
    begin
      SetWindowPos(FHandle, 0, 0, 0, 0, 0, ShowFlags[FShowing]);
    end;

    可是SetWindowPos会触发WM_PAINT消息吗?看MSDN没有这么说啊,那么显示所有WinControl子控件和调用它的WM_PAINT真正自绘,两者怎样才能联系起来呢?

  • 相关阅读:
    uestc Can You Help God Wu
    uestc 方老师开橙卡
    【JS】【24】监听鼠标滚轮事件
    【Java】【26】截取字符串
    【HTML&CSS】【5】点击号码可以调用手机拨号功能
    【JS】【23】on()绑定事件和off()解除绑定事件
    【Eclipse】【5】FreeMarker插件
    【Oracle】【18】获取数据库当前用户下所有表名和表名的注释
    【其他】【PL/SQL Developer】【2】报错Initialization error Could not load ".../oci.dll"解决方法
    【JDK】【1】下载官方版本
  • 原文地址:https://www.cnblogs.com/findumars/p/5361955.html
Copyright © 2011-2022 走看看