| 1 | |
| 2 | import wx |
| 3 | import wx.lib.intctrl |
| 4 | |
| 5 | #---------------------------------------------------------------------- |
| 6 | |
| 7 | class TestPanel( wx.Panel ): |
| 8 | def __init__( self, parent, log ): |
| 9 | |
| 10 | wx.Panel.__init__( self, parent, -1 ) |
| 11 | self.log = log |
| 12 | panel = wx.Panel( self, -1 ) |
| 13 | |
| 14 | self.set_min = wx.CheckBox( panel, -1, "Set minimum value:" ) |
| 15 | self.min = wx.lib.intctrl.IntCtrl( panel, size=( 50, -1 ) ) |
| 16 | self.min.Enable( False ) |
| 17 | |
| 18 | self.set_max = wx.CheckBox( panel, -1, "Set maximum value:" ) |
| 19 | self.max = wx.lib.intctrl.IntCtrl( panel, size=( 50, -1 ) ) |
| 20 | self.max.Enable( False ) |
| 21 | |
| 22 | self.limit_target = wx.CheckBox( panel, -1, "Limit control" ) |
| 23 | self.allow_none = wx.CheckBox( panel, -1, "Allow empty control" ) |
| 24 | self.allow_long = wx.CheckBox( panel, -1, "Allow long integers" ) |
| 25 | |
| 26 | label = wx.StaticText( panel, -1, "Resulting integer control:" ) |
| 27 | self.target_ctl = wx.lib.intctrl.IntCtrl( panel ) |
| 28 | |
| 29 | grid = wx.FlexGridSizer( 0, 2, 0, 0 ) |
| 30 | grid.Add( self.set_min, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) |
| 31 | grid.Add( self.min, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) |
| 32 | |
| 33 | grid.Add(self.set_max, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) |
| 34 | grid.Add( self.max, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) |
| 35 | |
| 36 | grid.Add( self.limit_target, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) |
| 37 | grid.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 ) |
| 38 | grid.Add( self.allow_none, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) |
| 39 | grid.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 ) |
| 40 | grid.Add( self.allow_long, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) |
| 41 | grid.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 ) |
| 42 | |
| 43 | grid.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 ) |
| 44 | grid.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 ) |
| 45 | |
| 46 | grid.Add( label, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) |
| 47 | grid.Add( self.target_ctl, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) |
| 48 | |
| 49 | outer_box = wx.BoxSizer( wx.VERTICAL ) |
| 50 | outer_box.Add( grid, 0, wx.ALIGN_CENTRE|wx.ALL, 20 ) |
| 51 | |
| 52 | panel.SetAutoLayout( True ) |
| 53 | panel.SetSizer( outer_box ) |
| 54 | outer_box.Fit( panel ) |
| 55 | panel.Move( (50,50) ) |
| 56 | self.panel = panel |
| 57 | |
| 58 | self.Bind(wx.EVT_CHECKBOX, self.OnSetMin, self.set_min) |
| 59 | self.Bind(wx.EVT_CHECKBOX, self.OnSetMax, self.set_max) |
| 60 | self.Bind(wx.EVT_CHECKBOX, self.SetTargetMinMax, self.limit_target) |
| 61 | self.Bind(wx.EVT_CHECKBOX, self.OnSetAllowNone, self.allow_none) |
| 62 | self.Bind(wx.EVT_CHECKBOX, self.OnSetAllowLong, self.allow_long) |
| 63 | |
| 64 | self.Bind(wx.lib.intctrl.EVT_INT, self.SetTargetMinMax, self.min) |
| 65 | self.Bind(wx.lib.intctrl.EVT_INT, self.SetTargetMinMax, self.max) |
| 66 | self.Bind(wx.lib.intctrl.EVT_INT, self.OnTargetChange, self.target_ctl) |
| 67 | |
| 68 | |
| 69 | def OnSetMin( self, event ): |
| 70 | self.min.Enable( self.set_min.GetValue() ) |
| 71 | self.SetTargetMinMax() |
| 72 | |
| 73 | def OnSetMax( self, event ): |
| 74 | self.max.Enable( self.set_max.GetValue() ) |
| 75 | self.SetTargetMinMax() |
| 76 | |
| 77 | |
| 78 | def SetTargetMinMax( self, event=None ): |
| 79 | min = max = None |
| 80 | self.target_ctl.SetLimited( self.limit_target.GetValue() ) |
| 81 | |
| 82 | if self.set_min.GetValue(): |
| 83 | min = self.min.GetValue() |
| 84 | |
| 85 | if self.set_max.GetValue(): |
| 86 | max = self.max.GetValue() |
| 87 | |
| 88 | cur_min, cur_max = self.target_ctl.GetBounds() |
| 89 | |
| 90 | if min != cur_min and not self.target_ctl.SetMin( min ): |
| 91 | self.log.write( "min (%d) > current max (%d) -- bound not set\n" % ( min, self.target_ctl.GetMax() ) ) |
| 92 | self.min.SetForegroundColour( wx.RED ) |
| 93 | else: |
| 94 | self.min.SetForegroundColour( wx.BLACK ) |
| 95 | |
| 96 | self.min.Refresh() |
| 97 | |
| 98 | if max != cur_max and not self.target_ctl.SetMax( max ): |
| 99 | self.log.write( "max (%d) < current min (%d) -- bound not set\n" % ( max, self.target_ctl.GetMin() ) ) |
| 100 | self.max.SetForegroundColour( wx.RED ) |
| 101 | else: |
| 102 | self.max.SetForegroundColour( wx.BLACK ) |
| 103 | |
| 104 | self.max.Refresh() |
| 105 | |
| 106 | if min != cur_min or max != cur_max: |
| 107 | new_min, new_max = self.target_ctl.GetBounds() |
| 108 | self.log.write( "current min, max: (%s, %s)\n" % ( str(new_min), str(new_max) ) ) |
| 109 | |
| 110 | |
| 111 | def OnSetAllowNone( self, event ): |
| 112 | self.target_ctl.SetNoneAllowed( self.allow_none.GetValue() ) |
| 113 | |
| 114 | |
| 115 | def OnSetAllowLong( self, event ): |
| 116 | self.target_ctl.SetLongAllowed( self.allow_long.GetValue() ) |
| 117 | |
| 118 | |
| 119 | def OnTargetChange( self, event ): |
| 120 | ctl = event.GetEventObject() |
| 121 | value = ctl.GetValue() |
| 122 | ib_str = [ " (out of bounds)", "" ] |
| 123 | self.log.write( "integer value = %s%s\n" % ( str(value), ib_str[ ctl.IsInBounds(value) ] ) ) |
| 124 | |
| 125 | |
| 126 | #---------------------------------------------------------------------- |
| 127 | |
| 128 | def runTest( frame, nb, log ): |
| 129 | win = TestPanel( nb, log ) |
| 130 | return win |
| 131 | |
| 132 | #---------------------------------------------------------------------- |
| 133 | |
| 134 | overview = """<html><body> |
| 135 | <P> |
| 136 | <B>IntCtrl</B> provides a control that takes and returns integers as |
| 137 | value, and provides bounds support and optional value limiting. |
| 138 | <P> |
| 139 | <P> |
| 140 | Here's the API for IntCtrl: |
| 141 | <DL><PRE> |
| 142 | <B>IntCtrl</B>( |
| 143 | parent, id = -1, |
| 144 | <B>value</B> = 0, |
| 145 | <B>min</B> = None, |
| 146 | <B>max</B> = None, |
| 147 | <B>limited</B> = False, |
| 148 | <B>allow_none</B> = False, |
| 149 | <B>allow_long</B> = False, |
| 150 | <B>default_color</B> = wxBLACK, |
| 151 | <B>oob_color</B> = wxRED, |
| 152 | pos = wxDefaultPosition, |
| 153 | size = wxDefaultSize, |
| 154 | style = 0, |
| 155 | name = "integer") |
| 156 | </PRE> |
| 157 | <UL> |
| 158 | <DT><B>value</B> |
| 159 | <DD>If no initial value is set, the default will be zero, or |
| 160 | the minimum value, if specified. If an illegal string is specified, |
| 161 | a ValueError will result. (You can always later set the initial |
| 162 | value with SetValue() after instantiation of the control.) |
| 163 | <BR> |
| 164 | <DL><B>min</B> |
| 165 | <DD>The minimum value that the control should allow. This can be |
| 166 | adjusted with SetMin(). If the control is not limited, any value |
| 167 | below this bound will be colored with the current out-of-bounds color. |
| 168 | <BR> |
| 169 | <DT><B>max</B> |
| 170 | <DD>The maximum value that the control should allow. This can be |
| 171 | adjusted with SetMax(). If the control is not limited, any value |
| 172 | above this bound will be colored with the current out-of-bounds color. |
| 173 | <BR> |
| 174 | <DT><B>limited</B> |
| 175 | <DD>Boolean indicating whether the control prevents values from |
| 176 | exceeding the currently set minimum and maximum values (bounds). |
| 177 | If <I>False</I> and bounds are set, out-of-bounds values will |
| 178 | be colored with the current out-of-bounds color. |
| 179 | <BR> |
| 180 | <DT><B>allow_none</B> |
| 181 | <DD>Boolean indicating whether or not the control is allowed to be |
| 182 | empty, representing a value of <I>None</I> for the control. |
| 183 | <BR> |
| 184 | <DT><B>allow_long</B> |
| 185 | <DD>Boolean indicating whether or not the control is allowed to hold |
| 186 | and return a value of type long as well as int. If False, the |
| 187 | control will be implicitly limited to have a value such that |
| 188 | -sys.maxint-1 <= n <= sys.maxint. |
| 189 | <BR> |
| 190 | <DT><B>default_color</B> |
| 191 | <DD>Color value used for in-bounds values of the control. |
| 192 | <BR> |
| 193 | <DT><B>oob_color</B> |
| 194 | <DD>Color value used for out-of-bounds values of the control |
| 195 | when the bounds are set but the control is not limited. |
| 196 | </UL> |
| 197 | <BR> |
| 198 | <BR> |
| 199 | <DT><B>EVT_INT(win, id, func)</B> |
| 200 | <DD>Respond to a wxEVT_COMMAND_INT_UPDATED event, generated when the |
| 201 | value changes. Notice that this event will always be sent when the |
| 202 | control's contents changes - whether this is due to user input or |
| 203 | comes from the program itself (for example, if SetValue() is called.) |
| 204 | <BR> |
| 205 | <BR> |
| 206 | <DT><B>SetValue(int)</B> |
| 207 | <DD>Sets the value of the control to the integer value specified. |
| 208 | The resulting actual value of the control may be altered to |
| 209 | conform with the bounds set on the control if limited, |
| 210 | or colored if not limited but the value is out-of-bounds. |
| 211 | A ValueError exception will be raised if an invalid value |
| 212 | is specified. |
| 213 | <BR> |
| 214 | <DT><B>GetValue()</B> |
| 215 | <DD>Retrieves the integer value from the control. The value |
| 216 | retrieved will be sized as an int if possible or a long, |
| 217 | if necessary. |
| 218 | <BR> |
| 219 | <BR> |
| 220 | <DT><B>SetMin(min=None)</B> |
| 221 | <DD>Sets the expected minimum value, or lower bound, of the control. |
| 222 | (The lower bound will only be enforced if the control is |
| 223 | configured to limit its values to the set bounds.) |
| 224 | If a value of <I>None</I> is provided, then the control will have |
| 225 | no explicit lower bound. If the value specified is greater than |
| 226 | the current lower bound, then the function returns 0 and the |
| 227 | lower bound will not change from its current setting. On success, |
| 228 | the function returns 1. |
| 229 | <DT><DD>If successful and the current value is |
| 230 | lower than the new lower bound, if the control is limited, the |
| 231 | value will be automatically adjusted to the new minimum value; |
| 232 | if not limited, the value in the control will be colored with |
| 233 | the current out-of-bounds color. |
| 234 | <BR> |
| 235 | <DT><B>GetMin()</B> |
| 236 | <DD>Gets the current lower bound value for the control. |
| 237 | It will return None if no lower bound is currently specified. |
| 238 | <BR> |
| 239 | <BR> |
| 240 | <DT><B>SetMax(max=None)</B> |
| 241 | <DD>Sets the expected maximum value, or upper bound, of the control. |
| 242 | (The upper bound will only be enforced if the control is |
| 243 | configured to limit its values to the set bounds.) |
| 244 | If a value of <I>None</I> is provided, then the control will |
| 245 | have no explicit upper bound. If the value specified is less |
| 246 | than the current lower bound, then the function returns 0 and |
| 247 | the maximum will not change from its current setting. On success, |
| 248 | the function returns 1. |
| 249 | <DT><DD>If successful and the current value |
| 250 | is greater than the new upper bound, if the control is limited |
| 251 | the value will be automatically adjusted to the new maximum value; |
| 252 | if not limited, the value in the control will be colored with the |
| 253 | current out-of-bounds color. |
| 254 | <BR> |
| 255 | <DT><B>GetMax()</B> |
| 256 | <DD>Gets the current upper bound value for the control. |
| 257 | It will return None if no upper bound is currently specified. |
| 258 | <BR> |
| 259 | <BR> |
| 260 | <DT><B>SetBounds(min=None,max=None)</B> |
| 261 | <DD>This function is a convenience function for setting the min and max |
| 262 | values at the same time. The function only applies the maximum bound |
| 263 | if setting the minimum bound is successful, and returns True |
| 264 | only if both operations succeed. <B><I>Note:</I></B> leaving out an argument |
| 265 | will remove the corresponding bound. |
| 266 | <DT><B>GetBounds()</B> |
| 267 | <DD>This function returns a two-tuple (min,max), indicating the |
| 268 | current bounds of the control. Each value can be None if |
| 269 | that bound is not set. |
| 270 | <BR> |
| 271 | <BR> |
| 272 | <DT><B>IsInBounds(value=None)</B> |
| 273 | <DD>Returns <I>True</I> if no value is specified and the current value |
| 274 | of the control falls within the current bounds. This function can also |
| 275 | be called with a value to see if that value would fall within the current |
| 276 | bounds of the given control. |
| 277 | <BR> |
| 278 | <BR> |
| 279 | <DT><B>SetLimited(bool)</B> |
| 280 | <DD>If called with a value of True, this function will cause the control |
| 281 | to limit the value to fall within the bounds currently specified. |
| 282 | If the control's value currently exceeds the bounds, it will then |
| 283 | be limited accordingly. |
| 284 | If called with a value of 0, this function will disable value |
| 285 | limiting, but coloring of out-of-bounds values will still take |
| 286 | place if bounds have been set for the control. |
| 287 | <DT><B>IsLimited()</B> |
| 288 | <DD>Returns <I>True</I> if the control is currently limiting the |
| 289 | value to fall within the current bounds. |
| 290 | <BR> |
| 291 | <BR> |
| 292 | <DT><B>SetNoneAllowed(bool)</B> |
| 293 | <DD>If called with a value of True, this function will cause the control |
| 294 | to allow the value to be empty, representing a value of None. |
| 295 | If called with a value of false, this function will prevent the value |
| 296 | from being None. If the value of the control is currently None, |
| 297 | ie. the control is empty, then the value will be changed to that |
| 298 | of the lower bound of the control, or 0 if no lower bound is set. |
| 299 | <DT><B>IsNoneAllowed()</B> |
| 300 | <DD>Returns <I>True</I> if the control currently allows its |
| 301 | value to be None. |
| 302 | <BR> |
| 303 | <BR> |
| 304 | <DT><B>SetLongAllowed(bool)</B> |
| 305 | <DD>If called with a value of True, this function will cause the |
| 306 | control to allow the value to be a long. If called with a value |
| 307 | of False, and the value of the control is currently a long value, |
| 308 | the value of the control will be adjusted to fall within the |
| 309 | size of an integer type, at either the sys.maxint or -sys.maxint-1, |
| 310 | for positive and negative values, respectively. |
| 311 | <DT><B>IsLongAllowed()</B> |
| 312 | <DD>Returns <I>True</I> if the control currently allows its |
| 313 | value to be of type long. |
| 314 | <BR> |
| 315 | <BR> |
| 316 | <DT><B>SetColors(default_color=wxBLACK, oob_color=wxRED)</B> |
| 317 | <DD>Tells the control what colors to use for normal and out-of-bounds |
| 318 | values. If the value currently exceeds the bounds, it will be |
| 319 | recolored accordingly. |
| 320 | <DT><B>GetColors()</B> |
| 321 | <DD>Returns a tuple of <I>(default_color, oob_color)</I> indicating |
| 322 | the current color settings for the control. |
| 323 | <BR> |
| 324 | <BR> |
| 325 | <DT><B>Cut()</B> |
| 326 | <DD>Will allow cuts to the clipboard of the text portion of the value, |
| 327 | leaving the value of zero if the entire contents are "cut." |
| 328 | <DT><B>Paste()</B> |
| 329 | <DD>Will paste the contents of the clipboard to the selected portion |
| 330 | of the value; if the resulting string does not represent a legal |
| 331 | value, a ValueError will result. If the result is out-of bounds, |
| 332 | it will either be adjusted or colored as appropriate. |
| 333 | </DL> |
| 334 | </body></html> |
| 335 | """ |
| 336 | |
| 337 | |
| 338 | |
| 339 | if __name__ == '__main__': |
| 340 | import sys,os |
| 341 | import run |
| 342 | run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) |