VCL TTimer останавливается при перетаскивании окна или нажатии раскрывающегося меню - PullRequest
4 голосов
/ 01 марта 2011

У меня включен TTimer, и предполагается, что он будет работать без остановок до тех пор, пока пользователь не остановит его.Тем не менее, это не работает таким образом.В событии OnTimer он снова и снова обрабатывает сообщения окна в миллисекундах.

Например, вот фрагмент моего кода.

procedure TDXCommDlg.Timer2Timer(Sender: TObject);
begin
  inherited;
  if Scanning then
  begin
    Timer1.Enabled := false;
    Timer2.Enabled := false;
     while not PostMessage(Handle,WM_USER + 10,1234,5678) do;
     Timer1.Enabled := true;
  end;
end;

Что происходит, вот что.Пока TTimer включен и работает, вы перетаскиваете любые окна приложения или щелкаете по раскрывающемуся меню, и событие TTimer полностью перестает работать, хотя я предпринял меры предосторожности в другой части кода, чтобы этого не произошло.Однако, похоже, это не помогает.

Единственный способ перезапустить событие OnTimer - это остановить и перезапустить таймер пользователем через событие TButton.

Тот же кодили программа работает нормально под Windows XP, скомпилированной с Delphi 7. В настоящее время я использую Windows 7 и Delphi 2010 для восстановления своей системы.

Я постараюсь дать вам больше информации.Я работаю над защищенным авторским правом программным обеспечением.

Существует определенная пользователем процедура, называемая HandleMsg.Это фактически обрабатывает сообщения последовательного порта.Для HandleMsg установлено событие Application onMessage;

Application.onMessage: = HandleMsg ();

PostMessage связано с событием onMessage приложения.

При каждом вызове PostMessage, он запускает событие onMessage, которое установлено в HandleMsg ().

Вот еще мой код:

 procedure TDXCommDlg.HandleMsg(var
 Msg: TMsg; var Handled: Boolean);
 begin
      Handled := false;
      case Msg.message of
      WM_USER + 10:
              begin
                   if (Msg.wParam = 1111) and (Msg.lParam = 2222) then
                   begin
                     SendLanMessage;
                     Handled := true;
                   end
                   else if (Msg.wParam = 1234) and (Msg.lParam = 5678) then
                   begin
                        SendMessage;
                        Handled := true;
                   end
                   else
                   begin
                     if (Msg.wParam = 4321) then
                     begin
                       MainFrm.CloseWindow(TViewFrm(Msg.lParam).WinCap);
                     end;
                   end;
              end;
      end; { case } end;

HandleMsg () отвечает на PostMessage.Поправь меня, если я ошибаюсь.

Ответы [ 2 ]

6 голосов
/ 01 марта 2011

В обоих случаях (начиная с изменения размера / перемещения окна или открытия меню) последнее сообщение, отправленное из TApplication.ProcessMessage, равно WM_NCLBUTTONDOWN (или WM_NCRBUTTONDOWN, если заголовок и системное меню существуют и щелкнули заголовок .. илиWM_RBUTTONUP при открытии контекстного меню и т. д.).Общим для всех является то, что они запускают модальный цикл сообщений.

Например, ниже приводится документация WM_ENTERSIZEMOVE:

Сообщение WM_ENTERSIZEMOVE отправляется один раз в окно после неговходит в модальный цикл перемещения или определения размера.[....] Операция завершается, когда возвращается DefWindowProc.

После запуска модального цикла сообщений вызов HandleMessage в TApplication.Run не будет возвращаться до DefWindowProc для соответствующего окна.возвращает (например, в случае WM_NCLBUTTONDOWN отправленное сообщение приведет к отправке WM_SYSCOMMAND в окно, которое запустит модальный цикл сообщений и не вернется до завершения перемещения / изменения размера).Таким образом, вы не сможете использовать обработчик приложения OnMessage в этот период, который называется TApplication.ProcessMessage.

Ваше решение простое.Вместо использования обработчика OnMessage обработайте сообщение с помощью обработчика сообщений вашей формы:

const
  WMUSER_10 = WM_USER + 10;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    procedure Timer1Timer(Sender: TObject);
  private
    procedure WmUser10(var Msg: TMsg); message WMUSER_10;
  public
  end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  PostMessage(Handle, WMUSER_10, 1234, 5678);
end;

procedure TForm1.WmUser10(var Msg: TMsg);
begin
  //
end;

Или введите свой код в событие OnTimer, поскольку WM_TIMER само по себе отправлено .

0 голосов
/ 01 марта 2011

Этого следовало ожидать.Таймер Windows основан на флаге очереди сообщений и является событием с самым низким приоритетом.Когда вы начинаете изменять размер окна, флаг таймера в основной очереди событий приложения перестает обрабатываться, и таймер останавливается.С этим ничего не поделаешь.Чтобы было ясно, обычные сообщения все еще будут работать, но таймер останавливается.Это очень легко проверить.

Теперь, чтобы решить эту проблему, вы можете либо отправлять себе сообщения WM_USER, которые должны пройти, либо лучшим решением является использование потока для выполнения критической операции и использование таймераобновить пользовательский интерфейс из информации, которую обновляет поток.Затем, когда пользователь изменяет размер окна, вы получаете паузу пользовательского интерфейса, но операции продолжаются.

...