listview的头部重画是一个历史遗留未解决的问题了,今天上午试验了下,能够重画了,但是效果不理想,在拉动分割条的时候,闪烁的厉害.我的解决方法只要通过子类消息截获然后重画.
问题主要出在:WM_PAINT 和 WM_NCPAINT:的处理上.请那位大虾帮忙解决.另外,还有就是在listview的行的重画上,如果谁有画当前选中行的方法,望告诉俺,如果解决必定高分送上.listview的stye 是report
下面是我的代码
unit Unit1;interfaceuses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, ImgList, StdCtrls;type
  TForm1 = class(TForm)
    ImageList1: TImageList;
    skinimg: TImageList;
    ListView1: TListView;
    procedure FormShow(Sender: TObject);
  private
    OldLVWndProc: TWndMethod;
    aMouseDown: Bool;    procedure SetupColumnToOwnerDraw();
    { Private declarations }
  public
    procedure NewLVWndProc(var Message: TMessage);
    { Public declarations }
  end;var
  Form1: TForm1;
var
  OldWndProc: Pointer;
  imgindex: integer;
  FormHandle: HWND;
  ISPaint: bool;
implementation
uses
  CommCtrl;
{$R *.dfm}procedure TForm1.SetupColumnToOwnerDraw();
var
  HeaderHandle: HWND;
  hdi: _HD_ITEM;
  i: integer;
begin
  HeaderHandle := GetDlgItem(ListView1.Handle, 0);
  for i := 0 to ListView1.Columns.Count - 1 do
  begin
    hdi.mask := HDI_TEXT + HDI_FORMAT + HDI_WIDTH;
 //    hdi.fmt := HDF_LEFT + HDF_OWNERDRAW + HDF_STRING;
    hdi.cxy := ListView1.Columns.Items[i].Width;
    hdi.cchTextMax := Length(ListView1.Columns.Items[i].Caption);
    hdi.pszText := PChar(ListView1.Columns.Items[i].Caption);
    hdi.hbm := ImageList1.GetImageBitmap; //();
    hdi.iImage := ListView1.Columns.Items[i].ImageIndex;
    hdi.fmt := DT_END_ELLIPSIS;
    Header_SetItem(HeaderHandle, i, hdi);
  end;end;procedure TForm1.NewLVWndProc(var Message: TMessage);
var
  dis: ^DRAWITEMSTRUCT;
  Rect: TRect;
  FCanvas: TCanvas;
  LVOffset: integer;
  ColCaption: string;
  pubbitmap: Tbitmap;
begin
  LVOffset := 0;
/////////////////////////////////////
  case message.Msg of    WM_DRAWITEM:
      begin
        dis := Pointer(Message.lParam);
        FCanvas := TCanvas.Create;
        FCanvas.Handle := dis.hDC;
        Rect := TRect(dis.rcItem);
        if (ListView1.SmallImages <> nil) and (ListView1.Columns.Items[dis.itemID].ImageIndex <> -1) then
        begin
          LVOffset := 16 + 12;
          ListView1.SmallImages.Draw(FCanvas, Rect.Left + 6, Rect.Top + 1,
            ListView1.Columns.Items[dis.itemID].ImageIndex, true);
        end;
        FCanvas.Font.Assign(ListView1.Font);
        FCanvas.Brush.Style := bsClear;
       // fcanvas.FillRect(Rect);
        ColCaption := ListView1.Columns.Items[dis.itemID].DisplayName;
        Rect.Left := Rect.Left + 1 + LVOffset;
        Rect.Top := Rect.Top;
        pubbitmap := Tbitmap.Create;
        skinimg.GetBitmap(imgindex, pubbitmap);
        FCanvas.StretchDraw(Rect, pubbitmap);
        DrawTextEx(
          FCanvas.Handle,
          PChar(ColCaption),
          Length(ColCaption),
          Rect,
          DT_CENTER or DT_BOTTOM,
          nil);
        FCanvas.Free;
        pubbitmap.Free;
        Message.Result := 1;
      end;
    WM_NCPAINT:
      begin
        if (ListView1.ViewStyle = vsReport) then
        begin
      //ÏȽøÐÐÕý³£»­
          OldLVWndProc(Message);
       //ÿһ´Î»­ÍêÖ®ºó¶¼±ØÐëÖØÐÂÉèÖÃÊôÐÔ
          SetupColumnToOwnerDraw();
       //ÔÙ»­
          OldLVWndProc(Message);
        end;
      end;
    WM_PAINT:
      begin
    //    if ISPaint then
        SetupColumnToOwnerDraw();        OldLVWndProc(Message);
      end;
  end;
  OldLVWndProc(Message);
