1

我正在使用 Delphi 10.1 Berlin,VCL 项目。我正在尝试使用触摸屏和从 Windows 生成的 WM_Touch 消息同时移动多个面板。我基于 Chris Benson 博客中的示例代码:http: //chrisbensen.blogspot.com/2009/11/touch-demo.html

只有当我先触摸背景表单上的某个位置,然后将手指拖到面板上时,它才会在一定程度上起作用。如果我先触摸背景,面板将用我的手指移动。据我所知,当我触摸窗体顶部的面板时,似乎不会调用 TForm1.WMTouch 过程。除非我先触摸表单,否则我不会收到 WM_Touch 消息。

在 Chris 的博客中,他调用了 RegisterTouchWindow(Handle, 0); 在表单创建中。我认为这就是为什么当您触摸表单时会调用该程序的原因。每当我触摸面板时,我将如何调用 WM_Touch 过程?

- 我尝试使用面板的 OnClick 事件,但这不起作用,因为它似乎没有将触摸注册为 OnClick 事件。

- 这是我应该使用继承类的东西吗?如果是这样,我将如何去做?

提前感谢您的任何想法!

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.
4

1 回答 1

3

据我所知,当我触摸窗体顶部的面板时,似乎不会调用 TForm1.WMTouch 过程。除非我先触摸表单,否则我不会收到 WM_Touch 消息。

正确,因为您没有触摸表单本身,而是触摸了表单顶部的面板。

在 Chris 的博客中,他调用了 RegisterTouchWindow(Handle, 0); 在表单创建中。我认为这就是为什么当您触摸表单时会调用该程序的原因。

是的。

每当我触摸面板时,我将如何调用 WM_Touch 过程?

您必须注册 PanelHWND而不是 Form 的HWND. 并为每个面板单独执行此操作。这甚至在RegisterTouchWindow()文档中也有很多说明:

Note 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.
于 2019-10-11T22:08:46.180 回答