268
|
1 |
|
|
2 |
'''
|
|
3 |
|
|
4 |
wxPython Custom Widget Collection 20060207
|
|
5 |
Written By: Edward Flick (eddy -=at=- cdf-imaging -=dot=- com)
|
|
6 |
Michele Petrazzo (michele -=dot=- petrazzo -=at=- unipex -=dot=- it)
|
|
7 |
Will Sadkin (wsadkin-=at=- nameconnector -=dot=- com)
|
|
8 |
Copyright 2006 (c) CDF Inc. ( http://www.cdf-imaging.com )
|
|
9 |
Contributed to the wxPython project under the wxPython project's license.
|
|
10 |
|
|
11 |
'''
|
|
12 |
|
|
13 |
import locale, wx, sys, cStringIO
|
|
14 |
|
|
15 |
import wx.lib.mixins.listctrl as listmix
|
|
16 |
import cPickle
|
|
17 |
from wx import ImageFromStream, BitmapFromImage
|
|
18 |
#----------------------------------------------------------------------
|
|
19 |
def getSmallUpArrowData():
|
|
20 |
return \
|
|
21 |
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
|
|
22 |
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
|
|
23 |
\x00\x00<IDAT8\x8dcddbf\xa0\x040Q\xa4{h\x18\xf0\xff\xdf\xdf\xffd\x1b\x00\xd3\
|
|
24 |
\x8c\xcf\x10\x9c\x06\xa0k\xc2e\x08m\xc2\x00\x97m\xd8\xc41\x0c \x14h\xe8\xf2\
|
|
25 |
\x8c\xa3)q\x10\x18\x00\x00R\xd8#\xec\xb2\xcd\xc1Y\x00\x00\x00\x00IEND\xaeB`\
|
|
26 |
\x82'
|
|
27 |
|
|
28 |
def getSmallUpArrowBitmap():
|
|
29 |
return BitmapFromImage(getSmallUpArrowImage())
|
|
30 |
|
|
31 |
def getSmallUpArrowImage():
|
|
32 |
stream = cStringIO.StringIO(getSmallUpArrowData())
|
|
33 |
return ImageFromStream(stream)
|
|
34 |
|
|
35 |
|
|
36 |
def getSmallDnArrowData():
|
|
37 |
return \
|
|
38 |
"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
|
|
39 |
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
|
|
40 |
\x00\x00HIDAT8\x8dcddbf\xa0\x040Q\xa4{\xd4\x00\x06\x06\x06\x06\x06\x16t\x81\
|
|
41 |
\xff\xff\xfe\xfe'\xa4\x89\x91\x89\x99\x11\xa7\x0b\x90%\ti\xc6j\x00>C\xb0\x89\
|
|
42 |
\xd3.\x10\xd1m\xc3\xe5*\xbc.\x80i\xc2\x17.\x8c\xa3y\x81\x01\x00\xa1\x0e\x04e\
|
|
43 |
?\x84B\xef\x00\x00\x00\x00IEND\xaeB`\x82"
|
|
44 |
|
|
45 |
def getSmallDnArrowBitmap():
|
|
46 |
return BitmapFromImage(getSmallDnArrowImage())
|
|
47 |
|
|
48 |
def getSmallDnArrowImage():
|
|
49 |
stream = cStringIO.StringIO(getSmallDnArrowData())
|
|
50 |
return ImageFromStream(stream)
|
|
51 |
#----------------------------------------------------------------------
|
|
52 |
|
|
53 |
class myListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
|
|
54 |
def __init__(self, parent, ID=-1, pos=wx.DefaultPosition,
|
|
55 |
size=wx.DefaultSize, style=0):
|
|
56 |
wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
|
|
57 |
listmix.ListCtrlAutoWidthMixin.__init__(self)
|
|
58 |
|
|
59 |
class TextCtrlAutoComplete (wx.TextCtrl, listmix.ColumnSorterMixin ):
|
|
60 |
|
|
61 |
def __init__ ( self, parent, colNames=None, choices = None,
|
|
62 |
multiChoices=None, showHead=True, dropDownClick=True,
|
|
63 |
colFetch=-1, colSearch=0, hideOnNoMatch=True,
|
|
64 |
selectCallback=None, entryCallback=None, matchFunction=None,
|
|
65 |
element_path=None, **therest) :
|
|
66 |
'''
|
|
67 |
Constructor works just like wx.TextCtrl except you can pass in a
|
|
68 |
list of choices. You can also change the choice list at any time
|
|
69 |
by calling setChoices.
|
|
70 |
'''
|
|
71 |
|
|
72 |
if therest.has_key('style'):
|
|
73 |
therest['style']=wx.TE_PROCESS_ENTER | therest['style']
|
|
74 |
else:
|
|
75 |
therest['style']=wx.TE_PROCESS_ENTER
|
|
76 |
|
|
77 |
wx.TextCtrl.__init__(self, parent, **therest )
|
|
78 |
|
|
79 |
#Some variables
|
|
80 |
self._dropDownClick = dropDownClick
|
|
81 |
self._colNames = colNames
|
|
82 |
self._multiChoices = multiChoices
|
|
83 |
self._showHead = showHead
|
|
84 |
self._choices = choices
|
|
85 |
self._lastinsertionpoint = 0
|
|
86 |
self._hideOnNoMatch = hideOnNoMatch
|
|
87 |
self._selectCallback = selectCallback
|
|
88 |
self._entryCallback = entryCallback
|
|
89 |
self._matchFunction = matchFunction
|
|
90 |
|
|
91 |
self._screenheight = wx.SystemSettings.GetMetric( wx.SYS_SCREEN_Y )
|
|
92 |
self.element_path = element_path
|
|
93 |
#sort variable needed by listmix
|
|
94 |
self.itemDataMap = dict()
|
|
95 |
|
|
96 |
#widgets
|
|
97 |
self.dropdown = wx.PopupWindow( self )
|
|
98 |
|
|
99 |
#Control the style
|
|
100 |
flags = wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_SORT_ASCENDING
|
|
101 |
if not (showHead and multiChoices) :
|
|
102 |
flags = flags | wx.LC_NO_HEADER
|
|
103 |
|
|
104 |
#Create the list and bind the events
|
|
105 |
self.dropdownlistbox = myListCtrl( self.dropdown, style=flags,
|
|
106 |
pos=wx.Point( 0, 0) )
|
|
107 |
|
|
108 |
#initialize the parent
|
|
109 |
if multiChoices: ln = len(multiChoices)
|
|
110 |
else: ln = 1
|
|
111 |
#else: ln = len(choices)
|
|
112 |
listmix.ColumnSorterMixin.__init__(self, ln)
|
|
113 |
|
|
114 |
#load the data
|
|
115 |
if multiChoices: self.SetMultipleChoices (multiChoices, colSearch=colSearch, colFetch=colFetch)
|
|
116 |
else: self.SetChoices ( choices )
|
|
117 |
|
|
118 |
#gp = self
|
|
119 |
#while ( gp != None ) :
|
|
120 |
# gp.Bind ( wx.EVT_MOVE , self.onControlChanged, gp )
|
|
121 |
# gp.Bind ( wx.EVT_SIZE , self.onControlChanged, gp )
|
|
122 |
# gp = gp.GetParent()
|
|
123 |
|
|
124 |
self.Bind( wx.EVT_KILL_FOCUS, self.onControlChanged, self )
|
|
125 |
self.Bind( wx.EVT_TEXT , self.onEnteredText, self )
|
|
126 |
self.Bind( wx.EVT_KEY_DOWN , self.onKeyDown, self )
|
|
127 |
|
|
128 |
#If need drop down on left click
|
|
129 |
if dropDownClick:
|
|
130 |
self.Bind ( wx.EVT_LEFT_DOWN , self.onClickToggleDown, self )
|
|
131 |
self.Bind ( wx.EVT_LEFT_UP , self.onClickToggleUp, self )
|
|
132 |
|
|
133 |
self.dropdown.Bind( wx.EVT_LISTBOX , self.onListItemSelected, self.dropdownlistbox )
|
|
134 |
self.dropdownlistbox.Bind(wx.EVT_LEFT_DOWN, self.onListClick)
|
|
135 |
self.dropdownlistbox.Bind(wx.EVT_LEFT_DCLICK, self.onListDClick)
|
|
136 |
self.dropdownlistbox.Bind(wx.EVT_LIST_COL_CLICK, self.onListColClick)
|
|
137 |
|
|
138 |
self.il = wx.ImageList(16, 16)
|
|
139 |
|
|
140 |
self.sm_dn = self.il.Add(getSmallDnArrowBitmap())
|
|
141 |
self.sm_up = self.il.Add(getSmallUpArrowBitmap())
|
|
142 |
|
|
143 |
self.dropdownlistbox.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
|
|
144 |
self._ascending = True
|
|
145 |
|
|
146 |
|
|
147 |
#-- methods called from mixin class
|
|
148 |
def GetSortImages(self):
|
|
149 |
return (self.sm_dn, self.sm_up)
|
|
150 |
|
|
151 |
def GetListCtrl(self):
|
|
152 |
return self.dropdownlistbox
|
|
153 |
|
|
154 |
# -- event methods
|
|
155 |
def onListClick(self, evt):
|
|
156 |
toSel, flag = self.dropdownlistbox.HitTest( evt.GetPosition() )
|
|
157 |
#no values on poition, return
|
|
158 |
if toSel == -1: return
|
|
159 |
self.dropdownlistbox.Select(toSel)
|
|
160 |
|
|
161 |
def onListDClick(self, evt):
|
|
162 |
self._setValueFromSelected()
|
|
163 |
|
|
164 |
def onListColClick(self, evt):
|
|
165 |
col = evt.GetColumn()
|
|
166 |
|
|
167 |
#reverse the sort
|
|
168 |
if col == self._colSearch:
|
|
169 |
self._ascending = not self._ascending
|
|
170 |
|
|
171 |
self.SortListItems( evt.GetColumn(), ascending=self._ascending )
|
|
172 |
self._colSearch = evt.GetColumn()
|
|
173 |
evt.Skip()
|
|
174 |
|
|
175 |
def onEnteredText(self, event):
|
|
176 |
text = event.GetString()
|
|
177 |
|
|
178 |
if self._entryCallback:
|
|
179 |
self._entryCallback()
|
|
180 |
|
|
181 |
if not text:
|
|
182 |
# control is empty; hide dropdown if shown:
|
|
183 |
if self.dropdown.IsShown():
|
|
184 |
self._showDropDown(False)
|
|
185 |
event.Skip()
|
|
186 |
return
|
|
187 |
|
|
188 |
|
|
189 |
found = False
|
|
190 |
if self._multiChoices:
|
|
191 |
#load the sorted data into the listbox
|
|
192 |
dd = self.dropdownlistbox
|
|
193 |
choices = [dd.GetItem(x, self._colSearch).GetText()
|
|
194 |
for x in xrange(dd.GetItemCount())]
|
|
195 |
else:
|
|
196 |
choices = self._choices
|
|
197 |
|
|
198 |
for numCh, choice in enumerate(choices):
|
|
199 |
if self._matchFunction and self._matchFunction(text, choice):
|
|
200 |
found = True
|
|
201 |
elif choice.lower().startswith(text.lower()) :
|
|
202 |
found = True
|
|
203 |
if found:
|
|
204 |
self._showDropDown(True)
|
|
205 |
item = self.dropdownlistbox.GetItem(numCh)
|
|
206 |
toSel = item.GetId()
|
|
207 |
self.dropdownlistbox.Select(toSel)
|
|
208 |
break
|
|
209 |
|
|
210 |
if not found:
|
|
211 |
self.dropdownlistbox.Select(self.dropdownlistbox.GetFirstSelected(), False)
|
|
212 |
if self._hideOnNoMatch:
|
|
213 |
self._showDropDown(False)
|
|
214 |
|
|
215 |
self._listItemVisible()
|
|
216 |
|
|
217 |
event.Skip ()
|
|
218 |
|
|
219 |
def onKeyDown ( self, event ) :
|
|
220 |
""" Do some work when the user press on the keys:
|
|
221 |
up and down: move the cursor
|
|
222 |
left and right: move the search
|
|
223 |
"""
|
|
224 |
skip = True
|
|
225 |
sel = self.dropdownlistbox.GetFirstSelected()
|
|
226 |
visible = self.dropdown.IsShown()
|
|
227 |
|
|
228 |
KC = event.GetKeyCode()
|
|
229 |
if KC == wx.WXK_DOWN :
|
|
230 |
if sel < (self.dropdownlistbox.GetItemCount () - 1) :
|
|
231 |
self.dropdownlistbox.Select ( sel+1 )
|
|
232 |
self._listItemVisible()
|
|
233 |
self._showDropDown ()
|
|
234 |
skip = False
|
|
235 |
elif KC == wx.WXK_UP :
|
|
236 |
if sel > 0 :
|
|
237 |
self.dropdownlistbox.Select ( sel - 1 )
|
|
238 |
self._listItemVisible()
|
|
239 |
self._showDropDown ()
|
|
240 |
skip = False
|
|
241 |
elif KC == wx.WXK_LEFT :
|
|
242 |
if not self._multiChoices: return
|
|
243 |
if self._colSearch > 0:
|
|
244 |
self._colSearch -=1
|
|
245 |
self._showDropDown ()
|
|
246 |
elif KC == wx.WXK_RIGHT:
|
|
247 |
if not self._multiChoices: return
|
|
248 |
if self._colSearch < self.dropdownlistbox.GetColumnCount() -1:
|
|
249 |
self._colSearch += 1
|
|
250 |
self._showDropDown()
|
|
251 |
|
|
252 |
if visible :
|
|
253 |
if event.GetKeyCode() == wx.WXK_RETURN :
|
|
254 |
self._setValueFromSelected()
|
|
255 |
skip = False
|
|
256 |
if event.GetKeyCode() == wx.WXK_ESCAPE :
|
|
257 |
self._showDropDown( False )
|
|
258 |
skip = False
|
|
259 |
if skip :
|
|
260 |
event.Skip()
|
|
261 |
|
|
262 |
def onListItemSelected (self, event):
|
|
263 |
self._setValueFromSelected()
|
|
264 |
event.Skip()
|
|
265 |
|
|
266 |
def onClickToggleDown(self, event):
|
|
267 |
self._lastinsertionpoint = self.GetInsertionPoint()
|
|
268 |
event.Skip ()
|
|
269 |
|
|
270 |
def onClickToggleUp ( self, event ) :
|
|
271 |
if ( self.GetInsertionPoint() == self._lastinsertionpoint ) :
|
|
272 |
self._showDropDown ( not self.dropdown.IsShown() )
|
|
273 |
event.Skip ()
|
|
274 |
|
|
275 |
def onControlChanged(self, event):
|
|
276 |
res = self.GetValue()
|
|
277 |
config = wx.ConfigBase.Get()
|
|
278 |
listentries = cPickle.loads(str(config.Read(self.element_path, cPickle.dumps([]))))
|
|
279 |
if len(res) and res not in listentries:
|
|
280 |
config.Write(self.element_path, cPickle.dumps((listentries + [res])[-10:]))
|
|
281 |
config.Flush()
|
|
282 |
self.SetChoices((listentries + [res])[-10:])
|
|
283 |
self._showDropDown( False )
|
|
284 |
event.Skip()
|
|
285 |
|
|
286 |
|
|
287 |
# -- Interfaces methods
|
|
288 |
def SetMultipleChoices(self, choices, colSearch=0, colFetch=-1):
|
|
289 |
''' Set multi-column choice
|
|
290 |
'''
|
|
291 |
self._multiChoices = choices
|
|
292 |
self._choices = None
|
|
293 |
if not isinstance(self._multiChoices, list):
|
|
294 |
self._multiChoices = [ x for x in self._multiChoices]
|
|
295 |
|
|
296 |
flags = wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_SORT_ASCENDING
|
|
297 |
if not self._showHead:
|
|
298 |
flags |= wx.LC_NO_HEADER
|
|
299 |
self.dropdownlistbox.SetWindowStyleFlag(flags)
|
|
300 |
|
|
301 |
#prevent errors on "old" systems
|
|
302 |
if sys.version.startswith("2.3"):
|
|
303 |
self._multiChoices.sort(lambda x, y: cmp(x[0].lower(), y[0].lower()))
|
|
304 |
else:
|
|
305 |
self._multiChoices.sort(key=lambda x: locale.strxfrm(x[0]).lower() )
|
|
306 |
|
|
307 |
self._updateDataList(self._multiChoices)
|
|
308 |
|
|
309 |
lChoices = len(choices)
|
|
310 |
if lChoices < 2:
|
|
311 |
raise ValueError, "You have to pass me a multi-dimension list"
|
|
312 |
|
|
313 |
for numCol, rowValues in enumerate(choices[0]):
|
|
314 |
|
|
315 |
if self._colNames: colName = self._colNames[numCol]
|
|
316 |
else: colName = "Select %i" % numCol
|
|
317 |
|
|
318 |
self.dropdownlistbox.InsertColumn(numCol, colName)
|
|
319 |
|
|
320 |
for numRow, valRow in enumerate(choices):
|
|
321 |
|
|
322 |
for numCol, colVal in enumerate(valRow):
|
|
323 |
if numCol == 0:
|
|
324 |
index = self.dropdownlistbox.InsertImageStringItem(sys.maxint, colVal, -1)
|
|
325 |
self.dropdownlistbox.SetStringItem(index, numCol, colVal)
|
|
326 |
self.dropdownlistbox.SetItemData(index, numRow)
|
|
327 |
|
|
328 |
self._setListSize()
|
|
329 |
self._colSearch = colSearch
|
|
330 |
self._colFetch = colFetch
|
|
331 |
|
|
332 |
def SetChoices(self, choices):
|
|
333 |
'''
|
|
334 |
Sets the choices available in the popup wx.ListBox.
|
|
335 |
The items will be sorted case insensitively.
|
|
336 |
'''
|
|
337 |
self._choices = choices
|
|
338 |
self._multiChoices = None
|
|
339 |
flags = wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_SORT_ASCENDING | wx.LC_NO_HEADER
|
|
340 |
self.dropdownlistbox.SetWindowStyleFlag(flags)
|
|
341 |
|
|
342 |
#if not isinstance(choices, list):
|
|
343 |
# self._choices = [ x for x in choices if len(x)]
|
|
344 |
self._choices = [ x for x in choices if len(x)]
|
|
345 |
#prevent errors on "old" systems
|
|
346 |
if sys.version.startswith("2.3"):
|
|
347 |
self._choices.sort(lambda x, y: cmp(x.lower(), y.lower()))
|
|
348 |
else:
|
|
349 |
self._choices.sort(key=lambda x: locale.strxfrm(x).lower())
|
|
350 |
|
|
351 |
self._updateDataList(self._choices)
|
|
352 |
|
|
353 |
self.dropdownlistbox.InsertColumn(0, "")
|
|
354 |
|
|
355 |
for num, colVal in enumerate(self._choices):
|
|
356 |
index = self.dropdownlistbox.InsertImageStringItem(sys.maxint, colVal, -1)
|
|
357 |
|
|
358 |
self.dropdownlistbox.SetStringItem(index, 0, colVal)
|
|
359 |
self.dropdownlistbox.SetItemData(index, num)
|
|
360 |
|
|
361 |
self._setListSize()
|
|
362 |
|
|
363 |
# there is only one choice for both search and fetch if setting a single column:
|
|
364 |
self._colSearch = 0
|
|
365 |
self._colFetch = -1
|
|
366 |
|
|
367 |
def GetChoices(self):
|
|
368 |
if self._choices:
|
|
369 |
return self._choices
|
|
370 |
else:
|
|
371 |
return self._multiChoices
|
|
372 |
|
|
373 |
def SetSelectCallback(self, cb=None):
|
|
374 |
self._selectCallback = cb
|
|
375 |
|
|
376 |
def SetEntryCallback(self, cb=None):
|
|
377 |
self._entryCallback = cb
|
|
378 |
|
|
379 |
def SetMatchFunction(self, mf=None):
|
|
380 |
self._matchFunction = mf
|
|
381 |
|
|
382 |
|
|
383 |
#-- Internal methods
|
|
384 |
def _setValueFromSelected( self ) :
|
|
385 |
'''
|
|
386 |
Sets the wx.TextCtrl value from the selected wx.ListCtrl item.
|
|
387 |
Will do nothing if no item is selected in the wx.ListCtrl.
|
|
388 |
'''
|
|
389 |
sel = self.dropdownlistbox.GetFirstSelected()
|
|
390 |
if sel > -1:
|
|
391 |
if self._colFetch != -1: col = self._colFetch
|
|
392 |
else: col = self._colSearch
|
|
393 |
|
|
394 |
itemtext = self.dropdownlistbox.GetItem(sel, col).GetText()
|
|
395 |
if self._selectCallback:
|
|
396 |
dd = self.dropdownlistbox
|
|
397 |
values = [dd.GetItem(sel, x).GetText()
|
|
398 |
for x in xrange(dd.GetColumnCount())]
|
|
399 |
self._selectCallback( values )
|
|
400 |
|
|
401 |
self.SetValue (itemtext)
|
|
402 |
self.SetInsertionPointEnd ()
|
|
403 |
self.SetSelection ( -1, -1 )
|
|
404 |
self._showDropDown ( False )
|
|
405 |
|
|
406 |
|
|
407 |
def _showDropDown ( self, show = True ) :
|
|
408 |
'''
|
|
409 |
Either display the drop down list (show = True) or hide it (show = False).
|
|
410 |
'''
|
|
411 |
if show :
|
|
412 |
size = self.dropdown.GetSize()
|
|
413 |
width, height = self . GetSizeTuple()
|
|
414 |
x, y = self . ClientToScreenXY ( 0, height )
|
|
415 |
if size.GetWidth() != width :
|
|
416 |
size.SetWidth(width)
|
|
417 |
self.dropdown.SetSize(size)
|
|
418 |
self.dropdownlistbox.SetSize(self.dropdown.GetClientSize())
|
|
419 |
if (y + size.GetHeight()) < self._screenheight :
|
|
420 |
self.dropdown . SetPosition ( wx.Point(x, y) )
|
|
421 |
else:
|
|
422 |
self.dropdown . SetPosition ( wx.Point(x, y - height - size.GetHeight()) )
|
|
423 |
self.dropdown.Show ( show )
|
|
424 |
|
|
425 |
def _listItemVisible( self ) :
|
|
426 |
'''
|
|
427 |
Moves the selected item to the top of the list ensuring it is always visible.
|
|
428 |
'''
|
|
429 |
toSel = self.dropdownlistbox.GetFirstSelected ()
|
|
430 |
if toSel == -1: return
|
|
431 |
self.dropdownlistbox.EnsureVisible( toSel )
|
|
432 |
|
|
433 |
def _updateDataList(self, choices):
|
|
434 |
#delete, if need, all the previous data
|
|
435 |
if self.dropdownlistbox.GetColumnCount() != 0:
|
|
436 |
self.dropdownlistbox.DeleteAllColumns()
|
|
437 |
self.dropdownlistbox.DeleteAllItems()
|
|
438 |
|
|
439 |
#and update the dict
|
|
440 |
if choices:
|
|
441 |
for numVal, data in enumerate(choices):
|
|
442 |
self.itemDataMap[numVal] = data
|
|
443 |
else:
|
|
444 |
numVal = 0
|
|
445 |
self.SetColumnCount(numVal)
|
|
446 |
|
|
447 |
def _setListSize(self):
|
|
448 |
if self._multiChoices:
|
|
449 |
choices = self._multiChoices
|
|
450 |
else:
|
|
451 |
choices = self._choices
|
|
452 |
|
|
453 |
longest = 0
|
|
454 |
for choice in choices :
|
|
455 |
longest = max(len(choice), longest)
|
|
456 |
|
|
457 |
longest += 3
|
|
458 |
itemcount = min( len( choices ) , 7 ) + 2
|
|
459 |
charheight = self.dropdownlistbox.GetCharHeight()
|
|
460 |
charwidth = self.dropdownlistbox.GetCharWidth()
|
|
461 |
self.popupsize = wx.Size( charwidth*longest, charheight*itemcount )
|
|
462 |
self.dropdownlistbox.SetSize ( self.popupsize )
|
|
463 |
self.dropdown.SetClientSize( self.popupsize )
|
|
464 |
|
|
465 |
|
|
466 |
|
|
467 |
|
|
468 |
class test:
|
|
469 |
def __init__(self):
|
|
470 |
args = dict()
|
|
471 |
if 1:
|
|
472 |
args["colNames"] = ("col1", "col2")
|
|
473 |
args["multiChoices"] = [ ("Zoey","WOW"), ("Alpha", "wxPython"),
|
|
474 |
("Ceda","Is"), ("Beta", "fantastic"),
|
|
475 |
("zoebob", "!!")]
|
|
476 |
args["colFetch"] = 1
|
|
477 |
else:
|
|
478 |
args["choices"] = ["123", "cs", "cds", "Bob","Marley","Alpha"]
|
|
479 |
|
|
480 |
args["selectCallback"] = self.selectCallback
|
|
481 |
|
|
482 |
self.dynamic_choices = [
|
|
483 |
'aardvark', 'abandon', 'acorn', 'acute', 'adore',
|
|
484 |
'aegis', 'ascertain', 'asteroid',
|
|
485 |
'beautiful', 'bold', 'classic',
|
|
486 |
'daring', 'dazzling', 'debonair', 'definitive',
|
|
487 |
'effective', 'elegant',
|
|
488 |
'http://python.org', 'http://www.google.com',
|
|
489 |
'fabulous', 'fantastic', 'friendly', 'forgiving', 'feature',
|
|
490 |
'sage', 'scarlet', 'scenic', 'seaside', 'showpiece', 'spiffy',
|
|
491 |
'www.wxPython.org', 'www.osafoundation.org'
|
|
492 |
]
|
|
493 |
|
|
494 |
|
|
495 |
app = wx.PySimpleApp()
|
|
496 |
frm = wx.Frame(None,-1,"Test",style=wx.TAB_TRAVERSAL|wx.DEFAULT_FRAME_STYLE)
|
|
497 |
panel = wx.Panel(frm)
|
|
498 |
sizer = wx.BoxSizer(wx.VERTICAL)
|
|
499 |
|
|
500 |
self._ctrl = TextCtrlAutoComplete(panel, **args)
|
|
501 |
but = wx.Button(panel,label="Set other multi-choice")
|
|
502 |
but.Bind(wx.EVT_BUTTON, self.onBtMultiChoice)
|
|
503 |
but2 = wx.Button(panel,label="Set other one-colum choice")
|
|
504 |
but2.Bind(wx.EVT_BUTTON, self.onBtChangeChoice)
|
|
505 |
but3 = wx.Button(panel,label="Set the starting choices")
|
|
506 |
but3.Bind(wx.EVT_BUTTON, self.onBtStartChoices)
|
|
507 |
but4 = wx.Button(panel,label="Enable dynamic choices")
|
|
508 |
but4.Bind(wx.EVT_BUTTON, self.onBtDynamicChoices)
|
|
509 |
|
|
510 |
sizer.Add(but, 0, wx.ADJUST_MINSIZE, 0)
|
|
511 |
sizer.Add(but2, 0, wx.ADJUST_MINSIZE, 0)
|
|
512 |
sizer.Add(but3, 0, wx.ADJUST_MINSIZE, 0)
|
|
513 |
sizer.Add(but4, 0, wx.ADJUST_MINSIZE, 0)
|
|
514 |
sizer.Add(self._ctrl, 0, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
|
|
515 |
panel.SetAutoLayout(True)
|
|
516 |
panel.SetSizer(sizer)
|
|
517 |
sizer.Fit(panel)
|
|
518 |
sizer.SetSizeHints(panel)
|
|
519 |
panel.Layout()
|
|
520 |
app.SetTopWindow(frm)
|
|
521 |
frm.Show()
|
|
522 |
but.SetFocus()
|
|
523 |
app.MainLoop()
|
|
524 |
|
|
525 |
def onBtChangeChoice(self, event):
|
|
526 |
#change the choices
|
|
527 |
self._ctrl.SetChoices(["123", "cs", "cds", "Bob","Marley","Alpha"])
|
|
528 |
self._ctrl.SetEntryCallback(None)
|
|
529 |
self._ctrl.SetMatchFunction(None)
|
|
530 |
|
|
531 |
def onBtMultiChoice(self, event):
|
|
532 |
#change the choices
|
|
533 |
self._ctrl.SetMultipleChoices( [ ("Test","Hello"), ("Other word","World"),
|
|
534 |
("Yes!","it work?") ], colFetch = 1 )
|
|
535 |
self._ctrl.SetEntryCallback(None)
|
|
536 |
self._ctrl.SetMatchFunction(None)
|
|
537 |
|
|
538 |
def onBtStartChoices(self, event):
|
|
539 |
#change the choices
|
|
540 |
self._ctrl.SetMultipleChoices( [ ("Zoey","WOW"), ("Alpha", "wxPython"),
|
|
541 |
("Ceda","Is"), ("Beta", "fantastic"),
|
|
542 |
("zoebob", "!!")], colFetch = 1 )
|
|
543 |
self._ctrl.SetEntryCallback(None)
|
|
544 |
self._ctrl.SetMatchFunction(None)
|
|
545 |
|
|
546 |
def onBtDynamicChoices(self, event):
|
|
547 |
'''
|
|
548 |
Demonstrate dynamic adjustment of the auto-complete list, based on what's
|
|
549 |
been typed so far:
|
|
550 |
'''
|
|
551 |
self._ctrl.SetChoices(self.dynamic_choices)
|
|
552 |
self._ctrl.SetEntryCallback(self.setDynamicChoices)
|
|
553 |
self._ctrl.SetMatchFunction(self.match)
|
|
554 |
|
|
555 |
|
|
556 |
def match(self, text, choice):
|
|
557 |
'''
|
|
558 |
Demonstrate "smart" matching feature, by ignoring http:// and www. when doing
|
|
559 |
matches.
|
|
560 |
'''
|
|
561 |
t = text.lower()
|
|
562 |
c = choice.lower()
|
|
563 |
if c.startswith(t): return True
|
|
564 |
if c.startswith(r'http://'): c = c[7:]
|
|
565 |
if c.startswith(t): return True
|
|
566 |
if c.startswith('www.'): c = c[4:]
|
|
567 |
return c.startswith(t)
|
|
568 |
|
|
569 |
def setDynamicChoices(self):
|
|
570 |
ctrl = self._ctrl
|
|
571 |
text = ctrl.GetValue().lower()
|
|
572 |
current_choices = ctrl.GetChoices()
|
|
573 |
choices = [choice for choice in self.dynamic_choices if self.match(text, choice)]
|
|
574 |
if choices != current_choices:
|
|
575 |
ctrl.SetChoices(choices)
|
|
576 |
|
|
577 |
def selectCallback(self, values):
|
|
578 |
""" Simply function that receive the row values when the
|
|
579 |
user select an item
|
|
580 |
"""
|
|
581 |
print "Select Callback called...:", values
|
|
582 |
|
|
583 |
|
|
584 |
if __name__ == "__main__":
|
|
585 |
test()
|
|
586 |
|