Home   Archive   Permalink



GUI status display

I want to have my cake and eat it too.
    
With help from a previous posting, I have made a little status window. The difficulty I had was that if I tried to view a status window, the program would wait on the various events from the viewed window, so I never could update the window because the program would top running and just wait. If I used view/new to view the window, the program would continue running after showing the window. So I did that as shown below and all is working, but now, as a final touch, I would like to add a 'cancel' option to the status window so the operator can kill the program if it seems to be running too long. It appears that I can't do that, because the program is not waiting on window events, but is running along as desired.    
    
Do we think there is a way to pop up a status window, update it as the program runs, but then allow the program to be canceled somehow through that same status window?    
    
Thank you. Current efforts so far follow.
    
R E B O L [
     Title: 'Status display'
     Purpose: {Show a reassuring status box indicating what a program
     is doing and how far along it is.}
]
    
;; [---------------------------------------------------------------------------]
;; [ This module is a few functions you can use to show a status display     ]
;; [ for a running program. You have to use them properly, because they     ]
;; [ don't do any checking.                                                    ]
;; [                                                                         ]
;; [ SHOW-STATUS-WINDOW: Do this first, to get a the status window showing.    ]
;; [     The view/new function shows the status box but lets your program     ]
;; [     continue.                                                             ]
;; [ SHOW-PHASE (phase-literal): Display one line of text indicating what     ]
;; [     the program is doing. Every time you call this function, the         ]
;; [     previous phase gets put into a history display above the current.     ]
;; [ SHOW-PROGRESS: (total-to-do amount-done): This function modifies the     ]
;; [     progress bar with a fraction calculated as the amount done divided    ]
;; [     by the total that must be done. Usually these are record counts,     ]
;; [     as in 500 records processed out of a total of 20000.                 ]
;; [     That would look like this: STATUS-BAR/SHOW-PROGRESS 20000 500         ]
;; [     It is your job to keep track of those numbers.                        ]
;; [ RESET-PROGRESS: Reset the progress bar to zero. This function exists     ]
;; [     in case you want to show several progress bars, one after another.    ]
;; [ CLOSE-STATUS-WINDOW: This just executes the unview function to make     ]
;; [     the status window disappear.                                         ]
;; [---------------------------------------------------------------------------]
    
STATUS-BOX: context [
     MAIN-WINDOW: layout [
         MAIN-BANNER: banner 'Program status'
         MAIN-HISTORY: text 200x50 wrap
         label 200 'Current phase:'
         MAIN-PHASE: info 200
         label 200 'Progress on this phase'
         MAIN-PROGRESS: progress 200
;;;;    button 'Cancel' [alert 'Operation canceled' quit] ;;; Does not work.
     ]
     SHOW-STATUS-WINDOW: does [
         view/new center-face MAIN-WINDOW
     ]
     SHOW-PHASE: func [
         PHASE
     ] [
         append MAIN-HISTORY/TEXT rejoin [
             MAIN-PHASE/text
             newline
         ]
         MAIN-HISTORY/line-list: none
         MAIN-HISTORY/para/scroll/y: negate
             (max 0 (second size-text MAIN-HISTORY) - (MAIN-HISTORY/size/y))
         show MAIN-HISTORY
         MAIN-PHASE/text: copy PHASE
         show MAIN-PHASE
     ]
     SHOW-PROGRESS: func [
         FULL-SIZE
         AMOUNT-DONE
     ] [
         set-face MAIN-PROGRESS (AMOUNT-DONE / FULL-SIZE)
     ]
     RESET-PROGRESS: does [
         set-face MAIN-PROGRESS 0
     ]
     CLOSE-STATUS-WINDOW: does [
         unview
     ]
]
    
;; Uncomment to test
STATUS-BOX/SHOW-STATUS-WINDOW
wait 2
STATUS-BOX/SHOW-PHASE 'Initializing'
wait 2
STATUS-BOX/SHOW-PHASE 'Phase 1'
wait 2
STATUS-BOX/SHOW-PHASE 'Extracting data'
CNT: 0
TOT: 100
loop 100 [CNT: CNT + 1 STATUS-BOX/SHOW-PROGRESS TOT CNT wait 0.1]
wait 2
STATUS-BOX/SHOW-PHASE 'Processing data'
STATUS-BOX/RESET-PROGRESS
CNT: 0
TOT: 100
loop 100 [CNT: CNT + 1 STATUS-BOX/SHOW-PROGRESS TOT CNT wait 0.1]
wait 2
STATUS-BOX/SHOW-PHASE 'Finishing'
wait 3
STATUS-BOX/CLOSE-STATUS-WINDOW
    


posted by:   Steven White       27-Feb-2017/17:08:37-8:00



Steve,
    
I was reflecting of your status bar implementation when I realized "oh shoot I forgot checking the existence of threads in Rebol".
    
Although not part of the language(yet :-) here is a solution:
    
https://stackoverflow.com/questions/2708494/rebol-how-to-do-another-task-while-waiting-an-alarm-to-trigger
    
I speculate Rebol can use the OS context switching through the graphic library timer.
    
Look for this line:
    
rate 1 feel [engage: :periodic]
    
in https://stackoverflow.com/questions/2708494/rebol-how-to-do-another-task-while-waiting-an-alarm-to-trigger
    
I modified to allow dynamic rate increase which in turn increases the number of context switching as reported by Sysinternal Process Explorer (in properties).
    
Have fun!
    
    
R E B O L [
     Title: "Alarmer"
     Original File: %alarm.r
     Author: oofoe
     Date: 2010-04-28
     Purpose: "Demonstrate non-blocking alarm."
     File: %thread-alarm02.r
     Modified: "by OneArb to dynamic change rate"
     Date: 2017-03-02
]
    
myrate: 1
alarm-data: none
digit: charset "0123456789"
    
alarm: func [
     "Set alarm for future time."
     seconds "Seconds from now to ring alarm."
     message [string! unset!] "Message to print on alarm."
] [
     alarm-data: reduce [now/time/precise + seconds message]
]
    
ring: func [
     "Action for when alarm comes due."
     message [string! unset!]
] [
     set-face monitor either message [message]["RIIIING!"]
     ; Your sound playing can also go here (my computer doesn't have speakers).
]
    
periodic: func [
     "Called every second / myrate, checks alarms."
     fact action event
] [
     print now/time/precise
    
     if alarm-data [
         ; Update alarm countdown.
         set-face monitor rejoin [
             "Alarm will ring in "
             to time! alarm-data/1 - now/time/precise
         ]
    
         ; Check alarm.
         if now/time/precise > alarm-data/1 [
             ring alarm-data/2
             alarm-data: none ; Reset once fired.
         ]
     ]
]
    
screen: [
     text "Try change rate"
     myrate-field: field form myrate [
        if (parse myrate-field/text [any digit]) [
         myrate: to-integer myrate-field/text
        ]
        view center-face layout screen
        focus myrate-field
     ]
     monitor: text 256 bold "Alarm messages will be shown here."    
        rate myrate feel [
         engage: :periodic
        ]
     button 256 "re/start countdown" [
        alarm 10 "This is the alarm message."
        set-face monitor "Alarm set."
     ]
]
    
print ""
view/new center-face layout screen
focus myrate-field
do-events

posted by:   OneArb       1-Mar-2017/19:28:49-8:00



You can do this:
    
R E B O L []
;; [---------------------------------------------------------------------------]
;; [ This module is a few functions you can use to show a status display     ]
;; [ for a running program. You have to use them properly, because they     ]
;; [ don"t do any checking.                                                    ]
;; [                                                                         ]
;; [ SHOW-STATUS-WINDOW: Do this first, to get a the status window showing.    ]
;; [     The view/new function shows the status box but lets your program     ]
;; [     continue.                                                             ]
;; [ SHOW-PHASE (phase-literal): Display one line of text indicating what     ]
;; [     the program is doing. Every time you call this function, the         ]
;; [     previous phase gets put into a history display above the current.     ]
;; [ SHOW-PROGRESS: (total-to-do amount-done): This function modifies the     ]
;; [     progress bar with a fraction calculated as the amount done divided    ]
;; [     by the total that must be done. Usually these are record counts,     ]
;; [     as in 500 records processed out of a total of 20000.                 ]
;; [     That would look like this: STATUS-BAR/SHOW-PROGRESS 20000 500         ]
;; [     It is your job to keep track of those numbers.                        ]
;; [ RESET-PROGRESS: Reset the progress bar to zero. This function exists     ]
;; [     in case you want to show several progress bars, one after another.    ]
;; [ CLOSE-STATUS-WINDOW: This just executes the unview function to make     ]
;; [     the status window disappear.                                         ]
;; [---------------------------------------------------------------------------]
        
write %status-window.r {
     R E B O L [title: "status"]
     SHOW-PHASE: func [
         PHASE
     ] [
         append MAIN-HISTORY/TEXT rejoin [
             MAIN-PHASE/text
             newline
         ]
         MAIN-HISTORY/line-list: none
         MAIN-HISTORY/para/scroll/y: negate
             (max 0 (second size-text MAIN-HISTORY) - (MAIN-HISTORY/size/y))
         show MAIN-HISTORY
         MAIN-PHASE/text: copy PHASE
         show MAIN-PHASE
     ]
     SHOW-PROGRESS: func [
         FULL-SIZE
         AMOUNT-DONE
     ] [
         set-face MAIN-PROGRESS (AMOUNT-DONE / FULL-SIZE)
     ]
     RESET-PROGRESS: does [
         set-face MAIN-PROGRESS 0
     ]
     CLOSE-STATUS-WINDOW: does [
         quit
     ]
     MAIN-WINDOW: layout [
         MAIN-BANNER: banner "Program status"
         MAIN-HISTORY: text 200x50 wrap
         label 200 "Current phase:"
         MAIN-PHASE: info 200
         label 200 "Progress on this phase"
         MAIN-PROGRESS: progress 200
         button "Cancel" [alert "Operation canceled" quit]
     ]
     view/new center-face MAIN-WINDOW
     forever [
         old: read %status.r
         wait .5
         if not viewed? MAIN-WINDOW [quit]
         if old <> current: read %status.r [do current]
     ]
}
write %status.r ""
launch %status-window.r
        
;; Uncomment to test
wait 2
write %status.r {SHOW-PHASE "Initializing"}
wait 2
write %status.r {SHOW-PHASE "Phase 1"}
wait 2
write %status.r {SHOW-PHASE "Extracting data"}
CNT: 0
TOT: 100
loop 100 [CNT: CNT + 1 write %status.r rejoin [{SHOW-PROGRESS } TOT { } CNT] wait 0.1]
wait 2
write %status.r {SHOW-PHASE "Processing data"}
write %status.r {RESET-PROGRESS}
CNT: 0
TOT: 100
loop 100 [CNT: CNT + 1 write %status.r rejoin [{SHOW-PROGRESS } TOT { }CNT] wait 0.1]
wait 2
write %status.r {SHOW-PHASE "Finishing"}
wait 3
write %status.r {CLOSE-STATUS-WINDOW}
    
    
Better yet, send the messages through a network connection.
    
Why not avoid all this and just print status updates to the console?

posted by:   Nick       2-Mar-2017/4:47:41-8:00



The console is the way I have been doing it. I just wanted to try something different.

posted by:   Steven White       2-Mar-2017/22:41:01-8:00