我已阅读了很多主题,但我找不到答案:
如何处理ListView中的滚动事件?
我尝试处理LVM_SCROLL
,WM_VSCROLL
和WM_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;
这有效......
答案 0 :(得分:3)
LVM_SCROLL
不是通知消息,因此不会显示在MainWndProc()
中。如果要在代码中手动滚动它,可以将该消息发送到ListView。但是,ListView会向其父窗口发送LVN_BEGINSCROLL
和LVN_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