编辑控件/组合框的窗口大小使用的MoveWindow或SetWindowPos时,不正确调整 [英] Window size of edit control/combobox is not properly adjusted when using MoveWindow or SetWindowPos

查看:374
本文介绍了编辑控件/组合框的窗口大小使用的MoveWindow或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 结构列表视图时不具有 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