VirtualTreeCtrl mixin class

Hi list,

For lists there’s the fabulous virtual mode of the list control. I want something similar for tree’s that works with wx.TreeCtrl, wx.gizmos.TreeListCtrl and Andrea’s CustomTreeCtrl. For consistencies sake, the API should look as similar to the OnGetItemXXX API of the virtual list control as possible. I have already done some work on this as part of Task Coach and there’s the examples on the Wiki, but I’d rather have it as a complete mixin class in wxPython. Also, the virtual tree in Task Coach refreshes parts of the tree that are not visible, so it can certainly be improved.

Who would be interested to work with me on this?

Cheers, Frank

Hi Frank,

For lists there's the fabulous virtual mode of the list control. I want
something similar for tree's that works with wx.TreeCtrl,
wx.gizmos.TreeListCtrl and Andrea's CustomTreeCtrl. For consistencies sake,
the API should look as similar to the OnGetItemXXX API of the virtual list
control as possible. I have already done some work on this as part of Task
Coach and there's the examples on the Wiki, but I'd rather have it as a
complete mixin class in wxPython. Also, the virtual tree in Task Coach
refreshes parts of the tree that are not visible, so it can certainly be
improved.

Who would be interested to work with me on this?

I would be surely interested, it would be a nice way to extend
CustomTreeCtrl and TreeListCtrl. Keep in mind, however, that my
mastering of Python/wxPython is far lower than yours. In any case,
apart of the example in the Wiki, do you have another example of the
work you did?

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.virgilio.it/infinity77/

···

On 1/11/07, Frank Niessink wrote:

I would be surely interested, it would be a nice way to extend
CustomTreeCtrl and TreeListCtrl. Keep in mind, however, that my
mastering of Python/wxPython is far lower than yours.

You’re way too modest!

In any case,
apart of the example in the Wiki, do you have another example of the

work you did?

Well, I didn’t do any of the examples in the Wiki, I just borrowed from them :wink: The TreeMixin in Task coach can be browsed here:
http://taskcoach.cvs.sourceforge.net/taskcoach/taskcoach/taskcoachlib/widgets/treectrl.py?revision=1.44&view=markup

However, that class, although it works with TreeCtrl, TreeListCtrl and CustomTreeCtrl, is far from perfect. It depends on other parts of Task Coach, it has an ugly API, it also provides for dragging and dropping (something for another mixin maybe?), etc.

Cheers, Frank

···

2007/1/11, Andrea Gavana andrea.gavana@gmail.com:

Hi Andrea, and any other interested people,

Here’s my first go at a virtual tree mixin. At the moment it only does text (so item images, fonts, colours, etc. are not refreshed). The API is quite small: subclass from both wx.TreeCtrl (other tree controls not yet tested) and VirtualTreeMixin and override OnGetItemText and OnGetChildrenCount. The only complicated issue as compared to a virtual list control is that a simple index doesn’t work for tree structures. So, to get the text for a specific item, or the number of children of specific item, the VirtualTreeMixin calls OnGetItemText or OnGetChildrenCount with a list of indices. The indices determine the item we’re talking about. For example, to get the text of the third child of the first child of the second root item, indices would be [1,0,2].

Comments welcome.

Cheers, Frank

PS: Should we take this off-list?

run.py (4.21 KB)

virtualtreemixin.py (5.17 KB)

VirtualTreeMixinDemo.py (2.37 KB)

VirtualTreeMixinTest.py (2.22 KB)

Here's a new version that also refreshes font, boldness, text colour,
background colour (although that doesn't seem to work for TreeListCtrl
and CustomTreeCtrl, suggestions anyone?), and images of items. It can
be mixed in with a regular TreeCtrl, a TreeListCtrl, and a
CustomTreeCtrl. See the demo. The main task to do next is to
'virtualize' the different attributes of CustomTreeCtrl-items like
Window, HyperText, Check-state, etc.

Cheers, Frank

run.py (4.21 KB)

virtualtreemixin.py (10 KB)

VirtualTreeMixinDemo.py (5.76 KB)

VirtualTreeMixinTest.py (2.41 KB)

···

2007/1/14, Frank Niessink <frank@niessink.com>:

Hi Andrea, and any other interested people,

