Отображение статуса и ProcessMessage

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Re: Отображение статуса и ProcessMessage

Сообщение daesher » 25.09.2018 10:03:16

tria писал(а):Ваять отдельный поток при проведении документа - это вообще не туда. Всего лишь нужно, чтобы пользователь дождался выполнения действий и видел прогресс выполнения

Что я тут могу сказать... Потоки - наверно, идеологически верное решение, но не всегда целесообразное. Они нужны, если:
1. Предполагается, что пользователь параллельно может запустить два или более расчета параллельно.
2. Предполагается, что пользователь будет активно взаимодействовать с интерфейсом (заполнять данные, загружать файл). Просто смотреть за прогрессом и (если что) нажимать на кнопочку "Остановить расчёт" - потоки не требуется.
3. Если удастся распараллелить вычисления.
В противном случае - поток - лишняя "головная боль" с синхронизацией (для того же ProgressBar) и, возможно, с отладкой. Что можно сделать? Создать отдельный модуль (возможно - со всей логикой расчётов), а в нём ввести логическую переменную IsCalculating (на время расчёта, очевидно, true). Во всех окнах, которые могут быть активны, в событие OnCloseQuery поставить проверку этой переменной. Должен ли "прогрессбар" (можно - вместе с кнопкой "остановить расчёт") быть модальным - это на любителя, плюс - основное окно будет автоматически "задизейблено", минус - всё остальное непредсказуемо.
tria писал(а):Пока что идея такая - перед началом действий для всех окон сделать enable=false, по окончанию - true.

Можно, но не строго обязательно. Некоторые элементы управления можно и оставить активными - другое дело, что пользователю будет неудобно, если между ProcessMessages будет около секунды расчётов. Опять же, можно на формы "повесить" таймер, в котором также будет проверяться IsCalculating (если да - всё лишнее отключается, нет - включается). Да, это требует небольших ресурсов, но не требуется перебирать окна вручную - окно отвечает само за себя.
Главное - не скупиться на ProcessMessages, иначе при расчёте при нажатии на форму система проверит и решит, что программа "зависла", предложит закрыть её.
daesher
постоялец
 
Сообщения: 221
Зарегистрирован: 09.03.2010 22:17:14

Re: Отображение статуса и ProcessMessage

Сообщение Alex2013 » 25.09.2018 12:49:16

Потоки хороши слов нет ... но управление ими довольно сложное и от балды "часики показать" ,"бегущую строку сообщений в статус баре вывести" они точно ИЗБЫТОЧНЫ . Для "мелкого параллелизма" есть таймер !
Даже с перерисовкой окон и выводом кадров видео он успешно справляется (не имея никакой сложности с обращением к GUI) главное что-бы задача четко "квантовалась" плюс минус несколько миллисекунд особого значения не имеет.
НО если предсказать завершение процесса трудно а данные успешно локализуются то "добро пожаловать в поток". А таймер действительно может ненавязчиво проверять завершение потока и готовить следующую порцию данных... для обработки видео потока это будет означать что некая сложная процедура распознавания или слежения выполняется не каждый кадр, а по мере готовности почти не тормозя вывод видео и все прочие задачи .
Зы
В идеале ProcessMessages ненужен совсем . Если все четко "квантуется" а процессы посложнее упрятаны в попок то НИКАОЙ надобности "в костыле отпускающем очередь сообщений" нет .
Зы Зы
Кстати есть довольно простой способ позволяющий в простейших случаях обходится без потка совсем . Просто "в тяжелых циклах" можно сделать проверку времени их исполнения, а при превышении лимита останавливать вычисления и переносить их в следующий "квант" (предусмотрев возможность продолжения расчета с места остановки )...
Последний раз редактировалось Alex2013 26.09.2018 06:12:56, всего редактировалось 3 раз(а).
Alex2013
долгожитель
 
Сообщения: 2923
Зарегистрирован: 03.04.2013 11:59:44

Re: Отображение статуса и ProcessMessage

Сообщение zub » 25.09.2018 13:10:46

предлагаю проголосовать. кто победит, tria так и сделает))

немодальный ProcessMessages
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

Re: Отображение статуса и ProcessMessage

Сообщение tria » 25.09.2018 13:34:08

