How to stop the bottom scrollbar from a CListCtrl

2019-07-31 01:09发布

I have a CListCtrl which is dynamically resized with the dialogue. I used a WM_SIZE message handler in the derived CListCtrl to resize the columns such that the total is the width of the control - 4, where the - 4 is to indicate the width of the border.

When I make the dialogue bigger, the control resizes correctly and I don't get the bottom scrollbar. However when I shrink the control, I sometimes get the horizontal scrollbar showing up.

void CMyListCtrl::OnSize(UINT nType, int cx, int cy)
{
    CListCtrl::OnSize(nType, cx, cy);
    ResizeLastColumn();
}

void CMyListCtrl::ResizeLastColumn()
{
    LVCOLUMN column;
    column.mask = LVCF_WIDTH;
    LONG maxWidth = 0;
    for (int i = 0; i < lastColumnIndex; ++i)
    {
        GetColumn(i, &column);
        maxWidth += column.cx;
    }
    CRect wndRect;
    GetWindowRect(&wndRect);

    SetColumnWidth(lastColumnIndex, wndRect.Width() - maxWidth - 4);
}

It is like the WM_SIZE message is getting to the control before the control is finally resized.

This is related to How to determine if a scrollbar for a CListCtrl is displaying?. However, this question is not dealing with the right scrollbar, and is assuming that it is not being displayed.

标签: mfc
1条回答
一纸荒年 Trace。
2楼-- · 2019-07-31 02:13

Resizing the window generates a message to test for horizontal scroll. SetColumnWidth will also generate the same message. It depends how ListView handles this internally, but a vertical scroll could also come in and go, this will change the client area, so the code may have to make recursive calls to figure out if the scroll should be visible or not. You can see this can easily run in to problems.

Try resizing the columns in WM_WINDOWPOSCHANGED, before calling the default procedure. Use SetRedraw to stop redundant paint messages.

ON_WM_WINDOWPOSCHANGED()
...
void CMyListCtrl::OnWindowPosChanged(WINDOWPOS *wpos)
{
    SetRedraw(FALSE);
    ResizeLastColumn();
    SetRedraw(TRUE);
    CListCtrl::OnWindowPosChanged(wpos);
}

You can use GetClientRect for the client area, then you don't need to subtract the border thickness (which is not always 4).

void ResizeLastColumn()
{
    int maxwidth = 0;
    int index = GetHeaderCtrl()->GetItemCount() - 1;
    for(int i = 0; i < index; ++i)
        maxwidth += GetColumnWidth(i);
    CRect rc;
    GetClientRect(&rc);
    SetColumnWidth(index, rc.Width() - maxwidth);
}

Also GetHeaderCtrl()->GetItemCount() returns the number of columns.

查看更多
登录 后发表回答