Here's my first go at a virtual tree mixin. At the moment it only does text
(so item images, fonts, colours, etc. are not refreshed). The API is quite
small: subclass from both wx.TreeCtrl (other tree controls not yet tested)
and VirtualTreeMixin and override OnGetItemText and OnGetChildrenCount. The
only complicated issue as compared to a virtual list control is that a
simple index doesn't work for tree structures. So, to get the text for a
specific item, or the number of children of specific item, the
VirtualTreeMixin calls OnGetItemText or OnGetChildrenCount with a list of
indices. The indices determine the item we're talking about. For example, to
get the text of the third child of the first child of the second root item,
indices would be [1,0,2].

Hi Frank,

Here's a new version that also refreshes font, boldness, text colour,
background colour (although that doesn't seem to work for TreeListCtrl
and CustomTreeCtrl, suggestions anyone?), and images of items. It can
be mixed in with a regular TreeCtrl, a TreeListCtrl, and a
CustomTreeCtrl. See the demo. The main task to do next is to
'virtualize' the different attributes of CustomTreeCtrl-items like
Window, HyperText, Check-state, etc.

Very nice update! I have got one problem however: wxPython is throwing
a couple of impossible error. The first one comes in the DOS console:

wx.version: 2.8.1.1 (msw-ansi)
pid: 3616
21:33:52: Debug: ..\..\src\msw\treectrl.cpp(795): assert "tvItem->hItem != ((HTR
EEITEM)(ULONG_PTR)-0x10000)" failed in wxTreeCtrl::DoGetItem(): can't retrieve v
irtual root item
21:33:52: Debug: not enough space for wxSpinCtrl!

The second one comes in the classical Windows "fatal error" and it
looks like it wants to reformat my hard drive :wink: . It's a dialog with
a title like "wxWidgets debug alert", and it contains this error:

21:33:52: Debug: ..\..\src\msw\treectrl.cpp(795): assert "tvItem->hItem != ((HTR
EEITEM)(ULONG_PTR)-0x10000)" failed in wxTreeCtrl::DoGetItem(): can't retrieve v
irtual root item
Do you want to stop the program?
You can also choose [Cancel] to suppress further warnings.

??? That's a nice one, it's got the first place for the nicest error
message 2007 :wink:

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.virgilio.it/infinity77/

And this version doesn't crash on Windows XP (previous one was
developed on Mac OSX).

Cheers, Frank

run.py (4.21 KB)

virtualtreemixin.py (10.1 KB)

VirtualTreeMixinDemo.py (5.76 KB)

VirtualTreeMixinTest.py (2.41 KB)

···

2007/2/5, Frank Niessink <frank@niessink.com>:

2007/1/14, Frank Niessink <frank@niessink.com>:
> Hi Andrea, and any other interested people,
>
> Here's my first go at a virtual tree mixin. At the moment it only does text
> (so item images, fonts, colours, etc. are not refreshed). The API is quite
> small: subclass from both wx.TreeCtrl (other tree controls not yet tested)
> and VirtualTreeMixin and override OnGetItemText and OnGetChildrenCount. The
> only complicated issue as compared to a virtual list control is that a
> simple index doesn't work for tree structures. So, to get the text for a
> specific item, or the number of children of specific item, the
> VirtualTreeMixin calls OnGetItemText or OnGetChildrenCount with a list of
> indices. The indices determine the item we're talking about. For example, to
> get the text of the third child of the first child of the second root item,
> indices would be [1,0,2].

Here's a new version that also refreshes font, boldness, text colour,
background colour (although that doesn't seem to work for TreeListCtrl
and CustomTreeCtrl, suggestions anyone?), and images of items. It can
be mixed in with a regular TreeCtrl, a TreeListCtrl, and a
CustomTreeCtrl. See the demo. The main task to do next is to
'virtualize' the different attributes of CustomTreeCtrl-items like
Window, HyperText, Check-state, etc.

And the fun part is that that version works fine on Mac OSX/wxPython
2.8.1. Anyway, your message and my previous message apparently crossed
somewhere in cyberspace. The last version I mailed should work.

Cheers, Frank

···

2007/2/6, Andrea Gavana <andrea.gavana@gmail.com>:

Very nice update! I have got one problem however: wxPython is throwing
a couple of impossible error. The first one comes in the DOS console:

