2016-08-07 114 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;