1

Delphi 2005を使用して、ユーザーが部品と数量を選択して見積もりを生成できるTwwDBGrid(InfoPower)があります。選択プロセスの一部は、ユーザーがDiscountAmountとDiscountTypeで構成される各部分に割引を追加できるようにすることです。DiscountAmountは割引額であり、DiscountTypeは割引額のタイプ(%オフ、$オフ、または定額)です。このデータは、ClientDataSetPartsと呼ばれるClientDataSetに保持されます。

OnCalcメソッド(ClientDataSetPartsCalcFields)内に、部品コストと割引に基づいてTotalPriceを再計算する次のコードがあります。RangePricingは、価格が範囲内の数量に基づいて計算される場合に使用されます(つまり、1-100 = $ 100、101-200 = $ 150など)。

procedure TfrmCustom_Services.ClientDataSetPartsCalcFields(
  DataSet: TDataSet);
begin
  inherited;
  // if part is selected then calculate Total
  if (ClientDataSetPartsSelected.Value) then begin
    // if range pricing is defined
    if (ClientDataSetParts.FieldByName('RangePricing').AsBoolean) then begin
      ClientDataSetParts.FieldByName('TotalPrice').Value :=
            ClientDataSetParts.FieldbyName('UnitPrice').Value;
    // otherwise use regular pricing
    end else begin
      ClientDataSetParts.FieldByName('TotalPrice').Value :=
          ClientDataSetParts.FieldbyName('UnitPrice').Value *
          ClientDataSetParts.FieldByName('Quantity').Value;
    end;

  // otherwise clear the Total
  end else begin
    ClientDataSetParts.FieldByName('TotalPrice').Clear;
    if (ClientDataSetParts.FieldByName('Quantity').Value <> null) then
      ClientDataSetParts.FieldByName('Quantity').Clear;
    if (ClientDataSetParts.FieldByName('DiscountAmount').Value <> null) then
      ClientDataSetParts.FieldByName('DiscountAmount').Clear;
    if (ClientDataSetParts.FieldByName('DiscountType').Value <> null) then
      ClientDataSetParts.FieldByName('DiscountType').Clear;
  end;

  // Update totals if Discount is applied
  // Only recalculate if both discount value and type are applied
  // otherwise will constantly get errors when switching fields
  if ((ClientDataSetPartsDiscountAmount.Value > 0) and (ClientDataSetPartsDiscountType.Value <> '')) then begin
    case StringToCaseSelect((ClientDataSetPartsDiscountType.Value), ['% Disc','$ Disc','Price']) of
      0 :
      begin
        ClientDataSetParts.FieldByName('DiscountDollarAmount').Value :=
            ClientDataSetParts.FieldByName('TotalPrice').Value * (ClientDataSetParts.FieldByName('DiscountAmount').Value/100);
        ClientDataSetPartsTotalPrice.Value := ClientDataSetPartsTotalPrice.Value - (ClientDataSetPartsTotalPrice.Value * (ClientDataSetPartsDiscountAmount.Value/100));
      end;
      1 :
      begin
        ClientDataSetParts.FieldByName('DiscountDollarAmount').Value := ClientDataSetPartsDiscountAmount.Value;
        ClientDataSetPartsTotalPrice.Value := ClientDataSetPartsTotalPrice.Value - ClientDataSetPartsDiscountAmount.Value;
      end;
      2 :
      begin
        ClientDataSetParts.FieldByName('DiscountDollarAmount').Value :=
            ClientDataSetPartsTotalPrice.Value - ClientDataSetPartsDiscountAmount.Value;
        ClientDataSetPartsTotalPrice.Value := ClientDataSetPartsDiscountAmount.Value;
      end;
    end;
  end;

end;

問題は、DiscountDollarAmount(APIを介して外部ソースに戻さなければならない割引の実際の金額)を計算しようとしたときに発生します。ClientDataSetParts.FieldByName('DiscountDollarAmount')。Valueを設定するたびに、ClientDataSetPartsCalcFieldsが再度呼び出され、無限の呼び出しが発生し、最終的にスタックオーバーフローが発生します。

ClientDataSetPartsCalcFieldsを再帰的に呼び出さずに、この値を更新するにはどうすればよいですか?

4

2 に答える 2

2

発生している無限ループは、コードが値を変更し、値が変更されたことを確認し、変更を再開することによって発生します(既にご存知のとおり)。これを修正するには、プロシージャの最初でOnCalcイベントをnilに設定し、最後にプロシージャに再設定します。このように、イベントモニタリングは、実際に処理している間は一時停止し、処理が完了して新しい値が割り当てられた後に再開します。

于 2012-10-17T15:53:03.613 に答える
2

この動作は、計算されていないフィールドを変更したときに発生します。イベントは、OnCalcFields計算されていないフィールドに変更を加えてはなりません。

私はあなたのデータベース構造について何も知りませんが、私の勘が正しければ、OnCalcFieldsイベントハンドラーのどこかで計算されていないフィールドを変更しています。また、計算されていないフィールドを変更するため、計算されたフィールドを再計算する必要があります。そしてそうOnCalcFields呼ばれています。これは、計算されていないフィールドを変更します。そして、まあ、あなたはこれがどこに向かっているのかを見ることができます!

于 2012-10-17T18:02:02.630 に答える