Аналог ProcessMessages (C Builder) в Clarion - ?

Clarion, Clarion 7

Модератор: Дед Пахом

Правила форума
При написании вопроса или обсуждении проблемы, не забывайте указывать версию Clarion который Вы используете.
А так же пользуйтесь спец. тегами при вставке исходников!!!
Ответить
Гость

Сообщение Гость »

Hello clalist,

Как выйти из ситуации?

Есть процедура:

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

!==============================================================

                     MEMBER('reports_year.clw')   ! Это модуль типа MEMBER
ReportVBLExcel       PROCEDURE (Year1, Month1, Year2, Month2, NRep) ! Объявление процедуры
FilesOpened          LONG
strPathRep           CSTRING('C:\ABON_PR\REPORTS\')
window WINDOW('Идет формирование отчета...'),AT(,,419,93),FONT('MS Sans Serif',8,,),CENTER,GRAY
       OLE,AT(4,4,26,24),USE(?OLE),HIDE
       BUTTON('Отмена!'),AT(177,75,45,14),USE(?ButBreak)
       END
     END

     
  !====================================
  CODE                        ! Начало исполняемого кода

      OPEN(window)
  
      ACCEPT
  
                IF EVENT()=EVENT:OpenWindow

                    ?OLE{PROP:Create} = 'Excel.Application'
                    
                    <=======Skipped=========>
                    ! создается отчет
                    <=======Skipped=========>
                    
                    RUN ('"' & ?OLE{'Application.Path'} & '\excel.exe" "' & FullName & '"')
                    BREAK
  
                END !if openwindow
      END !accept
  
  RETURN

!==============================================================
ВОПРОС:
Как мне обработать нажатие на кнопку для того чтобы прервать процесс формирования отчета?
Если отлавливать просто по

IF ACCEPTED() = ?ButBreak THEN
BREAK.

то при формирвоании отчета просто не удается нажать на эту кнопку.
Оно и понятно - у приложения (это все SDI - обычные окна без потоков и обычный Source(ШВС, C55EE(H))) нет времени обрабатывать очередь сообщений.

В C++Builder все решалось использованием функции ProcessMessages() которая заставляла приложения обработать все сообщения, что ему предназначааются.

А как быть в Clarion?

СПАСИБО

--
Best regards,
Иван mailto:shkmail@inbox.ru

(Добавление)
Оно и понятно - у приложения (это все SDI - обычные окна без потоков и обычный Source(ШВС, C55EE(H))) нет времени обрабатывать очередь сообщений.
не просто нет времени, а твой код не получает управления, пока работает что-там-из-RUN-вызвалось.
если надо RUN-ить, то есть предложение стартонуть отдельный поток (если ниже cw6, то руками апишный), опционально сделать ему SetThreadPriority поменьше, а в твоем accept-цикле ловить нажатия на кнопки и прибивать этот поток ежели на кнопку нажали.

--
Best regards,
Maxim Yemelyanov,
Enigma Soft Company
phone: +380 572 177977
WEB: http://enigmasoft.com.ua
e-mail: clalist@enigmasoft.com.ua
ICQ: 12253836

Спасибо за ответ, но все "проще"
RUN тут не при чем. Основные действия выполняются между

IF EVENT()=EVENT:OpenWindow

и

END !if openwindow

Но все равно Спасибо!

--
Best regards,
Иван

(Добавление)

Насколько я понял, возможность прерывания необходима именно в коде "! создается отчет"?

Если так, то есть два варианта:
- переработать код таким образом, что-бы процесс формирования отчета производился, например, по типу шаблона Report/Process.
- использовать классы типа моего BasicProcessType, который должен лежать на одном из общедоступных Кларион-серверов. При этом вся модификация кода сводится к вставке нескольких доп. строк кода:

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

MyProcess     BasicProcessType
ProcessBreak  BYTE

  ...
  MyProcess.Init(...)
  ProcessBreak = False
ИШ>     <=======Skipped=========>
  Loop  ! Цикл создания отчета
    if ~MyProcess.LoopStep()
       ProcessBreak = True
    End
ИШ>     ! создается отчет
  End
ИШ>     <=======Skipped=========>
  MyProcess.Kill()
  if ~ProcessBreak
ИШ>  RUN ('"' & ?OLE{'Application.Path'} & '\excel.exe" "' & FullName & '"')
  End
При этом на экране будет отображаться окно с "бегунком" процесса. Прервать можно или ESC-клавишей или нажатием на ?Cancel-буттон. Есть возможность отключить отображение окна класса и использовать свое.

Вообщем, я думаю понятно в чем причина?
Код создания отчета должен обязательно "проходить"
через ACCEPT-цикл? что-бы иметь возможность получать сообщения, которые и порождаются нажатием на кнопки и буттоны.

=============================
С уважением, Олег А. Руденко.
Oleg_Rudenko@mail.ru
Oleg_Rudenko@mail333.com
Библиотека DynaLib
http://dynalib.narod.ru

То есть в простейшем случае будет что-то вроде этого?

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

!======================================================
      i# = 0

      OPEN(window)
      ACCEPT
  
                IF EVENT()=EVENT:OpenWindow
                    i# = 1
                    ?OLE{PROP:Create} = 'Excel.Application'
                END !if openwindow

                IF i# = N
                    RUN ....
                    BREAK
                END

                IF i# > 0 AND i# < N
                    ! создается строка отчета
                    ! для текущего значения i#
                    ! ...
                    i#++
                END

      END !accept
  
  RETURN
!======================================================
Будет работать. интересно?
:lol:
С уважением, Олег А. Руденко.
--
Взаимно :),
Иван

