2016-08-07 50 views
0

在新項目中,我創建了一個包含2個面板的MainForm和一個帶按鈕的Form。父消息傳遞時消息未到達

我加在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; 

我的問題是:調用第一和第四版本時,一切都精細。

在第三個版本中沒有工作時缺少什麼?

爲什麼父母不包含正確的句柄?是不是通過父母的(一部分)點?

+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.Handle不是Form1.Handle而是您已將Panel2.Handle指定給它。

每個窗口控件都有自己的句柄。因此,您的面板具有與您的表單不同的句柄,並且它們無法處理在Form類中實現的消息。

儘管它不是您所期望的,但一切都可以正常工作。

1

您將Parent設置爲Form1.Panel2,而不是Form1本身。您的消息處理程序將只接收直接發佈到Form1的消息。您的其他電話發佈到Form1.Handle,這就是他們工作的原因。

如果你想將消息發佈到Parent.HandleParent不是Form1,你將不得不繼承要指定爲Parent面板:

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代替。

如果你每次使用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); 結束;

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;