wx.version: 2.8.1.1 (msw-ansi)
pid: 3616
21:33:52: Debug: ..\..\src\msw\treectrl.cpp(795): assert "tvItem->hItem != ((HTR
EEITEM)(ULONG_PTR)-0x10000)" failed in wxTreeCtrl::DoGetItem(): can't retrieve v
irtual root item
21:33:52: Debug: not enough space for wxSpinCtrl!

The second one comes in the classical Windows "fatal error" and it
looks like it wants to reformat my hard drive :wink: . It's a dialog with
a title like "wxWidgets debug alert", and it contains this error:

21:33:52: Debug: ..\..\src\msw\treectrl.cpp(795): assert "tvItem->hItem != ((HTR
EEITEM)(ULONG_PTR)-0x10000)" failed in wxTreeCtrl::DoGetItem(): can't retrieve v
irtual root item
Do you want to stop the program?
You can also choose [Cancel] to suppress further warnings.

??? That's a nice one, it's got the first place for the nicest error
message 2007 :wink:

Hi Andrea, I was trying to add support for Italic items and it seems
like CustomTreeCtrl.SetItemItalic() isn't working. I tried it in the
wxPython demo (look for SetItemBold and replace by SetItemItalic) and
it doesn't work there either. Any ideas?

Cheers, Frank

···

2007/2/5, Frank Niessink <frank@niessink.com>:

Here's a new version that also refreshes font, boldness, text colour,
background colour (although that doesn't seem to work for TreeListCtrl
and CustomTreeCtrl, suggestions anyone?), and images of items. It can
be mixed in with a regular TreeCtrl, a TreeListCtrl, and a
CustomTreeCtrl. See the demo. The main task to do next is to
'virtualize' the different attributes of CustomTreeCtrl-items like
Window, HyperText, Check-state, etc.

Hi Frank,

Hi Andrea, I was trying to add support for Italic items and it seems
like CustomTreeCtrl.SetItemItalic() isn't working. I tried it in the
wxPython demo (look for SetItemBold and replace by SetItemItalic) and
it doesn't work there either. Any ideas?

It looks like the if condition at line 2493 in customtreectrl.py:

if itemFont != wx.NullFont:

is not True, i.e. the item font is really a wx.NullFont (!). I don't
know how this is possible, I mean, the items are drawn with a font
(whether it is the default system font or not I don't care), so the
font can't be a wx.NullFont. Failing that test, the subsequent lines
of code can't execute:

            if itemFont != wx.NullFont:
                style = wx.ITALIC
                if not italic:
                    style = ~style

                item.SetItalic(italic)
                itemFont.SetStyle(style)
                self.SetItemFont(item, itemFont)
                self._dirty = True

I don't know if there is a workaround, I am thinking about it.
However, the behavior of SetItemItalic is different from the
SetItemBold one. Maybe there is a way to make them share the same code
(or the same approach).

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.virgilio.it/infinity77/

Hi again Frank,

Hi Frank,

> Hi Andrea, I was trying to add support for Italic items and it seems
> like CustomTreeCtrl.SetItemItalic() isn't working. I tried it in the
> wxPython demo (look for SetItemBold and replace by SetItemItalic) and
> it doesn't work there either. Any ideas?

It looks like the if condition at line 2493 in customtreectrl.py:

if itemFont != wx.NullFont:

is not True, i.e. the item font is really a wx.NullFont (!). I don't
know how this is possible, I mean, the items are drawn with a font
(whether it is the default system font or not I don't care), so the
font can't be a wx.NullFont.

Ok, I think I found the problem. GetItemFont() returns something like:

item.Attr().GetFont()

Where Attr() is the TreeItemAttr class, where fonts and
foreground/background colours are set. The main problem is that, by
default, that class is initialized as:

class TreeItemAttr:
    """Creates the item attributes (text colour, background colour and font)."""

    def __init__(self, colText=wx.NullColour, colBack=wx.NullColour,
font=wx.NullFont):
        """
        Default class constructor.
        For internal use: do not call it in your code!
        """

        self._colText = colText
        self._colBack = colBack
        self._font = font

So, normally the item font (unless explicitely set by the programmer),
is really a wx.NullFont.
The simplest fix I can think of is to substitute the line:

self._font = font

With these 2 lines in the TreeItemAttr class initialization:

systemFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
self._font = (font == wx.NullFont and [systemFont] or [font])[0]

It works for me here. What do you all think?

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.virgilio.it/infinity77/

···

On 2/7/07, Andrea Gavana wrote:

Well, wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) returns a
smaller font than the default fonts used in the wx.TreeCtrl and the
wx.TreeListCtrl. Couldn't/Shouldn't you use wx.NORMAL_FONT instead?

Cheers, Frank

···

2007/2/7, Andrea Gavana <andrea.gavana@gmail.com>:

The simplest fix I can think of is to substitute the line:

self._font = font

With these 2 lines in the TreeItemAttr class initialization:

systemFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
self._font = (font == wx.NullFont and [systemFont] or [font])[0]

It works for me here. What do you all think?

On Mac OSX/wxPython 2.8.1 that is...

Cheers, Frank

···

2007/2/7, Frank Niessink <frank@niessink.com>:

Well, wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) returns a
smaller font than the default fonts used in the wx.TreeCtrl and the
wx.TreeListCtrl. Couldn't/Shouldn't you use wx.NORMAL_FONT instead?

