Changeset 937
- Timestamp:
- May 30, 2013 4:01:11 PM (10 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/GSASIIgrid.py
r936 r937 146 146 when invalid input is supplied. As valid values are typed, 147 147 they are placed into the dict or list where the initial value 148 came from. The type of the initial value must be int, float or str; 149 this type is preserved. 148 came from. The type of the initial value must be int, 149 float or str or None (see :obj:`key` and :obj:`typeHint`); 150 this type (or the one in :obj:`typeHint`) is preserved. 150 151 151 152 Float values can be entered in the TextCtrl as numbers or also … … 155 156 156 157 :param wx.Panel parent: name of panel or frame that will be 157 the parent to the TextCtrl 158 the parent to the TextCtrl. Can be None. 158 159 159 160 :param dict/list loc: the dict or list with the initial value to be 160 placed in the TextCtrl 161 162 :param int/str key: the dict key or the list index for the value 163 164 :param bool notBlank: if True (default) blank values are not allowed 161 placed in the TextCtrl. 162 163 :param int/str key: the dict key or the list index for the value to be 164 edited by the TextCtrl. The ``loc[key]`` element must exist, but may 165 have value None. If None, the type for the element is taken from 166 :obj:`typeHint` and the value for the control is set initially 167 blank (and thus invalid.) This is a way to specify a field without a 168 default value: a user must set a valid value. 169 If the value is not None, it must have a base 170 type of int, float, str or unicode; the TextCrtl will be initialized 171 from this value. 172 173 :param bool notBlank: if True (default) blank values are invalid 165 174 for str inputs. 166 175 167 :param number min: Minimum allowed value. If None (default) the168 lower limit is unbounded 169 170 :param number max: Maximum allowed value. If None (default) the176 :param number min: minimum allowed valid value. If None (default) the 177 lower limit is unbounded. 178 179 :param number max: maximum allowed valid value. If None (default) the 171 180 upper limit is unbounded 172 181 … … 176 185 177 186 :param function OKcontrol: specifies a function or method that will be 178 called when the input is validated. It is supplied with one argument 179 which is False if the TextCtrl contains an invalid value and True if 180 the value is valid. Note that this function should check all values 181 in the dialog when True, since other entries might be invalid. 187 called when the input is validated. The called function is supplied 188 with one argument which is False if the TextCtrl contains an invalid 189 value and True if the value is valid. 190 Note that this function should check all values 191 in the dialog when True, since other entries might be invalid. 192 The default for this is None, which indicates no function should 193 be called. 194 195 :param function OnLeave: specifies a function or method that will be 196 called when the focus for the control is lost. 197 The called function is supplied with (at present) three keyword arguments: 198 199 :invalid: (*bool*) True if the value for the TextCtrl is invalid 200 :value: (*int/float/str*) the value contained in the TextCtrl 201 :tc: (*wx.TextCtrl*) the TextCtrl name 202 203 The number of keyword arguments may be increased in the future, if needs arise, 204 so it is best to code these functions with a \*\*kwargs argument so they will 205 continue to run without errors 206 207 The default for OnLeave is None, which indicates no function should 208 be called. 209 210 :param type typeHint: the value of typeHint is used if the initial value 211 for the dict/list element ``loc[key]`` is None. In this case typeHint 212 must be int or float, which specifies the type for input to the TextCtrl. 213 Defaults as None. 182 214 183 215 ''' 184 216 def __init__(self,parent,loc,key,notBlank=True,min=None,max=None, 185 size=None,OKcontrol=None): 217 size=None,OKcontrol=None,OnLeave=None,typeHint=None): 218 # save passed values needed outside __init__ 186 219 self.result = loc 187 220 self.key = key 188 221 self.OKcontrol=OKcontrol 189 self.invalid = None 222 self.OnLeave = OnLeave 223 # initialization 224 self.invalid = False # indicates if the control has invalid contents 225 self.evaluated = False # set to True when the validator recognizes an expression 190 226 val = loc[key] 191 if isinstance(val,int) :227 if isinstance(val,int) or (val is None and typeHint is int): 192 228 wx.TextCtrl.__init__( 193 self,parent,wx.ID_ANY, str(val),229 self,parent,wx.ID_ANY, 194 230 validator=NumberValidator(int,result=loc,key=key,min=min,max=max, 195 231 OKcontrol=OKcontrol) 196 232 ) 197 self.invalid = not self.Validate() 198 elif isinstance(val,int) or isinstance(val,float): 233 if val is not None: 234 self.SetValue(str(val)) 235 else: 236 self.ShowStringValidity() 237 elif isinstance(val,float) or (val is None and typeHint is float): 199 238 wx.TextCtrl.__init__( 200 self,parent,wx.ID_ANY, str(val),239 self,parent,wx.ID_ANY, 201 240 validator=NumberValidator(float,result=loc,key=key,min=min,max=max, 202 241 OKcontrol=OKcontrol) 203 242 ) 204 self.invalid = not self.Validate() 205 elif isinstance(val,str): 206 wx.TextCtrl.__init__(self,parent,wx.ID_ANY,str(val)) 243 if val is not None: 244 self.SetValue(str(val)) 245 else: 246 self.ShowStringValidity() 247 elif isinstance(val,str) or isinstance(val,unicode): 248 wx.TextCtrl.__init__(self,parent,wx.ID_ANY,val) 207 249 if notBlank: 208 250 self.Bind(wx.EVT_CHAR,self._onStringKey) … … 210 252 else: 211 253 self.invalid = False 254 elif val is None: 255 raise Exception,("ValidatedTxtCtrl error: value of "+str(key)+ 256 " element is None and typeHint not defined as int or float") 212 257 else: 213 raise Exception,"ValidatedTxtCtrl Unknown type "+str(type(val)) 258 raise Exception,("ValidatedTxtCtrl error: Unknown element ("+str(key)+ 259 ") type: "+str(type(val))) 214 260 if size: self.SetSize(size) 261 # When the mouse is moved away or the widget loses focus 262 # display the last saved value, if an expression 263 self.Bind(wx.EVT_LEAVE_WINDOW, self._onLoseFocus) 264 self.Bind(wx.EVT_KILL_FOCUS, self._onLoseFocus) 215 265 216 266 def _onStringKey(self,event): … … 246 296 self.SetForegroundColour("black") 247 297 self.Refresh() 248 self.result[self.key] = val249 298 if self.OKcontrol and previousInvalid: 250 299 self.OKcontrol(True) 300 self.result[self.key] = val # always store the result 301 302 def _onLoseFocus(self,event): 303 if self.evaluated: self.EvaluateExpression() 304 if self.OnLeave: self.OnLeave(invalid=self.invalid, 305 value=self.result[self.key], 306 tc=self) 307 308 def EvaluateExpression(self): 309 '''Show the computed value when an expression is entered to the TextCtrl 310 Make sure that the number fits by truncating decimal places and switching 311 to scientific notation, as needed. 312 Called on loss of focus. 313 ''' 314 if self.invalid: return # don't substitute for an invalid expression 315 if not self.evaluated: return # true when an expression is evaluated 316 if self.result is not None: # retrieve the stored result 317 val = self.result[self.key] 318 self.SetValue(G2py3.FormatValue(val)) 319 self.evaluated = False # expression has been recast as value, reset flag 251 320 252 321 class NumberValidator(wx.PyValidator): … … 259 328 If the number is valid, it is saved in result[key] 260 329 261 :param type typ: data type, int or float 262 263 :param bool positiveonly: used for typ=int. If True, only positive 264 integers are allowed (default False) 330 :param type typ: the base data type. Must be int or float. 331 332 :param bool positiveonly: If True, negative integers are not allowed 333 (default False). This prevents the + or - keys from being pressed. 334 Used with typ=int; ignored for typ=float. 265 335 266 336 :param number min: Minimum allowed value. If None (default) the … … 282 352 'Create the validator' 283 353 wx.PyValidator.__init__(self) 354 # save passed parameters 284 355 self.typ = typ 285 356 self.positiveonly = positiveonly … … 289 360 self.key = key 290 361 self.OKcontrol = OKcontrol 291 self.evaluated = False 292 # When the mouse is moved away or the widget loses focus 293 # display the last saved value 294 self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeave) 295 self.Bind(wx.EVT_KILL_FOCUS, self.OnLeave) 362 # set allowed keys by data type 296 363 if self.typ == int and self.positiveonly: 297 364 self.validchars = '0123456789' 298 self.Bind(wx.EVT_CHAR, self.OnChar)299 365 elif self.typ == int: 300 366 self.validchars = '0123456789+-' 301 self.Bind(wx.EVT_CHAR, self.OnChar)302 367 elif self.typ == float: 303 368 # allow for above and sind, cosd, sqrt, tand, pi, and abbreviations 304 369 # also addition, subtraction, division, multiplication, exponentiation 305 370 self.validchars = '0123456789.-+eE/cosindcqrtap()*' 306 self.Bind(wx.EVT_CHAR, self.OnChar)307 371 else: 308 372 self.validchars = None 373 self.Bind(wx.EVT_CHAR, self.OnChar) 309 374 def Clone(self): 310 375 'Create a copy of the validator, a strange, but required component' … … 330 395 If the value is valid, save it in the dict/list where 331 396 the initial value was stored, if appropriate. 397 398 :param wx.TextCtrl tc: A reference to the TextCtrl that the validator 399 is associated with. 332 400 ''' 333 401 tc.invalid = False # assume invalid … … 335 403 val = self.typ(tc.GetValue()) 336 404 except (ValueError, SyntaxError) as e: 337 if self.typ is float: # for float values, see if an expression can be 338 # evaluated 405 if self.typ is float: # for float values, see if an expression can be evaluated 339 406 val = G2py3.FormulaEval(tc.GetValue()) 340 407 if val is None: … … 342 409 return 343 410 else: 344 self.evaluated = True411 tc.evaluated = True 345 412 else: 346 413 tc.invalid = True … … 356 423 357 424 def ShowValidity(self,tc): 358 'Set the control colors to show invalid input' 425 '''Set the control colors to show invalid input 426 427 :param wx.TextCtrl tc: A reference to the TextCtrl that the validator 428 is associated with. 429 430 ''' 359 431 if tc.invalid: 360 432 tc.SetForegroundColour("red") … … 370 442 return True 371 443 372 def OnLeave(self, event):373 '''Show the computed value when an expression is entered to the TextCtrl374 Make sure that the number fits by truncating decimal places and switching375 to scientific notation, as needed.376 Called on loss of focus.377 '''378 tc = self.GetWindow()379 if tc.invalid: return # don't substitute for an invalid expression380 if not self.evaluated: return # true when an expression is evaluated381 self.evaluated = False382 if self.result is not None: # retrieve the stored result383 val = self.result[self.key]384 tc.SetValue(G2py3.FormatValue(val))385 386 444 def CheckInput(self,previousInvalid): 387 445 '''called to test every change to the TextCtrl for validity and … … 392 450 If valid, check for any other invalid entries only when 393 451 changing from invalid to valid, since that is slower. 452 453 :param bool previousInvalid: True if the TextCtrl contents were 454 invalid prior to the current change. 394 455 ''' 395 456 tc = self.GetWindow() … … 435 496 436 497 ################################################################################ 498 def CallScrolledMultiEditor(parent,dictlst,elemlst,prelbl=[],postlbl=[], 499 title='Edit items',header='',size=(300,250)): 500 '''Shell routine to call a ScrolledMultiEditor dialog. See 501 :class:`ScrolledMultiEditor` for parameter definitions. 502 503 :returns: True if the OK button is pressed; False if the window is closed 504 with the system menu or the Close button. 505 506 ''' 507 dlg = ScrolledMultiEditor(parent,dictlst,elemlst,prelbl,postlbl, 508 title,header,size) 509 if dlg.ShowModal() == wx.ID_OK: 510 dlg.Destroy() 511 return True 512 else: 513 dlg.Destroy() 514 return False 515 437 516 class ScrolledMultiEditor(wx.Dialog): 438 517 '''Define a window for editing a potentially large number of dict- or … … 472 551 (300,250). 473 552 474 :returns: the wx.Dialog created here. Use .ShowModal() to553 :returns: the wx.Dialog created here. Use method .ShowModal() to display it. 475 554 476 ''Example for use of ScrolledMultiEditor:''555 *Example for use of ScrolledMultiEditor:* 477 556 478 557 :: … … 484 563 print d[k] 485 564 486 ''Example definitions for dictlst and elemlst:''565 *Example definitions for dictlst and elemlst:* 487 566 488 567 :: … … 1230 1309 ################################################################################ 1231 1310 class AddHelp(wx.Menu): 1232 ''' This class a single entry for the help menu (used on the Mac only):1311 '''For the Mac: creates an entry to the help menu of type 1233 1312 'Help on <helpType>': where helpType is a reference to an HTML page to 1234 be opened 1235 1236 NOTE: the title when appending this menu should be '&Help' so the wx handles1237 it correctly.1313 be opened. 1314 1315 NOTE: when appending this menu (menu.Append) be sure to set the title to 1316 '&Help' so that wx handles it correctly. 1238 1317 ''' 1239 1318 def __init__(self,frame,helpType,helpLbl=None,title=''): … … 1255 1334 ################################################################################ 1256 1335 class MyHtmlPanel(wx.Panel): 1257 '''Defines a panel to display Help information''' 1336 '''Defines a panel to display HTML help information, as an alternative to 1337 displaying help information in a web browser. 1338 ''' 1258 1339 def __init__(self, frame, id): 1259 1340 self.frame = frame … … 1313 1394 ################################################################################ 1314 1395 class DataFrame(wx.Frame): 1315 '''Create the dataframe window and all the entries in menus. 1316 The binding is for the menus is not done here, but rather is done 1317 where the functions can be accessed (in various GSASII*GUI modules). 1396 '''Create the data item window and all the entries in menus used in 1397 that window. For Linux and windows, the menu entries are created for the 1398 current data item window, but in the Mac the menu is accessed from all 1399 windows. This means that a different menu is posted depending on which 1400 data item is posted. On the Mac, all the menus contain the data tree menu 1401 items, but additional menus are added specific to the data item. 1402 1403 Note that while the menus are created here, 1404 the binding for the menus is done later in various GSASII*GUI modules, 1405 where the functions to be called are defined. 1318 1406 ''' 1319 1407 def Bind(self,*args,**kwargs): … … 2944 3032 frm.Show(True) 2945 3033 Data1 = { 2946 'Order': 0,3034 'Order':1, 2947 3035 'omega':'string', 2948 3036 'chi':2.0, … … 2962 3050 header="""This is a longer\nmultiline and perhaps silly header""" 2963 3051 dlg = ScrolledMultiEditor(frm,dictlst,elemlst,prelbl,postlbl, 2964 3052 header=header) 2965 3053 print Data1 2966 3054 if dlg.ShowModal() == wx.ID_OK: 2967 3055 for d,k in zip(dictlst,elemlst): 2968 3056 print k,d[k] 2969 #app.MainLoop() 3057 dlg.Destroy() 3058 if CallScrolledMultiEditor(frm,dictlst,elemlst,prelbl,postlbl, 3059 header=header): 3060 for d,k in zip(dictlst,elemlst): 3061 print k,d[k] 3062 3063 #app.MainLoop() -
trunk/GSASIIpy3.py
r933 r937 23 23 be evaluated. 24 24 25 :param str string: Character string c 25 :param str string: Character string containing a Python expression 26 to be evaluated. 27 28 :returns: the value for the expression as a float or None if the expression does not 29 evaluate to a valid number. 30 26 31 ''' 27 32 try: … … 33 38 34 39 def FormatValue(val,maxdigits=10): 35 '''Format a float to fit in maxdigits spaces, showing as much 36 precision as possible, more or less 40 '''Format a float to fit in ``maxdigits`` spaces, showing as much 41 precision as possible, more or less. 42 43 :param float val: number to be formatted. 44 45 :param int maxdigits: the number of digits to be used for display of the 46 number (defaults to 10). 47 48 :returns: a string with <= maxdigits characters (I hope). 37 49 ''' 38 50 # does the standard str() conversion fit?
Note: See TracChangeset
for help on using the changeset viewer.