处理滚动事件ListView(Win32 API)

时间:2016-12-21 15:23:25

标签: listview winapi events scroll

我已阅读了很多主题,但我找不到答案:

如何处理ListView中的滚动事件?

我尝试处理LVM_SCROLLWM_VSCROLLWM_SYSCOMMAND。但是,当我滚动ListView时,我的WinMainProc()WndProc()函数中没有收到这些消息。

我需要处理这些事件来修改Edit组件的坐标。我在WM_LBUTTONDBLCLK中创建了编辑,用于更改ListView的文本字段。如果编辑已经创建,并且我滚动ListView,则编辑组件的坐标错误。

program WinApi;

{$APPTYPE GUI}
{$MODE OBJFPC}

{$R Resource.rc}

uses
  Windows, Messages, commdlg;

const
  //
  idListView = 1025;

var
  //
  WndMsg: MSG;
  //
  MainWndDestroy: Boolean;
  //
  hMainWnd, hListViewWnd: HWND;

//
procedure InitCommonControls; external 'comctl32.dll' name 'InitCommonControls';

//
function MainWndProc(Wnd: HWND; uMsg: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; Stdcall; forward;

procedure CreateListView;
var
  //
  lc: LV_COLUMN;
  //
  lvi: LV_ITEM;
begin
  //
  hListViewWnd:=CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, '', WS_VISIBLE or WS_CHILD or LVS_REPORT or LVS_SHOWSELALWAYS, 8, 8, 264, 96, hMainWnd, idListView, 0, nil);

  //
  lc.mask:=LVCF_FMT or LVCF_TEXT or LVCF_WIDTH;
  //
  lc.fmt:=LVCFMT_LEFT;
  //
  lc.iSubItem:=0; lc.cx:=130;
  //
  lc.pszText:='Params';
  //
  SendMessage(hListViewWnd, LVM_INSERTCOLUMN, 0, lParam(@lc));

  //
  lc.pszText:='Values';
  //
  SendMessage(hListViewWnd, LVM_INSERTCOLUMN, 1, lParam(@lc));

  //
  lvi.mask:=LVIF_STATE or LVIF_TEXT;
  //
  lvi.state:=0;
  //
  lvi.stateMask:=0;
  //
  lvi.iItem:=0;
  //
  lvi.iSubItem:=0;
  //
  lvi.pszText:='Param #0';
  //
  lvi.cchTextMax:=8;
  //
  SendMessage(hListViewWnd, LVM_INSERTITEM, 0, LPARAM(@lvi));

  //
  lvi.iItem:=1;
  //
  lvi.pszText:='Param #1';
  //
  SendMessage(hListViewWnd, LVM_INSERTITEM, 0, LPARAM(@lvi));

  //
  lvi.iItem:=2;
  //
  lvi.pszText:='Param #2';
  //
  SendMessage(hListViewWnd, LVM_INSERTITEM, 0, LPARAM(@lvi));

  //
  lvi.iItem:=3;
  //
  lvi.pszText:='Param #3';
  //
  SendMessage(hListViewWnd, LVM_INSERTITEM, 0, LPARAM(@lvi));

  //
  lvi.iItem:=4;
  //
  lvi.pszText:='Param #4';
  //
  SendMessage(hListViewWnd, LVM_INSERTITEM, 0, LPARAM(@lvi));

  //
  lvi.iItem:=5;
  //
  lvi.pszText:='Param #5';
  //
  SendMessage(hListViewWnd, LVM_INSERTITEM, 0, LPARAM(@lvi));

  //
  ListView_SetItemText(hListViewWnd, 0, 1, 'Value #1');
end;

function MainWndCreate: Boolean;
var
  //
  ClassEx: TWndClassEx;
