1 #----------------------------------------------------------------------------
2 # Name: wxPython.lib.intctrl.py
5 # Copyright: (c) 2003 by Will Sadkin
7 # License: wxWindows license
8 #----------------------------------------------------------------------------
10 # This was written to provide a standard integer edit control for wxPython.
12 # IntCtrl permits integer (long) values to be retrieved or set via
13 # .GetValue() and .SetValue(), and provides an EVT_INT() event function
14 # for trapping changes to the control.
16 # It supports negative integers as well as the naturals, and does not
17 # permit leading zeros or an empty control; attempting to delete the
18 # contents of the control will result in a (selected) value of zero,
19 # thus preserving a legitimate integer value, or an empty control
20 # (if a value of None is allowed for the control.) Similarly, replacing the
21 # contents of the control with '-' will result in a selected (absolute)
24 # IntCtrl also supports range limits, with the option of either
25 # enforcing them or simply coloring the text of the control if the limits
27 #----------------------------------------------------------------------------
28 # 12/08/2003 - Jeff Grimmett (grimmtooth@softhome.net)
30 # o 2.5 Compatability changes
32 # 12/20/2003 - Jeff Grimmett (grimmtooth@softhome.net)
34 # o wxIntUpdateEvent -> IntUpdateEvent
35 # o wxIntValidator -> IntValidator
36 # o wxIntCtrl -> IntCtrl
44 #----------------------------------------------------------------------------
46 from sys
import maxint
47 MAXINT
= maxint
# (constants should be in upper case)
50 #----------------------------------------------------------------------------
52 # Used to trap events indicating that the current
53 # integer value of the control has been changed.
54 wxEVT_COMMAND_INT_UPDATED
= wx
.NewEventType()
55 EVT_INT
= wx
.PyEventBinder(wxEVT_COMMAND_INT_UPDATED
, 1)
57 #----------------------------------------------------------------------------
59 # wxWindows' wxTextCtrl translates Composite "control key"
60 # events into single events before returning them to its OnChar
61 # routine. The doc says that this results in 1 for Ctrl-A, 2 for
62 # Ctrl-B, etc. However, there are no wxPython or wxWindows
63 # symbols for them, so I'm defining codes for Ctrl-X (cut) and
64 # Ctrl-V (paste) here for readability:
65 WXK_CTRL_X
= (ord('X')+1) - ord('A')
66 WXK_CTRL_V
= (ord('V')+1) - ord('A')
68 class IntUpdatedEvent(wx
.PyCommandEvent
):
69 def __init__(self
, id, value
= 0, object=None):
70 wx
.PyCommandEvent
.__init
__(self
, wxEVT_COMMAND_INT_UPDATED
, id)
73 self
.SetEventObject(object)
76 """Retrieve the value of the control at the time
77 this event was generated."""
81 #----------------------------------------------------------------------------
83 class IntValidator( wx
.PyValidator
):
85 Validator class used with IntCtrl; handles all validation of input
86 prior to changing the value of the underlying wx.TextCtrl.
89 wx
.PyValidator
.__init
__(self
)
90 self
.Bind(wx
.EVT_CHAR
, self
.OnChar
)
93 return self
.__class
__()
95 def Validate(self
, window
): # window here is the *parent* of the ctrl
97 Because each operation on the control is vetted as it's made,
98 the value of the control is always valid.
103 def OnChar(self
, event
):
105 Validates keystrokes to make sure the resulting value will a legal
106 value. Erasing the value causes it to be set to 0, with the value
107 selected, so it can be replaced. Similarly, replacing the value
108 with a '-' sign causes the value to become -1, with the value
109 selected. Leading zeros are removed if introduced by selection,
110 and are prevented from being inserted.
112 key
= event
.GetKeyCode()
113 ctrl
= event
.GetEventObject()
116 value
= ctrl
.GetValue()
117 textval
= wx
.TextCtrl
.GetValue(ctrl
)
118 allow_none
= ctrl
.IsNoneAllowed()
120 pos
= ctrl
.GetInsertionPoint()
121 sel_start
, sel_to
= ctrl
.GetSelection()
122 select_len
= sel_to
- sel_start
124 # (Uncomment for debugging:)
125 ## print 'keycode:', key
127 ## print 'sel_start, sel_to:', sel_start, sel_to
128 ## print 'select_len:', select_len
129 ## print 'textval:', textval
131 # set defaults for processing:
143 # Validate action, and predict resulting value, so we can
144 # range check the result and validate that too.
146 if key
in (wx
.WXK_DELETE
, wx
.WXK_BACK
, WXK_CTRL_X
):
148 new_text
= textval
[:sel_start
] + textval
[sel_to
:]
149 elif key
== wx
.WXK_DELETE
and pos
< len(textval
):
150 new_text
= textval
[:pos
] + textval
[pos
+1:]
151 elif key
== wx
.WXK_BACK
and pos
> 0:
152 new_text
= textval
[:pos
-1] + textval
[pos
:]
153 # (else value shouldn't change)
155 if new_text
in ('', '-'):
156 # Deletion of last significant digit:
157 if allow_none
and new_text
== '':
165 new_value
= ctrl
._fromGUI
(new_text
)
170 elif key
== WXK_CTRL_V
: # (see comments at top of file)
171 # Only allow paste if number:
172 paste_text
= ctrl
._getClipboardContents
()
173 new_text
= textval
[:sel_start
] + paste_text
+ textval
[sel_to
:]
174 if new_text
== '' and allow_none
:
179 # Convert the resulting strings, verifying they
180 # are legal integers and will fit in proper
181 # size if ctrl limited to int. (if not,
183 new_value
= ctrl
._fromGUI
(new_text
)
186 paste_value
= ctrl
._fromGUI
(paste_text
)
190 new_pos
= sel_start
+ len(str(paste_value
))
192 # if resulting value is 0, truncate and highlight value:
193 if new_value
== 0 and len(new_text
) > 1:
196 elif paste_value
== 0:
197 # Disallow pasting a leading zero with nothing selected:
199 and value
is not None
200 and ( (value
>= 0 and pos
== 0)
201 or (value
< 0 and pos
in [0,1]) ) ):
210 elif key
< wx
.WXK_SPACE
or key
> 255:
214 elif chr(key
) == '-':
215 # Allow '-' to result in -1 if replacing entire contents:
217 or (value
== 0 and pos
== 0)
218 or (select_len
>= len(str(abs(value
)))) ):
222 # else allow negative sign only at start, and only if
223 # number isn't already zero or negative:
224 elif pos
!= 0 or (value
is not None and value
< 0):
227 new_text
= '-' + textval
230 new_value
= ctrl
._fromGUI
(new_text
)
235 elif chr(key
) in string
.digits
:
236 # disallow inserting a leading zero with nothing selected
239 and value
is not None
240 and ( (value
>= 0 and pos
== 0)
241 or (value
< 0 and pos
in [0,1]) ) ):
243 # disallow inserting digits before the minus sign:
244 elif value
is not None and value
< 0 and pos
== 0:
247 new_text
= textval
[:sel_start
] + chr(key
) + textval
[sel_to
:]
249 new_value
= ctrl
._fromGUI
(new_text
)
259 # Do range checking for new candidate value:
260 if ctrl
.IsLimited() and not ctrl
.IsInBounds(new_value
):
262 elif new_value
is not None:
263 # ensure resulting text doesn't result in a leading 0:
264 if not set_to_zero
and not set_to_minus_one
:
265 if( (new_value
> 0 and new_text
[0] == '0')
266 or (new_value
< 0 and new_text
[1] == '0')
267 or (new_value
== 0 and select_len
> 1 ) ):
269 # Allow replacement of leading chars with
270 # zero, but remove the leading zero, effectively
271 # making this like "remove leading digits"
273 # Account for leading zero when positioning cursor:
274 if( key
== wx
.WXK_BACK
275 or (paste
and paste_value
== 0 and new_pos
> 0) ):
276 new_pos
= new_pos
- 1
278 wx
.CallAfter(ctrl
.SetValue
, new_value
)
279 wx
.CallAfter(ctrl
.SetInsertionPoint
, new_pos
)
283 # Always do paste numerically, to remove
284 # leading/trailing spaces
285 wx
.CallAfter(ctrl
.SetValue
, new_value
)
286 wx
.CallAfter(ctrl
.SetInsertionPoint
, new_pos
)
289 elif (new_value
== 0 and len(new_text
) > 1 ):
293 ctrl
._colorValue
(new_value
) # (one way or t'other)
295 # (Uncomment for debugging:)
297 ## print 'new value:', new_value
298 ## if paste: print 'paste'
299 ## if set_to_none: print 'set_to_none'
300 ## if set_to_zero: print 'set_to_zero'
301 ## if set_to_minus_one: print 'set_to_minus_one'
302 ## if internally_set: print 'internally_set'
304 ## print 'new text:', new_text
305 ## print 'disallowed'
310 wx
.CallAfter(ctrl
.SetValue
, new_value
)
313 # select to "empty" numeric value
314 wx
.CallAfter(ctrl
.SetValue
, new_value
)
315 wx
.CallAfter(ctrl
.SetInsertionPoint
, 0)
316 wx
.CallAfter(ctrl
.SetSelection
, 0, 1)
318 elif set_to_minus_one
:
319 wx
.CallAfter(ctrl
.SetValue
, new_value
)
320 wx
.CallAfter(ctrl
.SetInsertionPoint
, 1)
321 wx
.CallAfter(ctrl
.SetSelection
, 1, 2)
323 elif not internally_set
:
324 event
.Skip() # allow base wxTextCtrl to finish processing
326 elif not wx
.Validator_IsSilent():
330 def TransferToWindow(self
):
331 """ Transfer data from validator to window.
333 The default implementation returns False, indicating that an error
334 occurred. We simply return True, as we don't do any data transfer.
336 return True # Prevent wx.Dialog from complaining.
339 def TransferFromWindow(self
):
340 """ Transfer data from window to validator.
342 The default implementation returns False, indicating that an error
343 occurred. We simply return True, as we don't do any data transfer.
345 return True # Prevent wx.Dialog from complaining.
348 #----------------------------------------------------------------------------
350 class IntCtrl(wx
.TextCtrl
):
352 This class provides a control that takes and returns integers as
353 value, and provides bounds support and optional value limiting.
358 pos = wxDefaultPosition,
359 size = wxDefaultSize,
361 validator = wxDefaultValidator,
368 default_color = wxBLACK,
372 If no initial value is set, the default will be zero, or
373 the minimum value, if specified. If an illegal string is specified,
374 a ValueError will result. (You can always later set the initial
375 value with SetValue() after instantiation of the control.)
377 The minimum value that the control should allow. This can be
378 adjusted with SetMin(). If the control is not limited, any value
379 below this bound will be colored with the current out-of-bounds color.
380 If min < -sys.maxint-1 and the control is configured to not allow long
381 values, the minimum bound will still be set to the long value, but
382 the implicit bound will be -sys.maxint-1.
384 The maximum value that the control should allow. This can be
385 adjusted with SetMax(). If the control is not limited, any value
386 above this bound will be colored with the current out-of-bounds color.
387 if max > sys.maxint and the control is configured to not allow long
388 values, the maximum bound will still be set to the long value, but
389 the implicit bound will be sys.maxint.
392 Boolean indicating whether the control prevents values from
393 exceeding the currently set minimum and maximum values (bounds).
394 If False and bounds are set, out-of-bounds values will
395 be colored with the current out-of-bounds color.
398 Boolean indicating whether or not the control is allowed to be
399 empty, representing a value of None for the control.
402 Boolean indicating whether or not the control is allowed to hold
403 and return a long as well as an int.
406 Color value used for in-bounds values of the control.
409 Color value used for out-of-bounds values of the control
410 when the bounds are set but the control is not limited.
413 Normally None, IntCtrl uses its own validator to do value
414 validation and input control. However, a validator derived
415 from IntValidator can be supplied to override the data
416 transfer methods for the IntValidator class.
420 self
, parent
, id=-1, value
= 0,
421 pos
= wx
.DefaultPosition
, size
= wx
.DefaultSize
,
422 style
= 0, validator
= wx
.DefaultValidator
,
425 limited
= 0, allow_none
= 0, allow_long
= 0,
426 default_color
= wx
.BLACK
, oob_color
= wx
.RED
,
429 # Establish attrs required for any operation on value:
433 self
.__default
_color
= wx
.BLACK
434 self
.__oob
_color
= wx
.RED
435 self
.__allow
_none
= 0
436 self
.__allow
_long
= 0
437 self
.__oldvalue
= None
439 if validator
== wx
.DefaultValidator
:
440 validator
= IntValidator()
442 wx
.TextCtrl
.__init
__(
443 self
, parent
, id, self
._toGUI
(0),
444 pos
, size
, style
, validator
, name
)
446 # The following lets us set out our "integer update" events:
447 self
.Bind(wx
.EVT_TEXT
, self
.OnText
)
449 # Establish parameters, with appropriate error checking
451 self
.SetBounds(min, max)
452 self
.SetLimited(limited
)
453 self
.SetColors(default_color
, oob_color
)
454 self
.SetNoneAllowed(allow_none
)
455 self
.SetLongAllowed(allow_long
)
460 def OnText( self
, event
):
462 Handles an event indicating that the text control's value
463 has changed, and issue EVT_INT event.
464 NOTE: using wx.TextCtrl.SetValue() to change the control's
465 contents from within a wx.EVT_CHAR handler can cause double
466 text events. So we check for actual changes to the text
467 before passing the events on.
469 value
= self
.GetValue()
470 if value
!= self
.__oldvalue
:
472 self
.GetEventHandler().ProcessEvent(
473 IntUpdatedEvent( self
.GetId(), self
.GetValue(), self
) )
476 # let normal processing of the text continue
478 self
.__oldvalue
= value
# record for next event
483 Returns the current integer (long) value of the control.
485 return self
._fromGUI
( wx
.TextCtrl
.GetValue(self
) )
487 def SetValue(self
, value
):
489 Sets the value of the control to the integer value specified.
490 The resulting actual value of the control may be altered to
491 conform with the bounds set on the control if limited,
492 or colored if not limited but the value is out-of-bounds.
493 A ValueError exception will be raised if an invalid value
496 wx
.TextCtrl
.SetValue( self
, self
._toGUI
(value
) )
500 def SetMin(self
, min=None):
502 Sets the minimum value of the control. If a value of None
503 is provided, then the control will have no explicit minimum value.
504 If the value specified is greater than the current maximum value,
505 then the function returns 0 and the minimum will not change from
506 its current setting. On success, the function returns 1.
508 If successful and the current value is lower than the new lower
509 bound, if the control is limited, the value will be automatically
510 adjusted to the new minimum value; if not limited, the value in the
511 control will be colored with the current out-of-bounds color.
513 If min > -sys.maxint-1 and the control is configured to not allow longs,
514 the function will return 0, and the min will not be set.
516 if( self
.__max
is None
518 or (self
.__max
is not None and self
.__max
>= min) ):
521 if self
.IsLimited() and min is not None and self
.GetValue() < min:
532 Gets the minimum value of the control. It will return the current
533 minimum integer, or None if not specified.
538 def SetMax(self
, max=None):
540 Sets the maximum value of the control. If a value of None
541 is provided, then the control will have no explicit maximum value.
542 If the value specified is less than the current minimum value, then
543 the function returns 0 and the maximum will not change from its
544 current setting. On success, the function returns 1.
546 If successful and the current value is greater than the new upper
547 bound, if the control is limited the value will be automatically
548 adjusted to this maximum value; if not limited, the value in the
549 control will be colored with the current out-of-bounds color.
551 If max > sys.maxint and the control is configured to not allow longs,
552 the function will return 0, and the max will not be set.
554 if( self
.__min
is None
556 or (self
.__min
is not None and self
.__min
<= max) ):
559 if self
.IsLimited() and max is not None and self
.GetValue() > max:
570 Gets the maximum value of the control. It will return the current
571 maximum integer, or None if not specified.
576 def SetBounds(self
, min=None, max=None):
578 This function is a convenience function for setting the min and max
579 values at the same time. The function only applies the maximum bound
580 if setting the minimum bound is successful, and returns True
581 only if both operations succeed.
582 NOTE: leaving out an argument will remove the corresponding bound.
584 ret
= self
.SetMin(min)
585 return ret
and self
.SetMax(max)
590 This function returns a two-tuple (min,max), indicating the
591 current bounds of the control. Each value can be None if
592 that bound is not set.
594 return (self
.__min
, self
.__max
)
597 def SetLimited(self
, limited
):
599 If called with a value of True, this function will cause the control
600 to limit the value to fall within the bounds currently specified.
601 If the control's value currently exceeds the bounds, it will then
602 be limited accordingly.
604 If called with a value of 0, this function will disable value
605 limiting, but coloring of out-of-bounds values will still take
606 place if bounds have been set for the control.
608 self
.__limited
= limited
612 if not min is None and self
.GetValue() < min:
614 elif not max is None and self
.GetValue() > max:
622 Returns True if the control is currently limiting the
623 value to fall within the current bounds.
625 return self
.__limited
628 def IsInBounds(self
, value
=None):
630 Returns True if no value is specified and the current value
631 of the control falls within the current bounds. This function can
632 also be called with a value to see if that value would fall within
633 the current bounds of the given control.
636 value
= self
.GetValue()
638 if( not (value
is None and self
.IsNoneAllowed())
639 and type(value
) not in (types
.IntType
, types
.LongType
) ):
641 'IntCtrl requires integer values, passed %s'% repr(value
) )
645 if min is None: min = value
646 if max is None: max = value
648 # if bounds set, and value is None, return False
649 if value
== None and (min is not None or max is not None):
652 return min <= value
<= max
655 def SetNoneAllowed(self
, allow_none
):
657 Change the behavior of the validation code, allowing control
658 to have a value of None or not, as appropriate. If the value
659 of the control is currently None, and allow_none is 0, the
660 value of the control will be set to the minimum value of the
661 control, or 0 if no lower bound is set.
663 self
.__allow
_none
= allow_none
664 if not allow_none
and self
.GetValue() is None:
666 if min is not None: self
.SetValue(min)
667 else: self
.SetValue(0)
670 def IsNoneAllowed(self
):
671 return self
.__allow
_none
674 def SetLongAllowed(self
, allow_long
):
676 Change the behavior of the validation code, allowing control
677 to have a long value or not, as appropriate. If the value
678 of the control is currently long, and allow_long is 0, the
679 value of the control will be adjusted to fall within the
680 size of an integer type, at either the sys.maxint or -sys.maxint-1,
681 for positive and negative values, respectively.
683 current_value
= self
.GetValue()
684 if not allow_long
and type(current_value
) is types
.LongType
:
685 if current_value
> 0:
686 self
.SetValue(MAXINT
)
688 self
.SetValue(MININT
)
689 self
.__allow
_long
= allow_long
692 def IsLongAllowed(self
):
693 return self
.__allow
_long
697 def SetColors(self
, default_color
=wx
.BLACK
, oob_color
=wx
.RED
):
699 Tells the control what colors to use for normal and out-of-bounds
700 values. If the value currently exceeds the bounds, it will be
701 recolored accordingly.
703 self
.__default
_color
= default_color
704 self
.__oob
_color
= oob_color
710 Returns a tuple of (default_color, oob_color), indicating
711 the current color settings for the control.
713 return self
.__default
_color
, self
.__oob
_color
716 def _colorValue(self
, value
=None):
718 Colors text with oob_color if current value exceeds bounds
721 if not self
.IsInBounds(value
):
722 self
.SetForegroundColour(self
.__oob
_color
)
724 self
.SetForegroundColour(self
.__default
_color
)
728 def _toGUI( self
, value
):
730 Conversion function used to set the value of the control; does
731 type and bounds checking and raises ValueError if argument is
734 if value
is None and self
.IsNoneAllowed():
736 elif type(value
) == types
.LongType
and not self
.IsLongAllowed():
738 'IntCtrl requires integer value, passed long' )
739 elif type(value
) not in (types
.IntType
, types
.LongType
):
741 'IntCtrl requires integer value, passed %s'% repr(value
) )
743 elif self
.IsLimited():
746 if not min is None and value
< min:
748 'value is below minimum value of control %d'% value
)
749 if not max is None and value
> max:
751 'value exceeds value of control %d'% value
)
756 def _fromGUI( self
, value
):
758 Conversion function used in getting the value of the control.
761 # One or more of the underlying text control implementations
762 # issue an intermediate EVT_TEXT when replacing the control's
763 # value, where the intermediate value is an empty string.
764 # So, to ensure consistency and to prevent spurious ValueErrors,
765 # we make the following test, and react accordingly:
768 if not self
.IsNoneAllowed():
776 if self
.IsLongAllowed():
784 Override the wxTextCtrl's .Cut function, with our own
785 that does validation. Will result in a value of 0
786 if entire contents of control are removed.
788 sel_start
, sel_to
= self
.GetSelection()
789 select_len
= sel_to
- sel_start
790 textval
= wx
.TextCtrl
.GetValue(self
)
792 do
= wx
.TextDataObject()
793 do
.SetText(textval
[sel_start
:sel_to
])
794 wx
.TheClipboard
.Open()
795 wx
.TheClipboard
.SetData(do
)
796 wx
.TheClipboard
.Close()
797 if select_len
== len(wxTextCtrl
.GetValue(self
)):
798 if not self
.IsNoneAllowed():
800 self
.SetInsertionPoint(0)
801 self
.SetSelection(0,1)
805 new_value
= self
._fromGUI
(textval
[:sel_start
] + textval
[sel_to
:])
806 self
.SetValue(new_value
)
809 def _getClipboardContents( self
):
811 Subroutine for getting the current contents of the clipboard.
813 do
= wx
.TextDataObject()
814 wx
.TheClipboard
.Open()
815 success
= wx
.TheClipboard
.GetData(do
)
816 wx
.TheClipboard
.Close()
821 # Remove leading and trailing spaces before evaluating contents
822 return do
.GetText().strip()
827 Override the wxTextCtrl's .Paste function, with our own
828 that does validation. Will raise ValueError if not a
829 valid integerizable value.
831 paste_text
= self
._getClipboardContents
()
833 # (conversion will raise ValueError if paste isn't legal)
834 sel_start
, sel_to
= self
.GetSelection()
835 text
= wx
.TextCtrl
.GetValue( self
)
836 new_text
= text
[:sel_start
] + paste_text
+ text
[sel_to
:]
837 if new_text
== '' and self
.IsNoneAllowed():
840 value
= self
._fromGUI
(new_text
)
842 new_pos
= sel_start
+ len(paste_text
)
843 wx
.CallAfter(self
.SetInsertionPoint
, new_pos
)
847 #===========================================================================
849 if __name__
== '__main__':
853 class myDialog(wx
.Dialog
):
854 def __init__(self
, parent
, id, title
,
855 pos
= wx
.DefaultPosition
, size
= wx
.DefaultSize
,
856 style
= wx
.DEFAULT_DIALOG_STYLE
):
857 wx
.Dialog
.__init
__(self
, parent
, id, title
, pos
, size
, style
)
859 self
.int_ctrl
= IntCtrl(self
, wx
.NewId(), size
=(55,20))
860 self
.OK
= wx
.Button( self
, wx
.ID_OK
, "OK")
861 self
.Cancel
= wx
.Button( self
, wx
.ID_CANCEL
, "Cancel")
863 vs
= wx
.BoxSizer( wx
.VERTICAL
)
864 vs
.Add( self
.int_ctrl
, 0, wx
.ALIGN_CENTRE|wx
.ALL
, 5 )
865 hs
= wx
.BoxSizer( wx
.HORIZONTAL
)
866 hs
.Add( self
.OK
, 0, wx
.ALIGN_CENTRE|wx
.ALL
, 5 )
867 hs
.Add( self
.Cancel
, 0, wx
.ALIGN_CENTRE|wx
.ALL
, 5 )
868 vs
.Add(hs
, 0, wx
.ALIGN_CENTRE|wx
.ALL
, 5 )
870 self
.SetAutoLayout( True )
873 vs
.SetSizeHints( self
)
874 self
.Bind(EVT_INT
, self
.OnInt
, self
.int_ctrl
)
876 def OnInt(self
, event
):
877 print 'int now', event
.GetValue()
879 class TestApp(wx
.App
):
882 self
.frame
= wx
.Frame(None, -1, "Test", (20,20), (120,100) )
883 self
.panel
= wx
.Panel(self
.frame
, -1)
884 button
= wx
.Button(self
.panel
, 10, "Push Me", (20, 20))
885 self
.Bind(wx
.EVT_BUTTON
, self
.OnClick
, button
)
887 traceback
.print_exc()
891 def OnClick(self
, event
):
892 dlg
= myDialog(self
.panel
, -1, "test IntCtrl")
893 dlg
.int_ctrl
.SetValue(501)
894 dlg
.int_ctrl
.SetInsertionPoint(1)
895 dlg
.int_ctrl
.SetSelection(1,2)
897 print 'final value', dlg
.int_ctrl
.GetValue()
902 self
.frame
.Show(True)
909 traceback
.print_exc()