为什么制作的控件在Brush.Style设为bsClear时看不到控件后面的Form的栅格,而delphi提供的TShape却可以?
    我的控件是从TCustomControl直接继承的,在Paint方法中就是同样按TShape的Paint方法画框,Brush.Style设为bsClear,也还是把控件后面的Form的栅格挡住了,而TSaphe在这种状态下是透明的。请各位高手指点。先谢了!

解决方案 »

  1.   

    你看Paint事件,它根本没有涉及到Style。
    procedure TShape.Paint;
    var
      X, Y, W, H, S: Integer;
    begin
      with Canvas do
      begin
        Pen := FPen;
        Brush := FBrush;
        X := Pen.Width div 2;
        Y := X;
        W := Width - Pen.Width + 1;
        H := Height - Pen.Width + 1;
        if Pen.Width = 0 then
        begin
          Dec(W);
          Dec(H);
        end;
        if W < H then S := W else S := H;
        if FShape in [stSquare, stRoundSquare, stCircle] then
        begin
          Inc(X, (W - S) div 2);
          Inc(Y, (H - S) div 2);
          W := S;
          H := S;
        end;
        case FShape of
          stRectangle, stSquare:
            Rectangle(X, Y, X + W, Y + H);
          stRoundRect, stRoundSquare:
            RoundRect(X, Y, X + W, Y + H, S div 4, S div 4);
          stCircle, stEllipse:
            Ellipse(X, Y, X + W, Y + H);
        end;
      end;
    end;
    请参考它的Style事件。
    ========================
    procedure TShape.StyleChanged(Sender: TObject);
    begin
      Invalidate;
    end;========================
    跟踪过去,发现下面的代码。
    procedure TControl.Invalidate;
    begin
      InvalidateControl(Visible, csOpaque in ControlStyle);
    end;
    =======================
    继续跟踪,其实下面的代码我们已经不需要详细的追究它了。只要有上面的Code就OK。
    procedure TControl.InvalidateControl(IsVisible, IsOpaque: Boolean);
    var
      Rect: TRect;  function BackgroundClipped: Boolean;
      var
        R: TRect;
        List: TList;
        I: Integer;
        C: TControl;
      begin
        Result := True;
        List := FParent.FControls;
        I := List.IndexOf(Self);
        while I > 0 do
        begin
          Dec(I);
          C := List[I];
          with C do
            if C.Visible and (csOpaque in ControlStyle) then
            begin
              IntersectRect(R, Rect, BoundsRect);
              if EqualRect(R, Rect) then Exit;
            end;
        end;
        Result := False;
      end;begin
      if (IsVisible or (csDesigning in ComponentState) and
        not (csNoDesignVisible in ControlStyle)) and (Parent <> nil) and
        Parent.HandleAllocated then
      begin
        Rect := BoundsRect;
        InvalidateRect(Parent.Handle, @Rect, not (IsOpaque or
          (csOpaque in Parent.ControlStyle) or BackgroundClipped));
      end;
    end;
      

  2.   

    所以,请在你的控件中添加上StyleChange事件。当它的Style发生改变时,就触发Invalidate事件。重新刷新并且设置Style。
      

  3.   

    谢谢你,feng93017(Edge)!我忘了说明,我在Paint中是直接设置Brush.Style的,由定时器定时调用Invalidate,控件重画是没问题的,测试代码如下:with Canvas do
        begin
          Pen.Width:= 0;
          //if bColor then
           // begin
          //    Pen.Color:= FLineColor;
          //    Brush.Color:= FLineColor;
          //  end
          //else
          //  begin
          //    Pen.Color:= FFlowColor;
          //    Brush.Color:= FFlowColor;
          //  end;
          Brush.Style:= bsClear;        //测试用
          //Rectangle(X1,Y1,X2,Y2);
          Rectangle(0,0,Width,Height);   //测试用,但无法实现透明效果
        end;
      

  4.   

    控件重画是不需要你自己定义一个Timer来触发事件的。它有一个消息(事实上,自定义控件要用到很多的消息)是WM_PAINT,能自动定时或者在执行其他事件之后,比如:最大化、最小化时刷新。你只要覆盖它的这个消息就OK了。
      

  5.   

    谢谢,feng93017(Edge),我做的控件是与时间有关的,在设计状态是类似一根流动的线,定时器消息响应仅仅是调用Invalidate。但现在要命的是画出来的控件不是透明的。