Phoenix icon indicating copy to clipboard operation
Phoenix copied to clipboard

wx.lib.gizmos.treelistctrl.TreeListCtrl -> TR_FULL_ROW_HIGHLIGHT not working like described

Open roland171281 opened this issue 4 years ago • 7 comments

Operating system: WIN64 / LIN64 wxPython version & source: 4.1.1 / 4.0.7 Python version & source: 3.8 / 3.7

Description of the problem: At wxpython2.8 TR_FULL_ROW_HIGHLIGHT colors the full row as desribed in the help -> https://docs.wxpython.org/wx.lib.gizmos.treelistctrl.TreeListCtrl.html?highlight=treelist#wx.lib.gizmos.treelistctrl.TreeListCtrl

TR_FULL_ROW_HIGHLIGHT | 0x2000 | Use this style to have the background colour and the selection highlight extend over the entire horizontal row of the tree control window.

At 4.x this does not work anymore, only the background of the text of the given cell is colored. See modified example of the demos below.

I think i found the problem in the code -> see hypertreelist.py@2972

            elif drawItemBackground:

                pass
                # We have to colour the item background for each column separately
                # So it is better to move this functionality in the subsequent for loop.

            else:
                dc.SetTextForeground(colText)

If I revert the code to 2.8 and change it slightly it works again:

            elif drawItemBackground:
                itemrect = wx.Rect(0, item.GetY() + off_h, total_w-1, total_h - off_h)
                dc.SetBrush(wx.Brush(colBg, wx.SOLID))
                # mod: DrawRectangle instead of DrawRectangleRect
                dc.DrawRectangle(itemrect)
                dc.SetTextForeground(colText)
            else:
                dc.SetTextForeground(colText)

Thanks for your work! BR Roland

Code Example (click to expand)

import wx
import wx.lib.gizmos as gizmos  # Formerly wx.gizmos in Classic

import images

#----------------------------------------------------------------------

