Skip to content
Snippets Groups Projects
Commit a0cb2772 authored by Paul McCarthy's avatar Paul McCarthy
Browse files

EditableListBox implementation, as wx.gizmos.EditableListBox is a bit rubbish.

parent 08142e75
No related branches found
No related tags found
No related merge requests found
#!/usr/bin/env python
#
# elistbox.py - A wx EditableListBox implementation. The
# wx.gizmos.EditableListBox is buggy under OS X Mavericks,
# so I felt the need to replicate its functionality.
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
import logging
import wx
import wx.lib.newevent as wxevent
log = logging.getLogger(__name__)
# Event emitted when an item is selected. A ListSelectEvent
# has the following attributes (all are set to None if no
# item was selected):
#
# - idx: index of selected item
# - choice: label of selected item
# - data: client data associated with selected item
#
ListSelectEvent, EVT_ELB_SELECT_EVENT = wxevent.NewEvent()
# Event emitted when the 'add item' button is pushed. A
# ListAddEvent has the following attributes (all are set
# to None if no item was selected):
#
# - idx: index of selected item
# - choice: label of selected item
# - data: client data associated with selected item
#
ListAddEvent, EVT_ELB_ADD_EVENT = wxevent.NewEvent()
# Event emitted when the 'remove item' button is pushed. A
# ListAddEvent has the following attributes:
#
# - idx: index of selected item
# - choice: label of selected item
# - data: client data associated with selected item
#
ListRemoveEvent, EVT_ELB_REMOVE_EVENT = wxevent.NewEvent()
# Event emitted when one of the 'move up'/'move down'
# buttons is pushed. A ListAddEvent has the following
# attributes:
#
# - oldIdx: index of item before move
# - newIdx: index of item after move
# - choice: label of moved item
# - data: client data associated with moved item
#
ListMoveEvent, EVT_ELB_MOVE_EVENT = wxevent.NewEvent()
class EditableListBox(wx.Panel):
"""
An EditableListBox contains a ListBox containing some items,
and a strip of buttons for modifying said items. The underlying
wx.ListBox is accessible through an attribute called 'listBox'.
Parameters:
- parent: wx parent object
- choices: list of strings, the items in the list
- clientData: list of data associated with the list items.
"""
def __init__(
self,
parent,
choices,
clientData=None):
wx.Panel.__init__(self, parent)
if clientData is None: clientData = [None]*len(choices)
self.listBox = wx.ListBox(
self, style=wx.LB_SINGLE | wx.LB_NEEDED_SB)
for choice,data in zip(choices, clientData):
self.listBox.Append(choice, data)
self.buttonPanel = wx.Panel(self)
self.upButton = wx.Button(self.buttonPanel, label=u'\u25B2',
style=wx.BU_EXACTFIT)
self.downButton = wx.Button(self.buttonPanel, label=u'\u25BC',
style=wx.BU_EXACTFIT)
self.addButton = wx.Button(self.buttonPanel, label='+',
style=wx.BU_EXACTFIT)
self.removeButton = wx.Button(self.buttonPanel, label='-',
style=wx.BU_EXACTFIT)
self.listBox .Bind(wx.EVT_LISTBOX, self._itemSelected)
self.upButton .Bind(wx.EVT_BUTTON, self._moveItemUp)
self.downButton .Bind(wx.EVT_BUTTON, self._moveItemDown)
self.addButton .Bind(wx.EVT_BUTTON, self._addItem)
self.removeButton.Bind(wx.EVT_BUTTON, self._removeItem)
self.buttonPanelSizer = wx.BoxSizer(wx.VERTICAL)
self.buttonPanel.SetSizer(self.buttonPanelSizer)
self.buttonPanelSizer.Add(self.upButton, flag=wx.EXPAND)
self.buttonPanelSizer.Add(self.downButton, flag=wx.EXPAND)
self.buttonPanelSizer.Add(self.addButton, flag=wx.EXPAND)
self.buttonPanelSizer.Add(self.removeButton, flag=wx.EXPAND)
self.sizer = wx.BoxSizer(wx.HORIZONTAL)
self.SetSizer(self.sizer)
self.sizer.Add(self.buttonPanel, flag=wx.EXPAND)
self.sizer.Add(self.listBox, flag=wx.EXPAND, proportion=1)
self.sizer.Layout()
def _getSelection(self):
"""
Returns a 3-tuple containing the index, label, and associated client
data of the currently selected list item, or (None, None, None) if
no item is selected.
"""
idx = self.listBox.GetSelection()
choice = None
data = None
if idx == wx.NOT_FOUND:
idx = None
else:
choice = self.listBox.GetString( idx)
data = self.listBox.GetClientData(idx)
return idx, choice, data
def _itemSelected(self, ev):
"""
Called when an item in the list is selected. Posts an
EVT_ELB_SELECT_EVENT.
"""
idx, choice, data = self._getSelection()
log.debug('ListSelectEvent (idx: {}; choice: {})'.format(idx, choice))
ev = ListSelectEvent(idx=idx, choice=choice, data=data)
wx.PostEvent(self, ev)
def _moveItem(self, oldIdx, newIdx):
"""
Called when the 'move up' or 'move down' buttons are pushed. Moves
the selected item up or down and posts an EVT_ELB_MOVE_EVENT, unless
it doesn't make sense to do so.
"""
# nothing is selected, or the selected
# item is at the top/bottom of the list.
if oldIdx == wx.NOT_FOUND: return
if oldIdx < 0 or oldIdx >= self.listBox.GetCount(): return
if newIdx < 0 or newIdx >= self.listBox.GetCount(): return
choice = self.listBox.GetString( oldIdx)
data = self.listBox.GetClientData(oldIdx)
self.listBox.Delete(oldIdx)
self.listBox.Insert(choice, newIdx, data)
self.listBox.SetSelection(newIdx)
log.debug('ListMoveEvent (oldIdx: {}; newIdx: {}; choice: {})'.format(
oldIdx, newIdx, choice))
ev = ListMoveEvent(
oldIdx=oldIdx, newIdx=newIdx, choice=choice, data=data)
wx.PostEvent(self, ev)
def _moveItemDown(self, ev):
"""
Called when the 'move down' button is pushed. Calls the _moveItem
method.
"""
oldIdx = self.listBox.GetSelection()
newIdx = oldIdx+1
self._moveItem(oldIdx, newIdx)
def _moveItemUp(self, ev):
"""
Called when the 'move up' button is pushed. Calls the _moveItem
method.
"""
oldIdx = self.listBox.GetSelection()
newIdx = oldIdx-1
self._moveItem(oldIdx, newIdx)
def _addItem(self, ev):
"""
Called when the 'add item' button is pushed. Does nothing but post an
EVT_ELB_ADD_EVENT - it is up to a registered handler to implement the
functionality of adding an item to the list.
"""
idx, choice, data = self._getSelection()
ev = ListAddEvent(idx=idx, choice=choice, data=data)
wx.PostEvent(self, ev)
def _removeItem(self, ev):
"""
Called when the 'remove item' button is pushed. Removes the selected
item from the list, and posts an EVT_ELB_REMOVE_EVENT.
"""
idx, choice, data = self._getSelection()
if idx == None: return
self.listBox.Delete(idx)
self.listBox.SetSelection(wx.NOT_FOUND)
ev = ListRemoveEvent(idx=idx, choice=choice, data=data)
wx.PostEvent(self, ev)
def main(items):
"""
Little testing application.
"""
logging.basicConfig(
format='%(levelname)8s '\
'%(filename)20s '\
'%(lineno)4d: '\
'%(funcName)s - '\
'%(message)s',
level=logging.DEBUG)
app = wx.App()
frame = wx.Frame(None)
panel = wx.Panel(frame)
listbox = EditableListBox(panel, items)
panelSizer = wx.BoxSizer(wx.HORIZONTAL)
panel.SetSizer(panelSizer)
panelSizer.Add(listbox, flag=wx.EXPAND, proportion=1)
frameSizer = wx.BoxSizer(wx.HORIZONTAL)
frame.SetSizer(frameSizer)
frameSizer.Add(panel, flag=wx.EXPAND, proportion=1)
frame.Show()
app.MainLoop()
if __name__ == '__main__':
import sys
main(sys.argv[1:])
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment