cf17abdaa4a5955d75feb545c7a11d0ee99df7fd
[wxWidgets.git] / wxPython / wxPython / lib / intctrl.py
1 #----------------------------------------------------------------------------
2 # Name: wxPython.lib.intctrl.py
3 # Author: Will Sadkin
4 # Created: 01/16/2003
5 # Copyright: (c) 2003 by Will Sadkin
6 # RCS-ID: $Id$
7 # License: wxWindows license
8 #----------------------------------------------------------------------------
9 # NOTE:
10 # This was written to provide a standard integer edit control for wxPython.
11 #
12 # wxIntCtrl 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.
15 #
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)
22 # value of -1.
23 #
24 # wxIntCtrl also supports range limits, with the option of either
25 # enforcing them or simply coloring the text of the control if the limits
26 # are exceeded.
27
28 from wxPython.wx import *
29 import types, string
30 from sys import maxint
31 MAXINT = maxint # (constants should be in upper case)
32 MININT = -maxint-1
33
34 #----------------------------------------------------------------------------
35
36 wxEVT_COMMAND_INT_UPDATED = wxNewEventType()
37
38 # wxWindows' wxTextCtrl translates Composite "control key"
39 # events into single events before returning them to its OnChar
40 # routine. The doc says that this results in 1 for Ctrl-A, 2 for
41 # Ctrl-B, etc. However, there are no wxPython or wxWindows
42 # symbols for them, so I'm defining codes for Ctrl-X (cut) and
43 # Ctrl-V (paste) here for readability:
44 WXK_CTRL_X = (ord('X')+1) - ord('A')
45 WXK_CTRL_V = (ord('V')+1) - ord('A')
46
47
48 def EVT_INT(win, id, func):
49 """Used to trap events indicating that the current
50 integer value of the control has been changed."""
51 win.Connect(id, -1, wxEVT_COMMAND_INT_UPDATED, func)
52
53
54 class wxIntUpdatedEvent(wxPyCommandEvent):
55 def __init__(self, id, value = 0, object=None):
56 wxPyCommandEvent.__init__(self, wxEVT_COMMAND_INT_UPDATED, id)
57
58 self.__value = value
59 self.SetEventObject(object)
60
61 def GetValue(self):
62 """Retrieve the value of the control at the time
63 this event was generated."""
64 return self.__value
65
66
67 #----------------------------------------------------------------------------
68
69 class wxIntValidator( wxPyValidator ):
70 """
71 Validator class used with wxIntCtrl; handles all validation of input
72 prior to changing the value of the underlying wxTextCtrl.
73 """
74 def __init__(self):
75 wxPyValidator.__init__(self)
76 EVT_CHAR(self, self.OnChar)
77
78 def Clone (self):
79 return self.__class__()
80
81 def Validate(self, window): # window here is the *parent* of the ctrl
82 """
83 Because each operation on the control is vetted as it's made,
84 the value of the control is always valid.
85 """
86 return 1
87
88
89 def OnChar(self, event):
90 """
91 Validates keystrokes to make sure the resulting value will a legal
92 value. Erasing the value causes it to be set to 0, with the value
93 selected, so it can be replaced. Similarly, replacing the value
94 with a '-' sign causes the value to become -1, with the value
95 selected. Leading zeros are removed if introduced by selection,
96 and are prevented from being inserted.
97 """
98 key = event.KeyCode()
99 ctrl = event.GetEventObject()
100
101
102 value = ctrl.GetValue()
103 textval = wxTextCtrl.GetValue(ctrl)
104 allow_none = ctrl.IsNoneAllowed()
105
106 pos = ctrl.GetInsertionPoint()
107 sel_start, sel_to = ctrl.GetSelection()
108 select_len = sel_to - sel_start
109
110 # (Uncomment for debugging:)
111 ## print 'keycode:', key
112 ## print 'pos:', pos
113 ## print 'sel_start, sel_to:', sel_start, sel_to
114 ## print 'select_len:', select_len
115 ## print 'textval:', textval
116
117 # set defaults for processing:
118 allow_event = 1
119 set_to_none = 0
120 set_to_zero = 0
121 set_to_minus_one = 0
122 paste = 0
123 internally_set = 0
124
125 new_value = value
126 new_text = textval
127 new_pos = pos
128
129 # Validate action, and predict resulting value, so we can
130 # range check the result and validate that too.
131
132 if key in (WXK_DELETE, WXK_BACK, WXK_CTRL_X):
133 if select_len:
134 new_text = textval[:sel_start] + textval[sel_to:]
135 elif key == WXK_DELETE and pos < len(textval):
136 new_text = textval[:pos] + textval[pos+1:]
137 elif key == WXK_BACK and pos > 0:
138 new_text = textval[:pos-1] + textval[pos:]
139 # (else value shouldn't change)
140
141 if new_text in ('', '-'):
142 # Deletion of last significant digit:
143 if allow_none and new_text == '':
144 new_value = None
145 set_to_none = 1
146 else:
147 new_value = 0
148 set_to_zero = 1
149 else:
150 try:
151 new_value = ctrl._fromGUI(new_text)
152 except ValueError:
153 allow_event = 0
154
155
156 elif key == WXK_CTRL_V: # (see comments at top of file)
157 # Only allow paste if number:
158 paste_text = ctrl._getClipboardContents()
159 new_text = textval[:sel_start] + paste_text + textval[sel_to:]
160 if new_text == '' and allow_none:
161 new_value = None
162 set_to_none = 1
163 else:
164 try:
165 # Convert the resulting strings, verifying they
166 # are legal integers and will fit in proper
167 # size if ctrl limited to int. (if not,
168 # disallow event.)
169 new_value = ctrl._fromGUI(new_text)
170 if paste_text:
171 paste_value = ctrl._fromGUI(paste_text)
172 else:
173 paste_value = 0
174 new_pos = sel_start + len(str(paste_value))
175
176 # if resulting value is 0, truncate and highlight value:
177 if new_value == 0 and len(new_text) > 1:
178 set_to_zero = 1
179
180 elif paste_value == 0:
181 # Disallow pasting a leading zero with nothing selected:
182 if( select_len == 0
183 and value is not None
184 and ( (value >= 0 and pos == 0)
185 or (value < 0 and pos in [0,1]) ) ):
186 allow_event = 0
187 paste = 1
188
189 except ValueError:
190 allow_event = 0
191
192
193 elif key < WXK_SPACE or key > 255:
194 pass # event ok
195
196
197 elif chr(key) == '-':
198 # Allow '-' to result in -1 if replacing entire contents:
199 if( value is None
200 or (value == 0 and pos == 0)
201 or (select_len >= len(str(abs(value)))) ):
202 new_value = -1
203 set_to_minus_one = 1
204
205 # else allow negative sign only at start, and only if
206 # number isn't already zero or negative:
207 elif pos != 0 or (value is not None and value < 0):
208 allow_event = 0
209 else:
210 new_text = '-' + textval
211 new_pos = 1
212 try:
213 new_value = ctrl._fromGUI(new_text)
214 except ValueError:
215 allow_event = 0
216
217
218 elif chr(key) in string.digits:
219 # disallow inserting a leading zero with nothing selected
220 if( chr(key) == '0'
221 and select_len == 0
222 and value is not None
223 and ( (value >= 0 and pos == 0)
224 or (value < 0 and pos in [0,1]) ) ):
225 allow_event = 0
226 # disallow inserting digits before the minus sign:
227 elif value is not None and value < 0 and pos == 0:
228 allow_event = 0
229 else:
230 new_text = textval[:sel_start] + chr(key) + textval[sel_to:]
231 try:
232 new_value = ctrl._fromGUI(new_text)
233 except ValueError:
234 allow_event = 0
235
236 else:
237 # not a legal char
238 allow_event = 0
239
240
241 if allow_event:
242 # Do range checking for new candidate value:
243 if ctrl.IsLimited() and not ctrl.IsInBounds(new_value):
244 allow_event = 0
245 elif new_value is not None:
246 # ensure resulting text doesn't result in a leading 0:
247 if not set_to_zero and not set_to_minus_one:
248 if( (new_value > 0 and new_text[0] == '0')
249 or (new_value < 0 and new_text[1] == '0')
250 or (new_value == 0 and select_len > 1 ) ):
251
252 # Allow replacement of leading chars with
253 # zero, but remove the leading zero, effectively
254 # making this like "remove leading digits"
255
256 # Account for leading zero when positioning cursor:
257 if( key == WXK_BACK
258 or (paste and paste_value == 0 and new_pos > 0) ):
259 new_pos = new_pos - 1
260
261 wxCallAfter(ctrl.SetValue, new_value)
262 wxCallAfter(ctrl.SetInsertionPoint, new_pos)
263 internally_set = 1
264
265 elif paste:
266 # Always do paste numerically, to remove
267 # leading/trailing spaces
268 wxCallAfter(ctrl.SetValue, new_value)
269 wxCallAfter(ctrl.SetInsertionPoint, new_pos)
270 internally_set = 1
271
272 elif (new_value == 0 and len(new_text) > 1 ):
273 allow_event = 0
274
275 if allow_event:
276 ctrl._colorValue(new_value) # (one way or t'other)
277
278 # (Uncomment for debugging:)
279 ## if allow_event:
280 ## print 'new value:', new_value
281 ## if paste: print 'paste'
282 ## if set_to_none: print 'set_to_none'
283 ## if set_to_zero: print 'set_to_zero'
284 ## if set_to_minus_one: print 'set_to_minus_one'
285 ## if internally_set: print 'internally_set'
286 ## else:
287 ## print 'new text:', new_text
288 ## print 'disallowed'
289 ## print
290
291 if allow_event:
292 if set_to_none:
293 wxCallAfter(ctrl.SetValue, new_value)
294
295 elif set_to_zero:
296 # select to "empty" numeric value
297 wxCallAfter(ctrl.SetValue, new_value)
298 wxCallAfter(ctrl.SetInsertionPoint, 0)
299 wxCallAfter(ctrl.SetSelection, 0, 1)
300
301 elif set_to_minus_one:
302 wxCallAfter(ctrl.SetValue, new_value)
303 wxCallAfter(ctrl.SetInsertionPoint, 1)
304 wxCallAfter(ctrl.SetSelection, 1, 2)
305
306 elif not internally_set:
307 event.Skip() # allow base wxTextCtrl to finish processing
308
309 elif not wxValidator_IsSilent():
310 wxBell()
311
312
313 def TransferToWindow(self):
314 """ Transfer data from validator to window.
315
316 The default implementation returns False, indicating that an error
317 occurred. We simply return True, as we don't do any data transfer.
318 """
319 return True # Prevent wxDialog from complaining.
320
321
322 def TransferFromWindow(self):
323 """ Transfer data from window to validator.
324
325 The default implementation returns False, indicating that an error
326 occurred. We simply return True, as we don't do any data transfer.
327 """
328 return True # Prevent wxDialog from complaining.
329
330
331 #----------------------------------------------------------------------------
332
333 class wxIntCtrl(wxTextCtrl):
334 """
335 This class provides a control that takes and returns integers as
336 value, and provides bounds support and optional value limiting.
337
338 wxIntCtrl(
339 parent, id = -1,
340 value = 0,
341 min = None,
342 max = None,
343 limited = False,
344 allow_none = False,
345 allow_long = False,
346 default_color = wxBLACK,
347 oob_color = wxRED,
348 pos = wxDefaultPosition,
349 size = wxDefaultSize,
350 style = 0,
351 name = "integer")
352
353 value
354 If no initial value is set, the default will be zero, or
355 the minimum value, if specified. If an illegal string is specified,
356 a ValueError will result. (You can always later set the initial
357 value with SetValue() after instantiation of the control.)
358 min
359 The minimum value that the control should allow. This can be
360 adjusted with SetMin(). If the control is not limited, any value
361 below this bound will be colored with the current out-of-bounds color.
362 If min < -sys.maxint-1 and the control is configured to not allow long
363 values, the minimum bound will still be set to the long value, but
364 the implicit bound will be -sys.maxint-1.
365 max
366 The maximum value that the control should allow. This can be
367 adjusted with SetMax(). If the control is not limited, any value
368 above this bound will be colored with the current out-of-bounds color.
369 if max > sys.maxint and the control is configured to not allow long
370 values, the maximum bound will still be set to the long value, but
371 the implicit bound will be sys.maxint.
372
373 limited
374 Boolean indicating whether the control prevents values from
375 exceeding the currently set minimum and maximum values (bounds).
376 If False and bounds are set, out-of-bounds values will
377 be colored with the current out-of-bounds color.
378
379 allow_none
380 Boolean indicating whether or not the control is allowed to be
381 empty, representing a value of None for the control.
382
383 allow_long
384 Boolean indicating whether or not the control is allowed to hold
385 and return a long as well as an int.
386
387 default_color
388 Color value used for in-bounds values of the control.
389
390 oob_color
391 Color value used for out-of-bounds values of the control
392 when the bounds are set but the control is not limited.
393 """
394 def __init__ (
395 self, parent, id=-1,
396 value = 0, min=None, max=None,
397 limited = 0, allow_none = 0, allow_long = 0,
398 default_color = wxBLACK, oob_color = wxRED,
399 pos = wxDefaultPosition, size = wxDefaultSize,
400 style = 0, name = "integer",
401 ):
402
403 # Establish attrs required for any operation on value:
404 self.__min = None
405 self.__max = None
406 self.__limited = 0
407 self.__default_color = wxBLACK
408 self.__oob_color = wxRED
409 self.__allow_none = 0
410 self.__allow_long = 0
411
412 wxTextCtrl.__init__(
413 self, parent, id, self._toGUI(0),
414 pos, size, style, wxIntValidator(), name )
415
416 # The following lets us set out our "integer update" events:
417 EVT_TEXT( self, self.GetId(), self.OnText )
418
419 # Establish parameters, with appropriate error checking
420
421 self.SetBounds(min, max)
422 self.SetLimited(limited)
423 self.SetColors(default_color, oob_color)
424 self.SetNoneAllowed(allow_none)
425 self.SetLongAllowed(allow_long)
426 self.SetValue(value)
427
428
429 def OnText( self, event ):
430 """
431 Handles an event indicating that the text control's value
432 has changed, and issue EVT_INT event.
433 """
434 try:
435 self.GetEventHandler().ProcessEvent(
436 wxIntUpdatedEvent( self.GetId(), self.GetValue(), self ) )
437 except ValueError:
438 return
439 # let normal processing of the text continue
440 event.Skip()
441
442
443 def GetValue(self):
444 """
445 Returns the current integer (long) value of the control.
446 """
447 return self._fromGUI( wxTextCtrl.GetValue(self) )
448
449 def SetValue(self, value):
450 """
451 Sets the value of the control to the integer value specified.
452 The resulting actual value of the control may be altered to
453 conform with the bounds set on the control if limited,
454 or colored if not limited but the value is out-of-bounds.
455 A ValueError exception will be raised if an invalid value
456 is specified.
457 """
458 wxTextCtrl.SetValue( self, self._toGUI(value) )
459 self._colorValue()
460
461
462 def SetMin(self, min=None):
463 """
464 Sets the minimum value of the control. If a value of None
465 is provided, then the control will have no explicit minimum value.
466 If the value specified is greater than the current maximum value,
467 then the function returns 0 and the minimum will not change from
468 its current setting. On success, the function returns 1.
469
470 If successful and the current value is lower than the new lower
471 bound, if the control is limited, the value will be automatically
472 adjusted to the new minimum value; if not limited, the value in the
473 control will be colored with the current out-of-bounds color.
474
475 If min > -sys.maxint-1 and the control is configured to not allow longs,
476 the function will return 0, and the min will not be set.
477 """
478 if( self.__max is None
479 or min is None
480 or (self.__max is not None and self.__max >= min) ):
481 self.__min = min
482
483 if self.IsLimited() and min is not None and self.GetValue() < min:
484 self.SetValue(min)
485 else:
486 self._colorValue()
487 return 1
488 else:
489 return 0
490
491
492 def GetMin(self):
493 """
494 Gets the minimum value of the control. It will return the current
495 minimum integer, or None if not specified.
496 """
497 return self.__min
498
499
500 def SetMax(self, max=None):
501 """
502 Sets the maximum value of the control. If a value of None
503 is provided, then the control will have no explicit maximum value.
504 If the value specified is less than the current minimum value, then
505 the function returns 0 and the maximum will not change from its
506 current setting. On success, the function returns 1.
507
508 If successful and the current value is greater than the new upper
509 bound, if the control is limited the value will be automatically
510 adjusted to this maximum value; if not limited, the value in the
511 control will be colored with the current out-of-bounds color.
512
513 If max > sys.maxint and the control is configured to not allow longs,
514 the function will return 0, and the max will not be set.
515 """
516 if( self.__min is None
517 or max is None
518 or (self.__min is not None and self.__min <= max) ):
519 self.__max = max
520
521 if self.IsLimited() and max is not None and self.GetValue() > max:
522 self.SetValue(max)
523 else:
524 self._colorValue()
525 return 1
526 else:
527 return 0
528
529
530 def GetMax(self):
531 """
532 Gets the maximum value of the control. It will return the current
533 maximum integer, or None if not specified.
534 """
535 return self.__max
536
537
538 def SetBounds(self, min=None, max=None):
539 """
540 This function is a convenience function for setting the min and max
541 values at the same time. The function only applies the maximum bound
542 if setting the minimum bound is successful, and returns True
543 only if both operations succeed.
544 NOTE: leaving out an argument will remove the corresponding bound.
545 """
546 ret = self.SetMin(min)
547 return ret and self.SetMax(max)
548
549
550 def GetBounds(self):
551 """
552 This function returns a two-tuple (min,max), indicating the
553 current bounds of the control. Each value can be None if
554 that bound is not set.
555 """
556 return (self.__min, self.__max)
557
558
559 def SetLimited(self, limited):
560 """
561 If called with a value of True, this function will cause the control
562 to limit the value to fall within the bounds currently specified.
563 If the control's value currently exceeds the bounds, it will then
564 be limited accordingly.
565
566 If called with a value of 0, this function will disable value
567 limiting, but coloring of out-of-bounds values will still take
568 place if bounds have been set for the control.
569 """
570 self.__limited = limited
571 if limited:
572 min = self.GetMin()
573 max = self.GetMax()
574 if not min is None and self.GetValue() < min:
575 self.SetValue(min)
576 elif not max is None and self.GetValue() > max:
577 self.SetValue(max)
578 else:
579 self._colorValue()
580
581
582 def IsLimited(self):
583 """
584 Returns True if the control is currently limiting the
585 value to fall within the current bounds.
586 """
587 return self.__limited
588
589
590 def IsInBounds(self, value=None):
591 """
592 Returns True if no value is specified and the current value
593 of the control falls within the current bounds. This function can
594 also be called with a value to see if that value would fall within
595 the current bounds of the given control.
596 """
597 if value is None:
598 value = self.GetValue()
599
600 if( not (value is None and self.IsNoneAllowed())
601 and type(value) not in (types.IntType, types.LongType) ):
602 raise ValueError (
603 'wxIntCtrl requires integer values, passed %s'% repr(value) )
604
605 min = self.GetMin()
606 max = self.GetMax()
607 if min is None: min = value
608 if max is None: max = value
609
610 # if bounds set, and value is None, return False
611 if value == None and (min is not None or max is not None):
612 return 0
613 else:
614 return min <= value <= max
615
616
617 def SetNoneAllowed(self, allow_none):
618 """
619 Change the behavior of the validation code, allowing control
620 to have a value of None or not, as appropriate. If the value
621 of the control is currently None, and allow_none is 0, the
622 value of the control will be set to the minimum value of the
623 control, or 0 if no lower bound is set.
624 """
625 self.__allow_none = allow_none
626 if not allow_none and self.GetValue() is None:
627 min = self.GetMin()
628 if min is not None: self.SetValue(min)
629 else: self.SetValue(0)
630
631
632 def IsNoneAllowed(self):
633 return self.__allow_none
634
635
636 def SetLongAllowed(self, allow_long):
637 """
638 Change the behavior of the validation code, allowing control
639 to have a long value or not, as appropriate. If the value
640 of the control is currently long, and allow_long is 0, the
641 value of the control will be adjusted to fall within the
642 size of an integer type, at either the sys.maxint or -sys.maxint-1,
643 for positive and negative values, respectively.
644 """
645 current_value = self.GetValue()
646 if not allow_long and type(current_value) is types.LongType:
647 if current_value > 0:
648 self.SetValue(MAXINT)
649 else:
650 self.SetValue(MININT)
651 self.__allow_long = allow_long
652
653
654 def IsLongAllowed(self):
655 return self.__allow_long
656
657
658
659 def SetColors(self, default_color=wxBLACK, oob_color=wxRED):
660 """
661 Tells the control what colors to use for normal and out-of-bounds
662 values. If the value currently exceeds the bounds, it will be
663 recolored accordingly.
664 """
665 self.__default_color = default_color
666 self.__oob_color = oob_color
667 self._colorValue()
668
669
670 def GetColors(self):
671 """
672 Returns a tuple of (default_color, oob_color), indicating
673 the current color settings for the control.
674 """
675 return self.__default_color, self.__oob_color
676
677
678 def _colorValue(self, value=None):
679 """
680 Colors text with oob_color if current value exceeds bounds
681 set for control.
682 """
683 if not self.IsInBounds(value):
684 self.SetForegroundColour(self.__oob_color)
685 else:
686 self.SetForegroundColour(self.__default_color)
687 self.Refresh()
688
689
690 def _toGUI( self, value ):
691 """
692 Conversion function used to set the value of the control; does
693 type and bounds checking and raises ValueError if argument is
694 not a valid value.
695 """
696 if value is None and self.IsNoneAllowed():
697 return ''
698 elif type(value) == types.LongType and not self.IsLongAllowed():
699 raise ValueError (
700 'wxIntCtrl requires integer value, passed long' )
701 elif type(value) not in (types.IntType, types.LongType):
702 raise ValueError (
703 'wxIntCtrl requires integer value, passed %s'% repr(value) )
704
705 elif self.IsLimited():
706 min = self.GetMin()
707 max = self.GetMax()
708 if not min is None and value < min:
709 raise ValueError (
710 'value is below minimum value of control %d'% value )
711 if not max is None and value > max:
712 raise ValueError (
713 'value exceeds value of control %d'% value )
714
715 return str(value)
716
717
718 def _fromGUI( self, value ):
719 """
720 Conversion function used in getting the value of the control.
721 """
722 if value == '':
723 if not self.IsNoneAllowed():
724 return 0
725 else:
726 return None
727 else:
728 try:
729 return int( value )
730 except ValueError:
731 if self.IsLongAllowed():
732 return long( value )
733 else:
734 raise
735
736
737 def Cut( self ):
738 """
739 Override the wxTextCtrl's .Cut function, with our own
740 that does validation. Will result in a value of 0
741 if entire contents of control are removed.
742 """
743 sel_start, sel_to = self.GetSelection()
744 select_len = sel_to - sel_start
745 textval = wxTextCtrl.GetValue(self)
746
747 do = wxTextDataObject()
748 do.SetText(textval[sel_start:sel_to])
749 wxTheClipboard.Open()
750 wxTheClipboard.SetData(do)
751 wxTheClipboard.Close()
752 if select_len == len(wxTextCtrl.GetValue(self)):
753 if not self.IsNoneAllowed():
754 self.SetValue(0)
755 self.SetInsertionPoint(0)
756 self.SetSelection(0,1)
757 else:
758 self.SetValue(None)
759 else:
760 new_value = self._fromGUI(textval[:sel_start] + textval[sel_to:])
761 self.SetValue(new_value)
762
763
764 def _getClipboardContents( self ):
765 """
766 Subroutine for getting the current contents of the clipboard.
767 """
768 do = wxTextDataObject()
769 wxTheClipboard.Open()
770 success = wxTheClipboard.GetData(do)
771 wxTheClipboard.Close()
772
773 if not success:
774 return None
775 else:
776 # Remove leading and trailing spaces before evaluating contents
777 return do.GetText().strip()
778
779
780 def Paste( self ):
781 """
782 Override the wxTextCtrl's .Paste function, with our own
783 that does validation. Will raise ValueError if not a
784 valid integerizable value.
785 """
786 paste_text = self._getClipboardContents()
787 if paste_text:
788 # (conversion will raise ValueError if paste isn't legal)
789 sel_start, sel_to = self.GetSelection()
790 text = wxTextCtrl.GetValue( self )
791 new_text = text[:sel_start] + paste_text + text[sel_to:]
792 if new_text == '' and self.IsNoneAllowed():
793 self.SetValue(None)
794 else:
795 value = self._fromGUI(new_text)
796 self.SetValue(value)
797 new_pos = sel_start + len(paste_text)
798 wxCallAfter(self.SetInsertionPoint, new_pos)
799
800
801
802 #===========================================================================
803
804 if __name__ == '__main__':
805
806 import traceback
807
808 class myDialog(wxDialog):
809 def __init__(self, parent, id, title,
810 pos = wxPyDefaultPosition, size = wxPyDefaultSize,
811 style = wxDEFAULT_DIALOG_STYLE ):
812 wxDialog.__init__(self, parent, id, title, pos, size, style)
813
814 self.int_ctrl = wxIntCtrl(self, NewId(), size=(55,20))
815 self.OK = wxButton( self, wxID_OK, "OK")
816 self.Cancel = wxButton( self, wxID_CANCEL, "Cancel")
817
818 vs = wxBoxSizer( wxVERTICAL )
819 vs.AddWindow( self.int_ctrl, 0, wxALIGN_CENTRE|wxALL, 5 )
820 hs = wxBoxSizer( wxHORIZONTAL )
821 hs.AddWindow( self.OK, 0, wxALIGN_CENTRE|wxALL, 5 )
822 hs.AddWindow( self.Cancel, 0, wxALIGN_CENTRE|wxALL, 5 )
823 vs.AddSizer(hs, 0, wxALIGN_CENTRE|wxALL, 5 )
824
825 self.SetAutoLayout( True )
826 self.SetSizer( vs )
827 vs.Fit( self )
828 vs.SetSizeHints( self )
829 EVT_INT(self, self.int_ctrl.GetId(), self.OnInt)
830
831 def OnInt(self, event):
832 print 'int now', event.GetValue()
833
834 class TestApp(wxApp):
835 def OnInit(self):
836 try:
837 self.frame = wxFrame(NULL, -1, "Test",
838 wxPoint(20,20), wxSize(120,100) )
839 self.panel = wxPanel(self.frame, -1)
840 button = wxButton(self.panel, 10, "Push Me",
841 wxPoint(20, 20))
842 EVT_BUTTON(self, 10, self.OnClick)
843 except:
844 traceback.print_exc()
845 return False
846 return True
847
848 def OnClick(self, event):
849 dlg = myDialog(self.panel, -1, "test wxIntCtrl")
850 dlg.int_ctrl.SetValue(501)
851 dlg.int_ctrl.SetInsertionPoint(1)
852 dlg.int_ctrl.SetSelection(1,2)
853 rc = dlg.ShowModal()
854 print 'final value', dlg.int_ctrl.GetValue()
855 del dlg
856 self.frame.Destroy()
857
858 def Show(self):
859 self.frame.Show(True)
860
861 try:
862 app = TestApp(0)
863 app.Show()
864 app.MainLoop()
865 except:
866 traceback.print_exc()