问题描述
引言:
我想实现可编辑的子项ListView控件。对于就地项目/子项目的编辑我用的编辑控件。
我相信,我已成功地妥善$上述项目/子项目的编辑控件的C $下将。
问题:
我不知道哪些事件我应该结束/取消子项目编辑(编辑隐藏控制,设置子项文本等),我应该怎么做。
的为了澄清,我说当用户结束时刻/取消在就地编辑。的
的此时编辑控件不再需要,所以我应该隐藏它(我不喜欢每次都重新创建它,我认为,一旦建立,然后显示/需要的时候隐藏它更有效)。 的
我是针对行为的属性窗口在Visual Studio中(见附件图像清楚地看到我指的是窗口)。
我要实现编辑/取消当用户presses ESC键/点击另一个窗口这个窗口不会以同样的方式/滚动条上点击等。
我的努力解决这个问题:
使用谷歌,我发现了几个例子,但他们都老了,不解决所有的相关案件,所以这就是为什么我问这里寻求帮助。
不过,我能发现,我必须考虑的一个事件是的,情况下,当用户presses ESC / ENTER 键,当用户点击超过编辑控件以外的东西的情况。
编辑:
我成功当用户点击另一个兄弟控制或交换机ALT + TAB窗口处理ESC和ENTER键,以及这种情况。我已经更新SSCCE有关修改
问:
为了实现默认行为一格(如果有一个用于Windows的应用程序),消息/事件必须我处理它?
的你能同时指出我应该在哪里编辑分项目,并隐藏编辑控件,并在那里我应该只是隐藏编辑控件?的
编辑:
我唯一的问题仍然是,当用户点击列表视图滚动条,或在主窗口的背景来处理这种情况。我只是不知道如何处理这一点,将AP preciate所有帮助我能。
相关信息:
我使用Visual Studio 2013,在Windows 7的x86;
我开发的C ++使用原始WinAPI的;
SSCCE
下面是解决方案,我至今。我试图彻底发表评论,但如果需要更多的信息发表评论,我会更新我的职务。
的#include<&WINDOWS.H GT;
#包括LT&;&windowsx.h GT; //各种列表视图宏等
#包括LT&;&CommCtrl.h GT;
#包括LT&;&stdio.h中GT; // swprintf_s()//启用视觉样式
的#pragma评论(连接/ manifestdependency:\\类型='win32的'\\
名称= Microsoft.Windows.Common - 控制版本='6.0.0.0'\\
的ProcessorArchitecture ='*'公钥='6595b64144ccf1df'\\
语言='*'\\)//与普通链接控件库
的#pragma评论(LIB,comctl32.lib)//全局变量
HINSTANCE HINST;//列表视图子类过程
LRESULT CALLBACK ListViewSubclassProc(HWND HWND,UINT的消息,
WPARAM wParam参数,LPARAM lParam的,
UINT_PTR uIdSubclass,DWORD_PTR dwRefData)
{
开关(消息)
{
案例WM_VSCROLL:
案例WM_HSCROLL:
//如果编辑控件具有焦点拿走,并给列表视图
如果(GetFocus()==函数GetDlgItem(的getParent(HWND),5000))
SetFocus的(HWND); //使用WM_NEXTDLGCTL为DialogBox的!!!!
打破;
案例WM_NCDESTROY:
:: RemoveWindowSubclass(HWND,ListViewSubclassProc,uIdSubclass);
返回DefSubclassProc(HWND,消息的wParam,lParam的);
}
返回:: DefSubclassProc(HWND,消息的wParam,lParam的);
}//为编辑控件类过程
LRESULT CALLBACK InPlaceEditControl_SubclassProc(HWND HWND,UINT的消息,WPARAM wParam参数,LPARAM lParam的,
UINT_PTR uIdSubclass,DWORD_PTR dwRefData)
{
开关(消息)
{
案例WM_GETDLG code:
返回(DLGC_WANTALLKEYS | DefSubclassProc(HWND,消息的wParam,lParam的));
案例WM_KILLFOCUS:
的ShowWindow(HWND,SW_HIDE);
返回DefSubclassProc(HWND,消息的wParam,lParam的);
案例WM_CHAR:
//处理该消息以避免消息发出蜂鸣声。
开关(wParam中)
{
案例VK_RETURN:
返回0L;
案例VK_ESCAPE:
返回0L;
默认:
返回:: DefSubclassProc(HWND,消息的wParam,lParam的);
}
打破;
案例WM_KEYDOWN:
开关(wParam中)
{
案例VK_RETURN:
{
//获取ListView控件的句柄
HWND hwndLV =函数GetDlgItem(的getParent(HWND),2000年);
//获取编辑控件的客户端矩形
RECT RC = {0};
GetClientRect(HWND,&安培; RC);
//因为编辑控件谎言项目矩形内
//我们可以测试任何坐标内编辑控件的
//客户端矩形
//我选择(rc.left,rc.top)
MapWindowPoints(HWND,hwndLV,(LPPOINT)及RC(的sizeof(RECT)/的sizeof(POINT)));
//获取项目和子项目指标
LVHITTESTINFO lvhti = {0};
lvhti.pt.x = rc.left;
lvhti.pt.y = rc.top;
ListView_SubItemHitTest(hwndLV,&安培; lvhti);
//获取编辑控件的文本
wchar_t的TXT [50] = L,;
Edit_GetText(HWND,TXT,50);
//编辑单元格文本
ListView_SetItemText(hwndLV,lvhti.iItem,lvhti.iSubItem,TXT);
//恢复焦点的ListView
//这触发EN_KILLFOCUS
//这将隐藏的编辑控件
SetFocus的(hwndLV);
}
返回0L;
案例VK_ESCAPE:
SetFocus的(函数GetDlgItem(的getParent(HWND),2000));
返回0L;
默认:
返回:: DefSubclassProc(HWND,消息的wParam,lParam的);
}
打破;
案例WM_NCDESTROY:
:: RemoveWindowSubclass(HWND,InPlaceEditControl_SubclassProc,uIdSubclass);
返回DefSubclassProc(HWND,消息的wParam,lParam的); }
返回:: DefSubclassProc(HWND,消息的wParam,lParam的);
}
//主窗口过程
LRESULT CALLBACK的WndProc(HWND HWND,UINT MSG,WPARAM wParam参数,LPARAM lParam的)
{
开关(MSG)
{
案例WM_CREATE:
{
// ================创建控件
RECT REC = {0};
GetClientRect(HWND,&安培; REC); HWND hwndLV =函数CreateWindowEx(0,WC_LISTVIEW,
L,WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPSIBLINGS | LVS_REPORT,
50,50,250,200,HWND,(HMENU)2000,HINST,0);
//到位编辑控件
HWND hwndEdit =函数CreateWindowEx(0,WC_EDIT,L,ES_AUTOHSCROLL | WS_CHILD | WS_BORDER,
200,265,100,25,HWND,(HMENU)5000,HINST,0);
//编辑控件必须具有相同的字体列表视图
HFONT HF =(HFONT)的SendMessage(hwndLV,WM_GETFONT,0,0);
如果(HF)
SendMessage函数(hwndEdit,WM_SETFONT,(WPARAM)HF,(LPARAM)TRUE);
//子类编辑控件,所以我们可以编辑子项与ENTER键,或者
//取消与ESC编辑
SetWindowSubclass(hwndEdit,InPlaceEditControl_SubclassProc,0,0);
//设置的扩展列表视图风格
ListView_SetExtendedListViewStyle(hwndLV,LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_DOUBLEBUFFER);
//子类的ListView
SetWindowSubclass(hwndLV,ListViewSubclassProc,0,0); //添加一些列
LVCOLUMN LVC = {0}; lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvc.fmt = LVCFMT_LEFT; 为(长参数nIndex = 0;参数nIndex小于5;参数nIndex ++)
{
wchar_t的TXT [50];
swprintf_s(TXT,50,L列%D,参数nIndex); lvc.iSubItem =参数nIndex;
lvc.cx = 60;
lvc.pszText = TXT; ListView_InsertColumn(hwndLV,参数nIndex,&安培; LVC);
} //添加一些项目
LVITEM LVI; lvi.mask = LVIF_TEXT; 为(lvi.iItem = 0; lvi.iItem&下; 10000; lvi.iItem ++)
{
为(长参数nIndex = 0;参数nIndex小于5;参数nIndex ++)
{
wchar_t的TXT [50];
swprintf_s(TXT,50,L项目%D,lvi.iItem,参数nIndex); lvi.iSubItem =参数nIndex;
lvi.pszText = TXT; 如果(!参数nIndex)//项目
SendDlgItemMessage(HWND,2000年,LVM_INSERTITEM,0,reinter pret_cast< LPARAM>(安培; LVI));
//其他分项
SendDlgItemMessage(HWND,2000年,LVM_SETITEM,0,reinter pret_cast< LPARAM>(安培; LVI));
}
}
}
返回0L;
案例WM_NOTIFY:
{
如果(((LPNMHDR)的lParam) - GT; code == NM_DBLCLK)
{
开关(((LPNMHDR)的lParam) - GT; idFrom)
{
案例2000://记住,这是我们的ListView控件的ID
{
LPNMITEMACTIVATE lpnmia =(LPNMITEMACTIVATE)lParam的; // SHIFT / ALT / CTRL /及其组合,不能是pressed
如果((lpnmia-> uKeyFlags || 0)== 0)
{
//店项目/子项目矩形
RECT RC = {0,0,0,0};
//帮手值,需要处理部分可见的物品
INT topIndex = ListView_GetTopIndex(lpnmia-> hdr.hwndFrom);
INT visibleCount = ListView_GetCountPerPage(lpnmia-> hdr.hwndFrom);
//如果产品垂直部分可见,使其完全可见
如果((topIndex + visibleCount)== lpnmia->的iItem)
{
//获取上述项目的矩形 - > lpnmia->的iItem - 1
ListView_GetSubItemRect(lpnmia-> hdr.hwndFrom,lpnmia->的iItem - 1,lpnmia-> iSubItem,LVIR_LABEL,和放大器; RC);
//保证点击的项目可见
ListView_EnsureVisible(lpnmia-> hdr.hwndFrom,lpnmia->的iItem,FALSE);
}
否则//产品完全可见,只得到了ectangle
ListView_GetSubItemRect(lpnmia-> hdr.hwndFrom,lpnmia->的iItem,lpnmia-> iSubItem,LVIR_LABEL,和放大器; RC); RECT RC客户机= {0}; //列表视图客户端矩形,如果项目部分可见的需要
GetClientRect(lpnmia-> hdr.hwndFrom,和放大器; RC客户机);
//产品水平部分可见 - >从右侧
如果(rcClient.right< rc.right)
{
//显示整个项目
ListView_Scroll(lpnmia-> hdr.hwndFrom,rc.right - rcClient.right,0);
//调整矩形,以便正确显示编辑控件
rc.left - = rc.right - rcClient.right;
rc.right = rcClient.right;
}
//产品水平部分可见 - >从左侧
如果(rcClient.left> rc.left)
{
//显示整个项目
ListView_Scroll(lpnmia-> hdr.hwndFrom,rc.left - rcClient.left,0);
//调整矩形,以便正确显示编辑控件
rc.right + = rcClient.left - rc.left;
rc.left = rcClient.left;
}
//现在是时候定位编辑控件,我们开始通过获取其窗口句柄
HWND hwndEdit =函数GetDlgItem(HWND,5000);
//获取项目的文本,并将其设置为编辑控件的文本
wchar_t的文[51];
ListView_GetItemText(lpnmia-> hdr.hwndFrom,lpnmia->的iItem,lpnmia-> iSubItem,文本,50);
Edit_SetText(hwndEdit,文字);
//选择全部文本
Edit_SetSel(hwndEdit,0,-1);
//地图列表视图客户矩形父矩形
//所以编辑控件可以妥善安置项目上方
MapWindowPoints(lpnmia-> hdr.hwndFrom,HWND,(LPPOINT)及RC(的sizeof(RECT)/的sizeof(POINT)));
//移动编辑控件
SetWindowPos(hwndEdit,HWND_TOP,rc.left,rc.top,rc.right - rc.left,
rc.bottom - rc.top,SWP_SHOWWINDOW);
//将焦点设置到我们的编辑控件
HWND previousWnd = SetFocus的(hwndEdit);
}
}
打破;
默认:
打破;
}
}
}
打破;
情况下WM_CLOSE:
::的DestroyWindow(HWND);
返回0L;
案例WM_DESTROY:
{
:: PostQuitMessage(0);
}
返回0L;
默认:
返回:: DefWindowProc函数(HWND,味精,的wParam,lParam的);
}
返回0;
}// WinMain函数
INT WINAPI的WinMain(HINSTANCE的hInstance,HINSTANCE ^ h prevInstance,LPSTR lpCmdLine,
INT的nCmdShow)
{
//店的hInstance为以后使用全局变量
HINST =实例句柄; WNDCLASSEX厕所;
HWND HWND;
MSG消息; //注册主窗口类
wc.cbSize = sizeof的(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc的;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = HINST;
wc.hIcon = LoadIcon(实例句柄,IDI_APPLICATION);
wc.hCursor =使用LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
wc.lpszMenuName = NULL;
wc.lpszClassName = LMain_Window
wc.hIconSm = LoadIcon(实例句柄,IDI_APPLICATION); 如果(RegisterClassEx(安培;!WC))
{
的MessageBox(NULL,L窗口注册失败!L错误!
MB_ICONEXCLAMATION | MB_OK); 返回0;
} //初始化通用控件
INITCOMMONCONTROLSEX iccex;
iccex.dwSize = sizeof的(INITCOMMONCONTROLSEX);
iccex.dwICC = ICC_LISTVIEW_CLASSES | ICC_STANDARD_CLASSES;
INITCOMMONCONTROLSEX(安培; iccex); //创建主窗口
HWND =函数CreateWindowEx(0,LMain_WindowL网格控制
WS_OVERLAPPEDWINDOW,50,50,400,400,NULL,NULL,的hInstance,0); 的ShowWindow(HWND,的nCmdShow);
UpdateWindow(HWND); 而(的GetMessage(安培;消息,NULL,0,0)大于0)
{
的TranslateMessage(安培;消息);
在DispatchMessage(安培;消息);
}
返回Msg.wParam;
}
更新:
在第二个想法,我在前面贴的方法是错误的。我认为这是设计错误,在这样的编辑框使用 SetCapture
,它可以与一堆其他东西干扰。我要删除我的旧的答案,pretend没有人看见了!
您自己的方法是罚款与检查 KILLFOCUS
,你只需要继承的ListView控件来检查滚动消息来模仿 LVN_XXXLABELEDIT
无效hideEdit(BOOL保存)
{
//保存或不...
的ShowWindow(hedit,SW_HIDE);
}LRESULT CALLBACK EditProc ...
{
如果(MSG == WM_KILLFOCUS)
hideEdit(1); 如果(MSG == WM_CHAR)
{
如果(wParam中== VK_ESCAPE){
hideEdit(0);
返回0;
}
如果(wParam中== VK_RETURN){
hideEdit(1);
返回0;
}
} 返回DefSubclassProc(...);
}LRESULT CALLBACK ListProc ...
{
如果(MSG == WM_VSCROLL ||味精== WM_HSCROLL)hideEdit(1);
返回DefSubclassProc(...);
}
INTRODUCTION:
I am trying to implement listview control with editable subitems. For in-place editing of items/subitems I use edit control.
I believe that I have managed to properly code placing of the edit control above item/subitem.
PROBLEM:
I do not know on which events I should end/cancel subitem editing ( hide edit control, set subitem text etc ) and how should I do it.
To clarify, I speak of the moment when user finishes/cancels in place editing.
At this point edit control is no longer needed, so I should hide it ( I do not like recreating it every time; I believe that creating it once and then showing/hiding it when needed is more efficient ).
I am targeting the behavior Properties window has in Visual Studio ( see attached image to see exactly the window I refer to ).
I want to achieve editing/canceling the same way this window does when user presses ESC key/clicks on another window/clicks on scrollbar etc.
MY EFFORTS TO SOLVE THIS:
Using Google, I found few examples but they are old and do not address all of the relevant cases, so that is why I ask here for help.
However, I was able to find out that one of the events I must consider are EN_KILLFOCUS
, case when user presses / key and the case when user clicks on something other than edit control.
EDIT:
I have managed to handle ESC and ENTER keys, as well as the case when user clicks on the another sibling control or switches windows with ALT + TAB. I have updated SSCCE with relevant changes
QUESTION:
In order to achieve default behavior for a grid ( if there is one for Windows apps ), which messages/events must I handle?
Can you also point out where should I edit subitem and hide edit control, and where should I just hide edit control?
EDIT:
My only problem remained is to handle the case when user clicks on the listview scrollbars, or on the background of the main window. I just do not know how to handle this and would appreciate all the help I can get.
RELEVANT INFORMATION:
I use Visual Studio 2013, on Windows 7 x86;
I am developing in C++ using raw WinAPI;
SSCCE:
Below is the solution I have so far. I have tried to thoroughly comment it, but if more info is required leave a comment and I will update my post.
#include <windows.h>
#include <windowsx.h> // various listview macros etc
#include <CommCtrl.h>
#include <stdio.h> // swprintf_s()
// enable Visual Styles
#pragma comment( linker, "/manifestdependency:\"type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' \
language='*'\"")
// link with Common Controls library
#pragma comment( lib, "comctl32.lib")
//global variables
HINSTANCE hInst;
// listview subclass procedure
LRESULT CALLBACK ListViewSubclassProc(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam,
UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (message)
{
case WM_VSCROLL:
case WM_HSCROLL:
// if edit control has the focus take it away and give to listview
if (GetFocus() == GetDlgItem(GetParent(hwnd), 5000))
SetFocus(hwnd); // use WM_NEXTDLGCTL for dialogbox !!!!
break;
case WM_NCDESTROY:
::RemoveWindowSubclass(hwnd, ListViewSubclassProc, uIdSubclass);
return DefSubclassProc(hwnd, message, wParam, lParam);
}
return ::DefSubclassProc(hwnd, message, wParam, lParam);
}
// subclass procedure for edit control
LRESULT CALLBACK InPlaceEditControl_SubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam,
UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (message)
{
case WM_GETDLGCODE:
return (DLGC_WANTALLKEYS | DefSubclassProc(hwnd, message, wParam, lParam));
case WM_KILLFOCUS:
ShowWindow(hwnd, SW_HIDE);
return DefSubclassProc(hwnd, message, wParam, lParam);
case WM_CHAR:
//Process this message to avoid message beeps.
switch (wParam)
{
case VK_RETURN:
return 0L;
case VK_ESCAPE:
return 0L;
default:
return ::DefSubclassProc(hwnd, message, wParam, lParam);
}
break;
case WM_KEYDOWN:
switch (wParam)
{
case VK_RETURN:
{
// get listview handle
HWND hwndLV = GetDlgItem(GetParent(hwnd), 2000);
// get edit control's client rectangle
RECT rc = { 0 };
GetClientRect(hwnd, &rc);
// since edit control lies inside item rectangle
// we can test any coordinate inside edit control's
// client rectangle
// I chose ( rc.left, rc.top )
MapWindowPoints(hwnd, hwndLV, (LPPOINT)&rc, (sizeof(RECT) / sizeof(POINT)));
// get item and subitem indexes
LVHITTESTINFO lvhti = { 0 };
lvhti.pt.x = rc.left;
lvhti.pt.y = rc.top;
ListView_SubItemHitTest(hwndLV, &lvhti);
// get edit control's text
wchar_t txt[50] = L"";
Edit_GetText(hwnd, txt, 50);
// edit cell text
ListView_SetItemText(hwndLV, lvhti.iItem, lvhti.iSubItem, txt);
// restore focus to listview
// this triggers EN_KILLFOCUS
// which will hide edit control
SetFocus(hwndLV);
}
return 0L;
case VK_ESCAPE:
SetFocus(GetDlgItem(GetParent(hwnd), 2000));
return 0L;
default:
return ::DefSubclassProc(hwnd, message, wParam, lParam);
}
break;
case WM_NCDESTROY:
::RemoveWindowSubclass(hwnd, InPlaceEditControl_SubclassProc, uIdSubclass);
return DefSubclassProc(hwnd, message, wParam, lParam);
}
return ::DefSubclassProc(hwnd, message, wParam, lParam);
}
// main window procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
{
//================ create controls
RECT rec = { 0 };
GetClientRect(hwnd, &rec);
HWND hwndLV = CreateWindowEx(0, WC_LISTVIEW,
L"", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPSIBLINGS | LVS_REPORT,
50, 50, 250, 200, hwnd, (HMENU)2000, hInst, 0);
// in place edit control
HWND hwndEdit = CreateWindowEx(0, WC_EDIT, L"", ES_AUTOHSCROLL | WS_CHILD | WS_BORDER,
200, 265, 100, 25, hwnd, (HMENU)5000, hInst, 0);
// edit control must have the same font as listview
HFONT hf = (HFONT)SendMessage(hwndLV, WM_GETFONT, 0, 0);
if (hf)
SendMessage(hwndEdit, WM_SETFONT, (WPARAM)hf, (LPARAM)TRUE);
// subclass edit control, so we can edit subitem with ENTER, or
// cancel editing with ESC
SetWindowSubclass(hwndEdit, InPlaceEditControl_SubclassProc, 0, 0);
// set extended listview styles
ListView_SetExtendedListViewStyle(hwndLV, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_DOUBLEBUFFER);
// subclass listview
SetWindowSubclass(hwndLV, ListViewSubclassProc, 0, 0);
// add some columns
LVCOLUMN lvc = { 0 };
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvc.fmt = LVCFMT_LEFT;
for (long nIndex = 0; nIndex < 5; nIndex++)
{
wchar_t txt[50];
swprintf_s(txt, 50, L"Column %d", nIndex);
lvc.iSubItem = nIndex;
lvc.cx = 60;
lvc.pszText = txt;
ListView_InsertColumn(hwndLV, nIndex, &lvc);
}
// add some items
LVITEM lvi;
lvi.mask = LVIF_TEXT;
for (lvi.iItem = 0; lvi.iItem < 10000; lvi.iItem++)
{
for (long nIndex = 0; nIndex < 5; nIndex++)
{
wchar_t txt[50];
swprintf_s(txt, 50, L"Item %d%d", lvi.iItem, nIndex);
lvi.iSubItem = nIndex;
lvi.pszText = txt;
if (!nIndex) // item
SendDlgItemMessage(hwnd, 2000, LVM_INSERTITEM, 0, reinterpret_cast<LPARAM>(&lvi));
else // sub-item
SendDlgItemMessage(hwnd, 2000, LVM_SETITEM, 0, reinterpret_cast<LPARAM>(&lvi));
}
}
}
return 0L;
case WM_NOTIFY:
{
if (((LPNMHDR)lParam)->code == NM_DBLCLK)
{
switch (((LPNMHDR)lParam)->idFrom)
{
case 2000: // remember, this was our listview's ID
{
LPNMITEMACTIVATE lpnmia = (LPNMITEMACTIVATE)lParam;
// SHIFT/ALT/CTRL/their combination, must not be pressed
if ((lpnmia->uKeyFlags || 0) == 0)
{
// store item/subitem rectangle
RECT rc = { 0, 0, 0, 0 };
// helper values, needed for handling partially visible items
int topIndex = ListView_GetTopIndex(lpnmia->hdr.hwndFrom);
int visibleCount = ListView_GetCountPerPage(lpnmia->hdr.hwndFrom);
// if item is vertically partially visible, make it fully visible
if ((topIndex + visibleCount) == lpnmia->iItem)
{
// get the rectangle of the above item -> lpnmia->iItem - 1
ListView_GetSubItemRect(lpnmia->hdr.hwndFrom, lpnmia->iItem - 1, lpnmia->iSubItem, LVIR_LABEL, &rc);
// ensure clicked item is visible
ListView_EnsureVisible(lpnmia->hdr.hwndFrom, lpnmia->iItem, FALSE);
}
else // item is fully visible, just get its ectangle
ListView_GetSubItemRect(lpnmia->hdr.hwndFrom, lpnmia->iItem, lpnmia->iSubItem, LVIR_LABEL, &rc);
RECT rcClient = { 0 }; // listview client rectangle, needed if item partially visible
GetClientRect(lpnmia->hdr.hwndFrom, &rcClient);
// item is horizontally partially visible -> from the right side
if (rcClient.right < rc.right)
{
// show the whole item
ListView_Scroll(lpnmia->hdr.hwndFrom, rc.right - rcClient.right, 0);
// adjust rectangle so edit control is properly displayed
rc.left -= rc.right - rcClient.right;
rc.right = rcClient.right;
}
// item is horizontally partially visible -> from the left side
if (rcClient.left > rc.left)
{
// show the whole item
ListView_Scroll(lpnmia->hdr.hwndFrom, rc.left - rcClient.left, 0);
// adjust rectangle so edit control is properly displayed
rc.right += rcClient.left - rc.left;
rc.left = rcClient.left;
}
// it is time to position edit control, we start by getting its window handle
HWND hwndEdit = GetDlgItem(hwnd, 5000);
// get item text and set it as edit control's text
wchar_t text[51];
ListView_GetItemText(lpnmia->hdr.hwndFrom, lpnmia->iItem, lpnmia->iSubItem, text, 50);
Edit_SetText(hwndEdit, text);
// select entire text
Edit_SetSel(hwndEdit, 0, -1);
// map listview client rectangle to parent rectangle
// so edit control can be properly placed above the item
MapWindowPoints(lpnmia->hdr.hwndFrom, hwnd, (LPPOINT)&rc, (sizeof(RECT) / sizeof(POINT)));
// move the edit control
SetWindowPos(hwndEdit, HWND_TOP, rc.left, rc.top, rc.right - rc.left,
rc.bottom - rc.top, SWP_SHOWWINDOW);
// set focus to our edit control
HWND previousWnd = SetFocus(hwndEdit);
}
}
break;
default:
break;
}
}
}
break;
case WM_CLOSE:
::DestroyWindow(hwnd);
return 0L;
case WM_DESTROY:
{
::PostQuitMessage(0);
}
return 0L;
default:
return ::DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
// WinMain
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
int nCmdShow)
{
// store hInstance in global variable for later use
hInst = hInstance;
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
// register main window class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
wc.lpszMenuName = NULL;
wc.lpszClassName = L"Main_Window";
wc.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, L"Window Registration Failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// initialize common controls
INITCOMMONCONTROLSEX iccex;
iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
iccex.dwICC = ICC_LISTVIEW_CLASSES | ICC_STANDARD_CLASSES;
InitCommonControlsEx(&iccex);
// create main window
hwnd = CreateWindowEx(0, L"Main_Window", L"Grid control",
WS_OVERLAPPEDWINDOW, 50, 50, 400, 400, NULL, NULL, hInstance, 0);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
Update:
On second thought, the method I posted earlier was wrong. I think it's design error to use SetCapture
in edit-box like that, it can interfere with bunch of other things. I am going to delete my old answer and pretend nobody saw it!
Your own method is fine with checking for KILLFOCUS
, you just need subclass for ListView to check scroll messages to mimic LVN_XXXLABELEDIT
void hideEdit(BOOL save)
{
//save or not...
ShowWindow(hedit, SW_HIDE);
}
LRESULT CALLBACK EditProc...
{
if (msg == WM_KILLFOCUS)
hideEdit(1);
if (msg == WM_CHAR)
{
if (wParam == VK_ESCAPE){
hideEdit(0);
return 0;
}
if (wParam == VK_RETURN){
hideEdit(1);
return 0;
}
}
return DefSubclassProc(...);
}
LRESULT CALLBACK ListProc...
{
if (msg == WM_VSCROLL || msg == WM_HSCROLL) hideEdit(1);
return DefSubclassProc(...);
}
这篇关于妥善处理与编辑子项目的ListView子项编辑(或子项编辑抵消)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!