2016-08-07 10 views
0

新しいプロジェクトでは、2つのパネルを持つメインフォームとボタン付きのフォームを作成しました。親ハンドルでメッセージが届かない

私は、MainFormを上でこのコードを追加しました:

interface 

type 
    TForm1 = class(TForm) 
    Panel1: TPanel; 
    Panel2: TPanel; 
    procedure FormCreate(Sender: TObject); 
    private 
    procedure OnMyMessage(var Msg: TMessage); message WM_FILEREADY; 
    public 
    { Public declarations } 
    end; 

implementation 

uses 
    PannelForm; 

{$R *.dfm} 


procedure TForm1.FormCreate(Sender: TObject); 
begin 
    with TForm2.Create(self) do 
    try 
    parent := panel2; 
    borderstyle := bsNone; 
    InnerHandle := self.Handle; 
    Show; 

    finally 

    end; 
end; 

procedure TForm1.OnMyMessage(var Msg: TMessage); 
begin 
    showmessage('got event'); 
end; 

、ボタンをフォーム上のこのコード:

type 
    TForm2 = class(TForm) 
    Button1: TButton; 
    procedure Button1Click(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    InnerHandle:HWND; 
    end; 

procedure TForm2.Button1Click(Sender: TObject); 
begin 
// PostMessage(Application.Mainform.Handle, WM_FILEREADY, 0, 0); // works 
// PostMessage(Application.Handle, WM_FILEREADY, 0, 0); // not working 
// PostMessage(parent.Handle, WM_FILEREADY, 0, 0); // not working 
    PostMessage(InnerHandle, WM_FILEREADY, 0, 0); // works 

end; 

私の質問は次のとおりです。最初と前後のバージョンを呼び出すときに、すべてがあります良い。

動作しない3番目のバージョンには何が欠けていますか?

なぜ親に正しいハンドルが含まれていないのですか?親を渡すことのポイントの一部ですか?

+2

ウインドウレクリエーションで燃え尽きます。 AllocateHWndを使用します。またはTThread.Synchronize.Queue。 –

+0

"通常、このメソッドはメッセージに応答する非ビジュアルウィンドウを作成するために使用される"ので、AllocateHWndはこの場合には該当しません。 http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/Classes_AllocateHWnd.htmlおよびTThreadを使用する理由問題を説明するためのリンクを指すことができますか、それを説明できますか? – none

答えて

2

TForm1にメッセージ処理を実装しましたが、Form2.Parent.HandleForm1.Handleではなく、Panel2.Handleに割り当てました。

各ウィンドウコントロールには、独自のハンドルがあります。したがって、パネルはフォームとは異なるハンドルを持ち、Formクラスで実装されたメッセージは処理できません。

期待どおりではないものの、すべてが正常に動作します。

1

Parentは、Form1ではなくForm1.Panel2に設定します。メッセージハンドラは、Form1に直接投稿されたメッセージのみを受信します。あなたの他の通話はForm1.Handleに転記されています。そのため、彼らが働いています。 、そうでない場合

type 
    TForm1 = class(TForm) 
    Panel1: TPanel; 
    Panel2: TPanel; 
    procedure FormCreate(Sender: TObject); 
    private 
    DefPanelWndProc: TWndMethod; 
    procedure PanelWndProc(var Msg: TMessage); 
    public 
    { Public declarations } 
    end; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    DefPanelWndProc := Panel2.WindowProc; 
    Panel2.WindowProc := PanelWndProc; 

    Form2 := TForm2.Create(Self); 
    Form2.Parent := Panel2; 
    Form2.BorderStyle := bsNone; 
    Form2.Show; 
end; 

procedure TForm1.PanelWndProc(var Msg: TMessage); 
begin 
    if Msg.Msg = WM_FILEREADY then 
    ShowMessage('got event') 
    else 
    DefPanelWndProc(Msg); 
end; 

代わりForm1にメッセージを投稿:ParentForm1ないときにParent.Handleにメッセージを投稿したい場合は

は、あなたがParentとして割り当てているパネルをサブクラス化する必要があります。

都度Form1.Handleプロパティを使用して投稿すると、すべてが問題なくなります(TWinControl.Handleはスレッドセーフではないため、マルチスレッドコードは数えません)。しかし、Form1.Handleの値を変数にキャッシュしてからその変数を使用してポストすると、Form1.Handleが再作成された場合、コードは機能しなくなります(これは起こりうることです)。その場合、あなたはレクリエーションを検出し、それに応じて変数を更新する必要があります。

type 
    TForm1 = class(TForm) 
    Panel1: TPanel; 
    Panel2: TPanel; 
    procedure FormCreate(Sender: TObject); 
    protected 
    procedure CreateWnd; override; 
    procedure DestroyWnd; override; 
    private 
    procedure OnMyMessage(var Msg: TMessage); message WM_FILEREADY; 
    public 
    { Public declarations } 
    end; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    Form2 := TForm2.Create(Self); 
    Form2.Parent := Panel2; 
    Form2.BorderStyle := bsNone; 
    Form2.InnerHandle := Self.Handle; 
    Form2.Show; 
end; 

procedure TForm1.CreateWnd; 
begin 
    inherited; 
    if Form2 <> nil then 
    Form2.InnerHandle := Self.Handle; 
end; 

procedure TForm1.DestroyWnd; 
begin 
    if Form2 <> nil then 
    Form2.InnerHandle := 0; 
    inherited; 
end; 

procedure TForm1.OnMyMessage(var Msg: TMessage); 
begin 
    ShowMessage('got event'); 
end; 

そうでない場合は、まったくForm1.Handleを使用しないでください。再作成されない別のウィンドウを使用します。

あなたは、専用のウィンドウを作成するためにAllocateHWnd()を使用することができます。

type 
    TForm1 = class(TForm) 
    Panel1: TPanel; 
    Panel2: TPanel; 
    procedure FormCreate(Sender: TObject); 
    procedure FormDestroy(Sender: TObject); 
    private 
    MsgWnd: HWND; 
    procedure MsgWndProc(var Msg: TMessage); 
    public 
    { Public declarations } 
    end; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    MsgWnd := AllocateHWnd(MsgWndProc); 

    Form2 := TForm2.Create(Self); 
    Form2.Parent := Panel2; 
    Form2.Borderstyle := bsNone; 
    Form2.InnerHandle := MsgWnd; 
    Form2.Show; 
end; 

procedure TForm1.FormDestroy(Sender: TObject); 
begin 
    if MsgWnd <> 0 then 
    DeallocateHWnd(MsgWnd); 
end; 

procedure TForm1.MsgWndProc(var Msg: TMessage); 
begin 
    if Msg.Msg = WM_FILEREADY then 
    ShowMessage('got event') 
    else 
    Message.Result := DefWindowProc(MsgWnd, Msg.Msg, Msg.WParam, Msg.LParam); 
end; 

それとも、Application.Handleウィンドウを使用することができます

type 
    TForm1 = class(TForm) 
    Panel1: TPanel; 
    Panel2: TPanel; 
    procedure FormCreate(Sender: TObject); 
    procedure FormDestroy(Sender: TObject); 
    private 
    function AppWndProc(var Msg: TMessage): Boolean; 
    public 
    { Public declarations } 
    end; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    Application.HookMainWindow(AppWndProc); 

    Form2 := TForm2.Create(Self); 
    Form2.Parent := Panel2; 
    Form2.Borderstyle := bsNone; 
    Form2.InnerHandle := Application.Handle; 
    Form2.Show; 
end; 

procedure TForm1.FormDestroy(Sender: TObject); 
begin 

アプリケーションを。UnhookMainWindow(AppWndProc); end;

function TForm1.AppWndProc(var Msg: TMessage): Boolean: 
begin 
    if Msg.Msg = WM_FILEREADY then 
    begin 
    ShowMessage('got event'); 
    Result := True; 
    end else 
    Result := False; 
end; 
関連する問題