Перейти к содержанию
Fire Monkey от А до Я
  • 0

Как сделать Окно "подождите пожалуйста" (многие приложения при соединении с БД или отправке запроса к удаленному сервису поднимают окно "Please wait")


Archi_Ku

Вопрос

Доброго времени суток коллеги!

 

Прошу подсказать или выручить примером реализации окна "Подождите пожалуйста"/"Please wait". (Желательно стандартными компонентами)

Приложение планирую запускать на Android и IOS.

В дескопном клиенте делал Show и Hide (для того чтобы отобразить/спрятать окно), а для Android в частности аналогичное реализовать не удается, или может frame или layout использовать необходимо а я через form пытаюсь.

Третий день бьюсь над этим вопросом, Господа выручайте.

 

Читал вот эту статью ( http://fire-monkey.ru/topic/83-fgx-индикация-хода-выполнения-длительных-операций-виртуальная-клавиатура-и-actionsheet/ )

Почти всё меня устраивало, только вот достичь желаемого результата не удалось:

- поднять окно "Подождите пожалуйста"

- выполнить запрос к серверу(получить ответ сервера)

- по окончанию открыть другое окно(зависит от результата)

- закрыть окно "подождите пожалуйста"

 

Прошу поправить или подсказать как реализовать задуманное?! (если выручите примером буду премного благодарен)

-------------------------------------------------------------------------------------------

RAD Studio 10.2.2, Android SDK 24.0, IOS 11.3

 

 

PleaseWait.7z

Ссылка на комментарий

Рекомендуемые сообщения

  • 1

В Токио для того, чтобы показалось окно с прогрессом FGX нужно ресурсоемкую (длительную) операцию выполнять в отдельном потоке. самое простое примерно можно описать так:

TTask.Run(
  procedure ()
  begin

    //Выполнение операции

    TThread.Synchronize(nil,
      procedure ()
      begin
        ActionDialog.Hide;  
      end)
  end);

 

Ссылка на комментарий
  • 0

Концепция операций в таких случаях очень простая

1. поднять индикатор загрузки. отдельная форма, колесо, прогрессбар или любой другой вариант

2. запустить поток. указать ему что делать, когда он закончится

в "что делать" обязательно включаем гашение индикатора загрузки и обработку результата, чего там вернул поток

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

Реализовать таким образом, что если поток2 не успел до истечения таймера потока1, значит, когда/если он вернется, его результат будет просто проигнорирован.

Можно вместо первого потока обойтись простым таймером на форме. Тогда все еще проще.

Изменено пользователем krapotkin
Ссылка на комментарий
  • 1

вообще вам уже код написали в первом ответе, ну я могу дать альтернативную реализацию

procedure TForm1.ThreadEnd(Sender:TObject);
var th: TMyThread absolute Sender;
begin
  CloseProgressForm();
  // прочитать из Th все данные которые вам надо вернуть из потока
end;

...
ShowProgressForm();
th:=TMyThread.Create(true);
th.FreeOnTerminate := true;
th.OnTerminate := ThreadEnd;
// заполнить другие поля Th
th.Start;

 

Ссылка на комментарий
  • 1

я бы все-таки рекомендовал пользоваться моей техникой 

procedure TForm1.ThreadEnd(Sender:TObject);
var th: TMyThread absolute Sender;
begin

вместо поля формы TH

Изменено пользователем krapotkin
Ссылка на комментарий
  • 0
49 минут назад, krapotkin сказал:

if not Assigned(FFGActionDialog) then

Взял кусок кода из стандартного примера.

А так вобще верное замечание!

Откровенно да, выглядит всё сложно, если не сказать хуже...

Буду думать над оптимизацией. (У меня опыта работы  с потоками однозначно мало. Плаваю в том что касается передачи в поток, ожидания потока, возврата из потока)

 

Наткнулся на интересную(для меня) реализацию возврата переменной из потока.

unit uAwait;

interface

uses
  System.Classes
  ;

type
  TAwaitableProc<T> = reference to function : T;

  IAwaitable<T> = interface
    function Value: T;
  end;

  TAwaitable<T> = class(TInterfacedObject, IAwaitable<T>)
  private
    FThread: TThread;
    FValue: T;
  public
    constructor Create(AwaitableProc: TAwaitableProc<T>); reintroduce;
    destructor Destroy; override;

    function Value: T;
  end;

implementation

constructor TAwaitable<T>.Create(AwaitableProc: TAwaitableProc<T>);
begin
  inherited Create;

  FThread := TThread.CreateAnonymousThread(
    procedure begin
      FValue := AwaitableProc;
    end);

  FThread.FreeOnTerminate := False;
  FThread.Start;
end;

destructor TAwaitable<T>.Destroy;
begin
  FThread.Free;
  inherited;
end;

function TAwaitable<T>.Value: T;
begin
  FThread.WaitFor;
  Result := FValue;
end;

end.

и сам вызов

procedure TForm1.Button1Click(Sender: TObject);
var
  Wait: TAwaitable<string>;
begin
  Wait := TAwaitable<string>.Create(
    function : string
    begin
      Sleep(2500);
      Result := 'ewrewefewfrwe';
    end
  );

  ShowMessage(Wait.Value);
end;

 

Ссылка на комментарий
  • 0
1 час назад, krapotkin сказал:

я бы все-таки рекомендовал пользоваться моей техникой 


procedure TForm1.ThreadEnd(Sender:TObject);
var th: TMyThread absolute Sender;
begin

вместо поля формы TH

В чем прелесть? Может есть ссылка что почитать на эту тему?

Ссылка на комментарий
  • 0
31 минуту назад, Archi_Ku сказал:

В чем прелесть?

Если вы можете гарантировать, что Sender всегда будет типа TmyThread, то преимущество в использовании absolute есть:

вы можете сразу работать с полем th как с экземпляром своего потока. Что это дает? Ну, допустим у вас запущено несколько потоков, каждый по завершению вызывает этот обработчик. Если в обработчике использовать поле класса, то вы будете работать с одним (скорее всего - последним созданным) экземпляром потока. А если оперировать Sender-ом, то работа будет вестись именно с тем, кто вызвал метод.

Повторюсь - если можете гарантировать, что Sender будет нужного вам типа.

Но лучше все-таки не надеяться на это, а выполнять явные преобразования:

procedure TForm1.ThreadEnd(Sender:TObject); 
var 
  th: TMyThread;
begin
  if Sender is TmyThread then
    th:=TmyThread(Sender)
  else
    th:=nil;
  if not Assigned(th) then
    exit;
  // а вот далее th уже явно указывает на экземпляр TMyThread.

 

Ссылка на комментарий
  • 0

я обычно для разных классов потоков использую разные терминаторы

поэтому Sender у меня всегда ожидаемого типа.

а в остальном да, все именно так. Вы не знаете, какой поток к вам пришел умирать. Мало того, я обычно создаю пул потоков в TObjectList.

и в методе-терминаторе удаляю этот поток из списка. тем самым есть контроль, вдруг надо будет завершить работу,  и есть синхронизация по факту по архитектуре

Ссылка на комментарий

Присоединяйтесь к обсуждению

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

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...