zub писал(а):предлагаю проголосовать. кто победит, tria так и сделает))

немодальный ProcessMessages


Каким образом предлагаете блокировать интерфейс (произвольное кол-во окон)?
tria
постоялец
 
Сообщения: 401
Зарегистрирован: 03.04.2006 11:24:10

Re: Отображение статуса и ProcessMessage

Сообщение Alex2013 » 25.09.2018 13:35:23

Таймер без потока ... :idea: и да вообщем случае (ИМХО) немодальный диалог надежнее ! по возможности БЕЗ ProcessMessages ()

Добавлено спустя 6 минут 6 секунд:
tria писал(а):Каким образом предлагаете блокировать интерфейс (произвольное кол-во окон)?

Просто для всего списка твоих окон делать Enabled:=false; а по завершению работы с диалогом делать Enabled:=True;
(Ты их создаешь значит можешь завести обычный TList... и при закрытии удалять из него "убитые указатели" по IndexOf )
Еще можно "покапать" Application там есть список всех дочерних форм порожденных от класса Application.
Последний раз редактировалось Alex2013 25.09.2018 13:59:33, всего редактировалось 2 раз(а).
Alex2013
долгожитель
 
Сообщения: 2923
Зарегистрирован: 03.04.2013 11:59:44

Re: Отображение статуса и ProcessMessage

Сообщение zub » 25.09.2018 13:50:52

>>Каким образом предлагаете блокировать интерфейс (произвольное кол-во окон)?
Гуй ведь у вас на экшенах? если нет - переделать
Менюшки, тулбары, кнопки - штатными средствами экшенов. их можно разрешать-запрещать по ситуации в колбеке. Что там еще - смотреть по ситуации
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

Re: Отображение статуса и ProcessMessage

Сообщение Alex2013 » 25.09.2018 14:57:21

Самому стало интересно... "Где в Application список окон спрятан?" Вот где !
Код: Выделить всё
//Для "тотальной блокады" пишем что-то вроде этих трех строк ...
if Application.ComponentCount>0 then for I:=0 to  Application.ComponentCount-1 do
if Application. Components[i] is Tform then
Tform( Application. Components[i]). Enabled:=false;

//  если в  самом окне( например в конструкторе )  то ясный пень нужно добавить что-то вроде
// if Application. Components[i]<> Self then

Alex2013
долгожитель
 
Сообщения: 2923
Зарегистрирован: 03.04.2013 11:59:44

Re: Отображение статуса и ProcessMessage

Сообщение wadman » 25.09.2018 15:07:48

За поток. Тем более всё просто. Я выношу в потоки любую длительную задачу.

Код: Выделить всё
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
    Classes, SysUtils, Forms, Controls, Graphics, Dialogs, wcthread;

type

    { TForm1 }

    TForm1 = class(TForm)
        Task1: TTask;
        WCThread1: TWCThread;
        procedure FormCreate(Sender: TObject);
        procedure Task1Execute(const Sender: TTask; const Msg: Word; var Param: Variant);
        procedure Task1Finish(const Sender: TTask; const Msg: Word; const Param: Variant);
        procedure Task1Progress(const Sender: TTask; const Msg: Word; const Value: Word);
    private

    public

    end;

var
    Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
    Task1.Start; // основной поток, стартуем задачу в другом потоке
end;

procedure TForm1.Task1Execute(const Sender: TTask; const Msg: Word; var Param: Variant);
var int: integer;
begin
    // другой поток
    int := 0;
    while not Sender.Terminated do begin // работаем, пока не врервали. Например по выходу из приложения.
      Sender.WaitMs(100);
      inc(int);
      Sender.PostProgress(1, int);
      if int = 100 then break; // задача выполнена, прерываемся
    end;
    Param := int; // передаем результат работы
end;

procedure TForm1.Task1Finish(const Sender: TTask; const Msg: Word; const Param: Variant);
begin
    // основной поток, здесь задача рапортует об окончании работы. Результат в Param.
end;

procedure TForm1.Task1Progress(const Sender: TTask; const Msg: Word; const Value: Word);
begin
    if Msg = 1 then begin
        // основной поток, здесь задача рапортует о прогрессе через PostProgress
    end;
end;

end.


