zoukankan      html  css  js  c++  java
  • Delphi主消息循环研究(Application.Run和Application.Initialize执行后的情况)

      Application.Initialize;
      Application.CreateForm(TForm1, Form1);
      Application.Run;

    第一步,貌似什么都不做,但如果提前定义InitProc就不一样了

    procedure TApplication.Initialize;
    begin
      if InitProc <> nil then TProcedure(InitProc);
    end;

    第二步,创建一部分Form,特别是MainForm

    procedure TApplication.CreateForm(InstanceClass: TComponentClass; var Reference);
    var
      Instance: TComponent;
    begin
      Instance := TComponent(InstanceClass.NewInstance);
      TComponent(Reference) := Instance;
      try
        Instance.Create(Self);
      except
        TComponent(Reference) := nil;
        raise;
      end;
      if (FMainForm = nil) and (Instance is TForm) then
      begin
        TForm(Instance).HandleNeeded; // 这句话大有讲究,执行了许多动作。包括递归创建Parent的Handle
        FMainForm := TForm(Instance);
      end;
    end;

    第三步,使用repeat建立消息循环

    procedure TApplication.Run;
    var
      i: integer;
      d1,d2: TDateTime;
    begin
      i:=0;
      d1:=now;
      FRunning := True;
      try
        AddExitProc(DoneApplication);
        if FMainForm <> nil then
        begin
          case CmdShow of
            SW_SHOWMINNOACTIVE: FMainForm.FWindowState := wsMinimized;
            SW_SHOWMAXIMIZED: MainForm.WindowState := wsMaximized;
          end;
          if FShowMainForm then
            if FMainForm.FWindowState = wsMinimized then Minimize 
        else FMainForm.Visible := True;
          // 注意1,当鼠标移出当前窗口的范围时,不会继续执行当前repeat循环
          // 注意2,经测试发现,每次点击鼠标或者按键,都会产生5个消息。
          // 注意3,这里给每一个消息处理都包裹了一个异常处理。
          repeat
          begin
            try
              HandleMessage;
            except
              HandleException(Self);
            end;
        // 这里可以观察,当前窗口处理了多少个消息
            inc(i);
            if (i=200) then begin d2:=now; ShowMessage(IntToStr(MinutesBetween(d1,d2))); end;
            MainForm.Canvas.TextOut(0,0,IntToStr(i));
          end
          until Terminated;
        end;
      finally
        FRunning := False;
      end;
    end;

    第3.1步,具体处理每一个消息循环

    procedure TApplication.HandleMessage;
    var
      Msg: TMsg;
    begin
      if not ProcessMessage(Msg) then
      begin
        Idle(Msg);
      end;
    end;

    第3.2步,取得消息并分发消息,但是分发前好像还会先执行FOnMessage(Msg, Handled);

    function TApplication.ProcessMessage(var Msg: TMsg): Boolean;
    var
      Handled: Boolean;
    begin
      Result := False;
      if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then
      begin
        Result := True;
        if Msg.Message <> WM_QUIT then
        begin
          Handled := False;
          if Assigned(FOnMessage) then FOnMessage(Msg, Handled);
          if not IsHintMsg(Msg) and not Handled and not IsMDIMsg(Msg) and not IsKeyMsg(Msg) and not IsDlgMsg(Msg) then
          begin
            TranslateMessage(Msg);
            DispatchMessage(Msg);
          end;
        end
        else
          FTerminate := True;
      end;
    end;

    第3.3步 处理Hint,同步主线程,再调用 WaitMessage

    procedure TApplication.Idle(const Msg: TMsg);
    var
      Control: TControl;
      Done: Boolean;
    begin
      Control := DoMouseIdle;
      if FShowHint and (FMouseControl = nil) then CancelHint;
      Application.Hint := GetLongHint(GetHint(Control));
      Done := True;
      try
        if Assigned(FOnIdle) then FOnIdle(Self, Done);
        if Done then DoActionIdle;
      except
        HandleException(Self);
      end;
      if (GetCurrentThreadID = MainThreadID) and CheckSynchronize then
        Done := False;
      // 当一个线程的消息队列中无其它消息时,该函数就将控制权交给另外的线程,同时将该线程挂起,直到一个新的消息被放入线程的消息队列之中才返回。
      // 在指定类型的新的输入消息抵达之前,它是不会返回的。
      // 如果没有这句,或者不调用这个Idle,当前消息循环会不间断疯狂的去队列里取消息,1分钟即可执行30多万次,CPU 100%被占用
      if Done then WaitMessage; 
    end;

    第四步,程序员手工建立消息循环:
    自己建立一个消息处理循环(while),把当前消息队列的所有消息一次性处理完毕,且不调用Idle。可以在while加上计数,看每次处理了多少个消息。

    procedure TApplication.ProcessMessages;
    var
      Msg: TMsg;
    begin
      while ProcessMessage(Msg) do {loop};
    end;

     个人感想:程序的任何一个地方,都可以主动执行PeekMessage等消息函数,接管主程序的消息循环,参考:

    http://blog.csdn.net/mengde666/article/details/4045656

  • 相关阅读:
    查看uCOS-II的CPU使用率
    ARM的工作环境和工作模式
    一个简单的 JSON 生成/解析库
    [转] libtool的作用及应用
    Qt 使用 net-snmp 包的过程记录
    Qt 立体水晶按键实现
    xampp 修改 mysql 默认 root 密码
    mint 设置无线 AP
    dpkg 小记
    转-ubuntu清理卸载wine的残余项目
  • 原文地址:https://www.cnblogs.com/findumars/p/3267093.html
Copyright © 2011-2022 走看看