Solved

delphi - 2

Posted on 2013-06-15
14
286 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
  • 4
  • 3
  • 3
  • +3
14 Comments
 
LVL 6

Expert Comment

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

Expert Comment

by:Geert Gruwez
Comment Utility
take radiobutton :)
0
 

Author Comment

by:AbhiJeet
Comment Utility
i am searching a way to implement this taking tcheckbox only, any idea?
0
 
LVL 24

Expert Comment

by:jimyX
Comment Utility
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
Comment Utility
checkboxes are getting created dynamically, so i may not able to use these events easily.

Any other nice workaround?
0
 

Author Comment

by:AbhiJeet
Comment Utility
and obviously there are lot other components in the panel.
0
 
LVL 25

Expert Comment

by:Sinisa Vuk
Comment Utility
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
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 
LVL 24

Accepted Solution

by:
jimyX earned 500 total points
Comment Utility
>   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
Comment Utility
What is wrong with my example?
Did you try it?
It can work with runtime created components also.
0
 
LVL 36

Expert Comment

by:Geert Gruwez
Comment Utility
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
Comment Utility
>   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 36

Expert Comment

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

Expert Comment

by:jimyX
Comment Utility
Missed that. You are absolutely right.
0
 
LVL 32

Expert Comment

by:ewangoya
Comment Utility
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

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Suggested Solutions

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 Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

772 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

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now