Конференция "Основная" » Показ формы из компонента [D5, WinXP]
 
  • Petrovich (17.04.08 12:30) [0]
    Здравствуйте.
    Есть некий компонент, наследник TComponent. В нем происходит опрос внешней очереди сообщений. Упрощенно - вызов некоторой функции (Func, например), пока она не вернет True. Процесс этот может быть достаточно долгим по времени. Дабы не уходить в "вечное" ожидание был введет "тайм-аут", т.е. некоторый промежуток времени, в течение которого происходит вызов этой функции и "засыпание" проги (Sleep(100)).
    Вопрос №1. Идеологически правильно ли в цикле вызывать функцию и "слипаться" на короткий промежуток времени или правильнее сделать как-то по иному?

    Далее эта структура перестала устраивать и встала следующая задача: через N секунд (5, например) после запуска цикла вызова Func выводить формочку с продолжительностью операции в секундах и возможностью по нажатию пользователем ESC прервать цикл вызова нашей функции Func. Цикл вызова Func в компоненте переделан так:
    ...
     frmWait.DoWait := True; // Запуск таймера, запоминание времени.
     try
       repeat
         Result := Func;
         if Result then
           Exit;
         Sleep(WAIT_INTERVAL_LENGTH);
         Application.ProcessMessages;
       until not frmWait.DoWait;
     finally
       frmWait.DoWait := False; // Остановка таймера, форма прячется.
     end;
    ...
    Была нарисована обычная форма с таймером у которой при (frmWait.DoWait := True) включался TTimer. В обработчике OnTimer которого делается следующее:
    procedure TfrmWait.TimerTimer(Sender: TObject);
    var
     h, m, s, ms: Word;
    begin
     // Вывод прошедшего времени на лейбу.
     txtTime.Caption := FormatDateTime('hh:nn:ss', Now - FStartTime);
     DecodeTime(Now - FStartTime, h, m, s, ms);
     // Если прошли наши 5 сек с момента запуска, то показ самой формы.
     if (not Visible) and (s > WAIT_SHOW_DELAY) then                  
       Show;
     Application.ProcessMessages;
    end;
    Проблема: цикл вызова Func бегает, форма инициализируется (время старта запоминается, таймер включается), но потом форма ожидания не появляется, т.е. в OnTimer мы не прилетаем.

    Вопрос №2: где я надурил или как это надо написать, чтобы достич поставленной задачи?
  • tesseract © (17.04.08 12:48) [1]

    >  В нем происходит опрос внешней очереди сообщений. Упрощенно
    > - вызов некоторой функции (Func, например), пока она не
    > вернет True.


    А CallBack ввернуть, или из внешней очереди сообщений WM_USER высылать никак ?
  • Сергей М. © (17.04.08 12:50) [2]

    > Идеологически правильно ли в цикле вызывать функцию


    А есть варианты ?
    Я к тому что можно обойтись и без цикла, если реализовать эту Func в части возможности асинхронной нотификации о событиях, которые она контролирует.
  • Petrovich (17.04.08 14:43) [3]
    2tesseract, Сергей М.:

    > А CallBack ввернуть, или из внешней очереди сообщений WM_USER
    > высылать никак ?

    Никак, это внешняя ДЛЛ-ина от господ из IBM без таких возможностей. По докам существует возможность нотификации, если работать не с очередями сообщений, а с топиками, но это немного из другой подход. Тут надо верь проект курочить, что не приемлемо.

    > Я к тому что можно обойтись и без цикла, если реализовать
    > эту Func в части возможности асинхронной нотификации о событиях,
    >  которые она контролирует.

    Т.е. или колбек/юзер_сообщение или цыкл получается?
    Я думал, мало ли какие выверты Гуру могут предложить...
  • Сергей М. © (17.04.08 15:03) [4]
    Ну если ф-ция чужая, то можно вынести цикл в доп.поток ..
  • tesseract © (17.04.08 15:39) [5]

    > Никак, это внешняя ДЛЛ-ина от господ из IBM без таких возможностей.


    В доп поток. IBM кстати отличаеться нормальныи отношением у документированию.
  • Petrovich (18.04.08 11:26) [6]
    2Сергей М., tesseract:

    > В доп поток.

    А подробнее, "для чайника", объяснить можно?
    Вообще, получается, мне асинхронный вызов надо превратить в синхронный.
    В комноненте, по логике софта, мне надо отправить сообщение и получить ответ. Когда придет ответ, я не знаю. Как сюда прикрутить доп. поток?
    Основной поток продолжаться не может без ответа.
    Правильно ли я понял идею: создание доп. потока и "засыпание", пока флаг некий не станет True, например. Доп поток вызывает Func переодически и показывает форму с ожиданием и тикающими часиками. Если пользователь ничего не делает и приходит сообщение "извне", то сообщение передается в основной поток, флаг ожидания выставляется в True и доп. поток завершается. Если пользователь устал ждать и нажал ESC, то в основной поток передается ошибка и опять-таки выставляем влаг в True и завершаем доп. поток. В основном потоке когда будет выставлен флаг, то бесконецный цикл оканчивается и происходит анализ результата: если сообщение, то все путем и идем дальше по логике, если ошибка, то идем дальше на обработку ошибки.
    Так что ли?
  • Anatoly Podgoretsky © (18.04.08 11:34) [7]
    > Petrovich  (18.04.2008 11:26:06)  [6]

    Если не может продолжаться, то нафиг дополнительный поток, делай все в основном.
  • tesseract © (18.04.08 12:05) [8]

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


    Как раз наоборот. У тебя сейчас синхронный.


    > Основной поток продолжаться не может без ответа.


    Ну так сразу бы и сказал. Не изголяйся тогда.


    > Доп поток вызывает Func переодически и показывает форму
    > с ожиданием и тикающими часиками.


    А зачем  это ? Иконку поменяй - юзер поймёт.
  • Petrovich (18.04.08 14:20) [9]
    2tesseract:

    > Как раз наоборот. У тебя сейчас синхронный.

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

    > А зачем  это ? Иконку поменяй - юзер поймёт.

    Он-то ща и так видит, что процесс идет, но если сервак не отвечает 3-4 минуты и юзер хочет прекратить обработку данного запроса - вот в чем вся соль! Мне надо это окно показывать не просто так, а с возможностю обработать нажатие ESC и прервать ожидание основного потока, который вместо ответа сервера поднимет пользователю ошибку, типа "операция прервата пользователем".

    зы. Плиз, направьте меня по пути решения этой проблемы и, если можно, примером или внятной ссылкой "как что и по чем". :)
  • tesseract © (18.04.08 14:38) [10]
    Поток + цикл + Event + WaitForSingleObject + until terminated.

    Стандартный набор.
  • Сергей М. © (18.04.08 14:46) [11]

    > окно показывать не просто так, а с возможностю обработать
    > нажатие ESC


    А нафих окно нужно вообще ?

    Ну запустил юзер некую длительную операцию, ты ему показал песочные часы и для особо бестолковых в статус-баре написал, мол, "Подожди, идет супер-пупер операция, для ее прерывания жмакни ESC".
    Запускаешь свой цикл типа:

    EscPressedFlag := False;

    while not (Terminated or Func or EscPressedFlag) do
    begin
     sleep(0);
     Application.ProcessMessages;
    end;

    if EscPressedFlag then
     .. юзер жмакнул ESC ..
    else if Terminated then
     .. юзер закрывает приложение совсем ..
    else
     .. Func вернула флаг готовности ..

    А на форме, где юзер жмакнул кнопку для запуска операции, при KeyPreview=True обрабатываешь OnKeyPress, где ловишь ESC-жмак и тут же взводишь флаг EscPressedFlag.

    Все !

    Хочешь юзеру еще и время показать ?

    Не вопрос - при начале операции включай таймер и в обработчике выводи время, по возврату из операции выключай таймер.
  • Petrovich (21.04.08 12:05) [12]
    2Сергей М.:

    > А нафих окно нужно вообще ?

    Для начала напомню исходные: мы в компоненте, на не какой-либо форме все это ваяем, поэтому всякие

    > в статус-баре написал

    не прокатывают.

    > Не вопрос - при начале операции включай таймер и в обработчике
    > выводи время, по возврату из операции выключай таймер.

    В теории, все чудненько, но на практике

    > ... в OnTimer мы не прилетаем.


    2tesseract:

    > Поток + цикл + Event + WaitForSingleObject + until terminated.

    Ок. Попробую что-то подобное изобразить...
  • Сергей М. © (21.04.08 12:15) [13]

    > напомню исходные: мы в компоненте


    Чудненько.

    Тогда все это никак не вяжется ни с формами, ни с Application, ни с таймером - ни того, ни другого, ни третьего приложение, использующее твой компонент, может не предполагать и не допускать.
  • GrayFace © (21.04.08 12:29) [14]
    Сергей М. ©   (18.04.08 14:46) [11], а зачем Sleep(0)?
    Petrovich, не вызывается OnTimer - вызови явно после Application.ProcessMessages. if GetTickCount - InitTime > 5000 then ItsTime;
  • Сергей М. © (21.04.08 12:34) [15]

    > GrayFace ©   (21.04.08 12:29) [14]


    > зачем Sleep(0)?


    Затем чтобы не жрать попусту временные ресурсы системы.
 
Конференция "Основная" » Показ формы из компонента [D5, WinXP]
Есть новые Нет новых   [134434   +26][b:0][p:0.001]