begin
  //
  Result:=False;

  //
  ClassEx.cbSize:=SizeOf(ClassEx);
  //
  ClassEx.style:=CS_DBLCLKS or CS_OWNDC;
  //
  ClassEx.lpfnWndProc:=WndProc(@MainWndProc);
  //
  ClassEx.cbClsExtra:=0;
  //
  ClassEx.cbWndExtra:=0;
  //
  ClassEx.hInstance:=HInstance;
  //
  ClassEx.hIconSm:=LoadIcon(0, IDI_APPLICATION);
  //
  ClassEx.hIcon:=LoadIcon(0, IDI_APPLICATION);
  //
  ClassEx.hCursor:=LoadCursor(0, IDC_ARROW);
  //
  ClassEx.hbrBackground:=CreateSolidBrush($d8e9ec);
  //
  ClassEx.lpszMenuName:=nil;
  //
  ClassEx.lpszClassName:='WinApiWnd';

  //
  if RegisterClassEx(ClassEx) = 0 then Exit;

  //
  hMainWnd:=CreateWindowEx(WS_EX_CONTROLPARENT, 'WinApiWnd', 'WinApi', WS_DLGFRAME or WS_SYSMENU, 100, 100, 640, 480, GetDesktopWindow, 0, HInstance, nil);

  //
  if hMainWnd = 0 then Exit;

  //
  InitCommonControls;

  //
  CreateListView;

  //
  ShowWindow(hMainWnd, SW_SHOW);
  //
  UpdateWindow(hMainWnd);
  //
  Result:=True;
end;

function MainWndProc(Wnd: HWND; uMsg: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; Stdcall;
begin
  //
  if Wnd = hMainWnd then
    //
    if uMsg = WM_DESTROY then
      //
      MainWndDestroy:=True;

  //
  if uMsg = WM_VSCROLL then
    //
    MessageBox(0, 'WM_VSCROLL', '', 0);

  //
  if uMsg = LVM_SCROLL then
    //
    MessageBox(0, 'LVM_VSCROLL', '', 0);

  //
  Result:=DefWindowProc(Wnd, uMsg, wParam, lParam);
end;

begin
  //
  MainWndDestroy:=False;

  //
  ZeroMemory(@WndMsg, SizeOf(WndMsg));

  //
  if MainWndCreate then
    //
    while GetMessage(WndMsg, 0, 0, 0) do
    begin
      //
      TranslateMessage(WndMsg);
      //
      DispatchMessage(WndMsg);

      //
      if MainWndDestroy then Exit;
    end;
end.

决定(由 Remy Lebeau ):

  

... ListView确实发送了LVN_BEGINSCROLL和LVN_ENDSCROLL通知   消息到其父窗口,因此这些消息将出现在   MainWndProc()

我定义了:     LVN_BEGINSCROLL = 4294967116; 因为它在Lazarus中定义不正确。

并在MainWndProc中添加代码: ...

//
if uMsg = WM_NOTIFY then
  begin
//
pnm:=PNMHDR(lPrm);

//
if pnm^.code = LVN_BEGINSCROLL then
//
SetWindowText(hMainWnd, 'LVN_BEGINSCROLL');
  end; 

这有效......

1 个答案:

答案 0 :(得分:3)

LVM_SCROLL不是通知消息,因此不会显示在MainWndProc()中。如果要在代码中手动滚动它,可以将该消息发送到ListView。但是,ListView会向其父窗口发送LVN_BEGINSCROLLLVN_ENDSCROLL个通知消息,因此这些消息将显示在MainWndProc()中。

WM_VSCROLL不是通知消息,因此它也不会出现在MainWndProc()中。为了接收ListView的WM_VSCROLL消息,您需要使用SetWindowLongPtr(GWL_WNDPROC)SetWindowSubclass()对ListView本身进行子类化。

话虽如此,您不需要在ListView上嵌入单独的EDIT控件来编辑ListView的项目。为了这个目的,ListView有一个内置的编辑器(参见LVM_EDITLABEL)。请注意,在报告模式下,内置编辑器仅编辑第一列中的数据,但您可以直接操作编辑器以允许编辑其他列中的数据。我编写了以下代码来使用Delphi中的TListView处理该问题,但您可以使用它来使用普通的Win32 API:

How to use the Build-in Editor of TListView to Edit SubItems