Strange positioning and refresh behavior

The sample code below does not actually reproduce the problem I am having, but I have not been able to make it happen outside the application yet. I am still trying to get a simple version of the failure, but need some ideas about where to look.

Here is what is happening. I have a large application with a fairly typical layout using splitter windows. The bottom window displays application messages as they occur. The top is split into a left panel containing a TreeListCtrl for navigating through data and a right panel containing nested notebooks with tabs for editting and viewing data. The tabs are of various sizes and the largest one is about 1400x700. One of the tabs manages selecting data that will be displayed in a plot. We present a fairly typical two column list widget with buttons that allow a user to pick which data channels will be plotted and arrange them in the desired sequence. The panel containing this widget is much smaller than the largest panel in any other notebook tab. (BTW, if there is a freely usable widget out there that already behaves similar to our sample I would like to look at that also, maybe it won’t have the same issues).

Here is the problem:
When this widget is placed in a panel and the panel is in one of the nested notebook tabs, clicking any button, either of the list controls or any empty space within the widget causes the panel to refresh, reposition itself and flicker several times. Selecting another window and reselecting this on causes the same behavior. The behavior does not repeat with a second click at the same location, but will repeat when clicking somewhere else and coming back to this location.

If anyone has any ideas about what is happening, I am open to anything right now. Like I said at the top, I’m still trying to make a sample outside the application that has the same behavior and will post that if I am successful.

OS: Windows XP service pack 3
Wx version: 2.8.9.2

---------------------------- sample code

import wx
from wx.lib.mixins.inspection import InspectionMixin

class TwoColumnSelector(wx.Window):
“”“Widget provides two listboxes to facilitate data selection”""
def init(self, *args, **kwds):
boxtitle = kwds.pop(‘box’, None)
lefttitle = kwds.pop(‘left’, None)
righttitle = kwds.pop(‘right’, None)
super(TwoColumnSelector,self).init(*args, **kwds)

    # controls
    # static box if needed
    if boxtitle:
        twocolsizer_staticbox = wx.StaticBox(self, -1, boxtitle)
    # if there is any title, make sure there are both
    if lefttitle:
        lefttxt = wx.StaticText(self, -1, ' '+lefttitle)
        if righttitle:
            righttxt = wx.StaticText(self, -1, ' '+righttitle)
        else:
            righttxt = wx.StaticText(self, -1, "")
    else:
        if righttitle:
            lefttxt = wx.StaticText(self, -1, "")
            righttxt = wx.StaticText(self, -1, ' '+righttitle)
       
    # list boxes with titles if needed
    self.listboxLeft  = wx.ListBox(self, -1, style=wx.LB_EXTENDED|wx.LB_NEEDED_SB)
    self.listboxLeft.SetMinSize((120, 300))
    leftsizer = wx.BoxSizer(wx.VERTICAL)
    if lefttitle:
        leftsizer.Add(lefttxt,0,wx.BOTTOM,2)
    leftsizer.Add(self.listboxLeft)
   
    self.listboxRight = wx.ListBox(self, -1, style=wx.LB_EXTENDED|wx.LB_NEEDED_SB)
    self.listboxRight.SetMinSize((120,320))
    rightsizer = wx.BoxSizer(wx.VERTICAL)
    if righttitle:
        rightsizer.Add(righttxt,0,wx.BOTTOM,2)
    rightsizer.Add(self.listboxRight)

    # buttons
    btnRt    = wx.Button(self, -1, "->")
    btnAllRt = wx.Button(self, -1, ">>")
    btnLt    = wx.Button(self, -1, "<-")
    btnAllLt = wx.Button(self, -1, "<<")
    btnUp    = wx.Button(self, -1, "Move Up")
    btnDown  = wx.Button(self, -1, "Move Down")
    btnsizer = wx.BoxSizer(wx.VERTICAL)
    btnsizer.Add(btnRt,    0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 6)
    btnsizer.Add(btnAllRt, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 6)
    btnsizer.Add(btnLt,    0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 6)
    btnsizer.Add(btnAllLt, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 6)
    btnsizer.Add(btnUp,    0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 6)
    btnsizer.Add(btnDown,  0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 6)

    # adjust lists to be just a little bigger than button list
    sz = btnsizer.GetMinSize()
    lbsz = leftsizer.GetMinSize()
    lbsz = (lbsz[0], sz[1]+40)
    self.listboxLeft.SetMinSize(lbsz)
    self.listboxRight.SetMinSize(lbsz)

    # layout the panel
    if boxtitle:
        twocolsizer = wx.StaticBoxSizer(twocolsizer_staticbox,
                                        wx.HORIZONTAL)
    else:
        twocolsizer = wx.BoxSizer(wx.HORIZONTAL)
    twocolsizer.Add(leftsizer)
    twocolsizer.Add(btnsizer,0,
                    #wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER,8)
                    wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER,8)
    twocolsizer.Add(rightsizer)
    self.SetSizerAndFit(twocolsizer)
    self.Layout()

    # bind events
    btnRt.Bind(wx.EVT_BUTTON, self.OnBtnRt)
    btnAllRt.Bind(wx.EVT_BUTTON, self.OnBtnAllRt)
    btnLt.Bind(wx.EVT_BUTTON, self.OnBtnLt)
    btnAllLt.Bind(wx.EVT_BUTTON, self.OnBtnAllLt)
    btnUp.Bind(wx.EVT_BUTTON, self.OnBtnUp)
    btnDown.Bind(wx.EVT_BUTTON, self.OnBtnDown)

