• Delphi控件的透明与不透明(要挨个解释一下原因),对InvalidateControl的关键理解


    procedure TForm1.Button3Click(Sender: TObject);
    begin
    if (csOpaque in ControlStyle) then ShowMessage('不透明')
    else ShowMessage('透明') // Form透明
    end;

    procedure TForm1.Button3Click(Sender: TObject);
    begin
    if (csOpaque in Panel1.ControlStyle) then ShowMessage('不透明') // Panel不透明
    else ShowMessage('透明')
    end;

    if (csOpaque in Button1.ControlStyle) then ShowMessage('不透明')
    else ShowMessage('透明') // Button透明

    if (csOpaque in label1.ControlStyle) then ShowMessage('不透明') // Label不透明
    else ShowMessage('透明')

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

    if (csOpaque in bitbtn1.ControlStyle) then ShowMessage('不透明')
    else ShowMessage('透明') // bitbtn1有没有内容都是透明

    http://bbs.2ccc.com/topic.asp?topicid=461248

    ---------------------------------------------------------------

    对InvalidateControl的关键理解:

    1.它是TControl的非虚函数,虽然它可以被TWinControl调用,但是根据VCL的其它代码,充分证明它实际上只能被图形子控件所使用:

    procedure TWinControl.RemoveControl(AControl: TControl);
    begin
      Perform(CM_CONTROLCHANGE, Integer(AControl), Integer(False)); // 通知父控件
      if AControl is TWinControl then
        with TWinControl(AControl) do
        begin
          RemoveFocus(True); // 类函数
          DestroyHandle; // important5 销毁它和它所有的子控件
        end
      else
        if HandleAllocated then
          AControl.InvalidateControl(AControl.Visible, False); // important5 让图形控件消失使用这种手法
      Remove(AControl); // 类函数
      Perform(CM_CONTROLLISTCHANGE, Integer(AControl), Integer(False)); // 通知父控件
      Realign;
    end;
    
    procedure TControl.DoDock(NewDockSite: TWinControl; var ARect: TRect);
    begin
      { Erase TControls before UpdateboundsRect modifies position }
      if not (Self is TWinControl) then InvalidateControl(Visible, False);
      if Parent <> NewDockSite then
        UpdateBoundsRect(ARect) // 类函数
      else
        BoundsRect := ARect; // 类属性
      if (NewDockSite = nil) or (NewDockSite = NullDockSite) then Parent := nil;
    end;

    2. 它的实际内容:

    procedure TControl.InvalidateControl(IsVisible, IsOpaque: Boolean);
    var
      bParentOpaque: Boolean;
      bChlipped: Boolean; 
      Rect: TRect;
    begin
      if (IsVisible or (csDesigning in ComponentState) and not (csNoDesignVisible in ControlStyle))
         and (Parent <> nil) and Parent.HandleAllocated then
      begin
        Rect := BoundsRect; // 类函数,简单计算(根据控件的长宽高)标签的坐标以及尺寸
        bParentOpaque := csOpaque in Parent.ControlStyle; // Form默认透明(csOpaque不在风格里)。但是父控件不一定是Form,不要思维僵化在这里。
        bChlipped:=BackgroundClipped; 
        // 实验说明后两个一般情况下都是False
        // 第三个参数为False,则保持背景不变。Not作用符以后,有三者条件之一成立即可,就会保持背景不变。
        // IsOpaque表示TControl自己不透明,完全遮住了父控件相应的区域,当然不用重绘背景
        // bParentOpaque表示父控件自己就是不透明的,现有的背景已经足够(不需要更新父父控件的背景),那么无论TControl子控件怎么办自绘,都不需要更新背景。
        // bChlipped 重合了
        // 反过来说,自己透明(而且有可能是从不透明变成透明),这时当然要重绘背景。因为原来那部分背景根本就没有绘制。
        //           父控件透明,也可以从不透明变成透明,这时也要背景重绘。fixme 如果父控件一直是透明的呢,那么每次绘制都要求父父控件背景重绘,因为父父控件的状态也有可能在改变。
        // fixme 有空仔细研究背景消息 才能深刻理解
        InvalidateRect(Parent.Handle, @Rect, not (IsOpaque or bParentOpaque or bChlipped)); // API
      end;
    end;

    关键在于最后一个参数,三个条件之一成立,结果就是false,就不需要重绘背景了。这三个条件分别是:

    1. 自身不透明(比如自身是Panel,或者自身是默认状态的标签),那么在自己的区域坐标内,自己可以随意重绘,而整个父控件的大背景不用变化。这个最容易理解。

    2. 父控件不透明(比如父控件是Panel),那么父控件的背景不用看别的控件脸色,子控件在上面无论怎么自绘,也不需要改变父控件的背景。这个也能理解。

    3. 兄弟控件的矩形区域与自己完全相同(也就是当前控件的区域坐标,与另一个z轴比它低、且不透明的兄弟控件的区域坐标完全一致,此时bChipped=true,此时当前控件的背景色要看这个兄弟控件的颜色即可,与父控件的颜色完全无关了)。这个也好理解,当前控件怎么自绘,都不影响和不需要父控件的背景。

    但是,如果透明标签放在Form上,那么IsOpaque=false, bParentOpaque=false, bChipped=false,那么此时就会重绘整个句柄的区域,而不仅仅是指定的部分。

    If the bErase parameter is TRUE for any part of the update region, the background is erased in the entire region, not just in the specified part.

  • 相关阅读:
    Java设计模式——单例模式
    关于 "static" 关键字的那点事
    安卓 修改系统时间
    android sdk 5.0下载步骤
    Android开发中调用系统窗口的方法
    Eclipse 导入已有工程时.classpath和.project文件拒绝访 ...
    Android开发错误总结
    CursorIndexOutOfBoundsException
    html移动端适配方案rem
    pc端和移动端的viewport 以及 像素的含义
  • 原文地址:https://www.cnblogs.com/findumars/p/4756420.html
Copyright © 2020-2023  润新知