Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

delphi - 2

Posted on 2013-06-15
14
Medium Priority
?
301 Views
Last Modified: 2013-06-30
in a panel i have two check boxes. User can only check one checkbox at a time. It should show a message and doesn't allow to check the check box if one is already checked.

? to implement?( don't tell me to take radio button)
0
Comment
Question by:AbhiJeet
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
  • 3
  • +3
14 Comments
 
LVL 6

Expert Comment

by:bokist
ID: 39249941
Better use TCheckListBox instead of TCheckBox.
In attached example, I'm using it application wide.
Regards,
  Steve
Unit1.pas
Unit1.dfm
0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 39250013
take radiobutton :)
0
 

Author Comment

by:AbhiJeet
ID: 39250045
i am searching a way to implement this taking tcheckbox only, any idea?
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
LVL 24

Expert Comment

by:jimyX
ID: 39250088
It's your choice at the end to use the component you prefer.
To have the TCheckBoxes do exactly what you mentioned then you have many options:
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  if CheckBox1.Checked then
    CheckBox2.Enabled := False
  else
    CheckBox2.Enabled := True;
end;

procedure TForm1.CheckBox2Click(Sender: TObject);
begin
  if CheckBox1.Checked then
    CheckBox1.Enabled := False
  else
    CheckBox1.Enabled := True;
end;

Open in new window


Or:

procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  if CheckBox2.Checked then
    begin
      CheckBox1.Checked := False;
      CheckBox1.Hint := 'uncheck the other one first';  // or whatever hint you see better
      CheckBox1.ShowHint := True;
    end;

  if not CheckBox1.Checked then
    begin
      CheckBox2.Hint := '';
      CheckBox2.ShowHint := False;
    end;
end;

procedure TForm1.CheckBox2Click(Sender: TObject);
begin
  if CheckBox1.Checked then
    begin
      (Sender as TCheckBox).Checked := False;
      (Sender as TCheckBox).Hint := 'uncheck the other one first';
      (Sender as TCheckBox).ShowHint := True;
    end;

  if not CheckBox2.Checked then
    begin
      CheckBox1.Hint := '';
      CheckBox1.ShowHint := False;
    end;
end;

Open in new window

0
 

Author Comment

by:AbhiJeet
ID: 39250259
checkboxes are getting created dynamically, so i may not able to use these events easily.

Any other nice workaround?
0
 

Author Comment

by:AbhiJeet
ID: 39250261
and obviously there are lot other components in the panel.
0
 
LVL 27

Expert Comment

by:Sinisa Vuk
ID: 39250317
create procedure as jimyX suggest and attach it to runtime created components in code:
chk1.OnClick := CheckBox1Click;
chk2.OnClick := CheckBox2Click;

Open in new window

0
 
LVL 24

Accepted Solution

by:
jimyX earned 1500 total points
ID: 39250419
>   Any other nice workaround?
Of course.The code below uses OnFormCreate to create ten checkboxes and assign OnClick event that does the checking for whether there is any ticked checkbox on the panel:

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    procedure ChkBxClick(Sender: TObject);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure ChkBxsTicked(Pnl:TPanel; Sndr: TObject);
var
  I: Integer;
  OthrChkBx: TControl;
begin
  if Pnl <> nil then
    begin
      for I := 0 to Pnl.ControlCount - 1 do
        begin
          if Pnl.Controls[I] is TCheckBox then
            begin
              OthrChkBx := Pnl.Controls[I];
              if (OthrChkBx is TCheckBox) and (OthrChkBx <> Sndr) then
                begin
                  if (OthrChkBx as TCheckBox).Checked then
                    begin
                      (Sndr AS TCheckbox).Checked := False;
                      (Sndr AS TCheckbox).Hint := (OthrChkBx as TCheckBox).Caption +' is checked!';
                      (Sndr AS TCheckbox).ShowHint := True;
                    end;
                  if not (Sndr AS TCheckbox).Checked then
                    begin
                      (OthrChkBx as TCheckBox).Hint := '';
                      (OthrChkBx as TCheckBox).ShowHint := False;
                    end;
                end;
            end;
        end;
    end;
  end;

procedure TForm1.ChkBxClick(Sender: TObject);
begin
  ChkBxsTicked(Panel1, Sender);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  i:integer;
  ChkBx:TCheckBox;
begin
  for i := 1 to 10 do
    begin
      ChkBx := TCheckBox.Create(Panel1);
      ChkBx.Caption := Format('CheckBox %d', [i]);
      ChkBx.Parent := Panel1;
      ChkBx.Width := 97;
      ChkBx.Left := 12;
      ChkBx.Top := i * 20;
      ChkBx.OnClick := ChkBxClick;
    end;
end;

Open in new window

0
 
LVL 6

Expert Comment

