DELPHI 10,3 - l oop пока нажата клавиша, небольшая проблема - PullRequest
1 голос
/ 11 января 2020

Доброе утро, я написал очень простое приложение, в котором я должен ждать, пока пользователь нажмет клавишу (например, F2), чтобы продолжить обработку. Цикл ожидания для нажатия кнопки работает отлично, но проблема, с которой мне нужна помощь, заключается в следующем: если во время цикла ожидания нажатия кнопки я нажимаю на другое приложение, мое приложение теряет фокус и я больше не могу восстановить управление. Даже если я нажму на любую часть моего приложения, заголовок формы всегда останется серым, приложение будет ждать нажатия клавиши, и если я нажму нужную клавишу, очевидно, ничего не произойдет. Как восстановить контроль над моим приложением? Я думал, что поместил бы инструкции вроде SetFocus, StayOnTop, SetForegroundWindow, ... et c в то время как l oop, чтобы ВСЕГДА поддерживать приложение активным, но я не смог ничего скомбинировать ... Код выглядит следующим образом:

var

  Form2: TForm2;
  mkey: word; 

implementation

{$R *.dfm} 

procedure TForm2.FormActivate(Sender: TObject);

begin

  label1.Visible:= false;

  mkey:= 0;

  keyPreview:= true;

  while mkey <> VK_F2 do begin

    label1.Visible:= true;

    label1.Caption:= datetimetostr(now);   // for example

    application.ProcessMessages;

  end;

  label1.Visible:= false;

end; 

procedure TForm2.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);

begin

  mkey:= key;

end;

end.

1 Ответ

9 голосов
/ 11 января 2020

Я не хочу звучать хар sh, но, к сожалению, ваш дизайн в корне несовершенен.

Как указано в комментариях, графические Windows приложения - и, в частности, VCL приложения - управляемые событиями. (Под капотом это работает благодаря рассылкам сообщений, но разработчикам VCL чаще всего не нужно беспокоиться о таких деталях. В частности, новые Delphi разработчики обычно не знают о базовых рассылках сообщений и могут по-прежнему писать высокие качество GUI приложений, если они осторожны.)

Так, например, ожидание нажатия клавиши с использованием явного l oop почти всегда неверно. Кроме того, необходимость вызова Application.ProcessMessages является явным признаком (серьезного) недостатка проекта (во многих случаях, но не в этом, решение заключается в добавлении нового потока). Наконец, если казалось бы, базовая задача c вызывает проблемы, которые вам нужно добавить для обхода кода (например, SetFocus), вы всегда должны спрашивать себя, есть ли лучшее решение.

Я не точно знать, что вы пытаетесь сделать, но следующий пример может быть полезным.

  1. Создайте новое приложение VCL. Дайте главной форме правильное имя, например frmMain, с помощью инспектора объектов. В редакторе кода добавьте приватное поле FStarted: Boolean в класс формы. Поскольку это поле в классе, оно инициализируется (поскольку оно Boolean, False). 101

      private
        FStarted: Boolean;
    
  2. Добавление элемента управления TLabel в форму , Установите его имя на lblMainText с помощью инспектора объектов. Устанавливает его шрифт на что-то визуально приятное², а его заголовок - Press F2 to begin.

  3. В обработчик событий OnKeyDown формы добавьте следующий код³:

    procedure TfrmMain.FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    begin
      if (Key = VK_F2) and not FStarted then
      begin
        MessageBeep(MB_ICONASTERISK);
        lblMainText.Caption := 'Let''s get to work!';
        FStarted := True;
      end;
    end;
    
  4. Запустите приложение.

Screenshot of the application immediately after startup.

После нажатия F2:

Screenshot of the application after F2 has been pressed.

Обратите внимание, что повторное нажатие F2 ничего не делает; вы уже «запустили» систему.

Очевидно, что этот небольшой ответ не научит вас всему, что вам нужно знать для написания VCL-приложений. Это касается только 0,1% того, что вам нужно знать. Чтобы узнать больше, я настоятельно рекомендую купить хорошую книгу о Delphi программировании (в частности, о написании приложений для Win32 в Delphi).

¹ В Delphi глобальные переменные и члены класса инициализируются ( до 0, 0.0, False, nil и др. c.). Однако локальные переменные никогда не инициализируются (если они не относятся к управляемым типам).

² Segoe UI является хорошим выбором в соответствии с Microsoft Windows Руководством по пользовательскому интерфейсу . Фактически, вы можете использовать этот шрифт для самой формы ; тогда все дочерние элементы управления будут наследовать эту настройку шрифта автоматически.

³ Это будет работать, только если сама форма имеет фокус (и, например, не дочерний элемент управления). Чтобы это работало, даже если у ребенка есть контроль, лучше всего использовать TActionList. Они действительно полезны.

...