Por padrão, aplicações uniGUI são aplicações web padrão que funcionam em modo assíncrono. Isso significa que o servidor não precisa bloquear uma thread de sessão enquanto espera por uma resposta do usuário vinda do cliente.
Modo Assíncrono
Como usar ShowModal neste modo?
Vamos usar um exemplo bem simples. Vamos criar um formulário para inserir o nome de uma pessoa com botões para aceitar ou cancelar a solicitação. Outro formulário usará o formulário anterior para atualizar seu próprio campo interno FFullName.
Este formulário retornará o nome completo inserido ou 'John Doe' se o nome completo estiver vazio. Seu resultado dependerá do pressionamento do botão OK ou Cancel (ou do fechamento do formulário). Como o usamos?
O que acontece aqui?
1
Passo 1
Começamos pressionando o botão GetFullName.
2
Passo 2
Assim que chamamos UniForm3, uma instância do formulário TUniForm3 será criada e retornada.
3
Passo 3
A chamada para ShowModal exibirá o formulário e ele se comportará como um formulário modal do lado do cliente (significando que nenhuma interação adicional é permitida fora deste formulário).
4
Passo 4
No entanto, do lado do servidor, o programa continuará, o que neste caso significa que ele sairá do manipulador de evento OnClick.
5
Passo 5
Neste ponto, o servidor terminou a solicitação anterior (isto é, o evento OnClick acionado no cliente pelo usuário).
6
Passo 6
Quando o usuário finalmente clica em qualquer um dos botões (Ok ou Cancel) ou fecha o formulário, outra solicitação será enviada ao servidor: tratar o resultado do ShowModal para esse formulário.
7
Passo 7
O servidor identificará a sessão do usuário e executará o método anônimo que ainda mantém a referência a UniForm3 (comportamento padrão para métodos anônimos).
8
Passo 8
Uma vez que o método anônimo é executado, o formulário UniForm3 ficará disponível para descarte (sua vida útil sendo gerenciada pelo framework uniGUI).
Modo Síncrono
É sempre preferível criar a aplicação web em modo assíncrono, mas ao migrar aplicações VCL antigas, o desenvolvedor pode encontrar cenários que não poderiam ser implementados ou que tornariam a tarefa muito difícil. Se necessário, o uniGUI pode ser forçado a trabalhar como uma aplicação VCL típica.
Se o desenvolvedor precisar reproduzir o modo síncrono disponível em aplicações VCL, a propriedade MainModule.EnableSynchronousOperations deve ser definida como true.
ShowModal
Como usar ShowModal neste modo?
Este é o mesmo código que normalmente usamos para aplicações VCL. Também interrompe a execução após chamar ShowModal até que um resultado seja retornado. Esse tipo de código requer a criação de uma thread no servidor que ficará aguardando a solicitação/resposta do cliente. Como você pode esperar, esse tipo de aplicação consome mais recursos do que uma aplicação web padrão. Felizmente, o uniGUI usa um thread-pool interno para minimizar o uso de threads, mas para cada janela modal aguardando uma thread será consumida. Após o fechamento da janela modal, as threads de espera serão retornadas ao thread-pool para uso futuro.
Além de ShowModal, o uniGUI permite executar operações síncronas em outros cenários. Vamos examinar algumas demos.
Modais Bloqueantes
Há uma demo ilustrando modais bloqueantes, "BlockingModals".
BlockingModals
O código a seguir mostra como cada função agora é uma chamada bloqueante como era no VCL.
Barra de Progresso
A demo "SyncClientUpdate-1" mostra como atualizar uma barra de progresso enquanto executa uma tarefa longa.
SyncClientUpdate-1
Uma vez que o usuário clica no botão Start, este é o tipo de código que alcança o comportamento desejado:
A chamada UniSession.Synchronize força uma atualização imediata. Passar um argumento permite sincronizar em um período controlado (a cada alguns milissegundos).
Processamento síncrono usando ShowMask
A demo "SyncClientUpdate-3" executa uma sequência de tarefas com atualizações de status e usando ShowMask para evitar a interação do usuário com outros controles visuais.
SyncClientUpdate-3
O código para o botão Start é:
Sincronizar esperando por eventos ou timeout
A demo "SyncClientUpdate-5" mostra a diferença entre Synchronize(Wait : boolean) e Synchronize(Delay : integer).
SyncClientUpdate-5
Pressionar o botão "Start No Wait" moverá o UniPanel1 para o canto inferior direito 5 pixels a cada 200 milissegundos (mostrando o movimento).
Pressionar o botão "Start" realizará o mesmo, mas cada passo acontecerá apenas quando algum evento do lado do cliente for detectado (por exemplo, pressionar o botão dummy "Press!" ou redimensionar o formulário).
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms, uniGUITypes, uniGUIAbstractClasses,
uniGUIClasses, uniGUIForm, uniGUIBaseClasses, uniButton;
type
TUniForm1 = class(TUniForm)
btnGetFullName: TUniButton;
procedure btnGetFullNameClick(Sender: TObject);
private
{ Declarações privadas }
FFullName : string;
public
{ Declarações públicas }
end;
function UniForm1: TUniForm1;
implementation
{$R *.dfm}
uses
MainModule, uniGUIApplication,
Unit3;
function UniForm1: TUniForm1;
begin
Result := TUniForm1(UniMainModule.GetFormInstance(TUniForm1));
end;
procedure TUniForm1.btnGetFullNameClick(Sender: TObject);
begin
UniForm3.ShowModal
(
procedure (Sender: TComponent; AResult: Integer)
begin
if TModalResult(AResult) = mrOk then
FFullName := (Sender as TUniForm3).FullName;
end
);
end;
end.
procedure TUniForm1.btnGetFullNameClick(Sender: TObject);
begin
if UniForm3.ShowModal = mrOk then
FFullName := UniForm3.FullName;
end;
procedure TMainForm.btnShowModalClick(Sender: TObject);
var
M : TModalResult;
begin
M := UniForm1.ShowModal;
case M of
mrOK : ShowMessage('OK');
mrCancel : ShowMessage('Cancel');
mrNone : ShowMessage('None');
end;
ShowMessage('Done, ' + UniForm1.UniEdit1.Text);
end;
procedure TMainForm.btnMessageDlgClick(Sender: TObject);
var
Res : Integer;
begin
Res := MessageDlg('Test', mtConfirmation, mbYesNoCancel);
case Res of
mrYes : ShowMessage('Yes');
mrNo : ShowMessage('No');
mrCancel : ShowMessage('Cancel');
end;
end;
procedure TMainForm.btnPromptClick(Sender: TObject);
var
sResult : string;
begin
if Prompt('Please type something?', 'Value',
mtInformation, mbYesNoCancel, sResult, True) = mrYes then
ShowMessage('Result: ' + sResult);
end;
procedure TMainForm.btnNestedCallsClick(Sender: TObject);
var
sResult : string;
begin
if UniForm1.ShowModal = mrOK then
if Prompt('Please type something?', '',
mtInformation, mbYesNoCancel, sResult, True) = mrYes then
if MessageDlg('Continue?', mtConfirmation, mbYesNoCancel) = mrYes then
ShowMessage('Result: ' + sResult + ' ' + UniForm1.UniEdit1.Text );
end;
procedure TMainForm.btnNestedForms1Click(Sender: TObject);
begin
if UniForm1.ShowModal = mrOK then
if UniForm2.ShowModal = mrOK then
if UniForm3.ShowModal = mrOK then
if UniForm4.ShowModal = mrOK then
begin
ShowMessage('All shown!');
end;
end;
procedure TMainForm.btnNestedForms2Click(Sender: TObject);
begin
if UniForm5.ShowModal() = mrOK then
ShowMessage('Completed');
end;
procedure TMainForm.btnFileUploadClick(Sender: TObject);
begin
if UniFileUpload1.Execute then
begin
ShowMessage('File upload completed.' +
^M^M'Filename: ' + UniFileUpload1.FileName +
^M^M'Temporary file is located under:' +
UniFileUpload1.CacheFile);
end;
end;
begin
FCancelled := False;
UniProgressBar1.Min := 1;
UniProgressBar1.Max := MAX_FILES;
btnStart.Enabled := False;
btnCancel.Enabled := True;
// Resetar Progressbar e Label
UpdateClient(0);
// Atualização inicial antes de entrar no loop.
// (Progressbar e Label serão atualizados)
UniSession.Synchronize;
N := 0;
try
for I := 1 to MAX_FILES do
begin
// Atualizar o cliente em intervalos "X_INTERVAL"
if UniSession.Synchronize(X_INTERVAL) then
UpdateClient(N);
// Verificar se a operação foi cancelada.
// (Ou quando o botão Cancel é pressionado ou o formulário é fechado)
if FCancelled then Break;
// executar algumas tarefas aqui
CreateDummyFile(I);
Inc(N); // +1 número de arquivos criados
end;
UpdateClient(N);
finally
btnStart.Enabled := True;
btnCancel.Enabled := False;
end;
end;