@@ -274,6 +274,35 @@ def _focusout_validate(self, **kwargs):
274274
275275 return valid
276276
277+ class ValidatedRadioGroup (ttk .Frame ):
278+ """A validated radio button group"""
279+
280+ def __init__ (
281+ self , * args , variable = None , error_var = None ,
282+ values = None , button_args = None , ** kwargs
283+ ):
284+ super ().__init__ (* args , ** kwargs )
285+ self .variable = variable or tk .StringVar ()
286+ self .error = error_var or tk .StringVar ()
287+ self .values = values or list ()
288+ self .button_args = button_args or dict ()
289+
290+ for v in self .values :
291+ button = ttk .Radiobutton (
292+ self , value = v , text = v ,
293+ variable = self .variable , ** self .button_args
294+ )
295+ button .pack (
296+ side = tk .LEFT , ipadx = 10 , ipady = 2 , expand = True , fill = 'x'
297+ )
298+ self .bind ('<FocusOut>' , self .trigger_focusout_validation )
299+
300+ def trigger_focusout_validation (self , * _ ):
301+ self .error .set ('' )
302+ if not self .variable .get ():
303+ self .error .set ('A value is required' )
304+
305+
277306class BoundText (tk .Text ):
278307 """A Text widget with a bound variable."""
279308
@@ -310,7 +339,7 @@ class LabelInput(ttk.Frame):
310339 field_types = {
311340 FT .string : RequiredEntry ,
312341 FT .string_list : ValidatedCombobox ,
313- FT .short_string_list : ttk . Radiobutton ,
342+ FT .short_string_list : ValidatedRadioGroup ,
314343 FT .iso_date_string : DateEntry ,
315344 FT .long_string : BoundText ,
316345 FT .decimal : ValidatedSpinbox ,
@@ -353,7 +382,9 @@ def __init__(
353382 self .label .grid (row = 0 , column = 0 , sticky = (tk .W + tk .E ))
354383
355384 # setup the variable
356- if input_class in (ttk .Checkbutton , ttk .Button , ttk .Radiobutton ):
385+ if input_class in (
386+ ttk .Checkbutton , ttk .Button , ttk .Radiobutton , ValidatedRadioGroup
387+ ):
357388 input_args ["variable" ] = self .variable
358389 else :
359390 input_args ["textvariable" ] = self .variable
@@ -363,12 +394,12 @@ def __init__(
363394 # for Radiobutton, create one input per value
364395 self .input = tk .Frame (self )
365396 for v in input_args .pop ('values' , []):
366- button = ttk .Radiobutton (
367- self .input , value = v , text = v , ** input_args )
397+ button = input_class (
398+ self .input , value = v , text = v , ** input_args
399+ )
368400 button .pack (side = tk .LEFT , ipadx = 10 , ipady = 2 , expand = True , fill = 'x' )
369401 else :
370402 self .input = input_class (self , ** input_args )
371-
372403 self .input .grid (row = 1 , column = 0 , sticky = (tk .W + tk .E ))
373404 self .columnconfigure (0 , weight = 1 )
374405
0 commit comments