-6

ボタンのクリックで呼び出される実行ブロックで、ボタンがクリックされた場所に表示されるポップアップ メニューを作成します。現在は適切に表示されており、そのうちの 1 つにいくつかのサブアイテムがあるいくつかのアイテムがあります。これが一度実行されてからデストラクタを呼び出すと、問題ありません。しかし、それを 2 回実行すると (ポップアップを表示してアイテムを 2 回クリック)、破棄すると、アプリケーションがクラッシュします。ポップアップを正しく解放していないためだと思います(これはプライベートプロパティとして宣言されています)。

procedure TPlugIn.Execute(AParameters : WideString);
var
  i: Integer;
  pnt: TPoint;
begin
  GetCursorPos(pnt);

  FPopup := TPopupMenu.Create(nil);
  FPopup.OwnerDraw:=True;
  FPopup.AutoHotkeys := maManual;

  //SQL Upgrade
  Item := TMenuItem.Create(FPopup);
  Item.Caption := 'Database Install/Upgrade';
  Item.OnClick := ShowItemCaption;
  FPopup.Items.Add(Item);

  //Language Folder
  Item := TMenuItem.Create(FPopup);
  Item.Caption := 'Language Folder';
  Item.OnClick := ShowItemCaption;
  FPopup.Items.Add(Item);

  //Machines
  Item := TMenuItem.Create(FPopup);
  Item.Caption := 'Machines';

  MachineItem := TMenuItem.Create(FPopup);
  MachineItem.Caption := 'Sample Machine 1';
  MachineItem.OnClick := ShowItemCaption;
  Item.Add(MachineItem);

  MachineItem := TMenuItem.Create(FPopup);
  MachineItem.Caption := 'Sample Machine 2';
  MachineItem.OnClick := ShowItemCaption;
  Item.Add(MachineItem);


  FPopup.Items.Add(Item);

  Self.FPopup := FPopup;

  FPopup.Popup(pnt.X, pnt.Y);

end;

このShowItemCaption手順では、その送信者オブジェクトのキャプションを表示するだけです。特定のイベントはまだコーディングしていません。実行手順でポップアップを解放すると、ポップアップは表示されなくなります。

destructor TPlugIn.Destroy;
begin
  inherited;
  FPopup.Free;
  //ShowMessage('freed');
end;
4

1 に答える 1

2

まず第一に、あなたは問題を完全に誤診しています。その結果、明確な解決策を提供するために必要な情報が提供されていません。

提供されたコードを取得し、説明と同様にテストすると、1 つのボタンを使用して Execute メソッドのコードを呼び出し、別のボタンを使用して を実行してFree FPopupも、エラーは発生しません。実際、これは自分で試してみてください。エラーも発生しません。これは、問題が提供したコードにないことを意味します。

しかし、そうは言っても、私はあなたが問題をよりよく診断するのを助けることができます.
また、このコードには修正が必要な多くの間違いがあります - 間違いがアプリケーションのクラッシュを引き起こさない場合でも。


本当の問題を診断することから始めましょう。あなたのプログラムは本当にクラッシュしていますか、それともデバッガーで例外が発生しているだけですか? Delphi アプリケーションを完全にクラッシュさせるには、通常、もう少し極端な処理が必要になるためです。

例外が発生しただけの場合、デバッガーが次の行に移動していると思われますFPopup.Free;(これは問題のある行ではないことに注意してください。デバッガーは通常、次の行移動します。これは、問題が継承された行のどこかにあることを意味します。破壊)。また、取得している例外クラスとメッセージをお知らせください

いずれにせよ、アプリケーションが実際にクラッシュしている場合でも、ほとんどの場合、その前に例外が発生します。そして、その例外が発生している場所を正確に特定する必要があります。そのためには、次のことを行う必要があります。

  • デバッガーを使用してアプリケーションを実行します。
  • 例外が発生するたびにデバッガーが停止するように設定されていることを確認してください。
  • クラス内で例外が発生している可能性があるTPlugInため、ユニットがデバッグ情報を無効にしていないことを確認してください。
  • プロジェクト オプションを「Use Debug DCU's」に設定する必要がある場合もあります。
  • テストを行います。

例外が発生した場合、デバッガーは通常、例外の原因となった行の次の行を表示することを覚えておいてください。ここで、問題の行をエラー メッセージと併せて検討し、何が問題なのかを突き止める必要があります。

Access Violationが表示される場合は、通常、次のことを試みているためです。

  • 作成されていないものを使用します。
  • すでに破壊されたものを破壊する。
  • すでに破壊されているものを使用してください。

アクセス違反をさらに調査するには:

  • 問題のオブジェクトを特定します。
  • オブジェクトが作成/破棄されるコードにブレークポイントを配置します。
  • コードを実行してブレークポイントに到達し、何が起こっているかを把握します。

その他の問題

  1. 「実行手順でポップアップを解放すると、ポップアップが表示されなくなります」と述べました。(おそらく、これはメモリ リークを回避するための試みでした。) これは、呼び出し時にFPopup.Popup(pnt.X, pnt.Y);「コードを一時停止」せず、アイテムが選択されるのを待つためです。アイテムがクリックされると、メニューはイベント ドリブン モデルを使用してコールバックするため、コードは引き続き実行されます。したがって、ポップアップ メニューは破棄され、ポップアップした直後に消えます。
  2. この行Self.FPopup := FPopup;は完全に冗長で、何もしません。あなたは効果的に言っFPopup := FPopupています-FPopupの値を決して変更していません。
  3. 「ポップアップを 2 回解放するとアプリケーションがクラッシュする」というタイトルが完全に間違っていることは明らかです。コードと説明によると、ポップアップを2回作成し、 1回だけ解放しています。
  4. Jerryが指摘したように、メモリリークがあるため、それ自体が問題です。基本的に、コードは作成した最初の TPopup への参照を上書きし、それを「孤立」させてメモリに保持します。次に、TPlugIn デストラクタで最後Free/Destroyに作成されたものだけを作成します。
  5. TPlugIn の継承されたデストラクタを呼び出す前に、ポップアップを解放します。この場合は必要ありませんが、通常は作成と逆の順序でクリーンアップするのが賢明です。

Execute が呼び出されるたびにポップアップを再作成する必要はありません (少なくともそうすべきではありません)。あなたがしなければならないのは、それを再びポップアップさせることだけFPopup.Popupです。実際、これはFPopup をプライベート クラス フィールドにするポイントの一部です。つまり、一度セットアップして、必要に応じて再利用します。

遅延初期化と呼ばれる手法を使用できます。しかし実際には、通常は不必要な複雑さです。FPopup の作成と破棄を単純にミラーリングする方がはるかに優れています。つまり、TPlugIn が破棄されたときに FPopup を破棄する場合は、TPlugIn の作成時に FPopup を作成する必要があります。

于 2013-09-01T20:51:01.677 に答える