wxWidgets / Phoenix

wxPython's Project Phoenix. A new implementation of wxPython, better, stronger, faster than he was before.
http://wxpython.org/
2.29k stars 515 forks source link

New gizmos.TreeListCtrl much slower than 2.8 version #2083

Open roland171281 opened 2 years ago

roland171281 commented 2 years ago

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) ```python 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 commented 2 years ago

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) ```python 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) ```python 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

cbeytas commented 2 years ago

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

roland171281 commented 2 years ago

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:

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 commented 2 years ago

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.

cbeytas commented 2 years ago

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.