Delphi VCL - WM_Touch RegisterTouchWindow (Handle, 0);сообщение не будет обрабатываться при касании панели - PullRequest
1 голос
/ 11 октября 2019

Я использую Delphi 10.1 Berlin, проект VCL. Я пытаюсь переместить несколько панелей одновременно, используя сенсорный экран и сообщения WM_Touch, сгенерированные из Windows. Я основал его на примере кода из блога Криса Бенсона: http://chrisbensen.blogspot.com/2009/11/touch-demo.html

И он работает в определенной степени, ТОЛЬКО если я сначала коснусь где-нибудь на фоне формы, а затем перетащу палец на панель. Панели будут двигаться пальцами, если я сначала коснусь фона. Из того, что я могу сказать, похоже, что процедура TForm1.WMTouch не будет вызываться, когда я касаюсь панели, расположенной в верхней части формы. Я не получаю сообщения WM_Touch, если сначала не коснусь формы.

В блоге Криса он вызывает RegisterTouchWindow (Handle, 0);в форме Создать. Я предполагаю, почему процедура будет вызываться при прикосновении к форме. Как бы я начал вызывать процедуру WM_Touch при каждом касании панели?

-Я попытался использовать событие OnClick для панели, но это не сработало, так как кажется, что оно не регистрирует касание как событие OnClick.

-Это то, что я должен использовать класс Inherit? Если да, то как мне это сделать?

Заранее спасибо за любые идеи!

unit Unit2;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls;

type
  TOUCHINPUT = record
  x: Integer;
  y: Integer;
  hSource: THandle;
  dwID: DWORD;
  dwFlags: DWORD;
  dwMask: DWORD;
  dwTime: DWORD;
  dwExtraInfo: ULONG_PTR;
  cxContact: DWORD;
  cyContact: DWORD;
end;

type
    TForm1 = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    Panel3: TPanel;

    procedure WMTouch(var Message: TMessage); message wm_Touch;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);

  end;

var
  Form1: TForm1;

implementation
//==============================================================================

//======================== FORM CREATE =========================================

procedure TForm1.FormCreate(Sender: TObject);
begin
  //  inherited;
    RegisterTouchWindow(Handle, 0);
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
    UnregisterTouchWindow(Handle);
end;

//==============================================================================

//========================= WM TOUCH ===========================================

procedure TForm1.WMTouch(var Message: TMessage);
    //==============
    function TouchPointToPoint(const TouchPoint: TTouchInput): TPoint;
      begin
        Result := Point(TouchPoint.X div 100, TouchPoint.Y div 100);
        PhysicalToLogicalPoint(Handle, Result);
      end;
     //==============
 var
    TouchInputs: array of TTouchInput;
    TouchInput: TTouchInput;
    Handled: Boolean;
    Point: TPoint;

begin
  Handled := False;
  SetLength(TouchInputs, Message.WParam);
  GetTouchInputInfo(Message.LParam, Message.WParam,
  @TouchInputs[0], SizeOf(TTouchInput));
  try
      for TouchInput in TouchInputs do
      begin
          Point := TouchPointToPoint(TouchInput);
          if PtInRect(Panel1.BoundsRect,Point) then
          begin
              label1.Caption:='Touch ID: ' + inttostr(TouchInput.dwID);
              panel1.Top:=point.Y-100;
          end;
          if PtInRect(Panel2.BoundsRect,Point) then
          begin
              label1.Caption:='Touch ID: ' + inttostr(TouchInput.dwID);
              panel2.Top:=point.Y-100;
          end;
          if PtInRect(Panel3.BoundsRect,Point) then
          begin
              label1.Caption:='Touch ID: ' + inttostr(TouchInput.dwID);
              panel3.Top:=point.Y-100;
          end;
      end;
      Handled := True;
    finally
      if Handled then
        CloseTouchInputHandle(Message.LParam)
      else
      //  inherited;
  end;
end;
end.

1 Ответ

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

Из того, что я могу сказать, похоже, что процедура TForm1.WMTouch не будет вызываться, когда я касаюсь панели, расположенной в верхней части формы. Я не получаю сообщения WM_Touch, если сначала не коснусь формы.

Правильно, поскольку вы не касаетесь самой формы, вы касаетесь панели, находящейся в верхней части формы.

В блоге Криса он вызывает RegisterTouchWindow (Handle, 0);в форме Создать. Я предполагаю, почему процедура будет вызываться при прикосновении к Форме.

Да.

Как бы я мог вызывать процедуру WM_Touch при каждом касаниипанель?

Вы должны зарегистрировать HWND панели вместо HWND формы. И сделать это для каждой панели в отдельности. Это даже указано в документации RegisterTouchWindow():

Примечание RegisterTouchWindow необходимо вызывать в каждом окне, которое будет использоваться для касаниявход. Это означает, что если у вас есть приложение с несколькими окнами, RegisterTouchWindow необходимо вызывать для каждого окна в этом приложении, которое использует сенсорные функции. Кроме того, приложение может вызывать RegisterTouchWindow любое количество раз для одного и того же окна, если оно хочет изменить флаги модификатора. Окно может быть помечено как больше не требующее сенсорного ввода с использованием функции UnregisterTouchWindow.

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

Если вы хотите, чтобы каждая панель на форме поддерживала сенсорный ввод, достаточно простого класса вставки:

unit Unit2;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls;

type
  TPanel = class(Vcl.ExtCtrls.TPanel)
  protected
    procedure CreateWnd; override;
    procedure DestroyWnd; override;
    procedure WMTouch(var Message: TMessage); message WM_TOUCH;
  end;

  TForm1 = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    Panel3: TPanel;
  end;

var
  Form1: TForm1;

implementation

type
  TOUCHINPUT = record
    x: Integer;
    y: Integer;
    hSource: THandle;
    dwID: DWORD;
    dwFlags: DWORD;
    dwMask: DWORD;
    dwTime: DWORD;
    dwExtraInfo: ULONG_PTR;
    cxContact: DWORD;
    cyContact: DWORD;
  end;

procedure TPanel.CreateWnd;
begin
  inherited;
  RegisterTouchWindow(Handle, 0);
end;

procedure TPanel.DestroyWnd;
begin
  UnregisterTouchWindow(Handle);
  inherited;
end;

procedure TPanel.WMTouch(var Message: TMessage);
  function TouchPointToPoint(const TouchPoint: TTouchInput): TPoint;
  begin
    Result := Point(TouchPoint.X div 100, TouchPoint.Y div 100);
    PhysicalToLogicalPoint(Handle, Result);
  end;
var
  TouchInputs: array of TTouchInput;
  TouchInput: TTouchInput;
  Handled: Boolean;
  Point: TPoint;
begin
  Handled := False;
  SetLength(TouchInputs, Message.WParam);
  GetTouchInputInfo(Message.LParam, Message.WParam,
  @TouchInputs[0], SizeOf(TTouchInput));
  try
    for TouchInput in TouchInputs do
    begin
      Point := TouchPointToPoint(TouchInput);
      if PtInRect(BoundsRect, Point) then
      begin
        //labelX.Caption := 'Touch ID: ' + IntToStr(TouchInput.dwID);
        Top := Point.Y - 100;
      end;
      Handled := True;
    end;
  finally
    if Handled then
      CloseTouchInputHandle(Message.LParam)
    else
      inherited;
  end;
end;

end.
...