Нет. И что тут собственно изменилось по сравнению с начальным вариантом?

В C55 существует единственный способ прервать некий процесс, это установка таймера на окно. В этом случае, на событие
EVENT:Timer выполняются несколько итераций цикла формирования отчета. ACCEPT цикл снова прокручивается для обработки
всех возникших событий (нажатий на кнопки) и снова обрабытывает новое событие EVENT:Timer, выполняя следующие несколько
итераций.

Самое важное в этом деле - это подобрать правильное количество итераций, выполняемое на один тик таймера. Можно экспериментально, а можно и автоматизировать процесс.
Тут присутствуют всего два параметра.
TimerVal - величина PROP:Timer, по сути, это время отклика программы на итерактивное управление;
LoopVal - количество итераций одной обработки EVENT:Timer.

Таким образом, для оптимизации времени формирования отчета, следует максимально сократить простой ACCEPT цикла в период
формирования отчета, то есть минимизировать разницу времени TimerVal и времени исполнения одной порции итераций LoopVal.
Стоит оговориться, что установка заведомо большего количества LoopVal, чем может выполниться за TimeVal, приводит к
замедлению обработки и замедлению реакции на пользователя, это установлено экспериментально.

Ну так вот, рулить можно нашими двумя параметрами TimerVal и LoopVal.

Ниже пример как рулить подбором LoopVal, если рулить обоими пораметрами, то несколько сложнее.

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

TimerVal            LONG(100)
LoopVal             LONG(1)

ClockCount        LONG
FlagProc           BYTE(TRUE)          ! Можно ли формировать отчет

MyWin         WINDOW(...),..., TIMER(TimerVal)
                     ...
                   END

 CODE
 OPEN(MyWin)
 ACCEPT
      CASE EVENT()
        ...
        <обработка разных событий, в том числе нажатие на кнопку, если нужно остановить формирование отчета, то FlagProc
= FALSE>
        ...
        OF EVENT:Timer
             IF FlagProc
               ! Сохраняем время для расчета длительности выполнения LoopVal
               ClockCount = CLOCK()

               ! Выполняем порцию итераций
               LOOP LoopVal TIMES
                  ...
                  <обработка очередной итерации>
                  ...
                 IF <все данные отчета обработаны>
                    FlagProc = FALSE
                 END
               WHILE FlagProc

               ! Расчет количества LoopVal
               IF FlagProc
                   ClockCount  = CLOCK() - ClockCount

                   IF ClockCount > TimerVal
                       IF LoopVal > 1 THEN LoopVal -= 1.
                   ELSE
                       LoopVal += INT((TimerVal - ClockCount) / (ClockCount / LoopVal))
                   END
               END
             END
        ...
      END
 END
 CLOSE(MyWin)
Удачи!
__________________________________
Владимир Якимченко (IСQ 16 993 194)

(Добавление)

Именно так!
Будет работать. интересно?
Будет, но медленно. Для ускорения последний IF кода можно "покрутить" немного в цикле, раз так 10-30.
Конечно, если создание одной строки отчета трудоемкая операция и занимает некоторое время, то в цикле такой код крутить не стоит.

=============================
С уважением, Олег А. Руденко

Здравствуйте, Иван!

Есть очень простой способ сделать это, не выходя за рамки Кларион

Дело в том, что команды Accept могут быть вложены одна в другую
Конструкция

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

  0{Prop:Timer}=1 
  Accept 
    Break
  End 
  0{Prop:Timer}=0 
считывает сообщения с кнопок и клавиш. А дальше

If Event()=Event:Accepted And Field()=?Cancel ... Then ....

В принципе, здесь происходит процесс ожидания 0.01 секунды, поэтому стоит проверять не на каждой записи, а, например, на каждой сотой. Или через 1-2 секунды работы...

---------------------------------------
C уважением,
Юрий Философов,
Главный программист
Корпорация "Диполь", Саратов
E-mail yufil@tacis-dipol.ru (служ)
yufil@mail.ru (дом)
ICQ#75924439

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

> ИШ> !======================================================

EVET:LoopAgain  EQUATE(Evetn:User)

> ИШ>       i# = 0
> ИШ>       OPEN(window)
> ИШ>       ACCEPT
> ИШ>                 IF EVENT()=EVENT:OpenWindow
> ИШ>                     i# = 1
> ИШ>                     ?OLE{PROP:Create} = 'Excel.Application'
                               Post(EVET:LoopAgain)
> ИШ>                 END !if openwindow
                           IF EVENT()=Post(EVET:LoopAgain)
> ИШ>                 IF i# = N
> ИШ>                     RUN ....
> ИШ>                     BREAK
! Лучше Post(Evetn:CloseWindow)
> ИШ>                 END
> ИШ>                 IF i# > 0 AND i# < N
> ИШ>                     ! создается строка отчета
> ИШ>                     ! для текущего значения i#
> ИШ>                     ! ...
> ИШ>                     i#++
                               Post(EVET:LoopAgain)
                               Cycle
> ИШ>                 END
                           END ! IF EVENT()=Post(EVET:LoopAgain)
> ИШ>       END !accept
> ИШ>   RETURN
> ИШ> !======================================================
Бeет, но медленно.
"Летают. Ну, о-очень низенько." ;)

Не будет. Событий для повторного входа в тело ACCEPT не будет. Надо либо аймер на окошко вешать, либо свой эвент себе любимому посылать. См. ополнения в коде ^

WBR, Nick Tsigouro
Написал: ClaList(2)
Ответить