CPCS improve DisplayProgress Routine for Faster Reports

Reports run slower when the progress window is updated or DISPLAY() too much. This matters most when you have files with large record counts. Lee @lodestar is the report master here, and maintains CPCS, so hopefully he’ll comment on my ideas. I was running a report against 120,000 records where only 50 printed and the speed up of the progress was as massive performance boost.

CPCS templates generate code that for EVERY record does a DisplayProgress Routine to update the Progress Bar and PCT String. The default setting shows the Record Count in the PCT Text String using the below code:

DisplayProgress  ROUTINE
  RecordsProcessed += 1
  RecordsThisCycle += 1
  DisplayProgress = False
  IF PercentProgress < 100
    PercentProgress = (RecordsProcessed / RecordsToProcess)*100
    IF PercentProgress > 100
      PercentProgress = 100
    END
  END
  IF PercentProgress <> Progress:Thermometer THEN
    Progress:Thermometer = PercentProgress
    DisplayProgress = True
  END
  ?Progress:PctText{Prop:Text} = RecordsProcessed & ' ' & CPCS:ProgWinRecText !Bad: #1 Move up
  DisplayProgress = True   !Bad: #2 Remove this line
  IF DisplayProgress; DISPLAY().

This has two problem lines that I tagged above with !Bad:. #1 causes the PCT Text string to be updated and #2 a DISPLAY for EVERY record, which slows down report processing.

The template needs to be changed to generate the routine below:

DisplayProgress  ROUTINE
  RecordsProcessed += 1
  RecordsThisCycle += 1
  DisplayProgress = False
  IF PercentProgress < 100
    PercentProgress = (RecordsProcessed / RecordsToProcess)*100
    IF PercentProgress > 100
      PercentProgress = 100
    END
  END
  IF PercentProgress <> Progress:Thermometer THEN
    Progress:Thermometer = PercentProgress
    DisplayProgress = True
    ?Progress:PctText{Prop:Text} = RecordsProcessed & ' ' & CPCS:ProgWinRecText     !Moved UP
  END
    !Bad Moved up: ?Progress:PctText{Prop:Text} = RecordsProcessed & ' ' & CPCS:ProgWinRecText
    !Bad Removed:  DisplayProgress = True
  IF DisplayProgress; DISPLAY().

The routine already had code IF PercentProgress <> Progress:Thermometer THEN that limited changing the Progress Bar window to every 1% or 100 times no matter how many records.

The code changes moves the update of PctText with Records Process inside that IF so it only updates every 1%. I also removed that second DisplayProgress = True that causes a DISPLAY for every record.

With this new code there is no need I see for the DisplayProgress variable. Possibly there was embed code that checked that, so the safe bet is to leave it as is.

CPCS has an option to show the “Percent Complete” in the PctText string like the shipping templates. This is the default. It generates the below code:

DisplayProgress  ROUTINE
  RecordsProcessed += 1
  RecordsThisCycle += 1
  DisplayProgress = False
  IF PercentProgress < 100
    PercentProgress = (RecordsProcessed / RecordsToProcess)*100
    IF PercentProgress > 100
      PercentProgress = 100
    END
  END
  IF PercentProgress <> Progress:Thermometer THEN
    Progress:Thermometer = PercentProgress
    DisplayProgress = True
  END
  ?Progress:PctText{Prop:Text} = FORMAT(PercentProgress,@N3) & CPCS:ProgWinPctText  !Bad: #1 Move up
  IF DisplayProgress; DISPLAY().

This has one problem line that I tagged above with !Bad: #1 Move Up. It causes the PCT Text string to be updated for EVERY record, which slows down report processing.

The template needs to be changed to generate the routine below:

DisplayProgress  ROUTINE
  RecordsProcessed += 1
  RecordsThisCycle += 1
  DisplayProgress = False
  IF PercentProgress < 100
    PercentProgress = (RecordsProcessed / RecordsToProcess)*100
    IF PercentProgress > 100
      PercentProgress = 100
    END
  END
  IF PercentProgress <> Progress:Thermometer THEN
    Progress:Thermometer = PercentProgress
    DisplayProgress = True
    ?Progress:PctText{Prop:Text} = PercentProgress & CPCS:ProgWinPctText   !moved up & no Format @N3
  END
    !Bad Moved Up: ?Progress:PctText{Prop:Text} = FORMAT(PercentProgress,@N3) & CPCS:ProgWinPctText
  IF DisplayProgress; DISPLAY().

As above the routine already had code IF PercentProgress <> Progress:Thermometer THEN that limited changing the Progress Bar window to every 1% or 100 times no matter how many records.

The code changes moves the update of PctText with PercentProgress inside that IF so it only updates every 1%. I also removed the FORMAT(,@N3) as I saw no need for it to have leading spaces.

The template changes need to be made to CrtAbcRpt.TPW and CrtClaRpt.TPW in C:\Clarion#\accessory\template\win. Legacy and ABC have identical DisplayProgress code.

To change the templates

  1. Close All APP’s
  2. Open CrtAbcRpt.TPW or CrtClaRpt.TPW in the Editor
  3. Find the DisplayProgress ROUTINE
  4. Find the lines of code between #IF(SUB(%ProgressOption,1,1)='P')and #IF(%ProgressOption='Spinner')
  5. See that your existing code matches my Original Code
  6. Replace it with my Changed Code below
  7. Save the TPW then open an APP with a CPCS Report to verify the changes

This is the Original Code from my V3 files:

DisplayProgress  ROUTINE
...
#IF(SUB(%ProgressOption,1,1)='P')
  IF PercentProgress <> Progress:Thermometer THEN
    Progress:Thermometer = PercentProgress
    DisplayProgress = True
  END
#ENDIF
#IF(SUB(%ProgressOptionValue,1,1)='P')
  ?Progress:PctText{Prop:Text} = FORMAT(PercentProgress,@N3) & CPCS:ProgWinPctText
  #IF(%MDIProgWin AND %MDIProgWinIcon AND %MDIProgWinIconizedProg)
  IF PWinMinimized = True
    ProgressWindow{PROP:TEXT} = ?Progress:PctText{Prop:Text}
  END
  #ENDIF
#ELSIF(SUB(%ProgressOptionValue,1,1)='R')
  ?Progress:PctText{Prop:Text} = RecordsProcessed & ' ' & CPCS:ProgWinRecText
  DisplayProgress = True
  #IF(%MDIProgWin AND %MDIProgWinIcon AND %MDIProgWinIconizedProg)
  IF PWinMinimized = True
    ProgressWindow{PROP:TEXT} = ?Progress:PctText{Prop:Text}
  END
  #ENDIF
#ENDIF
#IF(%ProgressOption='Spinner')
...

Below is the Changed Code changed to move window updates to be every 1% inside IF PercentProgress <> Progress:Thermometer THEN

DisplayProgress  ROUTINE
...
#IF(SUB(%ProgressOption,1,1)='P')
  IF PercentProgress <> Progress:Thermometer THEN
    Progress:Thermometer = PercentProgress
    DisplayProgress = True
#!11/17/25 CB set Percent or Records string here only every 1% of records
 #CASE(SUB(%ProgressOptionValue,1,1))    #!11/17/25 CB
 #OF('P')
    ?Progress:PctText{Prop:Text} = PercentProgress & CPCS:ProgWinPctText
 #OF('R')
    ?Progress:PctText{Prop:Text} = RecordsProcessed &' '& CPCS:ProgWinRecText
 #ENDCASE                                #!11/17/25 CB end new code 
#!11/17/25 CB also move up the code to show progress in the window caption (when iconized) to only show every 1%
 #IF(%MDIProgWin AND %MDIProgWinIcon AND %MDIProgWinIconizedProg)
    IF PWinMinimized = True
       ProgressWindow{PROP:TEXT} = ?Progress:PctText{Prop:Text}
    END
 #ENDIF    
  END
#ENDIF
#IF(SUB(%ProgressOptionValue,1,1)='P')
#!11/17/25 CB moved up:  ?Progress:PctText{Prop:Text} = PercentProgress & CPCS:ProgWinPctText
#!  #IF(%MDIProgWin AND %MDIProgWinIcon AND %MDIProgWinIconizedProg)   11/17/25 CB moved up
#!  IF PWinMinimized = True
#!    ProgressWindow{PROP:TEXT} = ?Progress:PctText{Prop:Text}
#!  END
#!  #ENDIF
#ELSIF(SUB(%ProgressOptionValue,1,1)='R')
#!11/17/25 CB moved up:  ?Progress:PctText{Prop:Text} = RecordsProcessed & ' ' & CPCS:ProgWinRecText
#!11/17/25 CB bad idea:  DisplayProgress = True
#!  #IF(%MDIProgWin AND %MDIProgWinIcon AND %MDIProgWinIconizedProg)
#!  IF PWinMinimized = True
#!    ProgressWindow{PROP:TEXT} = ?Progress:PctText{Prop:Text}
#!  END
#!  #ENDIF
#ENDIF
#IF(%ProgressOption='Spinner')
...

FYI it may help to know some of variables from these template inputs:

#DISPLAY('Progress Indicator')
#PROMPT('',DROP('Progress Bar|Spinner|Icons')),%ProgressOption  

#PROMPT('For Progress show:',OPTION),%ProgressOptionValue
  #PROMPT('Percent Complete',RADIO)
  #PROMPT('Records Read',RADIO)
  #PROMPT('Neither',RADIO)

#PROMPT('Start Iconized', CHECK),%MDIProgWinIconize
#PROMPT('Show Progress when Iconized', CHECK),%MDIProgWinIconizedProg

One other change you can make is to improve the Progress Window. Its too small given the size of modern displays. It uses a Font that is too small and an ugly bit map FONT('MS Sans Serif',8,...).

You’ll find this current code:

ProgressWindow WINDOW('Progress...'),AT(,,162,64),FONT('MS Sans Serif',8,,FONT:regular),CENTER,TIMER(1),GRAY, |
 #IF(NOT %MDIProgWin)
         DOUBLE
 #ELSE
   #IF(NOT %MDIProgWinIcon)
         DOUBLE,MDI,SYSTEM
   #ELSE
         DOUBLE,MDI,SYSTEM,ICON('%MDIProgWinIcon'),IMM
   #ENDIF
 #ENDIF
       PROGRESS,USE(Progress:Thermometer),AT(25,15,111,12),RANGE(0,100),HIDE
       STRING(' '),AT(71,15,21,17),FONT('Arial',18,,FONT:bold),USE(?Spinner:Ctl),CENTER,HIDE
  #IF(%ProgressOption='Icons')
... Icon controls, No change, Don't use ...
  #ENDIF
       STRING(''),AT(0,3,161,10),USE(?Progress:UserString),CENTER
       STRING(''),AT(0,30,161,10),USE(?Progress:PctText),TRN,CENTER
       BUTTON('Cancel'),AT(55,42,50,15),USE(?Progress:Cancel)
     END
#ENDIF

I changed to this that uses Font Segoe UI 9pt and makes the Window and controls larger:

 #IF(NOT %MDIProgWin)
ProgressWindow WINDOW('Progress...'),AT(,,282,78),FONT('Segoe UI',9,,FONT:regular),CENTER,TIMER(1),GRAY
 #ELSE
   #IF(NOT %MDIProgWinIcon)
ProgressWindow WINDOW('Progress...'),AT(,,282,78),FONT('Segoe UI',9,,FONT:regular),CENTER,TIMER(1),GRAY,MDI,SYSTEM
   #ELSE
ProgressWindow WINDOW('Progress...'),AT(,,282,78),FONT('Segoe UI',9,,FONT:regular),CENTER,TIMER(1),GRAY,MDI,SYSTEM,ICON('%MDIProgWinIcon'),IMM
   #ENDIF
 #ENDIF
       PROGRESS,USE(Progress:Thermometer),AT(25,21,231,14),RANGE(0,100),HIDE
       STRING(' '),AT(131,21,21,17),FONT('Arial',18,,FONT:bold),USE(?Spinner:Ctl),CENTER,HIDE
  #IF(%ProgressOption='Icons')
... Icon controls, No change, Don't use ...
  #ENDIF
       STRING(''),AT(0,5,281),USE(?Progress:UserString),CENTER
       STRING(''),AT(0,40,281),USE(?Progress:PctText),TRN,CENTER
       BUTTON('Cancel'),AT(115,56,50,15),USE(?Progress:Cancel),SKIP
     END
#ENDIF
1 Like

When I begin the rewrite for the source version next year I’ll take these under consideration.

Thank you.

I made screen captures in the Clarion editor that the color makes it easier to see this simple change to only update the window every 1%:

Showing Record Count:

Showing Percent: