Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Speeding Up the Tree Control

0.00/5 (No votes)
22 Aug 2000 1  
Some notes on speed issues with the MS Tree control

Introduction

I was in a situation where my application became slower than I expected. The reason, I found, was the tree control's speed.

First problem was in drawing. I used my own OnPaint, and used a trick you can find in many examples:

void CMyTreeCtrl::OnPaint()
{
    CPaintDC paintDc(this);

    CDC dc;
    dc.CreateCompatibleDC(&paintDc);

    CRect clientRect;
    GetClientRect(&clientRect);

    CBitmap bitmap;
    bitmap.CreateCompatibleBitmap(&paintDc, clientRect.right, clientRect.bottom);

    CBitmap *pOldBitmap = dc.SelectObject(& bitmap);

    CWnd::DefWindowProc(WM_PAINT, (WPARAM)dc.m_hDC, 0);

    dc.SetBkMode(TRANSPARENT);

    HTREEITEM hItem = GetFirstVisibleItem();

    while(hItem != NULL)
    {
        //do here what you want

        hItem = GetNextVisibleItem(hItem);
    }

    paintDc.BitBlt(0, 0, clientRect.right, clientRect.bottom, 
                   &dc, 0, 0, SRCCOPY);

    dc.SelectObject(pOldBitmap);

    // Do not call CTreeCtrl::OnPaint() for painting messages
}

If you plan to use many items, then change the "//do here what you want" part to this:

CRect rItemRect;
GetItemRect(hItem, &rItemRect, FALSE);
if(dc.RectVisible(rItemRect))
{
    //do here what you want
}
else
{
    break; //from while
}

This way, drawing speed improved.

Multiple Fonts

Maybe you will not believe it but there can be situations where the tree control can use two fonts. This happened (in non-Unicode case) when some items contained not-English characters.

These items were drawn with another font so my own drawing in client's rectangle was sometimes clipped. Both fonts sometimes displayed the problematic characters the same way, or sometimes the second font displayed them wrong way.

It only happened on some machines, and then this problem was in another system too. It helped to set the windows default language to that which uses all the problematic characters.

Back to the Speed Case

I found there are actions that are slow because of tree control's nature (or better their author's). All of the following speed problems will grow with item count, meaning a time dependency on item count is not linear but quadratic.

One of the slow operations was, as you can expect, InsertItem. To do something with this is difficult. When you have application where you will from time to time insert some items, then this will not be a problem.

What was worse, and for me surprising, was that a slower operation than InsertItem was DeleteItem. For me, what was interesting was the case of deleting all items from the tree.

Possibly you will say: Stupid man, I will not have this problem because:

  • I will use (optimized) DeleteAllItems, possibly with SetRedraw combination, or
  • I will never call any Delete because I have a tree in dialog so it will be automatically destroyed at its end, or
  • I will call DestoyWindow and than Create.

No one of these solutions will help you - they will all take similar time.

Hopefully, you will never have 65536 items in a MS tree control. Of course, this depends on machine speed but for full tree, it can take more than half hour to remove all items. If you think you will jump over it by using list-control solution (I know from message boards reading only), you will not win.

Trying to set the parent to NULL to eliminate possible DeleteItem notifications did not work either.

I started to experiment with own all items deleting. The funny thing is I never found a slower solution than DeleteAllItems. The best solution I found was this:

SetRedraw(FALSE) 
//find last first-level item
HTREEITEM i1 = GetRootItem();
HTREEITEM i2 = i1;
while(i2 != NULL)
{
  i1 = i2;
  i2 = GetNextItem(i1, TVGN_NEXT);
}
//remove from end
while( i1 != NULL)
{
  i2 = GetNextItem(i1, TVGN_PREVIOUS);
  DeleteItem(i1);
  i1 = i2;
}
SetRedraw(TRUE) 

Note that calling SetRedraw(..) before and after the repeated operations stops the control from redrawing the control each time its contents are changed. This is a standard trick and works with most of the Windows common controls (thanks to Steve Driessens for this).

Overall, it was little bit quicker but similar to DeleteAllItems - minutes are still minutes. Plus, it is possible that at your machine, with your OS version, your commctrl.dll version will be slower (or faster) than this. In newer Windows versions (W2K experience), the situation is better. Adding SetRedraw()s and with Expand(hItem, TVE_COLLAPSE)s before your deletions, you can get a more usable state (you can do this in W9x/NT, but it won't result in any further speedup).

Maybe you will not agree with my methods, or have or know something better - please let know.

As an aside, try to using the spy tool on the workspace window in Developer Studio. From the class name, you will see that it does not use the system tree control.

There are some quicker non-MS tree controls but most are not free. Using them without source ownership could possibly bring problems with new OS versions.

License

This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.

A list of licenses authors might use can be found here.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here