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)
{
hItem = GetNextVisibleItem(hItem);
}
paintDc.BitBlt(0, 0, clientRect.right, clientRect.bottom,
&dc, 0, 0, SRCCOPY);
dc.SelectObject(pOldBitmap);
}
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))
{
}
else
{
break; }
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.
This 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 than this problem was in another system
too. It helped to set the windows default language to that what uses all the
problematic characters.
Back to the speed case.
I found there are actions what 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 was
interesting was the case of deleting all items from the tree.
Possibly you will say: Stupid man, I will have not 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 automaticaly detroyed at its end, or
- I will call
DestoyWindow and than Create.
No one of this 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)
HTREEITEM i1 = GetRootItem();
HTREEITEM i2 = i1;
while(i2 != NULL)
{
i1 = i2;
i2 = GetNextItem(i1, TVGN_NEXT);
}
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 it's 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 cound possibly bring problems with new OS
versions.