Андрей Рулин Опубликовано 11 августа, 2021 Опубликовано 11 августа, 2021 Допустим идут вычисления, мне надо в Label выводить, что они закончились на 10%...20%...100% После изменения текста я делаю Label1.Repaint; Invalidate; При этом текст не изменяется, пока не окончатся вычисления. Хотя в Vcl версии хватает Repaint для формы. Цитата
0 krapotkin Опубликовано 11 августа, 2021 Опубликовано 11 августа, 2021 Специально для этого придумали отдельные потоки. Даже сделали несколько реализаций, которые позволяют не заводить под них отдельный класс, а описывать прямо в коде процедуры, как в javascript Создайте поток, в нем через Synchronize() изменяйте компоненты, и все заработает Цитата
0 Андрей Рулин Опубликовано 2 ноября, 2021 Автор Опубликовано 2 ноября, 2021 Нет, так не работает. Возможно потому, что у меня основные вычисления идут в обработчике Timer1 Помогает добавить в обработчик if Timer1Busy then exit; Timer1Busy := True; И в цикле Application.ProcessMessages; Цитата
0 krapotkin Опубликовано 2 ноября, 2021 Опубликовано 2 ноября, 2021 ProcessMessages оставим в VCL. Не будет тут так работать. Если вычисления в таймере то оно и так нормально должно работать. Значит, что-то умалчивается. TForm2 = class(TForm) tmr1: TTimer; lbl1: TLabel; procedure tmr1Timer(Sender: TObject); private public pc: integer; end; var Form2: TForm2; implementation {$R *.fmx} procedure TForm2.tmr1Timer(Sender: TObject); begin if pc > 10 then begin tmr1.Enabled := false; exit; end; lbl1.Text := format('%d%%', [pc * 10]); inc(pc); end; Вот простейший код. Все обновляется. Цитата
0 Андрей Рулин Опубликовано 27 декабря, 2021 Автор Опубликовано 27 декабря, 2021 (изменено) В 11.08.2021 в 16:43, krapotkin сказал: Создайте поток, в нем через Synchronize() изменяйте компоненты, и все заработает Вот кстати по этому методу я написал следующий код procedure TThreadRenew.ChangeL2; begin Form2.Label2.Text:=IntToStr(CalibPercentw)+'%'; end; procedure TThreadRenew.Execute; begin while MainFlag do begin Synchronize(ChangeL2); //Synchronize(Form2.Invalidate); Sleep(1000); end; end; В Windows всё работает изменения идут ровно раз в секунду. В Андройде, увы... Как только вычисления заканчивается, тогда да, обновляет. Изменено 27 декабря, 2021 пользователем Андрей Рулин Цитата
0 Андрей Рулин Опубликовано 27 декабря, 2021 Автор Опубликовано 27 декабря, 2021 В 02.11.2021 в 12:36, krapotkin сказал: ProcessMessages оставим в VCL. Не будет тут так работать. Если вычисления в таймере то оно и так нормально должно работать. Значит, что-то умалчивается. Ну почему же, вот мы ваш код модифицируем и введём вычисления. procedure TForm2.Timer1Timer(Sender: TObject); var i,j,k:Integer; a:Double; begin if pc >=100 then begin Timer1.Enabled := false; exit; end; for i := 0 to 9 do begin for j := 0 to 5000 do for k := 0 to 10000 do begin a:=a+k/1000+k/500; end; inc(pc); Label1.Text := format('%d%%', [pc]); end; //inc(pc); end; Он даже в Windows будет обновляться по десяткам процентов , а надо , чтобы по единицам, причём даже если j до 10000 и более поставить, когда он не успевает завершить вычисления за отведённое время. Цитата
0 GASCHE Опубликовано 27 декабря, 2021 Опубликовано 27 декабря, 2021 (изменено) 1 час назад, Андрей Рулин сказал: Он даже в Windows будет обновляться по десяткам процентов Чтоб он писал десятками процентов надо чтоб pc изменялось по 10, смотрите кто у вас его меняет. У меня ваш код в Windows меняется по 1 проценту. Изменено 27 декабря, 2021 пользователем GASCHE Цитата
0 Андрей Рулин Опубликовано 28 декабря, 2021 Автор Опубликовано 28 декабря, 2021 (изменено) Вот как у вас и должно быть, чтобы по 1%. А у меня изменяется по 10% . А если вы j до 10 000 или 15 000 делаете , всё равно по 10% изменяется? Может у вас процессор быстрый? И я, если что компилировал в 10.4. Изменено 28 декабря, 2021 пользователем Андрей Рулин Цитата
0 GASCHE Опубликовано 28 декабря, 2021 Опубликовано 28 декабря, 2021 32 минуты назад, Андрей Рулин сказал: А у меня изменяется по 10% Тогда выложите здесь исходники с тем что вы здесь написали и скомпилированный вами код, зачем гадать на гуще. Цитата
0 Андрей Рулин Опубликовано 29 декабря, 2021 Автор Опубликовано 29 декабря, 2021 Да, вот выкладываю Debug.rar Там по 10% изменяется при максимальном j в 5000 Цитата
0 Андрей Рулин Опубликовано 29 декабря, 2021 Автор Опубликовано 29 декабря, 2021 Вот такой код работает в Windows. Но в андройде , увы и ах... По 10% прибавляет. unit Unit2; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls; type TForm2 = class(TForm) Timer1: TTimer; Label1: TLabel; procedure Timer1Timer(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; TThreadRenew = class(TThread) MainFlag : Boolean; constructor Create; Destructor Destroy; procedure Execute; override; procedure ChangeL2; end; var Form2: TForm2; ThreadRenew : TThreadRenew; pc: integer; Busy : Boolean = False; implementation {$R *.fmx} procedure TForm2.FormCreate(Sender: TObject); begin ThreadRenew := TThreadRenew.Create; end; procedure TForm2.Timer1Timer(Sender: TObject); var i,j,k:Integer; a:Double; begin if Busy then exit; Busy := True; if pc >=100 then begin Timer1.Enabled := false; ThreadRenew.MainFlag :=False; end else for i := 0 to 9 do begin for j := 0 to 5000 do for k := 0 to 10000 do begin a:=a+k/1000+k/500; end; inc(pc); Application.ProcessMessages; end; //inc(pc); Busy := False; end; constructor TThreadRenew.Create; begin inherited Create(False); //Автозапуск потока MainFlag := True; end; destructor TThreadRenew.Destroy; begin inherited Destroy; end; procedure TThreadRenew.ChangeL2; begin Form2.Label1.Text := format('%d%%', [pc]); // Form2.Invalidate; end; procedure TThreadRenew.Execute; begin while MainFlag do begin Synchronize(ChangeL2); //Synchronize(Form2.Invalidate); //Synchronize(Application.ProcessMessages); //if Stage>=4 then MainFlag := False //else Sleep(100); end; end; end. Цитата
0 OnePeople Опубликовано 29 декабря, 2021 Опубликовано 29 декабря, 2021 ну так у вас 10 раз inc(pc) for i := 0 to 9 do begin for j := 0 to 5000 do for k := 0 to 10000 do begin a:=a+k/1000+k/500; end; inc(pc); Цитата
0 GASCHE Опубликовано 29 декабря, 2021 Опубликовано 29 декабря, 2021 2 часа назад, Андрей Рулин сказал: По 10% прибавляет for i := 0 to 9 do begin уберите и будет вам счастье Цитата
0 Андрей Рулин Опубликовано 10 января, 2022 Автор Опубликовано 10 января, 2022 (изменено) В 29.12.2021 в 17:01, OnePeople сказал: ну так у вас 10 раз inc(pc) Правильно. И после каждого inc(pc) ожидается , что будет ОТОБРАЖАТЬСЯ +1% В 29.12.2021 в 17:19, GASCHE сказал: for i := 0 to 9 do begin уберите и будет вам счастье Ну извините, это в тестовом коде можно убрать, а не в реальных. Данный код , это максимальное упращение кода в сотни строк, и в это упрощении ошибка всё ещё появляется. Cуть в том, чтобы выполнять вычисления и параллельно отображаеть ход этих вычислений. Если убрать цикл, это значит просто последовательно вести СНАЧАЛА вычисления, а ПОТОМ отображение. А если вычисления идут час. И что , мы должны час оставлять пользователя с зависшей программой? Это не дело! Наверное я очень плохо обясняю, попытаюсь то же сказать более формальный языком. УСЛОВИЯ ТЕСТИРОВАНИЯ. Delphi 10.4 , системы Windows , Android приведённый тестовый код. ОЖИДАЕМЫЙ РЕЗУЛЬТАТ для цикла for i := 0 to 9 do после КАЖДОГО изменения inc(pc); должно отображаться изменение на 1%, например 49%...50%...51% ФАКТИЧЕСКИЙ РЕЗУЛЬТАТ (для Android) для цикла for i := 0 to 9 do изменения отображается ПОСЛЕ ЗАВЕРШЕНИЯ ЦИКЛА. В виде 40%...50%...60% (для всех вариантов кода). ФАКТИЧЕСКИЙ РЕЗУЛЬТАТ (для Windows) cовпадает с ОЖИДАЕМЫМ РЕЗУЛЬТАТОМ для кода в посте от 29.12.2021 15:02 Изменено 10 января, 2022 пользователем Андрей Рулин уточнение Цитата
0 OnePeople Опубликовано 10 января, 2022 Опубликовано 10 января, 2022 Ну так Application.ProcessMessages в Андроиде не работает так то Цитата
0 krapotkin Опубликовано 10 января, 2022 Опубликовано 10 января, 2022 ну так я же еще раз повторяю пока работает ваш код в основном потоке, не будет обновлений в основном потоке выносите в другой поток либо делите на части, чтобы по таймеру запускать каждую часть, тогда между ними будет проходить обновление Цитата
0 GASCHE Опубликовано 10 января, 2022 Опубликовано 10 января, 2022 (изменено) В 29.12.2021 в 15:02, Андрей Рулин сказал: Вот такой код работает в Windows. Но в андройде , увы и ах... По таймеру запускаете поток, в процедуре procedure TThreadRenew.Execute; производите расчет, когда значение внутри измениться на 1 синхронизируйтесь с основным потоком и меняете Label1.Text и даже "если вычисления идут час", то через час будет вам счастье Изменено 11 января, 2022 пользователем GASCHE Цитата
0 Андрей Рулин Опубликовано 12 января, 2022 Автор Опубликовано 12 января, 2022 В 10.01.2022 в 18:20, krapotkin сказал: ну так я же еще раз повторяю пока работает ваш код в основном потоке, не будет обновлений в основном потоке выносите в другой поток либо делите на части, чтобы по таймеру запускать каждую часть, тогда между ними будет проходить обновление Там у меня выше как раз 2 разных потока. Основной код в одно, обновление в другом. Или вы хотите , чтобы я вычисления вынес в дополнительный поток. К сожалению так не получится, т.к. у меня в реальной задаче идёт чтение из файла вместе с вычислениями. А на адройде чтение из файла идёт только в основном потоке. Я этот вопрос уже задавал в другой ветке, пока ни у кого не получилось чтение файла в побочном потоке. В 10.01.2022 в 18:50, GASCHE сказал: По таймеру запускаете поток, в процедуре procedure TThreadRenew.Execute; производите расчет, когда значение внутри измениться на 1 синхронизируйтесь с основным потоком и меняете Label1.Text и даже "если вычисления идут час", то через час будет вам счастье См. выше. К сожалению в побочном потоке не читаются файлы на Android. Только в основном. Я попробую выложить тестовую задачу, где будет это видно. Цитата
0 OnePeople Опубликовано 12 января, 2022 Опубликовано 12 января, 2022 28 минут назад, Андрей Рулин сказал: Я этот вопрос уже задавал в другой ветке, пока ни у кого не получилось чтение файла в побочном потоке. Можно ссылку на вопрос? Цитата
0 Андрей Рулин Опубликовано 12 января, 2022 Автор Опубликовано 12 января, 2022 В итоге решил проблему обходным путём. Сделал проверку репаинта. procedure TForm2.Label1Paint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF); begin RepaintFlag := True; end; В процедуре с таймером добавил. if not RepaintFlag then exit; К сожалению , как и говорил GASCHE пришлось убрать внешний цикл и заменять на 10 вызовов по таймеру, без убирания , увы не работает. Цитата
0 Андрей Рулин Опубликовано 12 января, 2022 Автор Опубликовано 12 января, 2022 8 минут назад, OnePeople сказал: Можно ссылку на вопрос? Чтение файлов в отдельном потоке Цитата
0 haword Опубликовано 12 января, 2022 Опубликовано 12 января, 2022 как то все через заднее место ) если я правильно понял то должно быть так - по таймеру запускается поток, в нем идет вычисление и синхронизация для обновления информации. если делать как у вас то в каждом цикле надо сообщать потоку что пора бы обновить данные. так как поток может хз когда вызваться и счетчик может уже далеко улететь. при этом если вы используете одновременно одну переменную ее надо делать потокобезопасной и блокировать. Цитата
0 krapotkin Опубликовано 12 января, 2022 Опубликовано 12 января, 2022 4 часа назад, Андрей Рулин сказал: Чтение файлов в отдельном потоке ну так там и написано, что все работает. и примеры есть. и у меня в приложениях файлы отлично читаются и пишутся в потоках Цитата
0 Андрей Рулин Опубликовано 14 января, 2022 Автор Опубликовано 14 января, 2022 Можете тестовый пример скинуть, как вы читаете? Цитата
Вопрос
Андрей Рулин
Допустим идут вычисления, мне надо в Label выводить, что они закончились на 10%...20%...100%
После изменения текста я делаю
При этом текст не изменяется, пока не окончатся вычисления. Хотя в Vcl версии хватает Repaint для формы.
23 ответа на этот вопрос
Рекомендуемые сообщения
Присоединяйтесь к обсуждению
Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.