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