Hi Frank,

> The simplest fix I can think of is to substitute the line:
>
> self._font = font
>
> With these 2 lines in the TreeItemAttr class initialization:
>
> systemFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
> self._font = (font == wx.NullFont and [systemFont] or [font])[0]
>
> It works for me here. What do you all think?

Well, wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) returns a
smaller font than the default fonts used in the wx.TreeCtrl and the
wx.TreeListCtrl. Couldn't/Shouldn't you use wx.NORMAL_FONT instead?

How does this modification relate to the other message you posted
today about TreeCtrls default fonts? I have no problem in making this
change, I just wanted to know if, by doing it, CustomTreeCtrl will be
consistent with the other 2 fellows treectrls...

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.virgilio.it/infinity77/

Hi Andrea, since the behaviour between TreeCtrl and TreeListCtrl is
not consistent, I really couldn't tell you what the best way forward
is. I hope Robin will chime in and enlighten us :wink:

Cheers, Frank

···

2007/2/7, Andrea Gavana <andrea.gavana@gmail.com>:

Hi Frank,

> Well, wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) returns a
> smaller font than the default fonts used in the wx.TreeCtrl and the
> wx.TreeListCtrl. Couldn't/Shouldn't you use wx.NORMAL_FONT instead?

How does this modification relate to the other message you posted
today about TreeCtrls default fonts? I have no problem in making this
change, I just wanted to know if, by doing it, CustomTreeCtrl will be
consistent with the other 2 fellows treectrls...

Andrea Gavana wrote:

The simplest fix I can think of is to substitute the line:

self._font = font

With these 2 lines in the TreeItemAttr class initialization:

systemFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
self._font = (font == wx.NullFont and [systemFont] or [font])[0]

It works for me here. What do you all think?

Does this mean that every item in the tree would have a font created for it? That could be a huge number for large trees... It is probably using reference counting on the C++ side so it would share the real font between them, but you'll still have the overhead of creating a Python proxy object that many times. I think I would leave it as wx.NullFont by default, and then later when you need to change the font attribute for an item you can just check for the NullFont and if the item doesn't have a real font yet create one for it and then modify the style as needed.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Hi Robin & All.

Andrea Gavana wrote:

> The simplest fix I can think of is to substitute the line:
>
> self._font = font
>
> With these 2 lines in the TreeItemAttr class initialization:
>
> systemFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
> self._font = (font == wx.NullFont and [systemFont] or [font])[0]
>
> It works for me here. What do you all think?

Does this mean that every item in the tree would have a font created for
it? That could be a huge number for large trees... It is probably
using reference counting on the C++ side so it would share the real font
between them, but you'll still have the overhead of creating a Python
proxy object that many times. I think I would leave it as wx.NullFont
by default, and then later when you need to change the font attribute
for an item you can just check for the NullFont and if the item doesn't
have a real font yet create one for it and then modify the style as needed.

Yes, you are right. Actually I didn't think about the impact of
creating thousands of wx.Fonts for big trees. However, I believe Frank
and me are trying to get a common base for the default font of all the
TreeCtrls wxPython has, so if you have any suggestion on how to
accomplish this I will be happy to hear it :smiley:

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.virgilio.it/infinity77/

···

On 2/8/07, Robin Dunn wrote: