views:

1395

answers:

2

I have a little logging app (written in wxPython) that receives data from a bit of kit we're developing, and I want to display the text in a scrolling window. As it stands I'm using a wx.TextCtrl for the text display, but I'm having some issues with the scrolling behaviour.

Basically, I'd like it so that if the scrollbar is at the bottom of the window (i.e. the end of the incoming data), adding more data should scroll the view onwards. If, however the view has been scrolled up a little (i.e. the user is looking at something interesting like an error message), the app should just add the text on the end without scrolling any more.

I've got two problems at the moment:

  1. I can't work out how to retrieve the current scroll position (calls to GetScrollPos() don't seem to work - they just return 0).
  2. I can't work out how to retrieve the current range of the scroll bar (calls to GetScrollRange() just return 1).

I've googled a bit and there seem to be a few hints that suggest GetScrollPos and GetScrollRange won't work for a wx.TextCtrl? Has anyone else had any experience in this area? Is there a nice easy way to solve the problem or am I going to have to roll my own wx.TextCtrl?

+1  A: 

I just tested a simple example (checking GetScrollPos(0) and GetScrollRange(0) in EVT_TEXT event handler for wx.TextCtrl) and it works fine for me - they return index of currently shown line and total number of lines, respectively.

Maybe the problem is your wxPython version? I used:

>>> import wx
>>> wx.version()
'2.8.9.1 (msw-unicode)'
DzinX
Good point - looks like I'd inadvertently been calling the window frame instead of the nested CTextCtrl.I'm still stuck trying to stop the thing scrolling when it's not at the bottom of the scroll range...
Jon Cage
+1  A: 

Okay, so here's where I've got to:

import wx
from threading import Timer
import time

class Form1(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)

        self.logger = wx.TextCtrl(self,5, "",wx.Point(20,20), wx.Size(200,200), \
                wx.TE_MULTILINE |  wx.TE_READONLY)# |  wx.TE_RICH2)

        t = Timer(0.1, self.AddText)
        t.start()

    def AddText(self):
        # Resart the timer
        t = Timer(0.25, self.AddText)
        t.start() 

        # Work out if we're at the end of the file
        currentCaretPosition = self.logger.GetInsertionPoint()
        currentLengthOfText = self.logger.GetLastPosition()
        if currentCaretPosition != currentLengthOfText:
            self.holdingBack = True
        else:
            self.holdingBack = False

        timeStamp = str(time.time())

        # If we're not at the end of the file, we're holding back
        if self.holdingBack:
            print "%s FROZEN"%(timeStamp)
            self.logger.Freeze()
            (currentSelectionStart, currentSelectionEnd) = self.logger.GetSelection()
            self.logger.AppendText(timeStamp+"\n")
            self.logger.SetInsertionPoint(currentCaretPosition)
            self.logger.SetSelection(currentSelectionStart, currentSelectionEnd)
            self.logger.Thaw()
        else:
            print "%s THAWED"%(timeStamp)
            self.logger.AppendText(timeStamp+"\n")

app = wx.PySimpleApp()
frame = wx.Frame(None, size=(550,425))
Form1(frame)
frame.Show(1)
app.MainLoop()

This simple demo app works almost perfectly. It scrolls neatly unless the user clicks a line which isn't at the end of the text. Thereafter it stays nice and still so you can select text (note: there's still a bug there in that if you select up not down it clears your selection).

The biggest annoyance is that if I try and enable the "| wx.TE_RICH2" option, it all goes a bit pear-shaped. I really need this to do syntax highlighting of errors, but if I can't enable that option, I'm doomed to monochrome - boo!

Any more ideas on how to hold back scrolling on the rich edit control?

Jon Cage