[wxpython-users] Auto scroll TextCtrl only when at bottom

1,437 views
Skip to first unread message

Nathan Fillhardt

unread,
Apr 29, 2009, 1:07:29 PM4/29/09
to wxpytho...@lists.wxwidgets.org
Hey All,
I have been trying to figure this out and I can't seem to get it to work. What I am trying to accomplish is to only auto scroll my output window when the user is looking at the last line of output. I am using a multi line txtctrl in which I am feeding output from a background process so there is almost always text going into the control. What I want is for the user to be able to look at lines of text without the output window jumping to the bottom( disable auto scroll), but when they are looking at the bottom line it should auto scroll for them. Right now I am not using append on the textctrl so I am not worring about wxPythons autoscroll, I am doig my scrollingmanually. The problem is I can't figure out when I am looking at the last line in the text control. If the last line in the output is visable I want autoscroll, if the last line is not visable then I will not autoscroll.

Thanks!
-Nathan


Vlastimil Brom

unread,
Apr 29, 2009, 3:50:50 PM4/29/09
to wxpytho...@lists.wxwidgets.org
2009/4/29 Nathan Fillhardt <fill...@gmail.com>:
> _______________________________________________
> wxpython-users mailing list
> wxpytho...@lists.wxwidgets.org
> http://lists.wxwidgets.org/mailman/listinfo/wxpython-users
>
>

Hi,
the specification is not quite clear to me, but it seems, that you
could use HitTest() for your task. See the sample displying the
currently visible lines in the title bar (on left-click).

hth,
vbr

############################################################

#! Python
# -*- coding: utf-8 -*-

import wx

def check_last_line_visible(evt=None):
"""
display an info about the currently visible lines (title bar)
"""
last_line_nr = testTxtCtrl.PositionToXY(testTxtCtrl.LastPosition)[1]
first_visible_line = testTxtCtrl.HitTest((0, 5))[2] # 5 pixels
from the margin - arbitrary
last_visible_line = testTxtCtrl.HitTest((0,
testTxtCtrl.GetSizeTuple()[1]-5))[2] # 5 px - ditto
last_line_visibility = "VISIBLE" if first_visible_line <=
last_line_nr <= last_visible_line else "INVISIBLE" # first part not
needed for the last line
info_txt = u"top vis.: %s; bottom vis.: %s; last line: %s; last
line is %s" % (first_visible_line, last_visible_line, last_line_nr,
last_line_visibility)
frm.SetTitle(info_txt)

evt.Skip()


appl = wx.App(redirect=False)
frm = wx.Frame(None, -1, "Last line - ??", size = (500, 500))

testTxtCtrl = wx.TextCtrl(frm, -1, style=wx.TE_MULTILINE | wx.TE_RICH2
| wx.WANTS_CHARS) #
testTxtCtrl.SetValue("\n".join(str(x).zfill(9) for x in range(0,101)))

testTxtCtrl.Bind(wx.EVT_LEFT_UP, check_last_line_visible)

sizerFrm = wx.BoxSizer(wx.HORIZONTAL)
sizerFrm.Add(testTxtCtrl, 1, wx.EXPAND)
frm.SetSizer(sizerFrm)

frm.Show()
appl.MainLoop()

############################################################

test-wx-TextCtrl-visible-lines.py

Robin Dunn

unread,
Apr 29, 2009, 11:07:12 PM4/29/09
to wxpytho...@lists.wxwidgets.org

If you're not locked in to using a wx.TextCtrl for some reason then it
would be fairly easy to create a custom widget that displays text and
behaves that way. Otherwise, there are enough variations in the native
text widgets that doing that consistently will be tricky at best.


--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

trevor

unread,
Jan 27, 2011, 5:13:20 PM1/27/11
to wxpytho...@googlegroups.com

> _______________________________________________
> wxpython-users mailing list
> wxpytho...@lists.wxwidgets.org
> http://lists.wxwidgets.org/mailman/listinfo/wxpython-users
>
>

Robin,

Can you point me in the right direction here? I too would like to know how
to create a 'logging' window. (i.e. a text window which is continually
appending text to the end and normally scrolls up except when the user has
moved the scroll bar thumb off from bottom to examine past history and
resumes scrolling when the user has moved the scroll bar thumb back to the
bottom.) I am sure a class for this already exists but I don't know where.
I am willing to create custom widget as you suggest ... but I need a few
hints on how to proceed.

Trevor
--
View this message in context: http://wxpython-users.1045709.n5.nabble.com/Auto-scroll-TextCtrl-only-when-at-bottom-tp2371998p3360550.html
Sent from the wxPython-users mailing list archive at Nabble.com.

Tim Roberts

unread,
Jan 27, 2011, 5:35:29 PM1/27/11
to wxpytho...@googlegroups.com
trevor wrote:
> Can you point me in the right direction here? I too would like to know how
> to create a 'logging' window. (i.e. a text window which is continually
> appending text to the end and normally scrolls up except when the user has
> moved the scroll bar thumb off from bottom to examine past history and
> resumes scrolling when the user has moved the scroll bar thumb back to the
> bottom.) I am sure a class for this already exists but I don't know where.
> I am willing to create custom widget as you suggest ... but I need a few
> hints on how to proceed.

I use a stock standard list box for exactly this purpose. You can use
SetFirstItem to scroll the proper item into view. You can even use the
standard cut-and-paste keystrokes to grab a copy for saving. (For
example, Ctrl-A, Ctrl-C to copy all.)

