Phoenix icon indicating copy to clipboard operation
Phoenix copied to clipboard

New gizmos.TreeListCtrl much slower than 2.8 version

Open roland171281 opened this issue 3 years ago • 5 comments

Operating system: LIN64 / WIN64 wxPython version & source: 2.8 / 4.1.1 Python version & source: 2.7 / 3.8

Description of the problem:

The new version of the TreeListCtrl (only a compatibility wrapper based on hypertreelist) is much slower, if it gets big (1000 entries +). With slow I mean it takes long to be filled and is very laggy at scrolling, opening subchilds, ...

I tested the hypertreelist in wxpython2.8 and it's the same behavior. Only the TreeListCtrl is fast at 2.8

Please see example below. You can switch between hypertreelist / treelistctrl in the main It runs with 2.8 / 4.1.1

Thank you for your work and best regards Roland

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)

        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(5000):
                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()

roland171281 avatar Jan 17 '22 05:01 roland171281

I spent some time profiling the hypertreelist and I think that there are several things which could be done more efficiency.

1. Initial opening of the example:

- if i remove the self.CalculateSize(item, dc)@4139 the opening time is reduced from about 20sec to 2secs
- I think he calculates the size of all element even if they are not drawn

2. Opening/closing the first level a few times:

- snakeviz shows, that the time is also spent in CalculateSize again
- and in this Function the time is mostly spent in GetFullMultiLineTextExtent
Profile Output (click to expand)
Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
  3962                                               @profile
  3963                                               def CalculateSize(self, item, dc):
  3964                                                   """
  3965                                                   Calculates overall position and size of an item.
  3966                                           
  3967                                                   :param `item`: an instance of :class:`TreeListItem`;
  3968                                                   :param `dc`: an instance of :class:`wx.DC`.
  3969                                                   """
  3970     20016      22433.0      1.1      0.4          if item.IsHidden():
  3971                                                       # Hidden items have a height of 0.
  3972                                                       item.SetHeight(0)
  3973                                                       return
  3974                                           
  3975     20016      19459.0      1.0      0.4          attr = item.GetAttributes()
  3976                                           
  3977     20016      11314.0      0.6      0.2          if attr and attr.HasFont():
  3978                                                       dc.SetFont(attr.GetFont())
  3979     20016      20974.0      1.0      0.4          elif item.IsBold():
  3980                                                       dc.SetFont(self._boldFont)
  3981                                                   else:
  3982     20016      38255.0      1.9      0.8              dc.SetFont(self._normalFont)
  3983                                           
  3984     20016      13785.0      0.7      0.3          text_w = text_h = wnd_w = wnd_h = 0
  3985    220176     158835.0      0.7      3.1          for column in range(self.GetColumnCount()):
  3986    200160    3269190.0     16.3     64.2              w, h, dummy = dc.GetFullMultiLineTextExtent(item.GetText(column))
  3987    200160     280539.0      1.4      5.5              text_w, text_h = max(w, text_w), max(h, text_h)
  3988                                           
  3989    200160     368483.0      1.8      7.2              wnd = item.GetWindow(column)
  3990    200160     116273.0      0.6      2.3              if wnd:
  3991                                                           wnd_h = max(wnd_h, item.GetWindowSize(column)[1])
  3992                                                           if column == self._main_column:
  3993                                                               wnd_w = item.GetWindowSize(column)[0]
  3994                                           
  3995     20016     392498.0     19.6      7.7          text_w, dummy, dummy = dc.GetFullMultiLineTextExtent(item.GetText(self._main_column))
  3996     20016      20624.0      1.0      0.4          text_h+=2
  3997                                           
  3998                                                   # restore normal font
  3999     20016      54587.0      2.7      1.1          dc.SetFont(self._normalFont)
  4000                                           
  4001     20016      13009.0      0.6      0.3          image_w, image_h = 0, 0
  4002     20016     114204.0      5.7      2.2          image = item.GetCurrentImage()
  4003                                           
  4004     20016      14265.0      0.7      0.3          if image != _NO_IMAGE:
  4005                                           
  4006                                                       if self._imageListNormal:
  4007                                           
  4008                                                           image_w, image_h = self._imageListNormal.GetSize(image)
  4009                                                           image_w += 2*_MARGIN
  4010                                           
  4011     20016      14806.0      0.7      0.3          total_h = ((image_h > text_h) and [image_h] or [text_h])[0]
  4012                                           
  4013     20016      25661.0      1.3      0.5          checkimage = item.GetCurrentCheckedImage()
  4014     20016      12786.0      0.6      0.3          if checkimage is not None:
  4015                                                       wcheck, hcheck = self._imageListCheck.GetSize(0)
  4016                                                       wcheck += 2*_MARGIN
  4017                                                   else:
  4018     20016      11841.0      0.6      0.2              wcheck = 0
  4019                                           
  4020     20016      12239.0      0.6      0.2          if total_h < 30:
  4021     20016      12932.0      0.6      0.3              total_h += 2            # at least 2 pixels
  4022                                                   else:
  4023                                                       total_h += total_h//10   # otherwise 10% extra spacing
  4024                                           
  4025     20016      13421.0      0.7      0.3          if total_h > self._lineHeight:
  4026         1          2.0      2.0      0.0              self._lineHeight = max(total_h, wnd_h+2)
  4027                                           
  4028     20016      32772.0      1.6      0.6          item.SetWidth(image_w+text_w+wcheck+2+wnd_w)
  4029     20016      29772.0      1.5      0.6          item.SetHeight(max(total_h, wnd_h+2))

