Delphi VCL form Arrow Key решение для управления запускается дважды - PullRequest
0 голосов
/ 10 октября 2019

У меня есть форма VCL со многими tframes (называемыми tcellFrame), содержащими компоненты, расположенные в сетке. Я использую щелчки мыши и клавиши со стрелками для пользователя, чтобы перемещаться между ними. Щелчки мыши работают нормально, но у меня были проблемы с клавишами со стрелками, пока я не обнаружил этот поток вопросов: Delphi XE и Trapping Arrow Key с OnKeyDown. Решение в ответе Сертака Акьюза обрабатывает получение сообщений клавиш со стрелками в форму, используя

procedure TForm1.DialogKey(var Msg: TWMKey);
begin
  case Msg.CharCode of
    VK_DOWN, VK_UP, VK_RIGHT, VK_LEFT:
      if Assigned(onKeyDown) then
        onKeyDown(Self, Msg.CharCode, KeyDataToShiftState(Msg.KeyData));
    else
      inherited
  end;
end;

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

Мое onKeyDown событие структурировано следующим образом:

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
var
  i : integer;
  g, r, c, str : string;
  tmpFrame : tcellFrame;  //frame component containing tlabels
begin
  ...

  case key of
    VK_UP:
      begin
        //calc new cell location values for g,r,c
        str := ('Cell'+g+r+c);
        picklist.Clear;  // picklist is a form-wide tstringlist variable containing currently selected cellframes.
        picklist.add (str);
        TmpFrame := FindComponent(picklist [0]) as TCellFrame;
        tmpframe.Color := pickClr;
      end;
    //VK_DOWN, VK_LEFT, VK_RIGHT: defined similarly to VK_UP

  end;
end;

В Formkeydown есть больше кода, ноэто все внутренние вычисления, чтобы определить правильное имя tcellframe для размещения в списке выбора.

Мои вопросы:

  • Что вызывает этот повтор?
  • Как прекратить реализацию сообщения после его первого экземпляра?

1 Ответ

3 голосов
/ 10 октября 2019

В вашем обработчике сообщений CM_DIALOGKEY верните ненулевое значение, если вы обрабатываете ключ, тогда оно не будет отправлено дальше.

procedure TForm1.DialogKey(var Msg: TWMKey);
begin
  case Msg.CharCode of
    VK_DOWN, VK_UP, VK_RIGHT, VK_LEFT:
      begin
        if Assigned(onKeyDown) then
          onKeyDown(Self, Msg.CharCode, KeyDataToShiftState(Msg.KeyData));
        Msg.Result := 1; // <-- add this
      end;
    else
      inherited;
  end;
end;

Однако, если вы включили KeyPreview=Trueформа и клавиши со стрелками уже отправляются в обычном режиме, тогда вообще не нужно обрабатывать CM_DIALOGKEY, просто пусть события формы OnKey... отправляются нормально. Вы не должны запускать события формы OnKey... из обработчика CM_DIALOGKEY.

См. Одиссея ключа для получения более подробной информации.

...