by:bokist
ID: 39250434
What is wrong with my example?
Did you try it?
It can work with runtime created components also.
0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 39257662
jimmy, doesn't the onclick fire when setting the checked ?

i came up with this... somewhat similar
pasfile:
unit uMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type
  TfrmCheckboxMaster = class(TForm)
    pnlCheckOptions: TPanel;
    chkItem1: TCheckBox;
    chkItem3: TCheckBox;
    chkItem2: TCheckBox;
    chkItem4: TCheckBox;
    procedure chkSingleMasterCheckboxClick(Sender: TObject);
  private
  public
  end;

var
  frmCheckboxMaster: TfrmCheckboxMaster;

implementation

{$R *.dfm}

procedure TfrmCheckboxMaster.chkSingleMasterCheckboxClick(Sender: TObject);
var
  MasterItem, SlaveItem: TCheckbox;
  MasterContainer: TWinControl;
  I: Integer;
begin
  // The master is the checkbox clicked
  // if checked, all other checkboxes in the same panel are disabled and unchecked
  // if unchecked all other checkboxes in the same panel are enabled and unchecked
  MasterItem := Sender as TCheckbox;
  // Find the parent of the Master checkbox
  MasterContainer := MasterItem.Parent;
  // Traverse all items in same panel
  for I := 0 to MasterContainer.ControlCount - 1 do
  begin
    // it the item is of the same class in this container, but not the same object
    if (MasterContainer.Controls[I].ClassType = MasterItem.ClassType) and
      (MasterContainer.Controls[I] <> MasterItem) then
    begin
      // Placeholder for the slave item
      SlaveItem := MasterContainer.Controls[I] as TCheckBox;
      // detach the onclick event
      SlaveItem.OnClick := Nil;
      try
        // If master is checked
        if MasterItem.Checked then
        begin
          // Uncheck the slave item
          if SlaveItem.Checked then
            SlaveItem.Checked := False;
          // Disable the slave item
          SlaveItem.Enabled := False;
        end
          else // master is not checked
        begin
          if not SlaveItem.Enabled then
            SlaveItem.Enabled := True;
        end;
      finally
        // Attach the onclick event again
        SlaveItem.OnClick := MasterItem.OnClick;
      end;
    end;
  end;
end;

end.

Open in new window


dfm:
object frmCheckboxMaster: TfrmCheckboxMaster
  Left = 689
  Top = 164
  Caption = 'frmCheckboxMaster'
  ClientHeight = 346
  ClientWidth = 637
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object pnlCheckOptions: TPanel
    Left = 24
    Top = 40
    Width = 489
    Height = 249
    TabOrder = 0
    object chkItem1: TCheckBox
      Left = 48
      Top = 16
      Width = 97
      Height = 17
      Caption = 'chkItem1'
      TabOrder = 0
      OnClick = chkSingleMasterCheckboxClick
    end
    object chkItem3: TCheckBox
      Left = 120
      Top = 48
      Width = 97
      Height = 17
      Caption = 'chkItem3'
      TabOrder = 1
      OnClick = chkSingleMasterCheckboxClick
    end
    object chkItem2: TCheckBox
      Left = 72
      Top = 72
      Width = 97
      Height = 17
      Caption = 'chkItem2'
      TabOrder = 2
      OnClick = chkSingleMasterCheckboxClick
    end
    object chkItem4: TCheckBox
      Left = 112
      Top = 112
      Width = 97
      Height = 17
      Caption = 'chkItem4'
      TabOrder = 3
      OnClick = chkSingleMasterCheckboxClick
    end
  end
end

Open in new window


basically, assign the onclick of all the checkboxes to this event

i see jimmy also hinted towards your next question
0
 
LVL 24

Expert Comment

by:jimyX
ID: 39260635
>   onclick fire when setting the checked
Correct Geert, that's why I set it back to false.

It was obvious that there are two ways to accomplish what the asker is after, either disable the other checkboxes or notify the user that there is a checkbox already checked and undo the checking.

The difference is not that much since you have to iterate through the TCheckBoxes on the panel.

For disabling the other checkboxes same code will be used but the procedure 'ChkBxsTicked' would be:
procedure ChkBxsTicked(Pnl:TPanel; Sndr: TObject);
var
  I: Integer;
  OthrChkBx: TControl;
begin
  if Pnl <> nil then
    begin
      for I := 0 to Pnl.ControlCount - 1 do
        begin
          if Pnl.Controls[I] is TCheckBox then
            begin
              OthrChkBx := Pnl.Controls[I];
              if (OthrChkBx is TCheckBox) and (OthrChkBx <> Sndr) then
                begin
                  if (Sndr AS TCheckbox).Checked then
                    (OthrChkBx as TCheckBox).Enabled := False
                  else
                    (OthrChkBx as TCheckBox).Enabled := True;
                end;
            end;
        end;
    end;
