简体   繁体   English

在FMX中处理OnResize的最佳方法是什么?

[英]What is the best way to handle OnResize in FMX?

When a window is resized I want to handle the OnResize event when resizing is finished as updating the graphic takes seconds. 调整窗口大小时,我想在调整大小时处理OnResize事件,因为更新图形需要几秒钟。 That is tricky because resizing a window generates lots of resize events. 这很棘手,因为调整窗口大小会产生大量的调整大小事件。 As updating the window takes a while I don't want the window being updated on each event. 由于更新窗口需要一段时间,我不希望在每个事件上更新窗口。 I tried to detect a mouse up to flag that as the event that finishes a resize but the mouseup is never detected. 我试图检测一个鼠标,将其标记为完成调整大小的事件,但从未检测到鼠标。

TLama had a nice solution but alas, that's VCL, I need it for Firemonkey. TLama有一个很好的解决方案,但唉,这是VCL,我需要Firemonkey。 Any suggestions for FMX? 有关FMX的任何建议吗?

What about something similar to the Debounce() or Throttle() function in Underscore.js ? 类似于Underscore.js中的Debounce()或Throttle()函数怎么样? Both functions provide ways to limit how regularly a procedure is executed. 这两个函数都提供了限制程序执行顺序的方法。

Here is a way to handle it in FMX on Windows, you need to change your form to inherit from TResizeForm and assign OnResizeEnd property. 这是一种在Windows上的FMX中处理它的方法,您需要将表单更改为从TResizeForm继承并分配OnResizeEnd属性。 Not very clean since it depends on on FMX internals, but should work. 不是很干净,因为它取决于FMX内部,但应该工作。

unit UResizeForm;

interface

uses
  Winapi.Windows,
  System.SysUtils, System.Classes,
  FMX.Types, FMX.Forms, FMX.Platform.Win;

type
  TResizeForm = class(TForm)
  strict private
    class var FHook: HHook;
  strict private
    FOnResizeEnd: TNotifyEvent;
  public
    property OnResizeEnd: TNotifyEvent read FOnResizeEnd write FOnResizeEnd;
    class constructor Create;
    class destructor Destroy;
  end;

implementation

uses Winapi.Messages;

var
  WindowAtom: TAtom;

function Hook(code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT stdcall;
var
  cwp: PCWPSTRUCT;
  Form: TForm;
  ResizeForm: TResizeForm;
begin
  try
    cwp := PCWPSTRUCT(lparam);
    if cwp.message = WM_EXITSIZEMOVE then
    begin
      if WindowAtom <> 0 then
      begin
        Form := TForm(GetProp(cwp.hwnd, MakeIntAtom(WindowAtom)));
        if Form is TResizeForm then
        begin
          ResizeForm := Form as TResizeForm;
          if Assigned(ResizeForm.OnResizeEnd) then
          begin
            ResizeForm.OnResizeEnd(ResizeForm);
          end;
        end;
      end;
    end;
  except
    // eat exception
  end;
  Result := CallNextHookEx(0, code, wparam, lparam);
end;

class constructor TResizeForm.Create;
var
  WindowAtomString: string;
begin
  WindowAtomString := Format('FIREMONKEY%.8X', [GetCurrentProcessID]);
  WindowAtom := GlobalFindAtom(PChar(WindowAtomString));
  FHook := SetWindowsHookEx(WH_CALLWNDPROC, Hook, 0, GetCurrentThreadId);
end;

class destructor TResizeForm.Destroy;
begin
  UnhookWindowsHookEx(FHook);
end;

end.

As a workaround add a TTimer to the form, set its initial state to disabled and the Interval property to 100 ms. 解决方法是在表单中添加TTimer ,将其初始状态设置为disabled,将Interval属性设置为100 ms。 To minimize the amount of times your application reacts to the OnResize event use the following code: 要最小化应用程序对OnResize事件做出反应的次数,请使用以下代码:

procedure TForm1.FormResize(Sender: TObject);
begin
    with ResizeTimer do
    begin
        Enabled := false;
        Enabled := true;
    end;
end;

procedure TForm1.ResizeTimerTimer(Sender: TObject);
begin
    ResizeTimer.Enabled := false;

    // Do stuff after resize
end;

The minimal delay should not be noticeable by the user. 用户不应注意到最小延迟。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM