@@ -283,6 +283,23 @@ def _focusout_validate(self, **kwargs):
283283
284284    return  valid 
285285
286+ class  ValidatedRadio (ttk .Radiobutton ):
287+   """A validated radio button""" 
288+ 
289+   def  __init__ (self , * args , error_var = None , ** kwargs ):
290+     super ().__init__ (* args , ** kwargs )
291+     self .error  =  error_var  or  tk .StringVar ()
292+     self .variable  =  kwargs .get ("variable" )
293+     self .bind ('<FocusOut>' , self ._focusout_validate )
294+ 
295+   def  _focusout_validate (self , * _ ):
296+     self .error .set ('' )
297+     if  not  self .variable .get ():
298+       self .error .set ('A value is required' )
299+ 
300+   def  trigger_focusout_validation (self ):
301+     self ._focusout_validate ()
302+ 
286303class  BoundText (tk .Text ):
287304  """A Text widget with a bound variable.""" 
288305
@@ -335,19 +352,24 @@ def __init__(
335352      self .label .grid (row = 0 , column = 0 , sticky = (tk .W  +  tk .E ))
336353
337354    # setup the variable 
338-     if  input_class  in  (ttk .Checkbutton , ttk .Button , ttk .Radiobutton ):
355+     if  input_class  in  (
356+         ttk .Checkbutton , ttk .Button , ttk .Radiobutton , ValidatedRadio 
357+     ):
339358      input_args ["variable" ] =  self .variable 
340359    else :
341360      input_args ["textvariable" ] =  self .variable 
342361
343362    # Setup the input 
344-     if  input_class  ==   ttk .Radiobutton :
363+     if  input_class  in  ( ttk .Radiobutton ,  ValidatedRadio ) :
345364      # for Radiobutton, create one input per value 
346365      self .input  =  tk .Frame (self )
347366      for  v  in  input_args .pop ('values' , []):
348-         button  =  ttk .Radiobutton (
349-           self .input , value = v , text = v , ** input_args )
367+         button  =  input_class (
368+           self .input , value = v , text = v , ** input_args 
369+         )
350370        button .pack (side = tk .LEFT , ipadx = 10 , ipady = 2 , expand = True , fill = 'x' )
371+       self .input .error  =  getattr (button , 'error' )
372+       self .input .trigger_focusout_validation  =  button .trigger_focusout_validation 
351373    else :
352374      self .input  =  input_class (self , ** input_args )
353375    self .input .grid (row = 1 , column = 0 , sticky = (tk .W  +  tk .E ))
@@ -438,7 +460,7 @@ def __init__(self, *args, **kwargs):
438460
439461    # line 2 
440462    LabelInput (
441-       r_info , "Lab" , input_class = ttk . Radiobutton ,
463+       r_info , "Lab" , input_class = ValidatedRadio ,
442464      var = self ._vars ['Lab' ], input_args = {"values" : ["A" , "B" , "C" ]}
443465    ).grid (row = 1 , column = 0 )
444466    LabelInput (
@@ -668,7 +690,7 @@ def on_save(self):
668690    # If it doesnt' exist, create it, 
669691    # otherwise just append to the existing file 
670692    datestring  =  datetime .today ().strftime ("%Y-%m-%d" )
671-     filename  =  "abq_data_record_{}.csv" . format ( datestring ) 
693+     filename  =  f "abq_data_record_{ datestring } 
672694    newfile  =  not  Path (filename ).exists ()
673695
674696    data  =  self .recordform .get ()
@@ -681,7 +703,7 @@ def on_save(self):
681703
682704    self ._records_saved  +=  1 
683705    self .status .set (
684-       "{ } records saved this session". format ( self . _records_saved ) 
706+       f" { self . _records_saved } 
685707    )
686708    self .recordform .reset ()
687709
0 commit comments