3

他のフォームのMDI親であるフォームの途中にTPanelを表示したいと思います。ある種の「スプラッシュ」形式ですが、完全ではありません。パネルには、ユーザーがその他を呼び出す場所からのリンク/ボタン/ショートカットが含まれます。関数。

主な要件は、MDIの子をクリックするときに、TPanelをMDIの子フォームの下に配置する必要があることです。ただし、現状では、TPanelは常にMDI子フォームの上に留まります。

Panel.SendToBackを呼び出すと、パネルが非表示になります。どのようにできるのか?

4

2 に答える 2

6

WindowProcパネルが常に MDI の子の背後にあるように、パネルをオーバーライドする必要があります。

TMainForm = class(TForm)
...
private
  FPanelWndProc: TWndMethod;
  procedure PanelWndProc(var M: TMessage);
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
  Windows.SetParent(Panel1.Handle, ClientHandle);
  // Override Panel1 WindowProc
  FPanelWndProc := Panel1.WindowProc;
  Panel1.WindowProc := PanelWndProc;
end;

procedure TMainForm.FormDestroy(Sender: TObject);
begin
  // Restore Panel1 WindowProc
  Panel1.WindowProc := FPanelWndProc;
end;

procedure TMainForm.PanelWndProc(var M: TMessage);
var
  P: ^WINDOWPOS;
begin
  if M.Msg = WM_WINDOWPOSCHANGING then
  begin
    P := Pointer(M.LParam);
    // Always place panel at bottom
    P.hwndInsertAfter := HWND_BOTTOM;
  end;
  FPanelWndProc(M);
end;

注: コードをすばやくテストするために、次の方法で MDI アプリケーションを作成できます。File -> New -> MDI Application


編集:上記のコードは事実上、最初の質問に答えます。「 Panel を何らかの形で MDI 子として動作させたい」(コメントの引用) 場合は、単純に (... うーん...) MDI 子フォームを使用します。つまり、 で新しいフォームを作成し、次の.FormStyle = fsMDIChildようなものを使用します。

SetWindowLong(Child.Handle, GWL_STYLE, 
   GetWindowLong(Child.Handle, GWL_STYLE) and not (WS_BORDER or WS_DLGFRAME or WS_SIZEBOX));

境界線を削除するには(単に設定すると.BorderStyle = bsNone機能しないため)。
そのフォームに必要なものを入力すると、クリックすると他の MDI フォームの上に移動します。

于 2012-08-20T09:04:32.857 に答える
1

MDI システムは、クライアント ウィンドウと呼ばれる、すべての MDI 子ウィンドウの親である単一のウィンドウを持つことによって機能します。そのクライアント ウィンドウは、MDI フォームの子です。MDI の VCL 実装により、子ウィンドウが作成されます。ClientHandle を介してウィンドウ ハンドルにアクセスできます。

クライアント ウィンドウはメイン フォームの子であり、すべての MDI フォームの親であるため、唯一の解決策は、このパネルをクライアント ウィンドウの一部にすることです。

クライアント ウィンドウの描画を制御できます。これを行うには、クライアント ウィンドウのウィンドウ プロシージャを独自のものに置き換えます。ボタンのクリックなども処理する必要がありますが、それはかなり面倒です。

ここで、おそらく、パネルをクライアント ウィンドウの子にすることができます。しかし、それがあなたのMDIを台無しにすることは間違いありません。

于 2012-08-18T20:39:58.317 に答える