Добавлено спустя 35 секунд:
Alex2013 писал(а):Вот где !

Ох... А если заглянуть в Screen.Form*?
wadman
постоялец
 
Сообщения: 122
Зарегистрирован: 18.10.2016 15:54:28

Re: Отображение статуса и ProcessMessage

Сообщение Alex2013 » 25.09.2018 15:23:47

Ох... А если заглянуть в Screen.Form*?

Сейчас проверю!
...
Упс ! :shock:
Код: Выделить всё
if Screen.FormCount >0 then for I:=0 to Screen.FormCount-1 do
if Screen.Forms[i]<> Self then Screen.Forms[i].Close;

Ну "Нельзя объять необъятное" ! :roll:
Мой способ тоже работает хотя разумеется юзать Screen.Forms[] по идее вернее и проще ....
Последний раз редактировалось Alex2013 25.09.2018 15:41:32, всего редактировалось 1 раз.
Alex2013
долгожитель
 
Сообщения: 2923
Зарегистрирован: 03.04.2013 11:59:44

Re: Отображение статуса и ProcessMessage

Сообщение wadman » 25.09.2018 15:31:21

Alex2013 писал(а):Ну "Нельзя объять необъятное" !

Отсюда и страхи перед потоками. :)

Для меня наличие в коде ProccessMessages как флаг профнепригодности.
До недавнего времени этой гадостью даже в FastReport пользовались (не смотря на красивую опцию "многопоточности"), что мешало из коробки пользоваться им для фоновой печати на производстве.
После каждого обновления приходилось исправлять это рукожопство. Но ничего, исправились.
wadman
постоялец
 
Сообщения: 122
Зарегистрирован: 18.10.2016 15:54:28

Re: Отображение статуса и ProcessMessage

Сообщение Alex2013 » 25.09.2018 16:00:11

wadman писал(а):
Alex2013 писал(а):Ну "Нельзя объять необъятное" !

Отсюда и страхи перед потоками. :)

Для меня наличие в коде ProccessMessages как флаг профнепригодности.
До недавнего времени этой гадостью даже в FastReport пользовались (не смотря на красивую опцию "многопоточности"), что мешало из коробки пользоваться им для фоновой печати на производстве.
После каждого обновления приходилось исправлять это рукожопство. Но ничего, исправились.


По ProccessMessages согласен, "меньше лучше"! :idea: А вот потоки штука сильно хитрая ... Синхронизация потоков может быть достаточно напряженным делом или например остановка потока на паузу это вообще "вещь в себе" (Гадать где (и главное когда ) именно он остановился можно примерно с тем же успехом что и пытаться найти точное местоположение арбуза раздавленного дорожным катком :wink: ) . "Повесить обработку на таймер" для более менее простых случае, бывает значительно проще и это куда более контролируемый метод.

Но потоков я разумеется не боюсь но не использую их бездумно для всех условно подходящих для их использования случаев! :idea:
Alex2013
долгожитель
 
Сообщения: 2923
Зарегистрирован: 03.04.2013 11:59:44

Re: Отображение статуса и ProcessMessage

Сообщение zub » 25.09.2018 21:01:56

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

