编辑控件/组合框的窗口大小使用的MoveWindow或SetWindowPos时,不正确调整 [英] Window size of edit control/combobox is not properly adjusted when using MoveWindow or SetWindowPos
问题描述
我想实现可编辑的项目和子项目ListView控件。而不是常规列表视图看,项目和子项目应该有编辑控件,复选框或组合框。
I am trying to implement listview control with editable items and subitems. Instead of regular listview look, items and subitems should have edit control, checkbox or combo box.
的我使用的原料 WinAPI的
和 C ++
。我瞄准的Windows XP
开始。的
I am using raw WinAPI
and C++
. I am targeting Windows XP
onwards.
研究在这里和在互联网上后,我只能够找到 MFC
的例子。它们都使用 LVN_BEGINLABELEDIT
的技术来实现此行为。
After researching here and on the Internet, I was able to only find examples in MFC
. They all use LVN_BEGINLABELEDIT
technique to implement this behavior.
不幸的是,所以我决定从头开始(我认为这也有利于提高那些编程技巧的最好方法)我不完全理解这个概念。
Unfortunately I do not understand entirely this concept so I have decided to start from scratch ( I consider this also to be the best approach for improving ones programming skills ).
的我的概念:的
我决定赶 NM_DBLCLK
的ListView和使用从那里得到的坐标 ListView_GetItemRect
或 ListView_GetSubItemRect
宏。
I have decided to catch NM_DBLCLK
for listview and to get coordinates from there using ListView_GetItemRect
or ListView_GetSubItemRect
macro.
然后我会简单地移到相应项/子项(组合框/编辑控件/复选框将被创建为独立的,隐藏窗口)组合框/复选框/编辑控件。
Then I would simply move the combobox/checkbox/edit control over corresponding item/subitem ( combobox/edit control/checkbox would be created as separate, hidden windows ).
用户的输入完成后(由pressing输入或更改焦点)我只想隐藏组合框/复选框/编辑控件。
After user finishes with input ( by pressing enter or changing focus ) I would simply hide the combobox/checkbox/edit control.
的我目前的结果:的
目前,我坚持组合框/编辑控件/复选框不是一样的项目/子项目的尺寸,当项目/子项目上面移动的尺寸。
At the moment, I am stuck with the dimensions of combobox/edit control/checkbox not being the same as item/subitem dimensions, when moved above the item/subitem.
可以在下面提交了我的code例子加以改进,以适当地调整组合框/编辑控件/复选框窗口大小的项目/子项目的规模?现在,我将只专注于这问题的一部分,以保持这个问题尽可能短。
Can my code example submitted below be improved to properly adjust combobox/edit control/checkbox window size to the size of the item/subitem? For now, I will only focus on this part of the problem, to keep this question as short as possible.
下面是创建小型应用程序,说明了这个问题的指示。请注意,我试图让事情是微乎其微,因为我可以:
Here is the instruction for creating small application that illustrates the problem. Notice that I have tried to keep things as minimal as I could:
1)。在的Visual Studio
(我用 VS 2008中创建默认
)。 Win32的项目
1.) Create default Win32 project
in Visual Studio
( I use VS 2008
).
2)增加以下 WM_CREATE
处理程序主窗口的过程:
2.) Add the following WM_CREATE
handler to main window's procedure:
case WM_CREATE:
{
HWND hEdit = CreateWindowEx( 0,WC_EDIT, L"",
WS_CHILD | WS_VISIBLE | WS_BORDER | ES_CENTER | ES_AUTOHSCROLL,
250, 10, 100, 20, hWnd, (HMENU)1500, hInst, 0 );
HWND hComboBox = CreateWindowEx( 0,WC_COMBOBOX, L"",
WS_CHILD | WS_VISIBLE | WS_BORDER | CBS_DROPDOWNLIST,
100, 10, 100, 20, hWnd, (HMENU)1600, hInst, 0 );
HWND hwndLV = CreateWindowEx( 0, WC_LISTVIEW,
L"Editable Subitems",
WS_CHILD | WS_VISIBLE | WS_BORDER |
LVS_REPORT | LVS_SINGLESEL,
150, 100, 250, 150, hWnd, (HMENU)2000, hInst, 0 );
// set extended listview styles
ListView_SetExtendedListViewStyle( GetDlgItem( hWnd, 2000 ),
LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_DOUBLEBUFFER );
// add some columns
LVCOLUMN lvc = {0};
lvc.iSubItem = 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 + 1 );
lvc.iSubItem = nIndex;
lvc.cx = 60;
lvc.pszText = txt;
ListView_InsertColumn( GetDlgItem( hWnd,2000 ), nIndex, &lvc );
}
// add some items
LVITEM lvi;
lvi.mask = LVIF_TEXT;
lvi.iItem = 0;
for( lvi.iItem = 0; lvi.iItem < 10; lvi.iItem++ )
for (long nIndex = 0; nIndex < 5; nIndex++ )
{
wchar_t txt[50];
swprintf_s( txt, 50, L"Item %d%d", lvi.iItem + 1, nIndex + 1 );
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;
3)添加以下处理程序 WM_NOTIFY
在主窗口的过程:
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 )
{
// this is where we store item/subitem rectangle
RECT rc = { 0, 0, 0, 0 };
if( (lpnmia->iSubItem) <= 0 ) // this is item so we must call ListView_GetItemRect
{
// this rectangle holds proper left coordinate
// since ListView_GetItemRect with LVIR_LABEL flag
// messes up rectangle's left cordinate
RECT rcHelp = { 0, 0, 0, 0 };
// this call gets the length of entire row
// but holds proper left coordinate
ListView_GetItemRect( lpnmia->hdr.hwndFrom,
lpnmia->iItem, &rcHelp, LVIR_BOUNDS );
// this call gets proper rectangle except for the left side
ListView_GetItemRect( lpnmia->hdr.hwndFrom,
lpnmia->iItem, &rc, LVIR_LABEL );
// now we can correct the left coordinate
rc.left = rcHelp.left;
}
else // it is subitem, so we must call ListView_GetSubItemRect
{
ListView_GetSubItemRect( lpnmia->hdr.hwndFrom,
lpnmia->iItem, lpnmia->iSubItem,
LVIR_BOUNDS, &rc );
}
// convert listview client coordinates to parent coordinates
// so edit control can be properly moved
POINT p;
p.x = rc.left;
p.y = rc.top;
ClientToScreen( lpnmia->hdr.hwndFrom, &p );
ScreenToClient( hWnd, &p );
MoveWindow( GetDlgItem( hWnd, 1500 ),
p.x, p.y,
rc.right - rc.left,
rc.bottom - rc.top, TRUE );
// set focus to our edit control
HWND previousWnd = SetFocus( GetDlgItem( hWnd, 1500 ) );
}
}
break;
default:
break;
}
}
}
break;
这是结果我得到:
And this is the result I get:
您可以清楚地看到编辑控件的顶部和底部边框不正确绘制。至于组合框,宽度适当地调整,但高度保持相同。
You can clearly see that top and bottom border of the edit control are not drawn properly. As for combobox, the width is properly adjusted, but height remains the same.
我曾尝试替换的MoveWindow
与 SetWindowPos
,但结果是一样的调用。
I have tried substituting MoveWindow
call with SetWindowPos
but the result was the same.
进一步篡改后,我发现, NMITEMACTIVATE
错误返回矩形时的一个子项,如果列表视图没有LVS_EX_FULLROWSELECT风格组。您可以通过简单地注释掉在我设置这种风格我 WM_CREATE
处理部分看到这一点。也许我做错了什么,这错误可能我的code引起的,但我没有看到这个问题。
After further tampering, I have found out that NMITEMACTIVATE
bugs when returning the rectangle of a subitem, if listview doesn't have LVS_EX_FULLROWSELECT style set. You can see this by simply commenting out the part in my WM_CREATE
handler where I set this style. Maybe I am doing something wrong and this "bug" may be caused by my code, but I don't see the problem.
修改是在九月17日2014:
EDITED on September, 17th 2014:
有关测试值后的iItem
和 iSubItem
NMITEMACTIVATE $ C成员$ C>结构列表视图时不具有
LVS_EX_FULLROWSELECT
我可以验证该错误是不是在我的code。它总是返回的iItem
为0,无论哪个子项我点击。这解释了错误的行为,删除此风格的时候我得到了。
After testing the values for iItem
and iSubItem
members of NMITEMACTIVATE
structure when listview doesn't have LVS_EX_FULLROWSELECT
I can verify that the bug is not in my code. It always returns iItem
to be 0, no matter which subitem I click. This explains the faulty behavior I got when removing this style.
如果需要进行任何进一步的信息,请发表评论,我会尽快采取行动越好。
If any further info is required please leave a comment and I will act as soon as possible.
感谢您的时间和努力来帮助。
Thank you for your time and efforts to help.
推荐答案
您所面临的问题是多方面的。
The issue you're facing is multi-faceted.
首先,编辑控件的默认字体比列表视图中大(高)。你可以很平凡解决这个问题的,首先让从列表视图的字体,然后将其设置为编辑控件。那么这样做将使得控制的底部边框可见。
Firstly, the default font of the edit control is larger (higher) than that of the list-view. You can fix this one quite trivially, by first getting the font from the list-view and then setting it to the edit control. Doing this will then make the bottom border of the control visible.
接下来的问题是,编辑控件的插入符号需要一个像素的上面和下面,以确保该控件没有边界干扰。除了空间这1个像素然后需要在边境的另一像素。
The next issue is that the caret of the edit control needs a pixel above and below it, to ensure that the control doesn't have its borders interfered with. In addition to this 1 pixel of 'space' you then need another pixel for the border.
添加到这第二点,通过计算尺寸rc.right - rc.left
和 rc.bottom - rc.top
为1像素太小。认为开始于1,1并延伸至2,2一个矩形的 - 这是4个像素一个矩形 - 2宽2高。简单地减去顶部/从底部左/右会给你每次只有1个像素的宽度/高度。为了解决这个问题,就需要1添加到每个这些减法的。
Added to this second point, the dimensions calculated by rc.right - rc.left
and rc.bottom - rc.top
are 1 pixel too small. Think of a rect that starts at 1,1 and extends to 2,2 - this is a rect of 4 pixels - 2 wide and 2 high. Simply subtracting the top/left from the bottom/right would give you a width/height of only 1 pixel each. To fix this, you need to add 1 to each of these subtractions.
最后,由于插入符是每个项目/分项的客户区的确切高度,你需要做的编辑控制比项目/分项高2个像素,并启动<击> 1 击> 2的像素比现在确实较高。
Finally, since the caret is exactly the height of the 'client-area' of each item/sub-item, you need to make the edit control 2 pixels taller than the item/sub-item, and start 1 2 pixels higher than it does currently.
下面是输出的建议的更改,当我得到:
Here's the output I get when making the suggested changes:
和这里的更改/补充我的。
And here's the changes/additions I made.
1。获取/设置字体。(创建列表视图后,并设置其扩展样式之前插入)
1. Get/Set the font. (inserted after creating the list-view and before setting its extended style)
HFONT lvFont = (HFONT)SendDlgItemMessage(hWnd, 2000, WM_GETFONT, 0, 0);
SendDlgItemMessage(hWnd, 1500, WM_SETFONT, (WPARAM)lvFont, TRUE);
2。设置窗口位置/大小
MoveWindow( GetDlgItem( hWnd, 1500 ),
p.x, p.y-2,
1+ rc.right - rc.left,
1+ 2 + rc.bottom - rc.top, TRUE );
最后,对比这对从code输出原文:
Finally, contrast this against the original output from your code:
更新:
这里是外观的快照时使用内置的标签编辑功能(LVS_EDITLABELS风格)
UPDATE: Here's a snapshot of the appearance when the built-in label editing functionality is used (LVS_EDITLABELS style)
这篇关于编辑控件/组合框的窗口大小使用的MoveWindow或SetWindowPos时,不正确调整的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!