def OnBtnRt(self, evt):
    """Move items selected on left to right"""
    l,r = self.shiftitems(self.listboxLeft, self.listboxRight, all=False)
    if l != -1:
        self.ResetItems(l,r)

def OnBtnAllRt(self, evt):
    """Move all items from left to right"""
    l,r = self.shiftitems(self.listboxLeft, self.listboxRight, all=True)
    if l != -1:
        self.ResetItems(l,r)

def OnBtnLt(self, evt):
    """Move items selected on right to left"""
    r,l = self.shiftitems(self.listboxRight, self.listboxLeft, all=False)
    if l != -1:
        self.ResetItems(l,r)

def OnBtnAllLt(self, evt):
    """Move all items from right to left"""
    r,l = self.shiftitems(self.listboxRight, self.listboxLeft, all=True)
    if l != -1:
        self.ResetItems(l,r)

def OnBtnUp(self, evt):
    """Move first item selected on right up one slot"""
    r, n = self.moveitems(self.listboxRight, -1)
    if n != -1:
        self.SetRightItems(r)
        self.listboxRight.SetSelection(n)

def OnBtnDown(self, evt):
    """Move first item selected on right down one slot"""
    r, n = self.moveitems(self.listboxRight, 1)
    if n != -1:
        self.SetRightItems(r)
        self.listboxRight.SetSelection(n)

def GetLeftItems(self):
    return self.listboxLeft.GetStrings()

def GetRightItems(self):
    return self.listboxRight.GetStrings()

def SetLeftItems(self, items):
    self.SetItems(self.listboxLeft, items)

def SetRightItems(self, items):
    self.SetItems(self.listboxRight, items)
   
def SetItems(self, listbox, items):
    self.Freeze()
    if items:
        listbox.Set(items)
    else:
        listbox.Clear()
    self.Thaw()

def ResetItems(self, leftitems, rightitems):
    self.SetLeftItems(leftitems)
    self.SetRightItems(rightitems)

def shiftitems(self, listbox1, listbox2, all=False):
    """removes indexed items from list1, adding to list2"""

    # get lists and which items to shift
    list1 = listbox1.GetStrings()
    list2 = listbox2.GetStrings()
    if all == True:
        indx = [n for n in range(len(list1))]
    else:
        indx = listbox1.GetSelections()
    if not indx:
        return (-1, -1)    # get out if nothing to do
    # shift items
    for i in indx:
        list2.append(list1[i])
    for i in sorted(indx, reverse=True):
        list1.pop(i)
    # give back altered lists
    return (list1, list2)

def moveitems(self, listbox, direction):
    """moves first selected item in listbox 'direction' slots"""
   
    # get list and selection
    itemlist = listbox.GetStrings()
    indx = listbox.GetSelections()
    if not indx:
        return (itemlist, -1)   # get out if nothing to do
    # leave selection on only the first item
    if len(indx) > 1:
        for n in indx[1:]:
            listbox.Deselect(n)
    # swap item n with new target location
    n = indx[0]
    new_n = n + direction
    swap = False
    if new_n >= 0 and new_n < len(itemlist):
        tmp = itemlist[n]
        itemlist[n] = itemlist[new_n]
        itemlist[new_n] = tmp
        swap = True
    if swap:
        return (itemlist, new_n)
    return (itemlist, -1)   # indicate nothing changed