end;

Open in new window

0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 39260850
fwiw ... pnl is the same as Sender.Parent
0
 
LVL 24

Expert Comment

by:jimyX
ID: 39261610
Missed that. You are absolutely right.
0
 
LVL 32

Expert Comment

by:Ephraim Wangoya
ID: 39279270
Here is an example that registers any check box created dynamically and handles the click independent of the form

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TNotifyList = class(TComponent)
  private
    FList: TList;
    FOnClick: TNotifyEvent;
    procedure DoClickCheck(Sender: TObject);
    function GetCheckedItem(ASkip: TCheckBox; out AItem: TCheckBox): Boolean;
    procedure SetOnClick(const Value: TNotifyEvent);
  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  public
    constructor Create(Aowner: TComponent); override;
    destructor Destroy; override;
    procedure RegisterItem(AItem: TCheckBox);
    property OnClick: TNotifyEvent read FOnClick write SetOnClick;
  end;

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    FNotifyList: TNotifyList;
    procedure OtherItemCheckedMessage(Sender: TObject);
    procedure TestCreateCheckBox(Top: Integer);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TNotifyList }

constructor TNotifyList.Create(AOwner: TComponent);
begin
  inherited;
  FList := TList.Create;
end;

destructor TNotifyList.Destroy;
begin
  FreeAndNil(FList);
  inherited;
end;

procedure TNotifyList.DoClickCheck(Sender: TObject);
var
  Chk, Chk2: TCheckBox;
  Index: Integer;
begin
  Index := FList.IndexOf(Sender);
  if Index >= 0 then
  begin
    Chk := TCheckBox(FList[Index]);
    if Chk.Checked and GetCheckedItem(Chk, Chk2) then
    begin
      Chk.OnClick := nil;
      Chk.Checked := False;
      Chk.OnClick := DoClickCheck;
      if Assigned(FOnClick) then
        FOnClick(Chk2);
    end;
  end;
end;

function TNotifyList.GetCheckedItem(ASkip: TCheckBox; out AItem: TCheckBox): Boolean;
var
  I: Integer;
begin
  for I := 0 to FList.Count -1 do
    if TCheckBox(FList[I]).Checked then
    begin
      AItem := TCheckBox(FList[I]);
      if AItem.Checked and (ASkip <> AItem) then
      begin
        Result := True;
        Exit;
      end;
    end;
  Result := False;
end;

procedure TNotifyList.Notification(AComponent: TComponent; Operation: TOperation);
var
  Index: Integer;
begin
  inherited Notification(AComponent, Operation);
  if (Operation = opRemove) and (AComponent is TCheckBox) then
  begin
    Index := FList.IndexOf(AComponent);
    if Index >= 0 then
      FList.Delete(Index);
  end;
end;

procedure TNotifyList.RegisterItem(AItem: TCheckBox);
begin
  if FList.IndexOf(AItem) < 0 then
  begin
    FList.Add(AItem);
    AItem.OnClick := DoClickCheck;
  end;
end;

procedure TNotifyList.SetOnClick(const Value: TNotifyEvent);
begin
  FOnClick := Value;
end;

//Test
procedure TForm1.FormCreate(Sender: TObject);
var
  I: Integer;
begin
  FNotifyList := TNotifyList.Create(Self);
  FNotifyList.OnClick := OtherItemCheckedMessage;
  //Create five check boxes
  for I := 1 to 5 do
    TestCreateCheckBox(I * 20);
end;

procedure TForm1.OtherItemCheckedMessage(Sender: TObject);
begin
  if Sender is TCheckBox then
    ShowMessage(TCheckBox(Sender).Caption + ' is already checked');
end;

procedure TForm1.TestCreateCheckBox(Top: Integer);
var
  Chk: TCheckBox;
begin
  Chk := TCheckBox.Create(Self);
  Chk.Parent := Self;
  Chk.Top := Top;
  Chk.Left := 8;
  Chk.Caption := 'CheckBox' + IntToStr(Top);
  FNotifyList.RegisterItem(Chk);
end;

end.

Open in new window


and the form
object Form1: TForm1
  Left = 192
  Top = 124
  Width = 870
  Height = 640
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
end

Open in new window

0

Featured Post

How to Use the Help Bell

Need to boost the visibility of your question for solutions? Use the Experts Exchange Help Bell to confirm priority levels and contact subject-matter experts for question attention.  Check out this how-to article for more information.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Do you want to know how to make a graph with Microsoft Access? First, create a query with the data for the chart. Then make a blank form and add a chart control. This video also shows how to change what data is displayed on the graph as well as form…
How to fix incompatible JVM issue while installing Eclipse While installing Eclipse in windows, got one error like above and unable to proceed with the installation. This video describes how to successfully install Eclipse. How to solve incompa…
Suggested Courses

688 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question