1

[コンパイラ: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;

注:^これは私の最終的なコードではなく、チェックボックスの処理方法の単なる例です。

のようなもの-

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

それらは最初に動作し、それから常にtrueと評価されますが、その理由は理解できます。elseビットは、最初のチェックボックスのチェックを外したときにのみ動作しますが、これは明らかに私の望ましい結果ではありません。

イベントが機能しなくなったようで、私の試みのいくつかでは、何らかの理由で2回発生しました。

cbListOptionsChangeのNewStateParam、これは何ですか、とにかく私を助けることができますか?

これに関するどんな助けも大いに感謝されるでしょう。

ありがとう。

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

2番目のチェックボックスがチェックされている場合はこのようなものを参照してください。最初のチェックボックスは必要に応じて機能しますが、その後は明らかに2番目のチェックボックスをチェックできなくなります。


ケンホワイト-スニペット(ワーキング)。他の人が混乱する可能性があるため、コンポーネントの名前をデフォルトに置き換えました。将来の質問を保存するためにデフォルトの名前付けに役立つ場合があります。

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;
4

2 に答える 2

6

私は に慣れていませんTRZCheckGroupが、現在のコードは常に項目をItmIndex0チェックし、他の項目をチェック解除します。

TCheckBoxStateDelphi のドキュメントでは次のように定義されています。

TCheckBoxState = (
  cbUnchecked,
  cbChecked,
  cbGrayed
);

SoNewStateは、 の新しく設定された状態を示しているように見え、CheckBoxどのIndexチェックボックスが変更されているかを示します。ほとんどのcbGrayed場合、値が設定されていないことを示すため、使用されません。通常、データベースの BOOLEAN (またはビット) 列を読み取っていて、それが NULL の場合にのみ役立ちます。

このイベントは、実際には 2 つのチェックボックスの状態を交互に切り替えることを意図したものではなく、表示されます。(アイテムのグループの中で)単一のアイテムがその状態を変更したときに反応できるようにするためのものです:

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;

2 つのチェックボックスの状態を逆にする (一方を代替状態に変更し、もう一方を反対の状態に変更する) には、次のようなものを使用できます (TCheckBox両方のイベントに同じイベントが定義された 2 つの標準コントロールを使用し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;

ただし、1 つをチェックし、他のすべてをチェックしない項目のリストを扱っているだけの場合は、TRadioGroup代わりに a を使用する必要があります。この動作は自動的に行われます。チェックボックスを使用すると、通常の 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 の動作に反するようなことをするのは、単純に間違っています。

于 2012-06-05T19:22:33.887 に答える
1

この例では、3 つの TCheckbox コントロールを使用しています。

3 つの TCheckbox コントロールをフォームにドロップします。この例では、名前を付けました

cbOpenorderscbClos​​edordersおよびcbAllorders

オブジェクト インスペクターのcbOpenorders.Onclickプロパティにイベントを追加します。

次に、cbClos​​edorders および cbAllorders の OnClick イベント プロパティをこの cbOpenorders イベントに設定します。3 つのボックスはすべて同じイベント ハンドラーを呼び出すため、必要なコードの量が削減されます。

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;

この例では、ユーザーは 1 つのボックスをオンにするか、またはボックスを 1 つもオンにできない制限付きの機能を持っています。

于 2012-06-07T00:15:01.063 に答える