Your requirements for the scroll bar are a bit contradictory. You might
need to provide a checkbox to enable "auto scroll", so they can disable
auto scroll while they scroll backwards.

--
Tim Roberts, ti...@probo.com
Providenza & Boekelheide, Inc.

Nat Echols

unread,
Jan 27, 2011, 6:40:16 PM1/27/11
to wxpytho...@googlegroups.com
On Thu, Jan 27, 2011 at 3:30 PM, trevor <trevor.ch...@hill.af.mil> wrote:
The wx.TextCtrl behaves exactly the same except that if/when new data is
appended, the window is automatically scrolled down to the bottom.
Basically, forcing the user to see the new data immediately.

What I would like in my custom/extended TextCtrl is for it to be scroll bar
thumb aware when appending new text.  If the thumb is at the bottom, then
behave normally (i.e. append and scroll).  If the thumb is not at the bottom
(i.e. the user is looking historical data), then just append the new data to
the end but leave the scrolled position alone thus allowing the user to
continue viewing previous lines for whatever length of time s/he needs.

I asked about this before, and I think the answer was that it simply isn't possible using the TextCtrl - you'd have to draw a custom widget.  It may be possible to work around the problem by subclassing and overriding AppendText, but the result isn't going to be very pretty.

-Nat

trevor

unread,
Jan 27, 2011, 6:52:57 PM1/27/11
to wxpytho...@googlegroups.com

I suspected as much. I have already done the subclassing/overriding but
without access to the scroll bar itself the solution is not elegant. I was
hoping that it was somehow possible to access the scroll bar widget/events
(i.e. wx.ScrollBar.GetThumbPosition(), etc.) I am just too inexperienced to
know all my options.

--
View this message in context: http://wxpython-users.1045709.n5.nabble.com/Auto-scroll-TextCtrl-only-when-at-bottom-tp2371998p3360639.html

trevor

unread,
Jan 27, 2011, 6:30:40 PM1/27/11
to wxpytho...@googlegroups.com

Thank you for your response. I am sorry for being unclear. I am not asking
for anything unusual. All linux terminal windows behave this way. A
terminal window allows the user to scroll backwards at any time and to leave
it there WHILE AT THE SAME TIME new text is being appended at the end
(although the user won't see it until/unless he scrolls the window back down
to the bottom.

The wx.TextCtrl behaves exactly the same except that if/when new data is
appended, the window is automatically scrolled down to the bottom.
Basically, forcing the user to see the new data immediately.

What I would like in my custom/extended TextCtrl is for it to be scroll bar
thumb aware when appending new text. If the thumb is at the bottom, then
behave normally (i.e. append and scroll). If the thumb is not at the bottom
(i.e. the user is looking historical data), then just append the new data to
the end but leave the scrolled position alone thus allowing the user to
continue viewing previous lines for whatever length of time s/he needs.

Is that clearer?
--
View this message in context: http://wxpython-users.1045709.n5.nabble.com/Auto-scroll-TextCtrl-only-when-at-bottom-tp2371998p3360618.html

Christopher Barker

unread,
Jan 28, 2011, 12:17:46 PM1/28/11
to wxpytho...@googlegroups.com
On 1/27/11 3:30 PM, trevor wrote:
> What I would like in my custom/extended TextCtrl is for it to be scroll bar
> thumb aware when appending new text. If the thumb is at the bottom, then
> behave normally (i.e. append and scroll). If the thumb is not at the bottom
> (i.e. the user is looking historical data), then just append the new data to
> the end but leave the scrolled position alone thus allowing the user to
> continue viewing previous lines for whatever length of time s/he needs.
>
> Is that clearer?

yup -- and it sure seems like you should be able to do that pretty
easily, but looking at the docs, there doesn't appear to be any way to
programmaticly control the scrolling of a wx.TextCtrl -- odd, I'd sure
think it would be common to want to scroll to a particular part of the
text with a method call.

But if it's really not there, then you may have to roll your own. That
may not be as hard as you think, particularly if it can be read-only and
used a fixed width font.

Or us a list control instead, as suggested by another poster.

-Chris

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris....@noaa.gov

Robin Dunn

unread,
Jan 28, 2011, 2:15:59 PM1/28/11
to wxpytho...@googlegroups.com
On 1/27/11 2:13 PM, trevor wrote:
> Can you point me in the right direction here? I too would like to know how
> to create a 'logging' window. (i.e. a text window which is continually
> appending text to the end and normally scrolls up except when the user has
> moved the scroll bar thumb off from bottom to examine past history and
> resumes scrolling when the user has moved the scroll bar thumb back to the
> bottom.) I am sure a class for this already exists but I don't know where.
> I am willing to create custom widget as you suggest ... but I need a few
> hints on how to proceed.

Here is one way to do it.

* Start with a wx.ScrolledWindow that maintains a list of strings and is
able to draw those strings in an EVT_PAINT handler, properly taking
scrolling into account.

* When adding a new line of text, append it to the list and check the
current scroll position. If the (former) end of the list is not in the
visible area of the window then you are done. If both the beginning and
the end of the list are visible then you just need to Refresh() and no
extra scrolling is needed. Otherwise you should just need to scroll the
window, that will move the existing pixels as needed and then
"invalidate" the area exposed by the scroll and that will result in a
paint event so you can draw the new text line and anything else that is
in the window's update region.

Nathan McCorkle

unread,
Aug 19, 2014, 10:40:38 PM8/19/14
to wxpytho...@googlegroups.com
Did anyone ever make a widget that does this for you?
Reply all
Reply to author
Forward
0 new messages