I was investigating using a RichTextCtrl in a dialog to display and edit the contents of a spellchecker’s personal word list. In my testing I used a file containing about 850 lines with one word per line. I found that scrolling the list on my linux PC was very slow and rather jerky. Further experiments with 1000 lines or more and it became nearly unusable. In contrast, scrolling the same list in a StyledTextCtrl was still quick and fluid.
When I made the lines of text longer, the behaviour of the RichTextCtrl became rather strange. When I released the scroll bar thumb after scrolling downwards, the lines would then start scrolling back upwards very slowly which made it totally unusable.
I tried the same tests on a more powerful linux PC and the response of the RichTextCtrl was only a little better, and the CPU usage was still running over 70% while it was trying to catch up with the scrolling.
I am using Python 3.8.10 + wxPython 4.1.1 gtk3 (phoenix) wxWidgets 3.1.5 + Linux Mint 20.3 on both PCs.
Does the same thing happen on other platforms, or is this just a Linux/GTK issue?
Below is a test app that has a RichTextCtrl. Clicking on one of the number buttons puts the corresponding number of lines in the control. If check box is checked the lines inserted will be longer.
import wx
import wx.richtext as rt
class MyDialog(wx.Dialog):
def __init__(self, *args, **kwds):
kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER
wx.Dialog.__init__(self, *args, **kwds)
self.SetSize((500, 600))
self.SetTitle("Sluggish Scroll in RichTextCtrl")
main_sizer = wx.BoxSizer(wx.VERTICAL)
self.rtc = rt.RichTextCtrl(self, wx.ID_ANY, style=rt.RE_MULTILINE)
main_sizer.Add(self.rtc, 1, wx.ALL | wx.EXPAND, 8)
lines_sizer = wx.BoxSizer(wx.HORIZONTAL)
main_sizer.Add(lines_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, 8)
self.button_250 = wx.Button(self, wx.ID_ANY, "250")
self.button_250.SetMinSize((65, 30))
lines_sizer.Add(self.button_250, 0, wx.RIGHT, 8)
self.button_500 = wx.Button(self, wx.ID_ANY, "500")
self.button_500.SetMinSize((65, 30))
lines_sizer.Add(self.button_500, 0, wx.RIGHT, 8)
self.button_1000 = wx.Button(self, wx.ID_ANY, "1000")
self.button_1000.SetMinSize((65, 30))
lines_sizer.Add(self.button_1000, 0, wx.RIGHT, 8)
self.button_1500 = wx.Button(self, wx.ID_ANY, "1500")
self.button_1500.SetMinSize((65, 30))
lines_sizer.Add(self.button_1500, 0, wx.RIGHT, 8)
self.long_lines_checkbox = wx.CheckBox(self, wx.ID_ANY, "Longer lines")
lines_sizer.Add(self.long_lines_checkbox, 0, wx.ALIGN_CENTER_VERTICAL, 0)
bottom_sizer = wx.BoxSizer(wx.HORIZONTAL)
main_sizer.Add(bottom_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.BOTTOM | wx.TOP, 8)
self.close_button = wx.Button(self, wx.ID_ANY, "Close")
bottom_sizer.Add(self.close_button, 0, 0, 0)
self.SetSizer(main_sizer)
self.Layout()
self.Bind(wx.EVT_BUTTON, self.OnClose, self.close_button)
self.Bind(wx.EVT_BUTTON, self.On250, self.button_250)
self.Bind(wx.EVT_BUTTON, self.On500, self.button_500)
self.Bind(wx.EVT_BUTTON, self.On1000, self.button_1000)
self.Bind(wx.EVT_BUTTON, self.On1500, self.button_1500)
def setLines(self, num_lines):
if self.long_lines_checkbox.GetValue():
line = "This is a longer, longer, longer line %d"
else:
line = "Line %d"
lines = [line % i for i in range(num_lines)]
text = '\n'.join(lines)
self.rtc.SetValue(text)
self.rtc.ShowPosition(self.rtc.GetLastPosition())
def On250(self, _event):
self.setLines(250)
def On500(self, _event):
self.setLines(500)
def On1000(self, _event):
self.setLines(1000)
def On1500(self, _event):
self.setLines(1500)
def OnClose(self, _event):
self.EndModal(wx.ID_CLOSE)
class MyApp(wx.App):
def OnInit(self):
self.dialog = MyDialog(None, wx.ID_ANY, "")
self.SetTopWindow(self.dialog)
self.dialog.ShowModal()
self.dialog.Destroy()
return True
if __name__ == "__main__":
app = MyApp(0)
app.MainLoop()