View Issue Details

IDProjectCategoryView StatusLast Update
0028133LazarusLCLpublic2015-12-19 14:32
Reportergilles58Assigned ToBart Broersma 
PrioritynormalSeverityminorReproducibilityalways
Status closedResolutionfixed 
PlatformOSLinuxOS VersionMint 17.1
Product Version1.4Product Build 
Target VersionFixed in Version1.6 
Summary0028133: Issue with ItemIndex in TRadioGroup (one more time)
DescriptionItemIndex := -1 in TRadioGroup doesn't work.
I've read old issues about this problem but the same problem occurs now again.

Steps To ReproducePut a TRadioGroup on a form.
Create two radio buttons with One and Two captions.
Compile and run : first one is always checked.

Put a button on the same form.
In its Onclick event type : RadioGroup.ItemIndex := -1;
Nothing happens...
Additional InformationIt appears that it works fine on Windows 8.1.
TagsNo tags attached.
Fixed in Revisionr50508
LazTarget1.6
WidgetsetGTK 2
Attached Files
  • radiogroup.diff (3,726 bytes)
    Index: lcl/extctrls.pp
    ===================================================================
    --- lcl/extctrls.pp	(revision 48844)
    +++ lcl/extctrls.pp	(working copy)
    @@ -649,6 +649,7 @@
         procedure UpdateControlsPerLine;
         procedure UpdateItems;
         procedure UpdateTabStops;
    +    procedure QueueInitItemIndex(Value: PtrInt);
       protected
         class procedure WSRegisterClass; override;
         procedure UpdateInternalObjectList;
    Index: lcl/include/radiogroup.inc
    ===================================================================
    --- lcl/include/radiogroup.inc	(revision 48844)
    +++ lcl/include/radiogroup.inc	(working copy)
    @@ -110,27 +110,15 @@
       Create the visual component of the Radiogroup.
      ------------------------------------------------------------------------------}
     procedure TCustomRadioGroup.InitializeWnd;
    -
    -  procedure RealizeItemIndex;
    -  var
    -    i: Integer;
    -  begin
    -    if (FItemIndex <> -1) and (FItemIndex<FButtonList.Count) then
    -      TRadioButton(FButtonList[FItemIndex]).Checked := true
    -    else if FHiddenButton<>nil then
    -      FHiddenButton.Checked:=true;
    -    for i:=0 to FItems.Count-1 do begin
    -      TRadioButton(FButtonList[i]).Checked := fItemIndex = i;
    -    end;
    -  end;
    -
     begin
       if FCreatingWnd then RaiseGDBException('TCustomRadioGroup.InitializeWnd');
       FCreatingWnd := true;
       //DebugLn(['[TCustomRadioGroup.InitializeWnd] A ',DbgSName(Self),' FItems.Count=',FItems.Count,' HandleAllocated=',HandleAllocated,' ItemIndex=',ItemIndex]);
       UpdateItems;
       inherited InitializeWnd;
    -  RealizeItemIndex;
    +  //You cannot set ItemIndex to -1 on GTK unless the control ia actaully drawn
    +  //unfortunately you cannot use {ifdef lclgtk2} at this point...
    +  Application.QueueAsyncCall(@QueueInitItemIndex, FItemIndex);
       //debugln(['TCustomRadioGroup.InitializeWnd END']);
       FCreatingWnd := false;
     end;
    @@ -369,6 +357,7 @@
     var
       OldItemIndex: LongInt;
       OldIgnoreClicks: Boolean;
    +  i: Integer;
     begin
       //DebugLn('TCustomRadioGroup.SetItemIndex ',dbgsName(Self),' Old=',dbgs(FItemIndex),' New=',dbgs(Value));
       if Value = FItemIndex then exit;
    @@ -395,8 +384,11 @@
               FHiddenButton.Checked:=true;
             // uncheck old radiobutton
             if (OldItemIndex <> -1) then begin
    +          //GTK does not allow to uncheck all _visible_ radiobuttons in a group (Issue 0028133)
    +          if (FItemIndex = -1) then FHiddenButton.Visible := True;
               if (OldItemIndex>=0) and (OldItemIndex<FButtonList.Count) then
    -            TRadioButton(FButtonList[OldItemIndex]).Checked := false
    +            TRadioButton(FButtonList[OldItemIndex]).Checked := false;
    +          if (FItemIndex = -1) then FHiddenButton.Visible := False;
             end else
               FHiddenButton.Checked:=false;
           finally
    @@ -520,6 +512,24 @@
       end;
     end;
     
    +procedure TCustomRadioGroup.QueueInitItemIndex(Value: PtrInt);
    +var
    +  i: Integer;
    +begin
    +  writeln('QueueInitItemIndex: FItemIndex = ',FItemIndex,' Value = ',Value);
    +  //GTK does not allow all visible radiobuttons to be unchecked
    +  if (FItemIndex = -1) then FHiddenButton.Visible := True;
    +
    +  if (FItemIndex <> -1) and (FItemIndex<FButtonList.Count) then
    +    TRadioButton(FButtonList[FItemIndex]).Checked := true
    +  else if FHiddenButton<>nil then
    +    FHiddenButton.Checked:=true;
    +  for i:=0 to FItems.Count-1 do begin
    +    TRadioButton(FButtonList[i]).Checked := fItemIndex = i;
    +  if (FItemIndex = -1) then FHiddenButton.Visible := False;
    +  end;
    +end;
    +
     class procedure TCustomRadioGroup.WSRegisterClass;
     begin
       inherited WSRegisterClass;
    @@ -539,6 +549,7 @@
       OwnerFormDesignerModified(Self);
     end;
     
    +
     procedure TCustomRadioGroup.SetAutoFill(const AValue: Boolean);
     begin
       if FAutoFill=AValue then exit;
    
    radiogroup.diff (3,726 bytes)
  • radiogroup.patch (913 bytes)
    diff -rupN lazarus/lcl/include/radiogroup.inc lazarus-update/lcl/include/radiogroup.inc
    --- lazarus/lcl/include/radiogroup.inc	2014-12-22 08:53:35.758129000 +0000
    +++ lazarus-update/lcl/include/radiogroup.inc	2015-11-26 09:24:01.596452016 +0000
    @@ -221,8 +221,6 @@ begin
             ARadioButton.Parent := Self;
           end;
           FHiddenButton.Parent:=Self;
    -      if HandleAllocated then
    -        FHiddenButton.HandleNeeded;
     
           // the checked and unchecked states can be applied only after all other
           for i := 0 to FItems.Count-1 do
    @@ -234,6 +232,8 @@ begin
           //FHiddenButton must remain the last item in Controls[], so that Controls[] is in sync with Items[]
           Self.RemoveControl(FHiddenButton);
           Self.InsertControl(FHiddenButton);
    +      if HandleAllocated then
    +        FHiddenButton.HandleNeeded;
           FHiddenButton.Checked := (FItemIndex = -1);
           UpdateTabStops;
         end;
    
    radiogroup.patch (913 bytes)