3. Scrolling around a little:

- here hypertreelist.py:2850(PaintItem) is dominant
Profile Output (click to expand)
File: /usr/local/lib/python3.8/dist-packages/wx/lib/agw/hypertreelist.py
Function: PaintItem at line 2849
Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
  2849                                               @profile
  2850                                               def PaintItem(self, item, dc):
  2851                                                   """
  2852                                                   Actually draws an item.
  2853                                           
  2854                                                   :param `item`: an instance of :class:`TreeListItem`;
  2855                                                   :param `dc`: an instance of :class:`wx.DC`.
  2856                                                   """
  2857                                           
  2858      7001      18431.0      2.6      0.1          def _paintText(text, textrect, alignment):
  2859                                                       """
  2860                                                       Sub-function to draw multi-lines text label aligned correctly.
  2861                                           
  2862                                                       :param `text`: the item text label (possibly multiline);
  2863                                                       :param `textrect`: the label client rectangle;
  2864                                                       :param `alignment`: the alignment for the text label, one of ``wx.ALIGN_LEFT``,
  2865                                                        ``wx.ALIGN_RIGHT``, ``wx.ALIGN_CENTER``.
  2866                                                       """
  2867                                           
  2868                                                       txt = text.splitlines()
  2869                                                       if alignment != wx.ALIGN_LEFT and len(txt):
  2870                                                           yorigin = textrect.Y
  2871                                                           for t in txt:
  2872                                                               w, h = dc.GetTextExtent(t)
  2873                                                               plus = textrect.Width - w
  2874                                                               if alignment == wx.ALIGN_CENTER:
  2875                                                                   plus //= 2
  2876                                                               dc.DrawLabel(t, wx.Rect(textrect.X + plus, yorigin, w, yorigin+h))
  2877                                                               yorigin += h
  2878                                                           return
  2879                                                       dc.DrawLabel(text, textrect)
  2880                                           
  2881      7001      18365.0      2.6      0.1          attr = item.GetAttributes()
  2882                                           
  2883      7001      11909.0      1.7      0.1          if attr and attr.HasFont():
  2884                                                       dc.SetFont(attr.GetFont())
  2885      7001      16332.0      2.3      0.1          elif item.IsBold():
  2886                                                       dc.SetFont(self._boldFont)
  2887      7001      14701.0      2.1      0.1          if item.IsHyperText():
  2888                                                       dc.SetFont(self.GetHyperTextFont())
  2889                                                       if item.GetVisited():
  2890                                                           dc.SetTextForeground(self.GetHyperTextVisitedColour())
  2891                                                       else:
  2892                                                           dc.SetTextForeground(self.GetHyperTextNewColour())
  2893                                           
  2894      7001     130109.0     18.6      0.7          colText = wx.Colour(*dc.GetTextForeground())
  2895                                           
  2896      7001      17903.0      2.6      0.1          if item.IsSelected():
  2897                                                       colTextHilight = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)
  2898                                           
  2899                                                   else:
  2900      7001      14465.0      2.1      0.1              attr = item.GetAttributes()
  2901      7001      11622.0      1.7      0.1              if attr and attr.HasTextColour():
  2902                                                           colText = attr.GetTextColour()
  2903                                           
  2904      7001      12483.0      1.8      0.1          if self._vistaselection:
  2905                                                       colText = colTextHilight = wx.BLACK
  2906                                           
  2907      7001      24101.0      3.4      0.1          total_w = self._owner.GetHeaderWindow().GetWidth()
  2908      7001      22933.0      3.3      0.1          total_h = self.GetLineHeight(item)
  2909      7001      19800.0      2.8      0.1          off_h = (self.HasAGWFlag(TR_ROW_LINES) and [1] or [0])[0]
  2910      7001      15741.0      2.2      0.1          off_w = (self.HasAGWFlag(TR_COLUMN_LINES) and [1] or [0])[0]
  2911                                           ##        clipper = wx.DCClipper(dc, 0, item.GetY(), total_w, total_h) # only within line
  2912                                           
  2913      7001     272515.0     38.9      1.5          text_w, text_h, dummy = dc.GetFullMultiLineTextExtent(item.GetText(self.GetMainColumn()))
  2914                                           
  2915      7001      15489.0      2.2      0.1          drawItemBackground = False
  2916                                                   # determine background and show it
  2917      7001      12342.0      1.8      0.1          if attr and attr.HasBackgroundColour():
  2918                                                       colBg = attr.GetBackgroundColour()
  2919                                                       drawItemBackground = True
  2920                                                   else:
  2921      7001      12998.0      1.9      0.1              colBg = self._backgroundColour
  2922                                           
  2923      7001      59361.0      8.5      0.3          dc.SetBrush(wx.Brush(colBg))
  2924      7001      12133.0      1.7      0.1          if attr and attr.HasBorderColour():
  2925                                                       colBorder = attr.GetBorderColour()
  2926                                                       dc.SetPen(wx.Pen(colBorder, 1))
  2927                                                   else:
  2928      7001      20446.0      2.9      0.1              dc.SetPen(wx.TRANSPARENT_PEN)
  2929                                           
  2930      7001      21436.0      3.1      0.1          if self.HasAGWFlag(wx.TR_FULL_ROW_HIGHLIGHT):
  2931                                           
  2932      7001      29993.0      4.3      0.2              itemrect = wx.Rect(0, item.GetY() + off_h, total_w-1, total_h - off_h)
  2933                                           
  2934      7001      13505.0      1.9      0.1              if item == self._dragItem:
  2935                                                           dc.SetBrush(self._hilightBrush)
  2936                                                           if wx.Platform == "__WXMAC__":
  2937                                                               dc.SetPen((item == self._dragItem) and [wx.BLACK_PEN] or [wx.TRANSPARENT_PEN])[0]
  2938                                           
  2939                                                           dc.SetTextForeground(colTextHilight)
  2940                                           
  2941      7001      15666.0      2.2      0.1              elif item.IsSelected():
  2942                                           
  2943                                                           wnd = item.GetWindow(self._main_column)
  2944                                                           wndx = 0
  2945                                                           if wnd:
  2946                                                               wndx, wndy = item.GetWindowSize(self._main_column)
  2947                                           
  2948                                                           itemrect = wx.Rect(0, item.GetY() + off_h, total_w-1, total_h - off_h)
  2949                                           
  2950                                                           if self._usegradients:
  2951                                                               if self._gradientstyle == 0:   # Horizontal
  2952                                                                   self.DrawHorizontalGradient(dc, itemrect, self._hasFocus)
  2953                                                               else:                          # Vertical
  2954                                                                   self.DrawVerticalGradient(dc, itemrect, self._hasFocus)
  2955                                                           elif self._vistaselection:
  2956                                                               self.DrawVistaRectangle(dc, itemrect, self._hasFocus)
  2957                                                           else:
  2958                                                               if wx.Platform in ["__WXGTK2__", "__WXMAC__"]:
  2959                                                                   flags = wx.CONTROL_SELECTED
  2960                                                                   if self._hasFocus: flags = flags | wx.CONTROL_FOCUSED
  2961                                                                   wx.RendererNative.Get().DrawItemSelectionRect(self._owner, dc, itemrect, flags)
  2962                                                               else:
  2963                                                                   dc.SetBrush((self._hasFocus and [self._hilightBrush] or [self._hilightUnfocusedBrush])[0])
  2964                                                                   dc.SetPen((self._hasFocus and [self._borderPen] or [wx.TRANSPARENT_PEN])[0])
  2965                                                                   dc.DrawRectangle(itemrect)
  2966                                           
  2967                                                           dc.SetTextForeground(colTextHilight)
  2968                                           
  2969                                                       # On GTK+ 2, drawing a 'normal' background is wrong for themes that
  2970                                                       # don't allow backgrounds to be customized. Not drawing the background,
  2971                                                       # except for custom item backgrounds, works for both kinds of theme.
  2972      7001      11844.0      1.7      0.1              elif drawItemBackground:
  2973                                           
  2974                                                           itemrect = wx.Rect(0, item.GetY() + off_h, total_w-1, total_h - off_h)
  2975                                                           dc.SetBrush(wx.Brush(colBg, wx.SOLID))
  2976                                                           dc.DrawRectangle(itemrect)
  2977                                                           dc.SetTextForeground(colText)
  2978                                           
  2979                                                       else:
  2980      7001      25767.0      3.7      0.1                  dc.SetTextForeground(colText)
  2981                                           
  2982                                                   else:
  2983                                           
  2984                                                       dc.SetTextForeground(colText)
  2985                                           
  2986      7001      16688.0      2.4      0.1          text_extraH = (total_h > text_h and [(total_h - text_h)//2] or [0])[0]
  2987      7001      13927.0      2.0      0.1          img_extraH = (total_h > self._imgHeight and [(total_h-self._imgHeight)//2] or [0])[0]
  2988      7001      11761.0      1.7      0.1          x_colstart = 0
  2989                                           
  2990     77011     163212.0      2.1      0.9          for i in range(self.GetColumnCount()):
  2991     70010     363623.0      5.2      2.0              if not self._owner.GetHeaderWindow().IsColumnShown(i):
  2992                                                           continue
  2993                                           
  2994     70010     235350.0      3.4      1.3              col_w = self._owner.GetHeaderWindow().GetColumnWidth(i)
  2995     70010     442336.0      6.3      2.4              dc.SetClippingRegion(x_colstart, item.GetY(), col_w, total_h) # only within column
  2996                                           
  2997     70010     126313.0      1.8      0.7              image = _NO_IMAGE
  2998     70010     125881.0      1.8      0.7              x = image_w = wcheck = hcheck = 0
  2999                                           
  3000     70010     151818.0      2.2      0.8              if i == self.GetMainColumn():
  3001      7001      15631.0      2.2      0.1                  x = item.GetX() + _MARGIN
  3002      7001      20233.0      2.9      0.1                  if self.HasButtons():
  3003      7001      14297.0      2.0      0.1                      x += (self._btnWidth-self._btnWidth2) + _LINEATROOT
  3004                                                           else:
  3005                                                               x -= self._indent//2
  3006                                           
  3007      7001      12086.0      1.7      0.1                  if self._imageListNormal:
  3008                                                               image = item.GetCurrentImage(i)
  3009                                           
  3010      7001      15206.0      2.2      0.1                  if item.GetType() != 0 and self._imageListCheck:
  3011                                                               checkimage = item.GetCurrentCheckedImage()
  3012                                                               wcheck, hcheck = self._imageListCheck.GetSize(item.GetType())
  3013                                                           else:
  3014      7001      12416.0      1.8      0.1                      wcheck, hcheck = 0, 0
  3015                                           
  3016                                                       else:
  3017     63009     114645.0      1.8      0.6                  x = x_colstart + _MARGIN
  3018     63009     242058.0      3.8      1.3                  image = item.GetImage(column=i)
  3019                                           
  3020     70010     120726.0      1.7      0.7              if image != _NO_IMAGE:
  3021                                                           image_w = self._imgWidth + _MARGIN
  3022                                           
  3023                                                       # honor text alignment
  3024     70010     300780.0      4.3      1.7              text = item.GetText(i)
  3025     70010     248684.0      3.6      1.4              alignment = self._owner.GetHeaderWindow().GetColumn(i).GetAlignment()
  3026                                           
  3027     70010    1523644.0     21.8      8.4              text_w, dummy, dummy = dc.GetFullMultiLineTextExtent(text)
  3028                                           
  3029     70010     164777.0      2.4      0.9              if alignment == wx.ALIGN_RIGHT:
  3030                                                           w = col_w - (image_w + wcheck + text_w + off_w + _MARGIN + 1)
  3031                                                           x += (w > 0 and [w] or [0])[0]
  3032                                           
  3033     70010     123745.0      1.8      0.7              elif alignment == wx.ALIGN_CENTER:
  3034                                                           w = (col_w - (image_w + wcheck + text_w + off_w + _MARGIN))//2
  3035                                                           x += (w > 0 and [w] or [0])[0]
  3036                                                       else:
  3037     70010     126904.0      1.8      0.7                  if image_w == 0 and wcheck:
  3038                                                               x += 2*_MARGIN
  3039                                           
  3040     70010     132645.0      1.9      0.7              text_x = x + image_w + wcheck + 1
  3041                                           
  3042     70010     161703.0      2.3      0.9              if i == self.GetMainColumn():
  3043      7001      17174.0      2.5      0.1                  item.SetTextX(text_x)
  3044                                           
  3045     70010     193593.0      2.8      1.1              if not self.HasAGWFlag(wx.TR_FULL_ROW_HIGHLIGHT):
  3046                                                           dc.SetBrush((self._hasFocus and [self._hilightBrush] or [self._hilightUnfocusedBrush])[0])
  3047                                                           dc.SetPen((self._hasFocus and [self._borderPen] or [wx.TRANSPARENT_PEN])[0])
  3048                                                           if i == self.GetMainColumn():
  3049                                                               if item == self._dragItem:
  3050                                                                   if wx.Platform == "__WXMAC__":  # don't draw rect outline if we already have the background colour
  3051                                                                       dc.SetPen((item == self._dragItem and [wx.BLACK_PEN] or [wx.TRANSPARENT_PEN])[0])
  3052                                           
  3053                                                                   dc.SetTextForeground(colTextHilight)
  3054                                           
  3055                                                               elif item.IsSelected():
  3056                                           
  3057                                                                   itemrect = wx.Rect(text_x-2, item.GetY() + off_h, text_w+2*_MARGIN, total_h - off_h)
  3058                                           
  3059                                                                   if self._usegradients:
  3060                                                                       if self._gradientstyle == 0:   # Horizontal
  3061                                                                           self.DrawHorizontalGradient(dc, itemrect, self._hasFocus)
  3062                                                                       else:                          # Vertical
  3063                                                                           self.DrawVerticalGradient(dc, itemrect, self._hasFocus)
  3064                                                                   elif self._vistaselection:
  3065                                                                       self.DrawVistaRectangle(dc, itemrect, self._hasFocus)
  3066                                                                   else:
  3067                                                                       if wx.Platform in ["__WXGTK2__", "__WXMAC__"]:
  3068                                                                           flags = wx.CONTROL_SELECTED
  3069                                                                           if self._hasFocus: flags = flags | wx.CONTROL_FOCUSED
  3070                                                                           wx.RendererNative.Get().DrawItemSelectionRect(self._owner, dc, itemrect, flags)
  3071                                                                       else:
  3072                                                                           dc.DrawRectangle(itemrect)
  3073                                           
  3074                                                                   dc.SetTextForeground(colTextHilight)
  3075                                           
  3076                                                               elif item == self._current:
  3077                                                                   dc.SetPen((self._hasFocus and [wx.BLACK_PEN] or [wx.TRANSPARENT_PEN])[0])
  3078                                           
  3079                                                               # On GTK+ 2, drawing a 'normal' background is wrong for themes that
  3080                                                               # don't allow backgrounds to be customized. Not drawing the background,
  3081                                                               # except for custom item backgrounds, works for both kinds of theme.
  3082                                                               elif drawItemBackground:
  3083                                           
  3084                                                                   if self.HasAGWFlag(TR_FILL_WHOLE_COLUMN_BACKGROUND):
  3085                                                                       itemrect = wx.Rect(text_x-2, item.GetY() + off_h, col_w-2*_MARGIN, total_h - off_h)
  3086                                                                   else:
  3087                                                                       itemrect = wx.Rect(text_x-2, item.GetY() + off_h, text_w+2*_MARGIN, total_h - off_h)
  3088                                                                   dc.SetBrush(wx.Brush(colBg))
  3089                                                                   dc.SetPen(wx.TRANSPARENT_PEN)
  3090                                                                   dc.DrawRectangle(itemrect)
  3091                                           
  3092                                                               else:
  3093                                                                   dc.SetTextForeground(colText)
  3094                                           
  3095                                                           else:
  3096                                           
  3097                                                               if self.HasAGWFlag(TR_FILL_WHOLE_COLUMN_BACKGROUND):
  3098                                                                   itemrect = wx.Rect(text_x-2, item.GetY() + off_h, col_w-2*_MARGIN, total_h - off_h)
  3099                                                               else:
  3100                                                                   itemrect = wx.Rect(text_x-2, item.GetY() + off_h, text_w+2*_MARGIN, total_h - off_h)
  3101                                                               colBgX = item.GetBackgroundColour(i)
  3102                                           
  3103                                                               if colBgX is not None and i != 0:
  3104                                                                   dc.SetBrush(wx.Brush(colBgX, wx.SOLID))
  3105                                                                   dc.SetPen(wx.TRANSPARENT_PEN)
  3106                                                                   dc.DrawRectangle(itemrect)
  3107                                           
  3108                                                               dc.SetTextForeground(colText)
  3109                                           
  3110                                                       else:
  3111                                           
  3112     70010     162127.0      2.3      0.9                  if not item.IsSelected():
  3113                                           
  3114     70010     154208.0      2.2      0.9                      if self.HasAGWFlag(TR_FILL_WHOLE_COLUMN_BACKGROUND):
  3115                                                                   itemrect = wx.Rect(text_x-2, item.GetY() + off_h, col_w-2*_MARGIN, total_h - off_h)
  3116                                                               else:
  3117     70010     419543.0      6.0      2.3                          itemrect = wx.Rect(text_x-2, item.GetY() + off_h, text_w+2*_MARGIN, total_h - off_h)
  3118     70010     194377.0      2.8      1.1                      colBgX = item.GetBackgroundColour(i)
  3119                                           
  3120     70010     125333.0      1.8      0.7                      if colBgX is not None:
  3121                                                                   dc.SetBrush(wx.Brush(colBgX, wx.SOLID))
  3122                                                                   dc.SetPen(wx.TRANSPARENT_PEN)
  3123                                                                   dc.DrawRectangle(itemrect)
  3124                                           
  3125                                           
  3126     70010     160851.0      2.3      0.9              if self.HasAGWFlag(TR_COLUMN_LINES):  # vertical lines between columns
  3127     70010     802545.0     11.5      4.4                  pen = wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DLIGHT), 1, wx.PENSTYLE_SOLID)
  3128     70010     669559.0      9.6      3.7                  dc.SetPen((self.GetBackgroundColour() == wx.WHITE and [pen] or [wx.WHITE_PEN])[0])
  3129     70010    1111372.0     15.9      6.2                  dc.DrawLine(x_colstart+col_w-1, item.GetY(), x_colstart+col_w-1, item.GetY()+total_h)
  3130                                           
  3131     70010     208158.0      3.0      1.2              dc.SetBackgroundMode(wx.TRANSPARENT)
  3132                                           
  3133     70010     132053.0      1.9      0.7              if image != _NO_IMAGE:
  3134                                                           y = item.GetY() + img_extraH
  3135                                                           if wcheck:
  3136                                                               x += wcheck
  3137                                           
  3138                                                           if item.IsEnabled():
  3139                                                               imglist = self._imageListNormal
  3140                                                           else:
  3141                                                               imglist = self._grayedImageList
  3142                                           
  3143                                                           imglist.Draw(image, dc, x, y, wx.IMAGELIST_DRAW_TRANSPARENT)
  3144                                           
  3145     70010     125815.0      1.8      0.7              if wcheck:
  3146                                                           if item.IsEnabled():
  3147                                                               imglist = self._imageListCheck
  3148                                                           else:
  3149                                                               imglist = self._grayedCheckList
  3150                                           
  3151                                                           if self.HasButtons():  # should the item show a button?
  3152                                                               btnWidth = self._btnWidth
  3153                                                           else:
  3154                                                               btnWidth = -self._btnWidth
  3155                                           
  3156                                                           imglist.Draw(checkimage, dc,
  3157                                                                        item.GetX() + btnWidth + _MARGIN,
  3158                                                                        item.GetY() + ((total_h > hcheck) and [(total_h-hcheck)//2] or [0])[0]+1,
  3159                                                                        wx.IMAGELIST_DRAW_TRANSPARENT)
  3160                                           
  3161     70010    1675573.0     23.9      9.3              text_w, text_h, dummy = dc.GetFullMultiLineTextExtent(text)
  3162     70010     214839.0      3.1      1.2              text_extraH = (total_h > text_h and [(total_h - text_h)//2] or [0])[0]
  3163     70010     194635.0      2.8      1.1              text_y = item.GetY() + text_extraH
  3164     70010     356173.0      5.1      2.0              textrect = wx.Rect(text_x, text_y, text_w, text_h)
  3165                                           
  3166     70010     197033.0      2.8      1.1              if self.HasAGWFlag(TR_ELLIPSIZE_LONG_ITEMS):
  3167                                                           if i == self.GetMainColumn():
  3168                                                               maxsize = col_w - text_x - _MARGIN
  3169                                                           else:
  3170                                                               maxsize = col_w - (wcheck + image_w + _MARGIN)
  3171                                           
  3172                                                           text = ChopText(dc, text, maxsize)
  3173                                           
  3174     70010     193795.0      2.8      1.1              if not item.IsEnabled():
  3175                                                           foreground = dc.GetTextForeground()
  3176                                                           dc.SetTextForeground(self._disabledColour)
  3177                                                           _paintText(text, textrect, alignment)
  3178                                                           dc.SetTextForeground(foreground)
  3179                                                       else:
  3180     70010     145029.0      2.1      0.8                  if ( wx.Platform == "__WXMAC__" and item.IsSelected() and
  3181                                                                self._hasFocus and i == self.GetMainColumn()) :
  3182                                                               # Use white on Macs, but only on the primary column if
  3183                                                               # TR_FULL_ROW_HIGHLIGHT is NOT turned on.
  3184                                                               dc.SetTextForeground(wx.WHITE)
  3185     70010    3389633.0     48.4     18.8                  _paintText(text, textrect, alignment)
  3186                                           
  3187     70010     303569.0      4.3      1.7              wnd = item.GetWindow(i)
  3188     70010     127941.0      1.8      0.7              if wnd:
  3189                                                           if text_w == 0:
  3190                                                               wndx = text_x
  3191                                                           else:
  3192                                                               wndx = text_x + text_w + 2*_MARGIN
  3193                                                           xa, ya = self.CalcScrolledPosition(0, item.GetY())
  3194                                                           wndx += xa
  3195                                                           if item.GetHeight() > item.GetWindowSize(i)[1]:
  3196                                                               ya += (item.GetHeight() - item.GetWindowSize(i)[1])//2
  3197                                           
  3198                                                           if wnd.GetPosition() != (wndx, ya):
  3199                                                               wnd.Move(wndx, ya, flags=wx.SIZE_ALLOW_MINUS_ONE)
  3200                                                           # Force window visible after any position changes were made.
  3201                                                           if not wnd.IsShown():
  3202                                                               wnd.Show()
  3203                                           
  3204     70010     136071.0      1.9      0.8              x_colstart += col_w
  3205     70010     759258.0     10.8      4.2              dc.DestroyClippingRegion()
  3206                                           
  3207                                                   # restore normal font
  3208      7001      27260.0      3.9      0.2          dc.SetFont(self._normalFont)

Hope this helps a little bit. I think there is some optimizaion potential like not always asking the sizes and set pens ... But it's also clear to me that this is risky & will cost much time to optimize. BR Roland

roland171281 avatar Jan 18 '22 09:01 roland171281

If you have a moment can you test out the pull request to see if it fixes your slowdown issues?

cbeytas avatar Jan 23 '22 20:01 cbeytas

Hi,

I tested your request and there is a huge speedup -> great work! Filling the table seems to as fast as the old gizmos version.

The only things I mentioned is:

  • scrolling in a big table is still a bit slower than using the 2.8 gizmos.TreeListCtrl -> time is spent in "_paintText:DrawLabel" and "GetFullMultiLineTextExtent" (with a huge number of calls)
  • closing big trees takes some time

BUT it also seems to be more reliable than the 2.8 gizmos.TreeListCtrl -> there is no "wrong drawing". So I can of course live with that.

Thank you very much!

BR Roland

roland171281 avatar Jan 24 '22 07:01 roland171281

What I found out is, that if I remove TR_HIDE_ROOT scrolling is much faster. And TR_VIRTUAL seems to be defective -> but maybe I'm just doing something wrong.

roland171281 avatar Jan 24 '22 12:01 roland171281

Can you post a program sample where the tree is still slow?

I don't think TR_VIRTUAL ever worked with HyperTreeList. The code looks broken even from 2010. If you have an example of a virtual tree that worked with the 2.8 gizmos.TreeListCtrl that would be very useful to help figure out how it should work.

cbeytas avatar Jan 25 '22 04:01 cbeytas