>>ля меня наличие в коде ProccessMessages как флаг профнепригодности.
в рамках задачи тс профнепригодны какраз предлагающие всякие таймеры, потоки и модальности((
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

Re: Отображение статуса и ProcessMessage

Сообщение serbod » 25.09.2018 22:11:46

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

При каждом изменении позиции прогресса происходит перерисовка, которая занимает примерно 10 мс. Получается, что 1000 шагов занимают 10 сек, при том, что без прогресса эти 1000 шагов выполняются за секунду.

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

Потом сделал выполнение шагов в отдельном потоке TThread и отправкой сообщений с текущей позицией через PostMessage() и обработчик этих сообщений, который менял позицию. Стало получше, но если там не 1000, а 100 000 шагов и очень шустрый проц, то сообщения с позицией валят быстрее, чем обрабатываются.

В итоге, добавил таймер на 100 мс (10 раз в секунду), в котором происходит установка позиции прогресса в соответствии с текущией позицией на момент опроса. Стало все гладко и красиво.
Аватара пользователя
serbod
постоялец
 
Сообщения: 449
Зарегистрирован: 16.09.2016 11:03:02
Откуда: Минск

Re: Отображение статуса и ProcessMessage

Сообщение Alex2013 » 26.09.2018 03:15:47

Вот именно ! Таймер управляем а поток не очень ... Да обработчик события от таймера не нельзя поставить на паузу вовремя его исполнения но при четком "квантовании" (то есть известном и небольшом времени исполнения обработчика это именно то что надо ! )
+ почти никаких проблем с обращением к внешним данным и GUI..

Не знаю точно что там в таймере с "очередью сообщений" но в нормальном случае это действительно ПРЕРЫВАНИЕ от аппаратного таймера . (Точно так-же как прерывание например от мышки ) Да программа (и ОС) точно должны иметь какой-то свой стек для работы нескольких таймеров ... но это "отдельная очередь"...

В общем случае ProcessMessage кроме возвращения тиков "в длинных и темных циклах" часто можно и нужно вызывать просто для для своевременной перерисовки вместо разных redraw repaint и refresh ... И там он определенно на месте !

Для самой работы таймера никакого ProcessMessage вызывать ненужно так-же как ненужно его вызвать для работы с мышкой . :idea:
Зы
А при попытках добиться истинной многопоточности нужно помнить, что во первых ВСЕ программы, по умолчанию запускаются в отдельных потоках плюс очень много системных вызовов работают в режиме "истинной многозадачности " и думать что даже в "обычной программе" все происходит последовательно большая ошибка ... То что делается с помощью явных потоков часто просто РУЧНОЕ УПРАВЛЕНИЕ тем, что ОС (и отчасти внутренний "движок" LCL) стараются делать автоматически.
Alex2013
долгожитель
 
Сообщения: 2923
Зарегистрирован: 03.04.2013 11:59:44

Re: Отображение статуса и ProcessMessage

Сообщение olegy123 » 26.09.2018 05:52:29

zub писал(а):Но чтобы прогрессбар порисовать...
DevExpress любит баловатся фоновыми задачами, AlphaControls так рисует копки, в том числе и progresbar.

zub писал(а):регистрируем обработчики "длинных" задач и вперед
мать моя женщина, это шо за юнит презентовал? какие вектора процедур? мне просто интересно, может действительно beginThread придумали глупые, uzelongprocesssupport наше светлое будущее?

zub писал(а):осле вызова всех обработчиков смотрим требуется ли комуто ProcessMessages и если со времени последнего ProcessMessages прошло времени больше установленного - делаем.
ах вот оно что, естественного главного майнлупа не хватает, будем ему помогать через uzelongprocesssupport.

Добавлено спустя 25 минут 37 секунд:
daesher писал(а):В противном случае - поток - лишняя "головная боль" с синхронизацией (для того же ProgressBar) и, возможно, с отладкой. Что можно сделать?

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

Alex2013 писал(а):Для "мелкого параллелизма" есть таймер !
посмотрите исходники таймера, там сидит TThread.

tria писал(а):Каким образом предлагаете блокировать интерфейс (произвольное кол-во окон)?
я в свое время ушел от блокировки окон. тоже столкнулся с проблемой правильной организации и синхронизации окон. Модальное окно нужно только когда от пользователя нужно заставить сделать сейчас от него работу - выбрать варианты, сообщить, показать на ошибку, выбрать рессурс для обработки данных(диалог выбора файла) и т.п.. Но не более.
Если будет много окон, то обмен данными между ними - уже перерастает в межпроцессорное сообщение. Оно требует еще больше сложной организации и не кроссплатформена.
Поэтому стал работать с PageControl.

Добавлено спустя 13 минут 41 секунду:
Alex2013 писал(а):В общем случае ProcessMessage кроме возвращения тиков "в длинных и темных циклах" часто можно и нужно вызывать просто для для своевременной перерисовки вместо разных redraw repaint и refresh ... И там он определенно на месте !
ProcessMessage это не волшебство!!! ProcessMessage заставляет главный поток перечитать стэк сообщений и выполнить их отсюда название Process+Message. Никакими самостоятельными перерисовками он не занимается, если есть сообщение типа WM_Paint то контрол выполнить обработку.
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20

Пред.След.

Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 31

Рейтинг@Mail.ru