end;function LVHeaderWndProc(hWnd: HWND; Msg, wParam, lParam: Longint): Longint; stdcall;
begin
  case Msg of
    WM_CAPTURECHANGED:
      begin
        imgindex := 0;
        postmessage(hwnd, WM_PAINT, 0, 0, );
      end;
    WM_NCHITTEST: //Êó±êÒƶ¯³ö±ß½ç
      begin
        imgindex := 0;
        postmessage(hwnd, WM_PAINT, 0, 0, );
      end;
    WM_NCDESTROY:
      begin
        Result := CallWindowProc(OldWndProc, HWND, Msg, wParam, lParam); //    FHeaderHandle := 0;
      end;    WM_LBUTTONDOWN:
      begin
        imgindex := 1;
        postmessage(hwnd, WM_PAINT, 0, 0, );
      end;
    WM_MOUSEMOVE:
      begin
        ISPaint := false;
      end;
    HDM_GETITEMRECT: //´óС¸Ä±äµÄʱºò·¢Éú´ËÏûÏ¢
      begin
       // ISPaint := false;
      //  postmessage(hwnd, WM_PAINT, 0, 0, );
      end;    HDM_ORDERTOINDEX:
      begin
    //    ISPaint := false;
      //  postmessage(hwnd, WM_PAINT, 0, 0, );
      end;
    WM_SETCURSOR: //Êó±ê½øÈë,»á¶à´ÎÒý·¢´ËÏûÏ¢
      begin
//        imgindex := 2;
 //       postmessage(hwnd, WM_PAINT, 0, 0, );
      end;
    WM_ERASEBKGND:
      begin
        ISPaint := true;
      end;    WM_lBUTTONUP: //Êó±ê×ó¼üËÉ¿ª
      begin
    //    ISPaint := true;
        imgindex := 0;
        postmessage(hwnd, WM_PAINT, 0, 0, );
      end;
  end;
  Result := CallWindowProc(OldWndProc, HWND, Msg, wParam, lParam);
end;procedure TForm1.FormShow(Sender: TObject);
var HeaderHandle: HWND;
begin
  OldLVWndProc := ListView1.WindowProc;
  ListView1.WindowProc := NewLVWndProc;  HeaderHandle := GetDlgItem(ListView1.Handle, 0);
  OldWndProc := Pointer(SetWindowlong(HeaderHandle, GWL_WNDPROC, Integer(@LVHeaderWndProc)));
end;end.

解决方案 »

  1.   


    procedure TFrmTmp.ListViewNewWndProc(var Msg: TMessage);
    var
      hdn: ^THDNotify;
    begin
      if Msg.Msg=WM_NOTIFY then
      begin
        hdn := Pointer(Msg.lParam);
        if (hdn.hdr.code=HDN_BeginTrackW)or(hdn.hdr.code=HDN_BeginTrackA) then
        begin//ListView 抬头开始拖动消息
          HeadDraging := True;
        end
        else if (hdn.hdr.code=HDN_EndTrackW)or(hdn.hdr.code=HDN_EndTrackA) then
        begin//ListView 抬头结束拖动消息
          LvAdv.Repaint;
          HeadDraging := false;
        end
        else
          FListViewOldWndProc(Msg);
      end
      else if Msg.Msg=WM_SETFOCUS then
      begin//无法得到焦点请注消下面一行代码
        FListViewOldWndProc(Msg);
      end
      else
        FListViewOldWndProc(Msg);
    end;
      

  2.   

    抖动厉害的话,提一种可能的情况,我以前做图片重绘时遇到过类似情况ListView本身从TWinControl开始处理WM_PAINT消息的,之后在TCustomListView上再次绘制,你如果是从TListView下继承绘制,或是直接在OnPaint上写(ListView好像没OnPaint,反正就是ListView的绘制事件),势必是需要先重新做一次TCustomView的绘制,再来做你自己的绘制,这样当然会抖动。解决办法就是直接截取WM_PAINT消息自己绘,或继承重写(Override)绘制相关的代码。
      

  3.   

    begin
    ...
      case message.Msg of
        WM_PAINT:
          begin
        //    if ISPaint then
            SetupColumnToOwnerDraw();        OldLVWndProc(Message);
          end;
      end;
      OldLVWndProc(Message);
    end;....
    你这不是执行了2次 OldLVWndProc(Message); 重绘2次?
      

  4.   

    这个问题我已经完美解决,加上listview行重绘,效果比迅雷的还好看...
    哈哈,谢谢大家关注.