Hello,
This is part a request for help, and part a bug report (I believe), and may even belong on another mailing list. My apologies if I am posting this in the wrong place. Further apologies if this confuses more than it helps. Code example at the end.
The bug is with the behaviour of ListView methods Focus and EnsureVisible. The setup is as follows: I have a wx.Listbook to which I am dynamically adding pages. When the number of pages reaches a certain threshold, the scroll bar (vertical in my case) appears, automatically, as it should. Unfortunately, the newly added pages are off the bottom of the scolled view, and the user must manually scroll to them. I would like to automatically update the scrolled view to show the newly added page, but the previously mentioned methods do not work as documented:
self refers to my subclass of wx.Listbook
listv = self.GetListView()
pages = listv.GetItemCount()
print ‘focusing …’
listv.Focus(pages-1)
nothing happens
print ‘ensuring visibile …’
listv.EnsureVisible(pages-1)
still nothing happens
self.Refresh() # just for really good measure
This is all for wxPython 2.8.6.1 on linux (using python 2.4). Just to be very clear, the above code fragment changes nothing with regard to the position of the scrollbar, so at the least this is a documentation bug.
Part of the problem seems to be that listview.Focus (in _listctrl.i) calls EnsureVisible, so if EnsureVisible does not work, neither will Focus (might want to add a note about this to the docs). EnsureVisible (in src/generic/listctrl.cpp) calls MoveToItem, which ultimately calls Scroll, and I guess that Scroll comes from wxScrolledWindow based on further experimentation, but I am not certain. In any case, I cannot (yet) explain why the code in MoveToItem is not working.
I then tried a recursive GetChildren on the Listbook, which reports having a wxListView child, which itself has a wxListMainWindow, after which the lineage ends. If I manually call the Scroll method of wxListMainWindow, I get the behaviour I desire:
listv.GetChildren()[0].Scroll(-1, 4*(pages-1))
wxListMainWindow appears to inherit all of the functions of a wxScrolledWindow, so when I query GetScrollPixelsPerUnit for the ListMainWindow, it reports 24 pixels (vertical). However, the scroll position seems to vary by 3 or 4 per page added to the ListBook, and the arguments to Scroll appear to be in “scroll units” not in pixels. Is there some place to find the required conversion ?
Thanks.
Erik Vogan, Ph.D.
Structural Biology and Computational Chemistry
Wyeth Research
— somewhat minimal code example —
import wx
this is the interesting bit of code
class TestLB(wx.Listbook):
def init(self, parent, id):
wx.Listbook.init(self, parent, id, style=wx.LB_LEFT)
self.count = 1
self.addPanel()
def makePanel(self, num):
panel = wx.Panel(self, -1)
st = wx.StaticText(panel, -1, ‘Page %4d’ % num)
return panel
def addPanel(self):
self.AddPage(self.makePanel(self.count), ‘Page %4d’ % self.count)
self.ChangeSelection(self.GetPageCount()-1)
these next two lines don’t do anything (but should?)
self.GetListView().Focus(self.GetPageCount()-1)
self.GetListView().EnsureVisible(self.GetPageCount()-1)
this works (but how) ?
self.GetListView().GetChildren()[0].Scroll(-1, 4*(self.GetPageCount()-1))
self.count += 1
this is nothing but layout … nothing interesting to see below here
class TestPanel(wx.Panel):
def init(self, parent, id):
wx.Panel.init(self, parent, id)
hsizer = wx.BoxSizer(wx.HORIZONTAL)
self.win = TestLB(self, wx.NewId())
hsizer.Add(self.win, 1, wx.EXPAND)
vsizer = wx.BoxSizer(wx.VERTICAL)
button = wx.Button(self, -1, ‘Add Page’)
vsizer.Add(hsizer, 1, wx.EXPAND)
vsizer.Add(button, 0, wx.ALIGN_CENTER)
self.SetSizer(vsizer)
vsizer.Fit(self)
button.Bind(wx.EVT_BUTTON, self.onAddPage)
def onAddPage(self, event):
self.win.addPanel()
if name == ‘main’:
app = wx.PySimpleApp()
frame = wx.Frame(None, -1, ‘Test App’)
TestPanel(frame, -1)
frame.Show(True)
app.MainLoop()