Adrian
Adrian

Reputation: 10911

How to stop the bottom scrollbar from a CListCtrl from displaying?

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.

Upvotes: 1

Views: 1147

Answers (2)

InsanityPants
InsanityPants

Reputation: 121

I'm facing the exact same issue, with the exact same Use Case.

To disable the horizontal scroll bar altogether, you add a message handler for WM_NCCALCSIZE

Using the Class Wizard this adds the following to your message map:

ON_WM_NCCALCSIZE()

In the implementation of this handler, you modify the style to disable the horizontal scroll bar.

void CMyListCtrl::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
{
    ModifyStyle(WS_HSCROLL, 0); // disable the horizontal scroll bar

    __super::OnNcCalcSize(bCalcValidRects, lpncsp);
}

In my own implementation of ResizeLastColumn(), which is similar to yours, I subtract ::GetSystemMetrics(SM_CXVSCROLL) from the width to account for the vertical scroll bar.

I realise this reply is rather late, but hopefully it will help someone.

(Edited to remove mentions of some problems I am having because a) they are off-topic and b) because I think they stem from me not using the Doc-View architecture and things not being wired up correctly as a result. I'm going to re-think my approach.)

Upvotes: 0

Barmak Shemirani
Barmak Shemirani

Reputation: 31599

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.

Upvotes: 2

Related Questions