end of class TwoColumnSelector

class MyFrame(wx.Frame):
def init(self, *args, **kwds):
kwds[“style”] = wx.DEFAULT_FRAME_STYLE
wx.Frame.init(self, *args, **kwds)
self.SetTitle(“wx Experiments [”+wx.version()+’]’)

    mainpanel = wx.Panel(self, -1)
    # add widgets to mainpanel
    self.widget = TwoColumnSelector(mainpanel, box='Plot Channels',
            left='Available', right='Selected')

    # layout
    mainpanel_sz = wx.BoxSizer(wx.VERTICAL)
    mainpanel_sz.Add(self.widget,0,wx.ALL,8)
    mainpanel.SetSizer(mainpanel_sz)
   
    frame_sz = wx.BoxSizer(wx.VERTICAL)
    frame_sz.Add(mainpanel,1,wx.EXPAND)
    self.SetSizerAndFit(frame_sz)
    frame_sz.SetSizeHints(self)
    self.Layout()

class MyApp(wx.App, InspectionMixin):
def OnInit(self):
wx.InitAllImageHandlers()
self.myframe = MyFrame(None, -1, “Wx Experiments”)
self.SetTopWindow(self.myframe)
InspectionMixin.Init(self)
self.myframe.Show()
return 1

if name == “main”:
app = MyApp(0)
app.myframe.widget.SetLeftItems([‘alpha’,‘beta’,‘gamma’,‘delta’])
app.myframe.widget.SetRightItems([‘one’,‘two’,‘three’,‘four’])
app.MainLoop()

···


Mike Conley

Mike Conley wrote:

Here is the problem:
When this widget is placed in a panel and the panel is in one of the nested notebook tabs, clicking any button, either of the list controls or any empty space within the widget causes the panel to refresh, reposition itself and flicker several times. Selecting another window and reselecting this on causes the same behavior. The behavior does not repeat with a second click at the same location, but will repeat when clicking somewhere else and coming back to this location.

Double check that the parentage of the panels and widgets is correct,
and also that siblings are not overlapping each other.

If anyone has any ideas about what is happening, I am open to anything right now. Like I said at the top, I'm still trying to make a sample outside the application that has the same behavior and will post that if I am successful.

Remember, if you create a sample that you think should show the problem
but it doesn't then it is likely that carefully comparing the sample and
your app will reveal what you did wrong in the app.

···

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

Looks like the problem is related to some of the automatic positioning done by scrolled windows (similar to my other post yesterday). After some experimenting found that binding to EVT_CHILD_FOCUS and not allowing the event to propagate fixes the problem.

I put
Bind(wx.EVT_CHILD_FOCUS, lambda evt: evt.Skip(False))
in the panel containing my troublesome widget and the annoying flicker stops. Luckily, the automatic repositioning is not useful for this particular dialog.

My guess is that the routines further up the hierarchy are getting confused about what the best visual should be and are scrolling the window to several different positions.

···


Mike Conley

On Wed, Mar 18, 2009 at 7:18 PM, Robin Dunn robin@alldunn.com wrote:

Mike Conley wrote:

Here is the problem:

When this widget is placed in a panel and the panel is in one of the nested notebook tabs, clicking any button, either of the list controls or any empty space within the widget causes the panel to refresh, reposition itself and flicker several times. Selecting another window and reselecting this on causes the same behavior. The behavior does not repeat with a second click at the same location, but will repeat when clicking somewhere else and coming back to this location.

Double check that the parentage of the panels and widgets is correct,

and also that siblings are not overlapping each other.

If anyone has any ideas about what is happening, I am open to anything right now. Like I said at the top, I’m still trying to make a sample outside the application that has the same behavior and will post that if I am successful.

Remember, if you create a sample that you think should show the problem

but it doesn’t then it is likely that carefully comparing the sample and

your app will reveal what you did wrong in the app.

Robin Dunn

Software Craftsman

http://wxPython.org Java give you jitters? Relax with wxPython!


wxpython-users mailing list

wxpython-users@lists.wxwidgets.org

http://lists.wxwidgets.org/mailman/listinfo/wxpython-users