Relationships

related to 0020510 resolvedLuiz Americo TRadiogroup.ItemIndex -1 does not work 
related to 0022013 resolvedLuiz Americo ItemIndex:=-1 doesn't work 
has duplicate 0029093 resolvedBart Broersma TRadioGroup ItemIndex set to -1 is Ignored 
related to 0028329 closedJuha Manninen gtk2: TPopupMenu GroupIndex = 0 is also valid index 

Activities

Zeljan Rikalo

2015-05-19 15:24

developer   ~0083791

It's gtk2 behaviour AFAIR.

Juha Manninen

2015-05-19 16:16

developer   ~0083795

> I've read old issues about this problem

Do you have IDs of those issue reports? How were they resolved?

Bart Broersma

2015-05-19 21:24

developer   ~0083810

Last edited: 2015-05-20 15:25

View 2 revisions

Wasn't that the reason why there is an "invisible" extra radiobutton in a TRadioGroup?

[edit]

    if (HandleAllocated) then
    begin
      // the radiobuttons are grouped by the widget interface
      // and some does not allow to uncheck all buttons in a group
      // Therefore there is a hidden button
      FItemIndex:=Value;
      OldIgnoreClicks:=FIgnoreClicks;
      FIgnoreClicks:=true;
      try
        if (FItemIndex <> -1) then
          TRadioButton(FButtonList[FItemIndex]).Checked := true
        else
          FHiddenButton.Checked:=true;

Bart Broersma

2015-05-20 15:49

developer   ~0083831

In TRadioGroup.SetItemIndex add

  if (Value = -1) then
  begin
    FHiddenButton.Visible := True;
    FHiddenButton.Visible := False;
  end;

This will "fix" it.

Mind you: setting ItemIndex at designtime to -1 still result in the first radiobutton being selected AND GetItemIndex returns -1, which does not correspond with the visual state.

Maybe GetItemIndex should ask the WidgetSet (if HandleAllocated) and SetItemIndex should check for GetIdemIndex, not for FItemIndex?

(OTOH I thing the GTK designers are right: a RadioGroup should always have one option set)

gilles58

2015-05-20 18:34

reporter   ~0083846

Last edited: 2015-07-12 12:13

View 3 revisions

