be cautious, the ideas go straight into the cloud
Nice
Is there a way to make the lines 1) bolder so they’re actually visible when changing the background color to light yellow, 2) remove the checkbox before each item, or even 3) the “+” sign?
And also 1) open/close a sub-tree through the Enter key, 2) edit an existing item by just typing, 3) add a new item by hitting Enter, and 3) move items around the tree with ALT+arrow (left, right, up, down)?
For the curious, EccoPro can be downloaded here.
#TODO lines between items not visible when changing background color
custom_tree = CT.CustomTreeCtrl(self, agwStyle=wx.TR_DEFAULT_STYLE|wx.TR_MULTIPLE|CT.TR_AUTO_CHECK_CHILD|CT.TR_AUTO_CHECK_PARENT|CT.TR_ROW_LINES)
#TODO blue line 00FFFF #TR_ROW_LINES
custom_tree.SetBackgroundColour('#FFFFE8') #(255,0,0)
Hm, did twitter not change to X
- The colour of the lines is automatically calculated from the background colour. See line 7117 in
customtreectrl.py
:
if self.HasAGWFlag(TR_ROW_LINES):
# if the background colour is white, choose a
# contrasting colour for the lines
medium_grey = wx.Pen(wx.Colour(200, 200, 200))
dc.SetPen(((self.GetBackgroundColour() == wx.WHITE) and [medium_grey] or [wx.WHITE_PEN])[0])
dc.DrawLine(0, y_top, 10000, y_top)
dc.DrawLine(0, y, 10000, y)
If you tweak the background colour a bit (e.g. '#f0f0d0'
) then the lines become a bit more noticeable.
-
To remove the checkboxes you simply omit the
ct_type=1
from theAddItem()
calls. You then do not need to passCT.TR_AUTO_CHECK_CHILD or CT.TR_AUTO_CHECK_PARENT
toagwStyle
. -
The ‘+’ and ‘-’ signs (or black triangles on my linux box) are referred to as ‘buttons’ in the docs. The bitmask
wx.TR_DEFAULT_STYLE
on my linux box is set to 5 (might be different on other platforms). That means it includeswx.TR_HAS_BUTTONS
andwx.TR_NO_LINES
. You can’t bitwise-or it withwx.TR_NO_BUTTONS
because that has a value of zero.
Therefore I tried:
agwStyle=CT.TR_NO_BUTTONS|CT.TR_NO_LINES|wx.TR_MULTIPLE|CT.TR_ROW_LINES
which seemed to work. However you now can’t just expand/collapse the item’s children by clicking on its button. Instead, you can either use the right/left arrow keys or double-click the item.
Here is the modified example:
import wx
import wx.lib.agw.customtreectrl as CT
class MyFrame(wx.Frame):
def __init__(self, parent):
super().__init__(parent, -1, "CustomTreeCtrl Demo", size=(400, 600))
# Create a CustomTreeCtrl instance
custom_tree = CT.CustomTreeCtrl(self, agwStyle=CT.TR_NO_BUTTONS|CT.TR_NO_LINES|wx.TR_MULTIPLE|CT.TR_ROW_LINES)
custom_tree.SetBackgroundColour('#f0f0d0')
# Add a root node to it
root = custom_tree.AddRoot("The Root Item")
# Create an image list to add icons next to an item
def _bullet(colour, w=16, r=4):
bmp = wx.Bitmap((w, w))
dc = wx.MemoryDC(bmp)
dc.SetBackground(wx.Brush('black'))
dc.SetBrush(wx.Brush(colour, style=wx.BRUSHSTYLE_SOLID))
dc.DrawCircle(w//2, w//2, r)
del dc
bmp.SetMaskColour('black')
return bmp
b1 = _bullet('blue')
b2 = _bullet('green')
b3 = _bullet('red')
il = wx.ImageList(16, 16)
fldridx = il.Add(b1)
fldropenidx = il.Add(b2)
fileidx = il.Add(b3)
custom_tree.SetImageList(il)
custom_tree.SetItemImage(root, fldridx, wx.TreeItemIcon_Normal)
custom_tree.SetItemImage(root, fldropenidx, wx.TreeItemIcon_Expanded)
for x in range(15):
child = custom_tree.AppendItem(root, "Item %d" % x)
custom_tree.SetItemImage(child, fldridx, wx.TreeItemIcon_Normal)
custom_tree.SetItemImage(child, fldropenidx, wx.TreeItemIcon_Expanded)
for y in range(5):
last = custom_tree.AppendItem(child, "item %d-%s" % (x, chr(ord("a")+y)))
custom_tree.SetItem3State(last, True)
custom_tree.SetItemImage(last, fldridx, wx.TreeItemIcon_Normal)
custom_tree.SetItemImage(last, fldropenidx, wx.TreeItemIcon_Expanded)
for z in range(5):
item = custom_tree.AppendItem(last, "item %d-%s-%d" % (x, chr(ord("a")+y), z))
custom_tree.SetItemImage(item, fileidx, wx.TreeItemIcon_Normal)
custom_tree.Expand(root)
if __name__ == '__main__':
app = wx.App(0)
frame = MyFrame(None)
app.SetTopWindow(frame)
frame.Show()
app.MainLoop()
A possible alternative would be to use the HyperTreeList
class. I noticed in the example in the wxPython Demo there was a TR_FILL_WHOLE_COLUMN_BACKGROUND
which had a better contrast between the lines and the background. However, I can’t find any reference to that style in the docs?
Here is another idea.
Create a subclass of CustomTreeCtrl
and add a copy of the original PaintLevel()
method. Then modify that method so it chooses a better colour for the lines.
In the example below I just set the colour to grey: wx.Colour(200, 200, 200).
custom_tree_control_demo_7.py (11.2 KB)
As the docs for the CustomTreeCtrl say that wx.TR_DEFAULT_STYLE
should always be used, it’s probably better to pass:
wx.TR_DEFAULT_STYLE^CT.TR_HAS_BUTTONS|wx.TR_MULTIPLE|CT.TR_ROW_LINES
to agwStyle, rather than:
CT.TR_NO_BUTTONS|CT.TR_NO_LINES|wx.TR_MULTIPLE|CT.TR_ROW_LINES
EDIT: the forum software won’t let me post more than 2 consecutive replies, so I have added the following to this post…
I’ve been doing some experiments to see if I can find a simple alternative to the current algorithm used by the CustomTreeCtrl
to select a contrasting colour for the lines.
The problem with the current algorithm is that it sets the line colour as medium grey only if the background colour is pure white, otherwise it sets the line colour to white. This makes the lines impossible to see for any bright background colours that are not pure white.
My first attempt was to sum the background colour’s RGB values and set the line colour to medium grey if the sum was above a certain threshold, otherwise it set the line colour to white. This worked better than the current algorithm, but there were still some background colours where it didn’t work very well.
My second attempt was to use a version of a function that converts the RGB value to HSV, calculates the contrasting colour and then converts it back to RGB. [I can’t remember where I found the original of this function online].
Below is an app which can be used to test these 2 functions. When you move the RGB sliders, the background colour of the ContrastPanel
is changed and a Refresh()
is triggered. This cause the panel to redraw itself using the new colours.
You need to comment/uncomment the static methods used in OnPaint()
to test each one.
contrast_colour_2.py (3.6 KB)
Thanks much.
At this point, the only thing left is being able to open/close a sub-tree with the Enter key, and move items (up, down, left, right) in the tree with ALT+arrow keys
I’ll read up on wx.lib.agw.customtreectrl