class TestPanel(wx.Panel):
    def __init__(self, parent, log):
        self.log = log
        wx.Panel.__init__(self, parent, -1)
        self.Bind(wx.EVT_SIZE, self.OnSize)

        self.tree = gizmos.TreeListCtrl(self, -1, style=0, agwStyle=
                                        gizmos.TR_DEFAULT_STYLE
                                        #| gizmos.TR_HAS_BUTTONS
                                        #| gizmos.TR_TWIST_BUTTONS
                                        | gizmos.TR_ROW_LINES
                                        | gizmos.TR_COLUMN_LINES
                                        #| gizmos.TR_NO_LINES
                                        #| gizmos.TR_LINES_AT_ROOT
                                        | gizmos.TR_FULL_ROW_HIGHLIGHT
                                   )

        isz = (16,16)
        il = wx.ImageList(isz[0], isz[1])
        fldridx     = il.Add(wx.ArtProvider.GetBitmap(wx.ART_FOLDER,      wx.ART_OTHER, isz))
        fldropenidx = il.Add(wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN,   wx.ART_OTHER, isz))
        fileidx     = il.Add(wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, isz))
        smileidx    = il.Add(images.Smiles.GetBitmap())

        self.tree.SetImageList(il)
        self.il = il

        # create some columns
        self.tree.AddColumn("Main column")
        self.tree.AddColumn("Column 1")
        self.tree.AddColumn("Column 2")
        self.tree.SetMainColumn(0) # the one with the tree in it...
        self.tree.SetColumnWidth(0, 175)


        self.root = self.tree.AddRoot("The Root Item")
        self.tree.SetItemText(self.root, "col 1 root", 1)
        self.tree.SetItemText(self.root, "col 2 root", 2)
        self.tree.SetItemImage(self.root, fldridx, which = wx.TreeItemIcon_Normal)
        self.tree.SetItemImage(self.root, fldropenidx, which = wx.TreeItemIcon_Expanded)


        for x in range(15):
            txt = "Item %d" % x
            child = self.tree.AppendItem(self.root, txt)
            self.tree.SetItemText(child, txt + "(c1)", 1)
            self.tree.SetItemText(child, txt + "(c2)", 2)
            self.tree.SetItemImage(child, fldridx, which = wx.TreeItemIcon_Normal)
            self.tree.SetItemImage(child, fldropenidx, which = wx.TreeItemIcon_Expanded)

            for y in range(5):
                txt = "item %d-%s" % (x, chr(ord("a")+y))
                last = self.tree.AppendItem(child, txt)
                self.tree.SetItemText(last, txt + "(c1)", 1)
                self.tree.SetItemText(last, txt + "(c2)", 2)
                self.tree.SetItemImage(last, fldridx, which = wx.TreeItemIcon_Normal)
                self.tree.SetItemImage(last, fldropenidx, which = wx.TreeItemIcon_Expanded)

                for z in range(5):
                    txt = "item %d-%s-%d" % (x, chr(ord("a")+y), z)
                    item = self.tree.AppendItem(last,  txt)
                    self.tree.SetItemText(item, txt + "(c1)", 1)
                    self.tree.SetItemText(item, txt + "(c2)", 2)
                    self.tree.SetItemImage(item, fileidx, which = wx.TreeItemIcon_Normal)
                    self.tree.SetItemImage(item, smileidx, which = wx.TreeItemIcon_Selected)
                    # set color for first cell
                    self.tree.SetItemBackgroundColour(item, wx.Colour(240, 167, 167))

        self.tree.Expand(self.root)

        self.tree.GetMainWindow().Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
        self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnActivate)


    def OnActivate(self, evt):
        self.log.write('OnActivate: %s' % self.tree.GetItemText(evt.GetItem()))


    def OnRightUp(self, evt):
        pos = evt.GetPosition()
        item, flags, col = self.tree.HitTest(pos)
        if item:
            self.log.write('Flags: %s, Col:%s, Text: %s' %
                           (flags, col, self.tree.GetItemText(item, col)))

    def OnSize(self, evt):
        self.tree.SetSize(self.GetSize())


#----------------------------------------------------------------------

def runTest(frame, nb, log):
    win = TestPanel(nb, log)
    return win

#----------------------------------------------------------------------



overview = """<html><body>
<h2><center>TreeListCtrl</center></h2>

The TreeListCtrl is essentially a wx.TreeCtrl with extra columns,
such that the look is similar to a wx.ListCtrl.

</body></html>
"""


if __name__ == '__main__':
    #raw_input("Press enter...")
    import sys,os
    import run
    run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])


roland171281 avatar Jan 14 '22 06:01 roland171281

Not quite sure what you're talking about, it seems to work correctly for me. Can you include a picture of what you're seeing?

cbeytas avatar Jan 19 '22 22:01 cbeytas

Hi,

of course:

Here is a small demo to clarify:

Code Example (click to expand)
import wx
import wx.lib.agw.hypertreelist as hypertreelist
import wx.gizmos as gizmos

import random