Old issues :
0020510
0022013

According to the guy that asked on a French forum why ItemIndex doesn't work properly with Lazarus 1.4.0 on Linux OS, it did work with Lazarus 1.0.10. I can't test it because i don't have this old version anymore.

Examining the code, i noticed this :

procedure TCustomRadioGroup.UpdateRadioButtonStates;
var
  i: Integer;
begin
  FItemIndex:=-1; // OK for hidden button with gtk
  FHiddenButton.Checked; // ???
  for i:=0 to FButtonList.Count-1 do
    if TRadioButton(FButtonList[i]).Checked then FItemIndex:=i;
  UpdateTabStops;
end;

Bart is right :
Wasn't that the reason why there is an "invisible" extra radiobutton in a TRadioGroup?

Bart Broersma

2015-07-12 13:47

developer  

radiogroup.diff (3,726 bytes)
Index: lcl/extctrls.pp
===================================================================
--- lcl/extctrls.pp	(revision 48844)
+++ lcl/extctrls.pp	(working copy)
@@ -649,6 +649,7 @@
     procedure UpdateControlsPerLine;
     procedure UpdateItems;
     procedure UpdateTabStops;
+    procedure QueueInitItemIndex(Value: PtrInt);
   protected
     class procedure WSRegisterClass; override;
     procedure UpdateInternalObjectList;
Index: lcl/include/radiogroup.inc
===================================================================
--- lcl/include/radiogroup.inc	(revision 48844)
+++ lcl/include/radiogroup.inc	(working copy)
@@ -110,27 +110,15 @@
   Create the visual component of the Radiogroup.
  ------------------------------------------------------------------------------}
 procedure TCustomRadioGroup.InitializeWnd;
-
-  procedure RealizeItemIndex;
-  var
-    i: Integer;
-  begin
-    if (FItemIndex <> -1) and (FItemIndex<FButtonList.Count) then
-      TRadioButton(FButtonList[FItemIndex]).Checked := true
-    else if FHiddenButton<>nil then
-      FHiddenButton.Checked:=true;
-    for i:=0 to FItems.Count-1 do begin
-      TRadioButton(FButtonList[i]).Checked := fItemIndex = i;
-    end;
-  end;
-
 begin
   if FCreatingWnd then RaiseGDBException('TCustomRadioGroup.InitializeWnd');
   FCreatingWnd := true;
   //DebugLn(['[TCustomRadioGroup.InitializeWnd] A ',DbgSName(Self),' FItems.Count=',FItems.Count,' HandleAllocated=',HandleAllocated,' ItemIndex=',ItemIndex]);
   UpdateItems;
   inherited InitializeWnd;
-  RealizeItemIndex;
+  //You cannot set ItemIndex to -1 on GTK unless the control ia actaully drawn
+  //unfortunately you cannot use {ifdef lclgtk2} at this point...
+  Application.QueueAsyncCall(@QueueInitItemIndex, FItemIndex);
   //debugln(['TCustomRadioGroup.InitializeWnd END']);
   FCreatingWnd := false;
 end;
@@ -369,6 +357,7 @@
 var
   OldItemIndex: LongInt;
   OldIgnoreClicks: Boolean;
+  i: Integer;
 begin
   //DebugLn('TCustomRadioGroup.SetItemIndex ',dbgsName(Self),' Old=',dbgs(FItemIndex),' New=',dbgs(Value));
   if Value = FItemIndex then exit;
@@ -395,8 +384,11 @@
           FHiddenButton.Checked:=true;
         // uncheck old radiobutton
         if (OldItemIndex <> -1) then begin
+          //GTK does not allow to uncheck all _visible_ radiobuttons in a group (Issue 0028133)
+          if (FItemIndex = -1) then FHiddenButton.Visible := True;
           if (OldItemIndex>=0) and (OldItemIndex<FButtonList.Count) then
-            TRadioButton(FButtonList[OldItemIndex]).Checked := false
+            TRadioButton(FButtonList[OldItemIndex]).Checked := false;
+          if (FItemIndex = -1) then FHiddenButton.Visible := False;
         end else
           FHiddenButton.Checked:=false;
       finally
@@ -520,6 +512,24 @@
   end;
 end;
 
