Hi, mates, I am struggling to maintain a scroll bar position after updating textctrl content. Let me show my code firstly:
class MyFrame(rtmgr.MyFrame):
def __init__(self, *args, **kwds):
rtmgr.MyFrame.__init__(self, *args, **kwds)
self.scroll_pos = 0
def updateCtrlMsg(self, msg):
self.scroll_pos = self.text_ctrl_1.GetScrollPos(wx.VERTICAL)
self.text_ctrl_1.SetValue(msg)
self.text_ctrl_1.SetScrollPos(wx.VERTICAL ,self.scroll_pos)
class MyApp(wx.App):
def OnInit(self):
self.frame = MyFrame(None, wx.ID_ANY, "")
self.SetTopWindow(self.frame)
self.frame.Show()
return True
def main(args=None):
app = MyApp(0)
# Start wxPython main loop
app.MainLoop()
if __name__ == '__main__':
main()
In another thread, I use wx.CallAfter(self.app.frame.updateCtrlMsg, data) to update the content of textctrl.
but one thing confuses me a lot, why the scroll bar of textctrl automatically reset to the top all the time even though i have scrolled down.
could anyone give some suggestions to me to fix it out?
the following gif shows the problems:
Hi,
I modified your code to get a runnable app. Instead of using a separate thread to update the TextCtrl
my code just uses a timer to call a function to get some random data.
When I used self.text_ctrl_1.SetScrollPos(wx.VERTICAL, self.scroll_pos)
in the updateCtrlMsg()
I got the same behaviour as you - the scrollbar kept jumping back to the top.
However, when I replaced that line with self.text_ctrl_1.ShowPosition(self.scroll_pos)
the scrollbar didn’t jump.
import wx
from random import randint
def getMsg():
msg = ''
for i in range(20):
msg += f"Line {i}: {randint(0, 9)}\n"
return msg
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
wx.Frame.__init__(self, *args, **kwds)
sizer = wx.BoxSizer(wx.VERTICAL)
self.text_ctrl_1 = wx.TextCtrl(self, -1, '', style=wx.TE_MULTILINE)
sizer.Add(self.text_ctrl_1, 1, wx.EXPAND, 0)
self.SetSizer(sizer)
self.scroll_pos = 0
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.OnTimer)
self.timer.Start(1000)
def OnTimer(self, _event):
msg = getMsg()
self.updateCtrlMsg(msg)
def updateCtrlMsg(self, msg):
self.scroll_pos = self.text_ctrl_1.GetScrollPos(wx.VERTICAL)
self.text_ctrl_1.SetValue(msg)
# self.text_ctrl_1.SetScrollPos(wx.VERTICAL, self.scroll_pos)
self.text_ctrl_1.ShowPosition(self.scroll_pos)
class MyApp(wx.App):
def OnInit(self):
self.frame = MyFrame(None, wx.ID_ANY, "")
self.SetTopWindow(self.frame)
self.frame.Show()
return True
def main():
app = MyApp(0)
app.MainLoop()
if __name__ == '__main__':
main()
I don’t know why it behaves differently.
I am using wxPython 4.2.1 gtk3 (phoenix) wxWidgets 3.2.4 + Python 3.12.3 + Linux Mint 22
it’s nice try to use ShowPostion API and I will do it later. Thanks for your great support. But still I would keep focusing on why it behaves differently. Highly appreciate if anyone would share their ideas.
wx.TextCtrl
inherits the SetScrollPos()
method from its wx.Window
ancestor class. In the documentation for the method it says:
Note: This function does not directly affect the contents of the window: it is up to the application to take note of scrollbar attributes and redraw contents accordingly.