【问题标题】:Delphi - when to call DragAcceptFilesDelphi - 何时调用 DragAcceptFiles
【发布时间】:2010-10-13 21:00:15
【问题描述】:

我有

procedure TMainForm.FormCreate(Sender: TObject);
begin
DragAcceptFiles (Handle, True ) ; 
end ;

但表单不接受拖动的文件 - 没有放置光标,没有触发 WM_DROPFILES 消息。

我的 FormShow 事件中有以下构造(出于不同的原因 - 在创建表单后我只想执行一次代码,并且 FormShow 在初始化期间多次触发):

procedure TMainForm.FormShow(Sender: TObject);

begin
if (not FRunOnce) then  // as FormShow can be called twice - if Form.Position assigned to
    begin
    DragAcceptFiles (Handle, True ) ; 
    FRunOnce := True ;
    end ;
end ;

所示位置的 DragAcceptFiles (Handle, True ) 仍然不起作用。如果我将它移到例程的顶部(因此它执行两次),它确实有效:

procedure TMainForm.FormShow(Sender: TObject);

begin
DragAcceptFiles (Handle, True ) ; 
if (not FRunOnce) then  // as FormShow can be called twice - if Form.Position assigned to
    begin
    FRunOnce := True ;
    end ;
end ;

我发现的所有示例代码似乎都在 OnCreate 期间调用了 DragAccept。我的实验表明这还为时过早,就像 OnShow 的第一次大火一样。我确定我的代码在其他地方有问题,但可能是什么原因造成的?

【问题讨论】:

    标签: delphi forms drag-and-drop oncreate


    【解决方案1】:

    任何 TWinControl 的 HWND 都可以在其生命周期内多次创建和重新创建。调用 DragAcceptFiles() 的最佳位置是在重写的 CreateWnd() 和 DestroyWnd() 方法中,以便您可以在所有(重新)创建期间(重新)注册并在所有销毁期间取消注册,例如:

    procedure TMainForm.CreateWnd;
    begin 
      inherited;
      DragAcceptFiles(Handle, True);  
    end;
    
    procedure TMainForm.DestroyWnd;
    begin 
      DragAcceptFiles(Handle, False);
      inherited;
    end;
    

    【讨论】:

      【解决方案2】:

      在您的应用程序中多次触发FormShow 事件表明窗体句柄至少被销毁并重新创建一次,这很可能是因为您更改了需要重新创建窗口句柄的属性之一。改变停留在顶部就是一个例子。

      如果句柄被重新创建,那么新的句柄当然不会收到前一个句柄注册接收的任何消息。

      您需要做的是在创建最终句柄之后调用DragAcceptFiles(),或者(因为这可能很难做到)确实多次。

      【讨论】:

      • 我认为这是关键。我没有意识到在表单的整个生命周期中句柄可能会有所不同。
      【解决方案3】:

      我发现这样的问题很容易通过您在 FormCreate 中发布给自己的自定义消息来处理。例如:

      CONST
        wm_FirstRun = WM_USER + 101;
      
      
      TYPE
        TForm1 = class(TForm)
        :
          Procedure wmFirstRun(var Msg:tMessage); message wm_FirstRun;
          procedure FormCreate(Sender: TObject); 
        :
        end;
      
      procedure TForm1.FormCreate(Sender: TObject);
      begin
        // other initialization code
        PostMessage(handle,wm_FirstRun,0,0);
      end;
      
      Procedure TForm1.wmFirstRun(var Msg:tMessage);
      begin
        // handle the code here that will run once the form is processing messages
      end;
      

      触发机制是PostMessage,因此无论何时调用该命令,它都会调用您的自定义消息例程。当然,如果是这样的话,我会称它为 wmFirstRun 以外的其他名称。

      【讨论】:

      • 所以您是说将 dragacceptFiles 放在此消息处理程序中将确保在 oncreate 和 onshow 事件之后调用它?
      • 是的...但只有一次,因为它是在 onCreate 中请求的。
      • 我注意到一些答案已经消失。谁这样做,为什么这样做?
      • 有些人会删除他们的答案,如果他们不再认为与问题相关以避免投票。
      猜你喜欢
      • 2011-03-17
      • 2011-08-13
      • 1970-01-01
      • 2012-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多