+procedure TCustomRadioGroup.QueueInitItemIndex(Value: PtrInt);
+var
+  i: Integer;
+begin
+  writeln('QueueInitItemIndex: FItemIndex = ',FItemIndex,' Value = ',Value);
+  //GTK does not allow all visible radiobuttons to be unchecked
+  if (FItemIndex = -1) then FHiddenButton.Visible := True;
+
+  if (FItemIndex <> -1) and (FItemIndex<FButtonList.Count) then
+    TRadioButton(FButtonList[FItemIndex]).Checked := true
+  else if FHiddenButton<>nil then
+    FHiddenButton.Checked:=true;
+  for i:=0 to FItems.Count-1 do begin
+    TRadioButton(FButtonList[i]).Checked := fItemIndex = i;
+  if (FItemIndex = -1) then FHiddenButton.Visible := False;
+  end;
+end;
+
 class procedure TCustomRadioGroup.WSRegisterClass;
 begin
   inherited WSRegisterClass;
@@ -539,6 +549,7 @@
   OwnerFormDesignerModified(Self);
 end;
 
+
 procedure TCustomRadioGroup.SetAutoFill(const AValue: Boolean);
 begin
   if FAutoFill=AValue then exit;
radiogroup.diff (3,726 bytes)

Bart Broersma

2015-07-12 13:49

developer   ~0084913

@Zeljan: possible patch attached.
Unfortunately it cannot be ifdef-ed for the widgetset ({ifdef lclgtk2}), since that will evaluate to FALSE always.

Tony Whyman

2015-11-26 11:45

reporter   ~0087605

As requested, I have uploaded the patch from 29093 which seems to fix the problem

Tony Whyman

2015-11-26 11:45

reporter  

radiogroup.patch (913 bytes)
diff -rupN lazarus/lcl/include/radiogroup.inc lazarus-update/lcl/include/radiogroup.inc
--- lazarus/lcl/include/radiogroup.inc	2014-12-22 08:53:35.758129000 +0000
+++ lazarus-update/lcl/include/radiogroup.inc	2015-11-26 09:24:01.596452016 +0000
@@ -221,8 +221,6 @@ begin
         ARadioButton.Parent := Self;
       end;
       FHiddenButton.Parent:=Self;
-      if HandleAllocated then
-        FHiddenButton.HandleNeeded;
 
       // the checked and unchecked states can be applied only after all other
       for i := 0 to FItems.Count-1 do
@@ -234,6 +232,8 @@ begin
       //FHiddenButton must remain the last item in Controls[], so that Controls[] is in sync with Items[]
       Self.RemoveControl(FHiddenButton);
       Self.InsertControl(FHiddenButton);
+      if HandleAllocated then
+        FHiddenButton.HandleNeeded;
       FHiddenButton.Checked := (FItemIndex = -1);
       UpdateTabStops;
     end;
radiogroup.patch (913 bytes)

Bart Broersma

2015-11-26 13:58

developer   ~0087609

Applied Tony's patch.
Please test and close if OK.

Issue History

Date Modified Username Field Change
2015-05-19 15:03 gilles58 New Issue
2015-05-19 15:24 Zeljan Rikalo Note Added: 0083791
2015-05-19 16:16 Juha Manninen Note Added: 0083795
2015-05-19 21:24 Bart Broersma Note Added: 0083810
2015-05-20 15:25 Bart Broersma Note Edited: 0083810 View Revisions
2015-05-20 15:49 Bart Broersma Note Added: 0083831
2015-05-20 18:34 gilles58 Note Added: 0083846
2015-05-20 18:35 gilles58 Note Edited: 0083846 View Revisions
2015-05-21 00:12 Juha Manninen Relationship added related to 0020510
2015-05-21 00:12 Juha Manninen Relationship added related to 0022013
2015-06-19 19:11 Zeljan Rikalo Relationship added related to 0028329
2015-07-12 12:13 Bart Broersma Note Edited: 0083846 View Revisions
2015-07-12 13:47 Bart Broersma File Added: radiogroup.diff
2015-07-12 13:47 Bart Broersma Assigned To => Zeljan Rikalo
2015-07-12 13:47 Bart Broersma Status new => assigned
2015-07-12 13:49 Bart Broersma Note Added: 0084913
2015-11-26 11:31 Bart Broersma Relationship added has duplicate 0029093
2015-11-26 11:45 Tony Whyman Note Added: 0087605
2015-11-26 11:45 Tony Whyman File Added: radiogroup.patch
2015-11-26 13:57 Bart Broersma Assigned To Zeljan Rikalo => Bart Broersma
2015-11-26 13:58 Bart Broersma Fixed in Revision => r50508
2015-11-26 13:58 Bart Broersma LazTarget => 1.6
2015-11-26 13:58 Bart Broersma Note Added: 0087609
2015-11-26 13:58 Bart Broersma Status assigned => resolved
2015-11-26 13:58 Bart Broersma Fixed in Version => 1.6
2015-11-26 13:58 Bart Broersma Resolution open => fixed
2015-12-19 14:32 gilles58 Status resolved => closed