一次仅选中一个复选框 [英] Only One CheckBox Checked at a time

查看:124
本文介绍了一次仅选中一个复选框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

[编译器:Delphi XE2]

[Compiler: Delphi XE2]

昨天我花了一整天的时间尝试各种方法来完成此特定任务,但它们都以相同的结果结束。

I have spent all day yesterday trying all sorts of ways to accomplish this specific task but they have all ended in the same result.

使用TRZCheckGroup和此示例查看已检查的内容。

Using TRZCheckGroup and this example to see what has been checked ect..

procedure TFrmMain.cbOptionsChange(Sender: TObject; Index: Integer; NewState: TCheckBoxState);
var
  ItmIndex0, ItmIndex1: Integer;
begin
  { Initialize ItemIndex's }
  ItmIndex0 := -1;
  ItmIndex1 := -1;

  { Return the position Index of the string's(0 and 1) }
  ItmIndex0 := cbOptions.Items.IndexOf('One');
  ItmIndex1 := cbOptions.Items.IndexOf('Two');

  { Which CheckBox has been Checked } 
  cbOptions.ItemChecked[ItmIndex0] := True;
  cbOptions.ItemChecked[ItmIndex1] := False;
end;

注意:^这不是我的最终代码,只是我如何处理CheckBoxes的示例。

NOTE: ^This is not my Final code just an example of how i am dealing with the CheckBoxes.

类似-

if cbOptions.ItemChecked[ItmIndex0] then
  cbOptions.ItemChecked[ItmIndex1] := False
else cbOptions.ItemChecked[ItmIndex1] := True;

他们是第一次工作,所以它总是评估为真,我理解为什么。 else位只有在我取消选中第一个CheckBox时才起作用,这显然不是我想要的结果。

They work the first time then it always evaluates to true which i understand why. The else bit will only be in action when i un-check the first CheckBox, which is obviously not my desired result.

似乎该事件停止了,并且在我的某些地方

Seems the Event stops working and on some of my attempts it has fired twice for some reason.

cbListOptionsChange上的NewState参数,这是什么,无论如何它可以帮助我?

The NewState Param on cbListOptionsChange, what is this and can it help me in anyway?

在此方面的任何帮助将不胜感激。

Any help on this will be much appreciated.

谢谢。

if cbOptions.ItemChecked[ItmIndex0] then
  cbOptions.ItemChecked[ItmIndex1] := False
else if cbOptions.ItemChecked[ItmIndex1] then
  cbOptions.ItemChecked[ItmIndex0] := False;

如果选中了第二个CheckBox,则请参见以下内容,然后我检查第一个CheckBox是否按要求工作,

See something like this if the second CheckBox is checked then i check the first one it works as required, but then obviously after that you cannot check the second CheckBox no more.

肯·怀特-片段(正在运行)。将组件的名称替换为默认,因为人们可能会感到困惑,有时会帮助使用默认命名来保存将来的问题。

Ken White - Snippet(Working). Replaced the name of the component with Default as people could get confused else, sometimes helps with default naming to save future questions.

procedure TForm1.RzCheckGroup1Change(Sender: TObject; Index: Integer; NewState: TCheckBoxState);
var
  i: Integer;
begin
  // Keep this event from being fired again while we're here.
  // Your code isn't clear about what the actual name of the
  // component or this event, (the event is named `cbListOptionsChange`,
  // but your code references `cbOptions` - I don't know which is
  // correct, so change it if needed in the next line and
  // the one in the `finally` block below. I'm using `cbListOptions`
  // here.
  RzCheckGroup1.OnChange := nil;

  try
    // If we're getting notified of a new item being checked...
    if NewState = cbChecked then
    begin
      // Iterate through the items, unchecking all that aren't
      // at the index that just became checked.
      // I wouldn't use `for..in`, because the ordering works better here
      for i := 0 to RzCheckGroup1.Items.Count - 1 do
        if i <> Index then
          RzCheckGroup1.ItemChecked[i] := False; // Ryan - Just changed to this from this cbListOptions.Items[i].Checked := False;
    end;

    // Ryan - Uncomment these two lines if you want one of them to be Checked at all times, this will set the CheckBox you are trying to Uncheck to Checked. 
    //if not RzCheckGroup1.ItemChecked[Index] then
    //  RzCheckGroup1.ItemChecked[Index] := True;

  finally
    // Reconnect the event
    RzCheckGroup1.OnChange := RzCheckGroup1Change;
  end;
end;


推荐答案

我对 TRZCheckGroup ,但是您当前的代码将始终在 ItmIndex0 上检查该项目,并取消选中其他项目。

I'm not familiar with TRZCheckGroup, but your current code will always check the item at ItmIndex0 and uncheck the other.

TCheckBoxState 在Delphi文档中定义为

TCheckBoxState is defined in the Delphi documentation as

TCheckBoxState = (
  cbUnchecked,
  cbChecked,
  cbGrayed
);

所以 NewState 似乎告诉了您设置 CheckBox 的状态,然后 Index 告诉您哪个复选框正在更改。大多数情况下,不使用 cbGrayed ,因为它表示从未设置过该值;通常仅当您在读取数据库中的BOOLEAN(或位)列且它为NULL时才有用。

So NewState appears to tell you the newly set state of the CheckBox, and Index tells you which checkbox is changing. Most of the time, cbGrayed isn't used, because it indicates the value has never been set; it's usually only useful when you're reading a BOOLEAN (or bit) column in a database and it's NULL.

此事件并不意味着真的会改变状态两个复选框,它将出现;它的意思是让您在单个项目(在项目组中)更改状态时做出反应:

This event isn't meant really to alternate the state of two checkboxes, it would appear; it's meant to just let you react when a single item (among the group of items) changes it's state:

procedure TFrmMain.cbListOptionsChange(Sender: TObject; Index: Integer; 
  NewState: TCheckBoxState);
begin
  case NewState of
    cbUnchecked: // Do whatever when cbOptions.Items[Index] is unchecked
    cbChecked:   // Do whatever when cbOptions.Items[Index] is checked
    cbGrayed:    // Usually ignored unless NULL in db column is indicated
  end;
end;

只反转两个复选框的状态(将一个更改为备用状态,将另一个更改为相反状态) ),则可以使用类似的方法(使用两个标准的 TCheckBox 控件,并为其两个 OnClick 定义相同的事件事件):

To just reverse the state of two checkboxes (changing one to the alternate state and the other to it's opposite), you can use something like this (uses two standard TCheckBox controls with the same event defined for both of their OnClick events):

procedure TFrmMain.CheckBoxClick(Sender: Object);
var
  ChkBox: TCheckBox;
  BoxToToggle: TCheckBox;
begin
  // If you're sure the event is only for TCheckBox
  ChangingBox := TCheckBox(Sender);
  // If there's a chance it's used for something else
  // if (Sender is TCheckBox) then
  // begin
  //   ChangingBox := TCheckBox(Sender); 
  //   
  // or
  //   ChangingBox := Sender as TCheckBox


  if ChangingBox = CheckBox1 then
    BoxToToggle := CheckBox2
  else
    BoxToToggle := CheckBox1;

  // Disable this event for both checkboxes, so it doesn't
  // fire recursively
  ChangingBox.OnClick := nil;
  BoxToToggle.OnClick := nil;
  try
    BoxToToggle.Checked := not ChangingBox.Checked;
  finally
    // Reconnect event handlers
    ChangingBox.OnClick := CheckBoxClick;
    BoxToToggle.OnClick := CheckBoxClick; 
  end;

但是,如果您只是处理一系列应检查的项目清单,其他未选中的选项,则应该使用 TRadioGroup 。它会自动为您提供此行为。使用复选框违反了正常的Windows GUI行为,并且会使您的用户感到困惑。

However, if you're just dealing with a list of items where one should be checked and all the others unchecked, you should be using a TRadioGroup instead. It gives you this behavior automatically. Using checkboxes is against the normal Windows GUI behavior, and will confuse your users.

话虽这么说(还有我的反对意见, strong 这!),并且未经测试,因为我没有您正在使用的组件,您可以尝试一下(这是我最好的判断甚至写的!):

With that being said (and with my strong objections to doing this!), and untested because I don't have the component you're using, you can try this (this is SO against my better judgement to even write!):

procedure TFrmMain.cbListOptionsChange(Sender: TObject; Index: Integer; 
  NewState: TCheckBoxState);
var
  i: Integer;
begin
  // Keep this event from being fired again while we're here.
  // Your code isn't clear about what the actual name of the
  // component or this event, (the event is named `cbListOptionsChange`,
  // but your code references `cbOptions` - I don't know which is
  // correct, so change it if needed in the next line and
  // the one in the `finally` block below. I'm using `cbListOptions`
  // here.
  cbListOptions.OnChange := nil;

  try
    // If we're getting notified of a new item being checked...
    if NewState = cbChecked then
    begin
      // Iterate through the items, unchecking all that aren't
      // at the index that just became checked.
      // I wouldn't use `for..in`, because the ordering works better here
      for i := 0 to cbListOptions.Items.Count - 1 do
        if i <> Index then
          cbListOptions.Items[i].Checked := False;
    end;        
  finally
    // Reconnect the event
    cbListOptions.OnChange := cbListOptionsChange;
  end;
end;

为清楚起见,我认为这是一个非常不好的主意 ,如果您为我工作,我将不允许。当有适当的可用选项IMO时,做与预期的Windows行为相反的事情就是错误

To make sure it's clear, I think this is a very bad idea, and if you were working for me I'd not allow it. It's simply wrong to do something so opposed to the expected Windows behavior when there's a proper option available, IMO.

这篇关于一次仅选中一个复选框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