interfaceuses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, 
  StdCtrls; type 
  TTransparentListBox = class(TListBox)
  private 
    { Private declarations } 
  protected 
    { Protected declarations } 
    procedure CreateParams(var Params: TCreateParams); override; 
    procedure WMEraseBkgnd(var Msg: TWMEraseBkgnd); message WM_ERASEBKGND; 
    procedure DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState); 
      override; 
  public 
    { Public declarations } 
    constructor Create(AOwner: TComponent); override; 
    procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override; 
  published 
    { Published declarations }
    property Style default lbOwnerDrawFixed; 
    property Ctl3D default False; 
    property BorderStyle default bsNone; 
  end; implementation constructor TTransparentListBox.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Ctl3D       := False;
  BorderStyle := bsNone;
  Style       := lbOwnerDrawFixed;  // changing it to lbStandard results
  // in loss of transparency
end;procedure TTransparentListBox.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  Params.ExStyle := Params.ExStyle or WS_EX_TRANSPARENT;
end;procedure TTransparentListBox.WMEraseBkgnd(var Msg: TWMEraseBkgnd);
begin
  Msg.Result := 1;           // Prevent background from getting erased
end;procedure TTransparentListBox.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
var
  tlbVisible: Boolean;
begin
  tlbVisible := (Parent <> nil) and IsWindowVisible(Handle);  // Check for   visibility
  if tlbVisible then ShowWindow(Handle, SW_HIDE);             // Hide-Move-Show    strategy
  inherited SetBounds(ALeft, ATop, AWidth, AHeight);          //  to prevent   background
  if tlbVisible then ShowWindow(Handle, SW_SHOW);             //  from   getting copied
end;procedure TTransparentListBox.DrawItem(Index: Integer; Rect: TRect;
  State: TOwnerDrawState);
var
  FoundStyle: TBrushStyle;
  R: TRect;
begin
  FoundStyle := Canvas.Brush.Style;       // Remember the brush style  R := Rect;                                     // Adapt coordinates of drawing   rect
  MapWindowPoints(Handle, Parent.Handle, R, 2);  //  to parent's coordinate   system
  InvalidateRect(Parent.Handle, @R, True);   // Tell parent to redraw the    item Position
  Parent.Update;                             // Trigger instant redraw   (required)  if not (odSelected in State) then
  begin  // If an unselected line is being      handled
    Canvas.Brush.Style := bsClear;  //   use a transparent background
  end
  else
  begin                          // otherwise, if the line needs to be     highlighted,
    Canvas.Brush.Style := bsSolid;  //   some colour to the brush is       essential
  end;  inherited DrawItem(Index, Rect, State); // Do the regular drawing and give   component users
  //  a chance to provide an    OnDrawItem handler  Canvas.Brush.Style := FoundStyle;  // Boy-scout rule No. 1: leave site as   you found it
end;
end.
参照网上的一段ListBox透明的代码,发现一个问题,在ListBox有数据时,的确可以整个ListBox透明,但是如果没数据不执行DrawItem则不会透明,有没有什么办法让ListBox在没数据的时候也可以透明

解决方案 »

  1.   

    一直都用一个比较邪恶的做法,就是在Clear的时候加上一个 Item.add(‘’)而后面添加数据的时候自动把这条删掉,但是治标不治本,想找个治本的办法
      

  2.   

    可以参考下 伴水大牛的 《屏幕画板》 里面有关透明的应该是截屏然后画到窗体上给人假象是透明的。http://topic.csdn.net/u/20110331/02/D6330B1C-B4B3-4DF1-836F-CB08B48EDFE9.html#r_73340803
      

  3.   

    从源码看,在WMPaint中对没数据的情况作了特殊处理,具体代码如下:procedure TCustomListBox.WMPaint(var Message: TWMPaint);  procedure PaintListBox;
      var
        DrawItemMsg: TWMDrawItem;
        MeasureItemMsg: TWMMeasureItem;
        DrawItemStruct: TDrawItemStruct;
        MeasureItemStruct: TMeasureItemStruct;
        R: TRect;
        Y, I, H, W: Integer;
    {$IF DEFINED(CLR)}
        LMessage: TMessage;
        LMeasureItemBuf: IntPtr;
        LDrawItemBuf: IntPtr;
    {$IFEND}
      begin
        if Items.Count = 0 then
        begin
          { Just fill it in with the color }
          with TBrush.Create do
          try
            Color := Self.Color;
            FillRect(Message.DC, ClientRect, Handle); //当没有数据时,这段代码往界面上填了东西
          finally
            Free;
          end;
          Exit;
        end;
    //...........................所以,解决办法是重写消息事件procedure WMPaint(var Message: TWMPaint); message WM_PAINT;在里面判断如果Items.Count=0,则触发父窗体的重绘,否则,调用继承的方法。
      

  4.   

    谢谢xinghun61,问题解决了
    在Items.Count=0时直接贴图到整个区域不同样也是透明效果么,以前一直都没转过弯来