-
Notifications
You must be signed in to change notification settings - Fork 22
/
qdac_fmx_modaldlg.pas
188 lines (164 loc) · 4.96 KB
/
qdac_fmx_modaldlg.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
unit qdac_fmx_modaldlg;
{ FMX.ModalDlg FMX 下 ShowModal 的增强和接口统一
本单元统一了 FMX 和 TForm.ShowModal 的操作接口,原来 Delphi 自带的 ShowModal 的
匿名函数版本传递的只是一个 ModalResult 参数,无法通过局部变量进一步控制。此版本
参数改为窗体的实例,你可以访问其 ModalResult 以及各个相关的成员,以方便进一步控
制。
受平台限制,Android 下并不是实际的ShowModal(不过和 ShowModal 差不多,因为它都是
全屏覆盖的,下层的窗口你也操作不了),而其它平台都是真正的模态窗口。
2016.3.4
========
+ 1.0 版
}
interface
uses classes, sysutils, fmx.types, fmx.forms, fmx.controls, System.Messaging,
uitypes;
type
TFormModalProc = reference to procedure(F: TForm);
TFormClass = class of TForm;
/// <summary>显示一个模态窗口</summmary>
/// <param name="F">窗口实例</param>
/// <param name="OnResult">用户关闭窗口时的操作</param>
/// <param name="ACloseAction">窗口关闭时的动作,默认caFree释放掉</param>
/// <remarks>在 Windows/iOS/OSX 上是真正 ShowModal 出来,然后调用 OnResult,而在
/// Android 上,是 Show 以后,在用户关闭或设置 ModalResult 时调用的 OnResult。
/// 也就是说,Android 上受平台限制是模拟的 ShowModal 效果。</remarks>
procedure ModalDialog(F: TForm; OnResult: TFormModalProc;
ACloseAction: TCloseAction = TCloseAction.caFree); overload;
/// <summary>显示一个模态窗口,并在关闭时释放</summmary>
/// <param name="F">窗口实例</param>
/// <param name="OnResult">用户关闭窗口时的操作</param>
/// <remarks>在 Windows/iOS/OSX 上是真正 ShowModal 出来,然后调用 OnResult,而在
/// Android 上,是 Show 以后,在用户关闭或设置 ModalResult 时调用的 OnResult。
/// 也就是说,Android 上受平台限制是模拟的 ShowModal 效果。</remarks>
procedure ModalDialog(AClass: TFormClass; OnResult: TFormModalProc); overload;
implementation
type
TFormModalHook = class(TComponent)
private
FForm: TForm;
FCloseAction: TCloseAction;
FOldClose: TCloseEvent;
FResultProc: TFormModalProc;
procedure DoFormClose(Sender: TObject; var Action: TCloseAction);
public
constructor Create(AOwner: TComponent); override;
procedure ShowModal(AResult: TFormModalProc);
end;
TFormDisposeMgr = class
private
FIdleMsgId: Cardinal;
FPendings: array of TObject;
FCount: Integer;
procedure DoAppIdle(const Sender: TObject;
const Msg: System.Messaging.TMessage);
public
constructor Create; overload;
destructor Destroy; override;
procedure Push(AObj: TObject);
end;
var
FreeMgr: TFormDisposeMgr;
procedure ModalDialog(F: TForm; OnResult: TFormModalProc;
ACloseAction: TCloseAction = TCloseAction.caFree);
var
AHook: TFormModalHook;
begin
AHook := TFormModalHook.Create(F);
AHook.FCloseAction := ACloseAction;
AHook.ShowModal(OnResult);
end;
procedure ModalDialog(AClass: TFormClass; OnResult: TFormModalProc); overload;
var
F: TForm;
begin
F := AClass.Create(Application);
ModalDialog(F, OnResult, TCloseAction.caFree);
end;
{ TFormModalHook }
constructor TFormModalHook.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FForm := AOwner as TForm;
FOldClose := FForm.OnClose;
FForm.OnClose := DoFormClose;
FCloseAction := TCloseAction.caFree;
end;
procedure TFormModalHook.DoFormClose(Sender: TObject; var Action: TCloseAction);
begin
if FForm.ModalResult = mrNone then
FForm.ModalResult := mrCancel;
Action := FCloseAction;
CloseAllPopups;
if Assigned(FOldClose) then
FOldClose(Sender, FCloseAction);
end;
procedure TFormModalHook.ShowModal(AResult: TFormModalProc);
begin
FResultProc := AResult;
{$IFDEF ANDROID}
FForm.ShowModal(
procedure(AResult: TModalResult)
begin
if Assigned(FForm) then
begin
FForm.OnClose := FOldClose;
if Assigned(FResultProc) then
FResultProc(FForm);
end;
// if (not Assigned(FOldClose)) and (FCloseAction = TCloseAction.caFree) then
// FreeMgr.Push(FForm);
CloseAllPopups;
end);
{$ELSE}
FForm.ShowModal;
if Assigned(FResultProc) then
FResultProc(FForm);
CloseAllPopups;
if FCloseAction=TCloseAction.caFree then
FForm.DisposeOf;
{$ENDIF}
end;
{ TFormDisposeMgr }
constructor TFormDisposeMgr.Create;
begin
inherited;
FIdleMsgId := TMessageManager.DefaultManager.SubscribeToMessage(TIdleMessage,
DoAppIdle);
end;
destructor TFormDisposeMgr.Destroy;
begin
TMessageManager.DefaultManager.Unsubscribe(TIdleMessage, FIdleMsgId);
inherited;
end;
procedure TFormDisposeMgr.DoAppIdle(const Sender: TObject;
const Msg: System.Messaging.TMessage);
var
I: Integer;
begin
if FCount > 0 then
begin
for I := 0 to FCount - 1 do
FPendings[I].DisposeOf;
if Length(FPendings) > 32 then
SetLength(FPendings, 32);
FCount := 0;
end;
end;
procedure TFormDisposeMgr.Push(AObj: TObject);
begin
if FCount = Length(FPendings) then
begin
if FCount = 0 then
SetLength(FPendings, 32)
else
SetLength(FPendings, Length(FPendings) shl 1);
end;
FPendings[FCount] := AObj;
Inc(FCount);
end;
initialization
FreeMgr := TFormDisposeMgr.Create;
finalization
FreeMgr.DisposeOf;
end.