在一个新项目中,我创建了一个包含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;
这个代码在Form上有一个按钮:
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;
我的问题是:在拨打第一个和第四个版本时,一切都很好。
第三个版本缺少什么?
为什么Parent不包含正确的句柄?是不是传递父母的(部分)点?
答案 0 :(得分:2)
您已在TForm1
中实施了邮件处理,但Form2.Parent.Handle
不是Form1.Handle
,而是已为其分配了Panel2.Handle
。
每个窗口控件都有自己的句柄。因此,您的面板具有与表单不同的句柄,并且它们无法处理在Form类中实现的消息。
尽管不是你所期望的,但一切都按预期工作。
答案 1 :(得分:1)
您将Parent
设置为Form1.Panel2
,而不是Form1
。您的邮件处理程序将仅接收直接发布到Form1
的邮件。您的其他来电正在发布到Form1.Handle
,这就是他们工作的原因。
如果您希望在Parent.Handle
不是Parent
时将消息发布到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
Application.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;