[编译:Delphi XE2]
我昨天花了一整天时间尝试各种方法来完成这项具体任务,但他们都以相同的结果结束了。
使用TRZCheckGroup和此示例查看已检查的内容等。
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的一个例子。
之类的东西 -
if cbOptions.ItemChecked[ItmIndex0] then
cbOptions.ItemChecked[ItmIndex1] := False
else cbOptions.ItemChecked[ItmIndex1] := True;
他们第一次工作然后总是评估为真,我理解为什么。当我取消检查第一个CheckBox时,else位才会生效,这显然不是我想要的结果。
似乎事件停止工作,并且我的一些尝试因为某种原因而被解雇了两次。
关于cbListOptionsChange的NewState Param,这是什么,它能帮助我吗?
对此的任何帮助将不胜感激。
感谢。
if cbOptions.ItemChecked[ItmIndex0] then
cbOptions.ItemChecked[ItmIndex1] := False
else if cbOptions.ItemChecked[ItmIndex1] then
cbOptions.ItemChecked[ItmIndex0] := False;
如果第二个CheckBox被选中,请查看类似的内容,然后根据需要检查第一个CheckBox,但之后显然不能再检查第二个CheckBox。
Ken White - 片段(工作)。将组件的名称替换为Default,因为人们可能会混淆其他名称,有时会帮助默认命名以保存将来的问题。
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;
答案 0 :(得分:6)
我不熟悉TRZCheckGroup
,但您当前的代码将始终检查ItmIndex0
处的项目并取消选中另一项。
TCheckBoxState
在Delphi文档中定义为
TCheckBoxState = (
cbUnchecked,
cbChecked,
cbGrayed
);
因此,NewState
似乎会告诉您新设置的CheckBox
状态,Index
会告诉您哪个复选框正在更改。大多数情况下,cbGrayed
未使用,因为它表示从未设置过值;它通常只在您读取数据库中的BOOLEAN(或位)列时才有用,并且它是NULL。
这个事件并不意味着要交替出现两个复选框的状态,它会出现;当一个项目(在一组项目中)改变它的状态时,它只是让你做出反应:
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
事件:
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行为,会使用户感到困惑。
有了这样说(并且我的强烈反对这样做!),并且未经测试,因为我没有你正在使用的组件,你可以试试这个(这是反对的我更好的判断甚至写!):
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行为相反的事情只是错误。
答案 1 :(得分:1)
此示例使用三个TCheckbox控件。
将三个TCheckbox控件拖放到表单上。在这个例子中,我将它们命名为
cbOpenorders , cbClosedorders 和 cbAllorders
将事件添加到对象检查器中的 cbOpenorders.Onclick 属性。
然后,将cbClosedorders和cbAllorders的OnClick事件属性设置为此cbOpenorders事件。所有三个框都将调用相同的事件处理程序,从而减少所需的代码量。
procedure TFrmPreorderViewDialog.cbOpenOrdersClick(Sender: TObject);
begin
if TCheckbox(Sender).Checked then
begin
cbOpenorders.Checked := (TCheckbox(Sender) = cbOpenorders);
cbClosedorders.checked := (TCheckbox(Sender) = cbClosedorders);
cbAllorders.checked := (TCheckbox(Sender) = cbAllorders);
End;
end;
在此示例中,用户检查一个框或没有框的能力有限。