• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

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

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

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.


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap