DC_GetProgress with unknown upper bound

This forum is for eXpress++ general support.
Message
Author
User avatar
Eugene Lutsenko
Posts: 1649
Joined: Sat Feb 04, 2012 2:23 am
Location: Russia, Southern federal district, city of Krasnodar
Contact:

DC_GetProgress with unknown upper bound

#1 Post by Eugene Lutsenko »

Hey, Roger!

I commonly use function DC_GetProgress(). I'm doing this is standard and quite successfully. But recently I wanted to display the stage of the execution process not by the number of operations, but by the time of execution. I measured the time elapsed since the beginning of the process and calculated the forecast for the end. After that I want to display, and the forecast of the end changes all the time. And not always in a big way, and sometimes less. But the upper limit of the range must be set before running the DC_GetProgress () function. Is it possible somehow not to ask from outside? Or maybe change it inside the loop execution, as if DCPROGRESS also is inside it? As a result, now sometimes the progress bar is displayed, and sometimes not as lucky.

Code: Select all

nMax = N_InpFiles
Mess = L('2.3.2.6. Объединение нескольких файлов исходных данных в один'
@ 4,5 DCPROGRESS oProgress SIZE 70,1.1 MAXCOUNT nMax COLOR GRA_CLR_CYAN PERCENT EVERY 100
DCREAD GUI TITLE Mess PARENT @oDialog FIT EXIT
oDialog:show()
nTime = 0
DC_GetProgress(oProgress,0,nMax)
FOR ff=1 TO N_InpFiles
    DC_GetProgress(oProgress, ++nTime, nMax)
NEXT
*MsgBox('STOP')
DC_GetProgress(oProgress,nMax,nMax)
oDialog:Destroy()
[/size]

User avatar
Auge_Ohr
Posts: 1428
Joined: Wed Feb 24, 2010 3:44 pm

Re: DC_GetProgress with unknown upper bound

#2 Post by Auge_Ohr »

a Progressbar always start from 0% and end at 100% so you have to prepare your Data

Code: Select all

EVERY = Max/100 
Last edited by Auge_Ohr on Tue Aug 21, 2018 12:25 pm, edited 1 time in total.
greetings by OHR
Jimmy

User avatar
Eugene Lutsenko
Posts: 1649
Joined: Sat Feb 04, 2012 2:23 am
Location: Russia, Southern federal district, city of Krasnodar
Contact:

Re: DC_GetProgress with unknown upper bound

#3 Post by Eugene Lutsenko »

Hey, Jimmy!

I know that it is quite possible to change the parameter of the function outside the loop while inside the loop. I only have a syntax problem.

It is better to display the execution process not by operations, but by the time of their execution. This is more correct, because the duration of the operation may vary. It turns out that the progress bar reflecting the past and projected execution time is more informative and versatile.

User avatar
Auge_Ohr
Posts: 1428
Joined: Wed Feb 24, 2010 3:44 pm

Re: DC_GetProgress with unknown upper bound

#4 Post by Auge_Ohr »

Eugene Lutsenko wrote:I know that it is quite possible to change the parameter of the function outside the loop while inside the loop. I only have a syntax problem.
i calculate time between EVERY

Code: Select all

IF nCount % nEvery == 0
  CalcTime(nStart,nCount,nMaxCount)
ENDIF
greetings by OHR
Jimmy

User avatar
rdonnay
Site Admin
Posts: 4813
Joined: Wed Jan 27, 2010 6:58 pm
Location: Boise, Idaho USA
Contact:

Re: DC_GetProgress with unknown upper bound

#5 Post by rdonnay »

It is better to display the execution process not by operations, but by the time of their execution.
I agree that this is an optimal goal but very hard to achieve.

You would have to create an algorithm that calculates the percentage of time to complete the tasks.
We have all seen attempts to do this and they are not very successful.
How many time have you installed some software and the progress meter says "4 minutes remaining" then later says "8 minutes remaining"? The algorithm would need to be very dynamic and would have to calculate time based on many variables. If you are able to write such an algorithm, it is very easy to apply it to DC_GetProgress().

Code: Select all

nTotalTime := CalcTotalTime()
nSeconds := Seconds()
DO WHILE .NOT. done

  nTime := Seconds() - nSeconds
  IF nTime > nTotalTime
    nTime := nTotalTime // don't let it go past 100%
  ENDIF
  DC_GetProgress( oProgress, nTime, nTotalTime )

  .. Do something

ENDDO

The eXpress train is coming - and it has more cars.

User avatar
Auge_Ohr
Posts: 1428
Joined: Wed Feb 24, 2010 3:44 pm

Re: DC_GetProgress with unknown upper bound

#6 Post by Auge_Ohr »

before you have not reach 1% you don't know how long it might take

as i say i have % EVERY in my loop where it is always Max/100

Code: Select all

IF nCount % nEvery == 0
   CalcTime(nStarttime,nCount,nMaxCount)
ENDIF
the "Trick" is to SUM Time so you get closer every time Progressbar move
remember only every 1% step so it can be a long time between update ...

---

i use a ARRAY and hold all time. this Way i can SUM it and calculate new (better) time.
Problem : you must have 2 x Item to calculate so it begin at 2%

Code: Select all

METHOD DXE_ProgressBar:CalcTime()
LOCAL nRange := 0
LOCAL nPart  := 0
LOCAL nLen   := 0
LOCAL nTime  := 0
LOCAL nProz  := 0
LOCAL nSum   := 0
LOCAL nCount := 0
LOCAL nFull  := 0
LOCAL i, nStart, nStop

   IF ::nValue = 0
      ::aTimeSec  := {}
      ::cTimeText := "calculate ..."
      RETURN ::cTimeText
   ENDIF

   nRange := ::nMaximum - ::nMinimum
   IF nRange = 0
      ::cTimeText := "calculate ..."
      RETURN ::cTimeText
   ENDIF

   nProz := nRange / 100
   nPart := INT(::nValue/nProz)

   nLen  := LEN(::aTimeSec)
   IF nLen = nPart-1
      AADD(::aTimeSec,SECONDS())
   ENDIF
   nLen := LEN(::aTimeSec)

   IF nLen = 1
   ELSEIF nLen > 1
      FOR i := 2 TO nLen
         nStart := ::aTimeSec[i-1]
         nStop  := ::aTimeSec[i]
         nSum   += nStop - nStart
         nCount++
      NEXT
      nFull := (nSum / nCount) * 100
      nTime := nFull - nSum
      ::cTimeText := Sec2HMS(nTime)
   ENDIF
	
RETURN ::cTimeText
PBAR_TIME.ZIP
v1.9.355
(502.66 KiB) Downloaded 800 times
p.s. there is a Express++ Version but i do not remember how to add new VAR UseShowTime to it
greetings by OHR
Jimmy

User avatar
Eugene Lutsenko
Posts: 1649
Joined: Sat Feb 04, 2012 2:23 am
Location: Russia, Southern federal district, city of Krasnodar
Contact:

Re: DC_GetProgress with unknown upper bound

#7 Post by Eugene Lutsenko »

Hi, Roger and Jimmy!

The calculation of the time I do so:

Code: Select all

***********************************************************************************************************
****** Графический прогресс-бар (на основе примера XSample_14() xdemo.exe)
***********************************************************************************************************
STATIC FUNCTION Time_Progress (Time_Progress, Wsego, oProgress, lOk )

    LOCAL nMaxCount := Wsego

    xtime = Time_Progress

    ** Отображение занимает очень много времени, поэтому
    ** Если Wsego > 100 показывать прогресс не для всех х, 
    ** а только для таких, которые нацело делятся на Wsego/100

    IF xtime = 0 .OR. xtime = Wsego .OR. Wsego < 100             // Всегда показывать прогресс в начале и конце процесса
    ELSE                                                         // и для малого числа событий: Wsego < 100
       Wsego100 = ROUND(Wsego/100,0)
       IF xtime <> Wsego100*INT(xtime/Wsego100)
          RETURN lOk
       ENDIF
    ENDIF

    *** Индикация времени исполнения

    ***** Процесс может идти больше суток, поэтому для определения
    ***** во всех случаях вычисляется время, прошедшее с начала года
*   T_Mess1 = L("Начало:")+" "+TIME()        // Начало

    ***** Прошло секунд с начала процесса
    PUBLIC T_Mess2 := "ch:mi:se"
    Sec_2   = (DOY(DATE())-1)*86400+SECONDS() - Sec_1
    ch2 = INT(Sec_2/3600)                    // Часы
    mm2 = INT(Sec_2/60)-ch2*60               // Минуты
    cc2 = Sec_2-ch2*3600-mm2*60              // Секунды
    T_Mess2 = L("Прошло:")+" "+ALLTRIM(STRTRAN(T_Mess2,"ch",STR(ch2,19)))
    T_Mess2 = STRTRAN(T_Mess2,"mi",STRTRAN(STR(mm2,2)," ","0"))
    T_Mess2 = STRTRAN(T_Mess2,"se",STRTRAN(STR(cc2,2)," ","0"))
    *@19,2 SAY T_Mess2+L(" всего: ")+ALLTRIM(STR(Sec_2,17))+L(" сек.")

    PUBLIC T_Mess3 := "ch:mi:se"             // Осталось
    Sec_3 = Sec_2*Wsego/xtime                // Прогн.длит.исп. в секундах
    ch3 = INT(Sec_3/3600)                    // Часы
    mm3 = INT(Sec_3/60)-ch3*60               // Минуты
    cc3 = Sec_3-ch3*3600-mm3*60              // Секунды
    T_Mess3 = ALLTRIM(STRTRAN(T_Mess3,"ch",STR(ch3,19)))
    T_Mess3 = STRTRAN(T_Mess3,"mi",STRTRAN(STR(mm3,2)," ","0"))
    T_Mess3 = STRTRAN(T_Mess3,"se",STRTRAN(STR(cc3,2)," ","0"))
    *@20,2 SAY T_Mess3+L(" всего: ")+ALLTRIM(STR(Sec_3,17))+L(" сек.")

    PUBLIC T_Mess4 := "ch:mi:se"             // Окончание
    Sec_4 = Sec_1 + Sec_3 - (DOY(DATE())-1)*86400
    ch4 = INT(Sec_4/3600)                    // Часы
    mm4 = INT(Sec_4/60)-ch4*60               // Минуты
    cc4 = Sec_4-ch4*3600-mm4*60              // Секунды
    T_Mess4 = L("Окончание:")+" "+ALLTRIM(STRTRAN(T_Mess4,"ch",STR(ch4,19)))
    T_Mess4 = STRTRAN(T_Mess4,"mi",STRTRAN(STR(mm4,2)," ","0"))
    T_Mess4 = STRTRAN(T_Mess4,"se",STRTRAN(STR(cc4,2)," ","0"))
    *@21,2 SAY T_Mess4+L(" всего:) "+ALLTRIM(STR(Sec_4,17L())+" сек.с нач.суток")

    PUBLIC T_Mess5 := "Средн.время обработки 1-го объекта: ch:mi:se"
    Sec_5 = Sec_2/xtime
    ch5 = INT(Sec_5/3600)                    // Часы
    mm5 = INT(Sec_5/60)-ch5*60               // Минуты
    cc5 = Sec_5-ch5*3600-mm5*60              // Секунды
    T_Mess5 = ALLTRIM(STRTRAN(T_Mess5,"ch",STR(ch5,19)))
    T_Mess5 = STRTRAN(T_Mess5,"mi",STRTRAN(STR(mm5,2)," ","0"))
    T_Mess5 = STRTRAN(T_Mess5,"se",STRTRAN(STR(cc5,2)," ","0"))
    *@22,2 SAY T_Mess5+L(" всего: ")+ALLTRIM(STR(Sec_5,17))+L(" сек.")

    PUBLIC T_Mess6 := "ch:mi:se"             // Осталось
    Sec_6 = Sec_3 - Sec_2
    ch6 = INT(Sec_6/3600)                    // Часы
    mm6 = INT(Sec_6/60)-ch6*60               // Минуты
    cc6 = Sec_6-ch6*3600-mm6*60              // Секунды
    T_Mess6 = L("Осталось:")+" "+ALLTRIM(STRTRAN(T_Mess6,"ch",STR(ch6,19)))
    T_Mess6 = STRTRAN(T_Mess6,"mi",STRTRAN(STR(mm6,2)," ","0"))
    T_Mess6 = STRTRAN(T_Mess6,"se",STRTRAN(STR(cc6,2)," ","0"))
    *@23,2 SAY T_Mess6+L(" всего: ")+ALLTRIM(STR(Sec_6,17))+L(" сек.")

    Mess98 = T_Mess1+SPACE(142-LEN(T_Mess1)-LEN(T_Mess4))+T_Mess4  // Начало, окончание (прогноз) 145
    oSay98:SetCaption(Mess98);oSay98:SetCaption(oSay98:caption)

    Mess99 = T_Mess2+SPACE(144-LEN(T_Mess2)-LEN(T_Mess6))+T_Mess6  // Прошло, осталось (прогноз)  146
    oSay99:SetCaption(Mess99);oSay99:SetCaption(oSay99:caption)

    DC_GetProgress( oProgress, Time_Progress, Wsego )              // Отображение графического Progress-bar

*   Sec_1   // Начало
*   Sec_4   // Окончание
*   Sec_2   // Прошло секунд с начала процесса
*   Sec_6   // Осталось секунд до окончания

*   mWsego=1000;mTimeProgress=ROUND(Sec_2/(Sec_2+Sec_6)*mWsego,0)
*   DC_GetProgress( oProgress, mTimeProgress, mWsego )             // Отображение графического Progress-bar

*   DC_GetProgress( oProgress, ROUND(Sec_2,0), ROUND(Sec_2+Sec_6,0) )                // Отображение графического Progress-bar

*   MsgBox(STR(ROUND(Sec_2,0))+STR(ROUND(Sec_2+Sec_6,0)))
*   MsgBox(STR(mTimeProgress))
*   MILLISEC(1000)

    DC_AppEvent( @lOk, 0, .01 )

RETURN lOk
[/size]

Do the forecast execution time all of the time specified. But I don't see anything wrong with that. And then always exactly the same as the fact.

Now I realized that the progress bar I do not always updated for some other reason than I thought. The fact is that the time is always updated correctly, and the progress bar is not always drawn.

The Time_Progress() function is used inside the loop just like DC_GetProgress(). Only initialize it should be just lines:

Code: Select all

        / / the beginning of the reference time to predict the duration of execution
        Time_progress = 0
        // Seconds have passed since the start of the process
        // The process may take more than a day, so to determine
        // in all cases, the time elapsed since the beginning of the year is calculated
        T_Mess1 = L("Start:")+" "+TIME() // Start
        Sec_1 = (DOY(DATE())-1)*86400+SECONDS()
Jimmy!

When the time is used, there is no question about the two events, because the initialization event of the function is always earlier than its use for display
Attachments
Безымянный.jpg
Безымянный.jpg (169.16 KiB) Viewed 14324 times

User avatar
Auge_Ohr
Posts: 1428
Joined: Wed Feb 24, 2010 3:44 pm

Re: DC_GetProgress with unknown upper bound

#8 Post by Auge_Ohr »

ok, my calculation does not handle pass midnight :roll:

but you wasting to much performance with your Code
have a look at FUNCTION DC_GetProgress() in \Source\Dclipx\_DCGETBX.PRG

Code: Select all

  // have split line to show it 
  IF nEvery > 0 .AND.;
     nCurrCount % Int(nEvery) # 0 .AND. ;  // this line will kick you out
     Valtype(nMaxCount) = 'N' .AND.;
     nCurrCount < nMaxCount
     RETURN nil            // better .F.
  ENDIF
all GRA paint will not happend !

while 1 Pixel is minimum you can calculate nEvery

Code: Select all

   nEvery := nMax / oProgress:currentSize()[1]
so it just move when "full" Pixel is reach

---

as i see you need Scale less 1 % ... or other Concept :idea:

what about a Thread looking every Sec. how much have nCurrCount ?

Code: Select all

nMaxCount / nCurrCount = x / nStart-SECONDS()
so you can calculate how much time is left.
greetings by OHR
Jimmy

User avatar
Eugene Lutsenko
Posts: 1649
Joined: Sat Feb 04, 2012 2:23 am
Location: Russia, Southern federal district, city of Krasnodar
Contact:

Re: DC_GetProgress with unknown upper bound

#9 Post by Eugene Lutsenko »

Jimmy!

Please specifically tell me what to do to make the progress bar drawn (GRA) always for any values .
My maximum value can be any value, not only 100.

I had the impression that the display of the progress bar is visible, it is not visible, about as the spokes of the bike in the video (moire or stroboscopic effect)

User avatar
Auge_Ohr
Posts: 1428
Joined: Wed Feb 24, 2010 3:44 pm

Re: DC_GetProgress with unknown upper bound

#10 Post by Auge_Ohr »

hi,
Eugene Lutsenko wrote: Please specifically tell me what to do to make the progress bar drawn (GRA) always for any values .
you just have oProgress:currentSize()[1] Pixel so it make no sence to update more than that.
as i say calculate EVERY when you get a "fill" Pixel
Eugene Lutsenko wrote:My maximum value can be any value, not only 100.
Maximun is always 100 %
greetings by OHR
Jimmy

Post Reply