Отображение информациии во время выполнения цикла
Модератор: Модераторы
Отображение информациии во время выполнения цикла
День добрый. Подскажите, пожалуйста, сделать, что-бы во время выполнения цикла, на каждой итерации промежуточные значения переменных отображались на Label? Добавляю их в Мемо - все ок (добавляются по мере выполнения цикла), а в Label показывает только последнее значение в конце выполнения. Пробовал через таймер читать из глобалки - тоже самое. Не могу понять, как сделать...
- Снег Север
- долгожитель
- Сообщения: 3067
- Зарегистрирован: 27.11.2007 15:14:47
- Контактная информация:
Код: Выделить всё
for i := 0 to 100 do
begin
label1.caption := IntToStr(i);
Application.ProcessMessages;
end;
учтите, что на современном быстром компе цикл пролетает за миллисекунды, так что промежуточных значений вы, скорее всего, не увидите всё равно
ускорим цикл чуток
Делаем application process messages только каждые 50 мс.
в вообще делай так:
все промежуточные будут видны
Код: Выделить всё
var
t : qword;
begin
...
t:=GetTickCount64;
for i := 0 to 100 do
begin
label1.caption := IntToStr(i);
if GetTickCount64 - t > 50 then begin
Application.ProcessMessages;
t:=GetTickCount64;
end;
end;Делаем application process messages только каждые 50 мс.
на каждой итерации промежуточные значения переменных отображались на Label? Добавляю их в Мемо - все ок (добавляются по мере выполнения цикла)
в вообще делай так:
Код: Выделить всё
label1.Text := label1.Text + InttoStr(i)+';'
все промежуточные будут видны
скалогрыз писал(а):ускорим цикл чуток
Дим, по феншую итерацию вообще надо бы в доп.поток обернуть, а рисовать в основном. Вдруг чел пишет сложные вычисления для атомной электростанции?
Код: Выделить всё
procedure TForm1.Button1Click(Sender: TObject);
var
MyThr: TMyThr;
begin
Button1.Enabled:= False;
MyThr:= TMyThr.Create(True);
try
while not MyThr.Finished do
begin
Application.ProcessMessages;
end;
finally
FreeAndNil(MyThr);
Button1.Enabled:= True;
end;
end;
{ TMyThr }
procedure TMyThr.ShowCounter;
begin
Form1.Label1.Caption:= Format('Текущее значение счетчика: %d',[FCnt]);
end;
procedure TMyThr.Execute;
begin
while FCnt < 100 do
begin
FCnt:= FCnt + 1;
Synchronize(@ShowCounter);
Sleep(50);
end;
end;
constructor TMyThr.Create(CreateSuspended: Boolean);
begin
Inherited Create(CreateSuspended);
FreeOnTerminate:= False;
Priority:= tpLower;
FCnt:= 0;
if CreateSuspended then Start;
end;
У вас нет необходимых прав для просмотра вложений в этом сообщении.
- serbod
- постоялец
- Сообщения: 449
- Зарегистрирован: 16.09.2016 10:03:02
- Откуда: Минск
- Контактная информация:
Совет автора софта в том числе для атомной электростанции - не использовать Application.ProcessMessages().
Дело даже не в том, что нарушается порядок выполнения кода и обработки исключений, растет стек и возможно вхождение в рекурсию с переполнением стека. И еще куча неочевидных проблем с блокировками и хендлами. Основная проблема, что программа будет работать в тысячу раз медленней. Если вас это устроит, то пожалуйста.
Правильное решение уже озвучили - выполнять вычисления не в основном потоке приложения, а в отдельном потоке. А в основном по таймеру каждые 100 миллисекунд (10 раз в секунду) обновлять отображаемое значение прогресса.
Если производительность не важна, но нужно видеть каждый шаг цикла (исследование алгоритмов, например) то это лучше сделать без цикла, в виде отдельной процедуры, которую нужно несколько раз запускать. И запускать нажатием кнопки и/или по таймеру.
Дело даже не в том, что нарушается порядок выполнения кода и обработки исключений, растет стек и возможно вхождение в рекурсию с переполнением стека. И еще куча неочевидных проблем с блокировками и хендлами. Основная проблема, что программа будет работать в тысячу раз медленней. Если вас это устроит, то пожалуйста.
Правильное решение уже озвучили - выполнять вычисления не в основном потоке приложения, а в отдельном потоке. А в основном по таймеру каждые 100 миллисекунд (10 раз в секунду) обновлять отображаемое значение прогресса.
Если производительность не важна, но нужно видеть каждый шаг цикла (исследование алгоритмов, например) то это лучше сделать без цикла, в виде отдельной процедуры, которую нужно несколько раз запускать. И запускать нажатием кнопки и/или по таймеру.
кстати как там дела в лазарусе с выделением ГУИ в отдельный поток? есть какоето штаnное решение?
- Снег Север
- долгожитель
- Сообщения: 3067
- Зарегистрирован: 27.11.2007 15:14:47
- Контактная информация:
serbod, вы в принципе правы, но такие проблемы актуальны, разве что, для атомных электростанций...
Топикстартер же, судя по самому вопросу, весьма далек от проектов подобной сложности.
Топикстартер же, судя по самому вопросу, весьма далек от проектов подобной сложности.
Application.ProcessMessages;
Нужен для принудительного "пинания" стэка сообщений.. В винде все оконные взаимодействия осущетвляются путем засылки TMessage.
Application.ProcessMessages; - пинает главный проток на прочтения этих сообщений.
Application.ProcessMessages; - для линивых и новичков и рукожопых..
TThread и в нем Synchronize; - это способ правильно вмешатся в главный поток, когда он закончил работу и впал в Idle, попробовать в этот момент поработать за него.. например переменные поменять..
Такой же подход применяется в Android, там вообще запрещено сейчас даже работать со http без отдельного потока и без вызова типа runOnUiThread. Главному потоку ничего не должно мешать во время работы, чтобы не словить ошибку или не заморозить (frezze) аппликуху..
TTimer.OnTimer - очень схожий с
только он более простой и правильный.. так как работает вместе главным потоком..
Главный поток буде обрабатывать TTimer.OnTimer в очереди сообщений..
TTimer более подходит. Но при жестком "реальном" времени правильнее использовать TThread + Synchronize возможны мютексы, сигналы, защищеные переменные.. и т.п.
Нужен для принудительного "пинания" стэка сообщений.. В винде все оконные взаимодействия осущетвляются путем засылки TMessage.
Application.ProcessMessages; - пинает главный проток на прочтения этих сообщений.
Application.ProcessMessages; - для линивых и новичков и рукожопых..
TThread и в нем Synchronize; - это способ правильно вмешатся в главный поток, когда он закончил работу и впал в Idle, попробовать в этот момент поработать за него.. например переменные поменять..
Такой же подход применяется в Android, там вообще запрещено сейчас даже работать со http без отдельного потока и без вызова типа runOnUiThread. Главному потоку ничего не должно мешать во время работы, чтобы не словить ошибку или не заморозить (frezze) аппликуху..
TTimer.OnTimer - очень схожий с
Код: Выделить всё
procedure TMyThr.Execute;
begin
while FCnt < 100 do
begin
FCnt:= FCnt + 1;
Synchronize(@ShowCounter);
Sleep(50);
end;
end;Главный поток буде обрабатывать TTimer.OnTimer в очереди сообщений..
TTimer более подходит. Но при жестком "реальном" времени правильнее использовать TThread + Synchronize возможны мютексы, сигналы, защищеные переменные.. и т.п.
olegy123 писал(а):Application.ProcessMessages; - для линивых и новичков и рукожопых..
Хорошо сказал. Попробуй в моем коде выше убрать ProcessMessages из главного потока.
зы. Не люблю я TTimer, не помню точно почему, но не люблю
Предназначение главного потока - это работа с оконными сообщениями в системе windows и linux: перерисовать окно, изменить размеры, произошел клик мышкой и т.п.
Frizze апликейшен происходит тогда когда главный поток заблудился в написанном неправильно коде, потождать загрузки с сайта, выполнить миллиардный подсчет в цикле.. Ему некогда разобрать сообщения от windows.
Цель, если нужно независимо от главного потока(т.е. без внутренного подсчета им, а это "морозит" окно)..
То нужно сделать параллельное работу. TTimer удобен тем что не создает проблемы в коде если нужно "распаралелить" в рамках главного потока задачи, TTimer посылает в очередь сообщение о необходимости обработать OnTimer процедуру.. Так что это не совсем параллельное вычисление.
Тут важно чтобы в OnTimer небыло тяжелой работы для главного потока, потому что это может также заморозить окно.
Для тяжелой работы предназначен TThread, но он работает на уровне операционной системы и CPU, которые не знают о существовании главного потока. Synchronize это способ правильно разрулить и развести когда есть необходимость влезть в сферу главного потока. Принудительно вызывать в нем Application.ProcessMessages - это неправильно.
Frizze апликейшен происходит тогда когда главный поток заблудился в написанном неправильно коде, потождать загрузки с сайта, выполнить миллиардный подсчет в цикле.. Ему некогда разобрать сообщения от windows.
zoltanleo писал(а):Попробуй в моем коде выше убрать ProcessMessages из главного потока.
Цель, если нужно независимо от главного потока(т.е. без внутренного подсчета им, а это "морозит" окно)..
То нужно сделать параллельное работу. TTimer удобен тем что не создает проблемы в коде если нужно "распаралелить" в рамках главного потока задачи, TTimer посылает в очередь сообщение о необходимости обработать OnTimer процедуру.. Так что это не совсем параллельное вычисление.
Тут важно чтобы в OnTimer небыло тяжелой работы для главного потока, потому что это может также заморозить окно.
Для тяжелой работы предназначен TThread, но он работает на уровне операционной системы и CPU, которые не знают о существовании главного потока. Synchronize это способ правильно разрулить и развести когда есть необходимость влезть в сферу главного потока. Принудительно вызывать в нем Application.ProcessMessages - это неправильно.
- Снег Север
- долгожитель
- Сообщения: 3067
- Зарегистрирован: 27.11.2007 15:14:47
- Контактная информация:
Дополнительные потоки точно так же занимают память и процессор, как и основной процесс. Поэтому единственная польза от них - работа в "режиме Юлия Цезаря"
, выполнение каких-то очень длительных вычислений в отрыве от других работ в интерфейсе. Нужда в таком возникает не то что не всегда, а, скорее, достаточно редко, в специфических случаях.
olegy123 писал(а):Synchronize это способ правильно разрулить и развести когда есть необходимость влезть в сферу главного потока. Принудительно вызывать в нем Application.ProcessMessages - это неправильно.
Мне кажется, мы спорим о разных вещах. Application.ProcessMessages в данном коде - это возможность основному потоку делать все свои привычные дела, пока доп.поток делает какие-то свои темные делишки. Ты можешь вообще в доп.потоке использовать Queue(@...) вместо Synchronize, тогда доп.поток совсем перестанет обращать внимание на окружающий мир
По поводу TTimer, я согласен со Снег Север - штука достаточная специфичная и применяться она должна в зависимости от текущей задачи.
Если уж тебя так смущает ProcessMessages в цикле главного потока, поставь в коде после него sleep(...) - будет полная имитация твоего любимого таймера
Я про то что в данном вопросе лучше использовать TTimer для обновления TProgressBar и других значков.
Самый простой и верный способ.
Можно использовать TThread но тогда нужно понимать как происходит межпроцессорное взаимодействие.
TTimer в основе лежит TThread, создатели свели к минимуму писанины, для программиста требуется просто указать что нужно делать в событии TTimer.OnTimer
Самый простой и верный способ.
Можно использовать TThread но тогда нужно понимать как происходит межпроцессорное взаимодействие.
TTimer в основе лежит TThread, создатели свели к минимуму писанины, для программиста требуется просто указать что нужно делать в событии TTimer.OnTimer
Всем большое спасибо.
TThread - решил проблему. Впервые с ним имел дело. Попыхтеть пришлос чуток - инфы не много в инете. Но вроде справился и работает как хотел.
Прога архивирует 200гигов (160т.файлов). Процесс нифига не быстрый и хотел примерно представлять где оно все в данный момент. Сейчас показывает текущую статистику в цифрах (в label) и лог ошибок в memo. К стати - мемо тоже похоже в отдельном потоке рисуется - т.к. туда и без TThread все сыпалось
TThread - решил проблему. Впервые с ним имел дело. Попыхтеть пришлос чуток - инфы не много в инете. Но вроде справился и работает как хотел.
Прога архивирует 200гигов (160т.файлов). Процесс нифига не быстрый и хотел примерно представлять где оно все в данный момент. Сейчас показывает текущую статистику в цифрах (в label) и лог ошибок в memo. К стати - мемо тоже похоже в отдельном потоке рисуется - т.к. туда и без TThread все сыпалось