class MyFrame(wx.Frame):
    def __init__(self, tree_type):

        wx.Frame.__init__(self, None, wx.ID_ANY)

        # Contains a HyperTreeList
        if wx.version().startswith("4"):
            if tree_type.startswith("hyper"):
                tree = hypertreelist.HyperTreeList(self, -1, style=0, agwStyle=hypertreelist.TR_DEFAULT_STYLE | hypertreelist.TR_HIDE_ROOT |
                                                                               hypertreelist.TR_FULL_ROW_HIGHLIGHT | hypertreelist.TR_ROW_LINES |
                                                                               hypertreelist.TR_COLUMN_LINES)
            else:
                tree = gizmos.TreeListCtrl(self, -1,  style=0, agwStyle=gizmos.TR_DEFAULT_STYLE | gizmos.TR_HIDE_ROOT | gizmos.TR_FULL_ROW_HIGHLIGHT |
                                                                        gizmos.TR_ROW_LINES | gizmos.TR_COLUMN_LINES)
        else:
            if tree_type.startswith("hyper"):
                tree = hypertreelist.HyperTreeList(self, -1, style=0, agwStyle=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT |
                                                                               wx.TR_FULL_ROW_HIGHLIGHT | wx.TR_ROW_LINES |
                                                                               wx.TR_HAS_VARIABLE_ROW_HEIGHT | wx.TR_NO_LINES |
                                                                               wx.TR_COLUMN_LINES)
            else:
                tree = gizmos.TreeListCtrl(self, -1, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT | wx.TR_FULL_ROW_HIGHLIGHT |
                                                           wx.TR_ROW_LINES | wx.TR_COLUMN_LINES)
        col_count = 10
        for i in range(col_count):
            tree.AddColumn("Column "+str(i))
        tree.SetMainColumn(0)

        root = tree.AddRoot("The root item")
        for i in range(2):
            child = tree.AppendItem(root, "platform "+str(i))
            for i in range(50):
                tree.SetItemBackgroundColour(child, wx.Colour(240, 167, 167))
                child_child = tree.AppendItem(child, "job "+str(i))
                for col in range(col_count):

                    tree.SetItemText(child_child, str(random.randrange(10)), col+1)
                for i in range(2):
                    tree.AppendItem(child_child, "diff "+str(i))




if __name__ == '__main__':

    app = wx.App(False)
    mainwin = MyFrame("hyper")
    #mainwin = MyFrame("gizmos")
    mainwin.Show(True)
    mainwin.SetSize((1100, 800))
    app.MainLoop()

wxpython2.8 - all cells are colors: wxpython2 8_row_colored

wxpython4.1.1 - only text of first cell is colored: wxpython4 1 1_row_NOT_colored

Of course, I can loop over all columns and set the background color by hand for each cell, but the help tells: TR_FULL_ROW_HIGHLIGHT | 0x2000 | Use this style to have the background colour and the selection highlight extend over the entire horizontal row of the tree control window.

You could also adapt the help, but keep in mind, that looping can be very slow for thousands of cells. If this behavior is too hidden, extracting the functionality to a "SetItemBackgroundColourForRow(item)" would be fine?

Hope this helps & BR Roland

roland171281 avatar Jan 20 '22 06:01 roland171281

Hi Roland, I have the same problem as you. In addition, wx.TR_MULTIPLE no longer has any effect in wxpython4.x.x. wx-3.0-msw works correctly. No changes in the code. I have been working with wx.TreeListCtrl for over 10 years.

I hope for a solution and remain with best regards Eckhardt

senior-py-developer avatar Jan 20 '22 21:01 senior-py-developer

This seems to be a misunderstanding with the addition of the TR_FILL_WHOLE_COLUMN_BACKGROUND feature. See PR #1338 and resulting bugfix PR #1389 I suppose the ideal behavior would be to fill the entire background if the TR_FULL_ROW_HIGHLIGHT flag is set, but not if the TR_FILL_WHOLE_COLUMN_BACKGROUND flag is also set.

@senior-py-developer I don't see an issue with TR_MULTIPLE for gizmos.treelistctrl. It seems to work fine in the demo and I can select multiple items. Can you file a separate bug with an example?

cbeytas avatar Jan 21 '22 06:01 cbeytas

@cbeytas Sorry, I hadn't found the TreeListCtrl in the demo. The problem was that I used style = wx.TR_MULTIPLE instead of agwstyle = gizmos.TR_MULTIPLE. Now it works again. I will not create an issue because of this.

senior-py-developer avatar Jan 21 '22 10:01 senior-py-developer

Could you test if the pull request fixes the highlight and behaves as you expect now?

cbeytas avatar Jan 23 '22 20:01 cbeytas

Hi,

I tested your request and it works like expected! Thank you very much!

BR Roland

roland171281 avatar Jan 24 '22 05:01 roland171281