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

FMX асинхронное управление интерфейсом в процедуре до её завершения.


Светлана

Вопрос

Ну всё в принципе как всегда, либо я барашка, либо лыжи не едут)

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

Пока что для тестов сделала элементарно кнопку Update (speedbutton с image), данные элементарно грузятся и отображаются в GridPanel, а поверх него, чтоб пользователь и не смог куда либо тыкнуть, замостила панелькой с Image, вращаемой по таймеру (всё это дело наверху Visible:=false). И когда клацаем по кнопке Update, то панельку сверху грида делаю отображаемой и запускаю таймер, потом этот же обработчик/процедура грузит данные, а по окончанию останавливаем таймер и скрываем полупрозрачну, еще кстати, панельку. Аля вот так:

procedure TForm1.SB_DataUpdateClick(Sender: TObject);
	begin
      //отображаем лого загрузки
      P_showLoad.Visible := true;
      Timer_load_rotate.Enabled := true; //с запуском таймера
		
      GetDeD_List(DE_set.Date); //процедура загрузки и отображения чего нам надо, которая весьма долго выполняется

	  //и скрывае лого загрузки
      Timer_load_rotate.Enabled := false; //уже в обратном порядке
      P_showLoad.Visible := false;
    end;

иии... ни черта не происходит как я хочу(

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

procedure TForm1.SB_DataUpdateClick(Sender: TObject);
	begin
      TThread.Queue(TThread.Current,  //TThread.Queue TThread.Synchronize ForceQueue
        procedure()
        begin
           P_showLoad.Visible := true;
           Timer_load_rotate.Enabled := true;
        end);
		
      GetDeD_List(DE_set.Date); //процедура загрузки и отображения чего нам надо, которая весьма долго выполняется
    end;

И опять оно отображается только после того, как всё загрузится и проработает вся процедура. И уже чего только не пробовала и Synchronize и ForceQueue; и через TTask.Run и |task := TTask.Create(procedure () ... и т.д.| ничего не подходит, вот хоть убейся это всё дело будет отображаться только после полной отработки процедуры клика. Может я не в том направлении вообще рою и это как то по другому делается? Может я еще пока отлаживаю на Win32, а не всё на android, а там вот пара вариантов и норм на нём работают? Но чтот я никак не могу понять, что к чему... должно же быть как то просто, а я чтот никак не могу понять как(

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

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

  • 0
1 час назад, Светлана сказал:

Логика мне стала подсказывать, что следовало его как то отобразить выполнив в параллельном асинхронном потоке

Ну правильно Вам логика подсказала, вот только в отдельном потоке надо запускать ВСЁ. Аля так:

TThread.CreateAnonymousThread(procedure
  begin
    TThread.ForceQueue(TThread.Current,  
      procedure
      begin
        P_showLoad.Visible := true;
        Timer_load_rotate.Enabled := true;
      end);

    GetDeD_List(DE_set.Date);

    TThread.ForceQueue(TThread.Current,  
      procedure
      begin
        P_showLoad.Visible := False;
        Timer_load_rotate.Enabled := False;
      end);
  end);

P.S.

Не проверял, но логика, я думаю, ясна

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

TThread.CreateAnonymousThread(procedure begin ... end);

Либо не работает вообще, либо пробую дописать .Start и выбивает ошибку.

Логика ясна, начала перебирать варианты, но... меня терзают какие то смутные сомнения, что может ничего не получиться, потому что реакция на вложения еще хуже, чем ожидалось. Хотелось бы всё таки более ясный мануал за потоки к FMX, почитать, чтоб точно понять как они работают и на основе этого сделать как лучше, а не методом тыка костыли создавать.

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

Либо не работает вообще, либо пробую дописать .Start и выбивает ошибку

Да, извините - забыл, конечно надо TThread.CreateAnonymousThread(procedure begin ... end).Start, ведь он создаётся как Suspended

14 минут назад, Светлана сказал:

но... меня терзают какие то смутные сомнения, что может ничего не получиться,

Я их довольно часто использовал (пока не перешёл на работу с TTask), всегда всё отрабатывало нормально.

15 минут назад, Светлана сказал:

Хотелось бы всё таки более ясный мануал

Пройдитесь по форумам или блогам, почитайте хелп :)

 

А Вообще - в Вашем случае Image и таймер никогда не будет отрабатывать, пока GetDeD_List запускается в главном потоке

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

А если я ловлю ошибку иногда "Exception class DOMException with message 'Microsoft MSXML is not installed'" - это значит, что то типа потоку не доступна та или иная lib для выполнения?

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

Логика ясна, начала перебирать варианты, но... меня терзают какие то смутные сомнения, что может ничего не получиться, потому что реакция на вложения еще хуже, чем ожидалось. Хотелось бы всё таки более ясный мануал за потоки к FMX, почитать, чтоб точно понять как они работают и на основе этого сделать как лучше, а не методом тыка костыли создавать.

"Курите" мануалы! Купите книжку "Delphi High Performance" в конце концов, там хорошо все разжевано!

На YouTube есть множество роликов о том как правильно делать...

Все видимое выполняйте в главном потоке, все вычисления, запросы, обработку выносите в потоки и будет Вам счастье Анатолий Светлана!

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

Светлана, вот как делаю я:

 

procedure TMainClient.ОбновитьДанныеВПотоке
begin
  TThread.CreateAnonymousThread(procedure ()
    begin
      TThread.Synchronize (nil, //Из потока обращаемся к контролам только через главгый поток
      procedure ()
      begin
        Показываем котролы запускаем мультик
      end);
      
      Выполняем обработку данных без использования визуальных элементов 

      TThread.Synchronize(nil, 
      procedure ()
      begin
        Выполняем остановку мультика скрываем контролы
      end);
  end).Start;
end;

 

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

А если я ловлю ошибку иногда "Exception class DOMException with message 'Microsoft MSXML is not installed'" - это значит, что то типа потоку не доступна та или иная lib для выполнения?

А это означает, что в этом потоке Вы не вызвали CoInitialize, прежде чем работать с XML

Ссылка на комментарий
  • 0
В 16.10.2019 в 02:29, Светлана сказал:

А если я ловлю ошибку иногда "Exception class DOMException with message 'Microsoft MSXML is not installed'" - это значит, что то типа потоку не доступна та или иная lib для выполнения?

Еще, причем, если будете запускать не только на Windows, сразу выберете кросплатформенного поставщика (DOM Vendor) ADOM XML v4

Тогда не надо будет вызывать CoInitialize, который и работает только для Windows

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

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

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

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

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

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

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

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

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

  • Похожий контент

    • Автор Delpher-X
      Я обратил внимание, что если в VCL цвет формы, а также некоторых других компонентов можно менять, то в FMX это сделать нельзя - доступен только дефолтно-серый, во всяком случае, при компиляции под Android. Есть ли какие-то способы это поправить? 
    • Автор Delpher-X
      У меня есть следующий код, который передает данные из потока в объект типа TStrings: 
      var F : TMemoryStream; S : TStrings; begin F := TMemoryStream.Create; S := TStringList.Create; F.LoadFromFile('C:/File.jpg'); S.LoadFromStream(F); Из TMemoryStream в TStrings все передается нормально. Однако - как обратно? Как снова преобразовать объект TString в поток данных, дабы снова можно было бы сохранить его в полноценный файл? 
    • Автор slav_z
      Все разработчики при работе с FMX рано или поздно сталкиваются с одной и той же проблемой: необходимо исключить "случайное" срабатывание нажатий элементов внутри скроллбокса во время его скроллинга. Идут годы, а решения так и нет. Давайте попробуем это исправить. Поехали!
      Запускаем IDE, создаем новый проект, кидаем на форму TVertScrollBox и на него чего-нибудь побольше... запускаем на мобильном устройстве, пытаемся скроллировать,

      получаем проблемы в виде срабатывания разных событий типа OnClick элементов.
      Решение состоит в том, чтобы сделать элементы "невидимыми" для событий связанных с действиями пользователя с экраном во время скроллинга.
      Делаем следующее:

      Все. Переносим код в базовую форму, делаем его более гибким, убираем все те костыли, которые мы уже успели сделать ранее...
      Удачи!
      https://github.com/slav-libx/scroll-click.git
    • Автор uakmal
      Здравствуйте!
      Создаю медиаплеер для Android TV. 
      Запускаю плеер, нажимаю на условную кнопку, которая делает следующее: 
      MediaPlayer1.FileName:='/storage/emulated/0/download/1.mp4'; После нажатия вылетает окошко с надписью:
      java.lang.java.lang.illegalargumentexception после закрытия окошки нажимаю на play, но ничего не происходит.
      Подскажите, пожалуйста как исправить это?
    • Автор Delpher-X
      Итак, я пробовал использовать компоненты AppTethering для передачи данных между VCL-приложением работающим под Windows и мобильным FMX-приложением и потерпел неудачу, так как выяснилось что потоки данных данные компоненты на деле не передают. И у меня возник вопрос: а нет ли каких других компонентов в современной Embarcadero Studio, которые бы позволяли передавать как строковые данные, так и файлы между приложениями? Особенно меня интересуют все же файлы. 
    • Автор Delpher-X
      Доброе время суток. У меня есть код, который отправляет данные, в частности файлы, из одного приложения в другое, используя технологию AppTethering. Вот код, который отправляет данные: 
      var ImageToStream : TMemoryStream; begin ImageToStream := TMemoryStream.Create; ImageToStream.LoadFromFile('Здесь находится путь к файлу'); ImageToStream.Position := 0; TetheringAppProfile1.Resources.FindByName('ImageTransfer').Value := ImageToStream; ImageToStream.Free; end; А вот который принимает: 
      procedure TForm1.TetheringAppProfile1Resources3ResourceReceived( const Sender: TObject; const AResource: TRemoteResource); var GetImage : TMemoryStream; begin GetImage := TMemoryStream.Create; GetImage.Position := 0; GetImage.LoadFromStream(AResource.Value.AsStream); ImageViewer1.Bitmap.LoadFromStream(GetImage); GetImage.Free; end; Пока передача данных идет между двумя Windows-приложениями, все работает прекрасно. Однако, когда я пытаюсь отправить данные от Windows-приложения в Android-приложение, которое исполняется на смартфоне, подключенном к компьютеру через USB-шнур, данные не проходят.  
    • Автор Delpher-X
      У меня есть код, который должен скачивать файл с сайта: 
      var LoadFile : TMemoryStream; begin LoadFile := TMemoryStream.Create; IdHTTP1.Get('https://sitename.pro/Folder/FileName.txt', LoadFile); LoadFile.SaveToFile('FileName.txt'); LoadFile.Free; end; Проблема однако в том, что вместо скачивания файла программа выдает: Could not load SSL library, хотя я никакой "SSL library" не просил)). При этом, когда я попробовал скачать файл с сайта работающего по старинке, на http (в отличие от https), все скачалось нормально, то есть проблема явно в данном протоколе. Поиск по Интернету ничего не дал.  
    • Автор Anatoliy_
      Приветствую
      Подскажите, планируется ли в RAD Studio возможность компиляции Delphi программ  для WebAssembly?
       
    • Автор Delpher-X
      Есть код для копирования файлов:
      procedure TForm1.Timer2Timer(Sender: TObject); var FileIndex, FileName : String; I : Integer; begin randomize; FileIndex := IntToStr(random(5000)); for I := 0 to ListBox1.Items.Count-1 do begin FileIndex := IntToStr(StrToInt(FileIndex) + 1); FileName := FileIndex + Exp; TFile.Copy(ListBox1.Items[I], FileName); end; Timer2.Enabled := False; end; Когда я его запускаю, все работает, однако постоянно выскакивает сообщение об ошибке: specified file already exists, то есть копируемый файл уже существует. То есть, программа пытается каждый файл скопировать дважды. Вопрос: почему? С чем это связано и как от этого избавиться? 
    • Автор Delpher-X
      Здравствуйте. У меня такая проблема. 
      Пытаюсь скачать файл:
       
      var S : TMemoryStream; begin S := TMemoryStream.Create(); IdHTTP1.Get('http://sitename.com/7UlmBU7IXHA.jpg', S); S.SaveToFile('/storage/emulated/0/ImageFile.jpg'); S.Free; end;
      Проблема возникает на последней стадии - при сохранении файла. Android пишет, Cannot create file: '/storage/emulated/0/ImageFile.jpg'. Permission denied, то есть доступ запрещен. Но как его разрешить? Когда я устанавливаю приложение, система пишет, что никаких разрешений данная программа не требует.
  • Последние посетители   0 пользователей онлайн

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

×
×
  • Создать...