Sticky Button Down State
[1/11] from: ishtahara:yaho:o at: 30-Jun-2003 9:19
Thanks to Anton and Carl for helpful button solutions.
One more question, if I may. Given:
sites: [
http://www.rebol.com
http://www.rebol.org
http://www.reboltech.com
http://www.rebolforces.com
]
view layout [
button "Start Scan" [
foreach site sites [print read site]
]
]
The button state remains as pressed until the foreach
operation is complete (may be long operations).
The sticky button is not very disirable to see, but
even less, if user clicks button during wait, the
events held in queue and then processed. Returning
button immediately to "up" state is desireable but
invites user clicks.
Any list advice for this situations? Progress is one
way, but I maybe dont want to attach progress to all
such buttons. I plan to release some reblets with SDK,
and extra thorogh style will reduce users support
questions.
Thanks again!
~D
[2/11] from: SunandaDH::aol::com at: 30-Jun-2003 14:43
Daril:
> The sticky button is not very disirable to see, but
> even less, if user clicks button during wait, the
> events held in queue and then processed. Returning
> button immediately to "up" state is desireable but
> invites user clicks.
You have several "real world" issues here and, as usual, they complicate code
that looks very simple until you start adding the stuff to handle them.
As I see it, you have four main issues:
1. How to stop a block of code being executed a number of times concurrently
if someone repeatedly presses the button. This is important as REBOL can
crash if someone tries this;
2. How to allow the user to cancel a long-running operation;
3. How to change a button state to show "in-progess" or some such;
4. How to show a progress bar.
The last two are relatively trivial, so I'll leave them up to you. The first
two need some extra code. In the rewrite of your code below, I've added:
-- two extra "state variables" so we can track if a process is underway, and
we can request a termination;
-- A cancel button so the user can request the termination;
-- wait 0 in the action loop -- important as otherwise the cancel action will
be deferred until the main process is complete -- not what you want.
=====
Cancel-requested: false
in-process: false
sites: [
http://www.rebol.com
http://www.rebol.org
http://www.reboltech.com
http://www.rebolforces.com
]
unview/all
view layout [
button "Start Scan" [
if in-process [return true]
in-process: true
cancel-requested: false
foreach site sites [
wait 0
if cancel-requested [in-process: false
return true]
print read site
] ;; for
in-process: false
] ;; action
button "Cancel" red [
cancel-requested: true
] ;; action
] ;; layout
=====
[In the real, real world, you'd want to surround some of this with a 'try
block so that the extra variables get set correctly in the event of an error --
otherwise, higher level recovery and restart code may leave the variables
incorrectly set....If in-process
is accidentally left true for any reason, the button becomes effectively
disabled. Error-recover code can seem endless :-) ]
Sunanda
[3/11] from: maximo:meteorstudios at: 30-Jun-2003 16:42
Hi,
here is my unsticky solution...
with this example everything stays active... the last suggestion, if run, still jams
the ui when I tested it.
The code below is simplified, but the wait loop is the real issue. it tests to see if
we are currently scanning and if the user presses start again, it opens a warning box...
if you want to do it for multiple files just iterate on the do-start and add an argument
to it for the file to browse.
==========
rebol []
gui: layout [
button "start" [do-start]
button "stop" [do-stop]
]
user-cancel: false
started: false
do-start: does [
either not started [
started: true
data: open/lines http://www.rebol.com
user-cancel: false
until [
print first data
wait 0
if user-cancel [break]
data: next data
tail? data
]
if tail? data [print "==== END OF FILE ===="]
close data
started: false
][
request/ok "==== ALREADY PRINTING ===="
]
]
do-stop: does [
user-cancel: true
started: false
]
view gui
==========
HTH
-max
[4/11] from: ishtahara:yah:oo at: 30-Jun-2003 15:47
Thanks to Maxim and Sunanda--
Your examples are very helpful. I can see the
necessary extra work and code when programming for the
real world. Sadly much simplicity and elegance are
lost, especially after adding all the try/attempt
code.
Thank you very much for this insight, which would have
been much longer arrived without your help.
~D
[5/11] from: antonr:iinet:au at: 1-Jul-2003 11:51
Gabriele Santilli first showed me this technique
of covering the button with a blurred face:
view layout [
b: button "go" [cover/offset: face/offset show cover]
c: button "cancel" [cover/offset: negate cover/size show cover]
at (negate b/size) cover: box b/size effect [merge emboss]
]
(You can try the other effects than emboss: luma -20, blur etc.)
Anton.
[6/11] from: greggirwin:mindspring at: 30-Jun-2003 22:28
Hi Daril,
DN> I can see the necessary extra work and code when programming for the
DN> real world. Sadly much simplicity and elegance are
DN> lost, especially after adding all the try/attempt code.
I don't have time to respond in proper detail, but don't forget that
this is true for any event driven system, not just REBOL (I'm
guessing you know that, so I say it for the benefit of lurkers who may
not). I remember reviewing VB apps suffering from cascading events and
unhandled multiply-triggered events (multivents? :).
So, what to do? In small apps, you can treat things specifically with
only minor pain and suffering but, as you point out, a loss of
elegance and simplicity.
In more complex situations another solution may be called for. I
haven't done it, but you could probably write styles that handle
multivents at least better than the raw styles do now.
My main tool against this kind of problem is a state machine. Events
are placed into a queue and dispatched from there. It means thinking
about things in a different way, and isn't always a good fit but it's
served me well in both VB and REBOL.
-- Gregg
[7/11] from: ishtahara:ya:hoo at: 1-Jul-2003 5:06
--- Gregg Irwin wrote:
> I don't have time to respond in proper detail, but
> don't forget that this is true for any event driven
> system, not just REBOL
Very true. Program hardening is not avoided in any
development.
> In more complex situations another solution may be
> called for. I haven't done it, but you could
> probably write styles that handle multivents at
> least better than the raw styles do now.
I don't do much View programming now, but when I do it
would be great to see examples or a How-to. ^_^
> My main tool against this kind of problem is a state
> machine. Events are placed into a queue and
> dispatched from there.
Sounds complex...
Thinking further about Anton's (Gabriele's) trick:
Maybe the following could work:
- Set button text to gray
- Set feel to none at beginning of action block
- Process actions
- Reset feel to accept button clicks
- Reset button text to original color
Maybe this would not stop events from building in
queue though.
~D
[8/11] from: antonr:iinet:au at: 1-Jul-2003 23:48
Yes it does stop events. If a face has no feel to
process events, then it is ignored by view's
event system.
view layout [
b: button "go" [
face/font/color: gray face/state: no
show face
face/feel: none
]
do [my-feel: b/feel]
button "cancel" [
b/font/color: white b/feel: my-feel show b
]
]
Anton.
[9/11] from: greggirwin:mindspring at: 1-Jul-2003 9:47
Hi Daril,
DN> I don't do much View programming now, but when I do it
DN> would be great to see examples or a How-to. ^_^
Agreed. I think we all want that.
>> My main tool against this kind of problem is a state
>> machine. Events are placed into a queue and dispatched from there.
DN> Sounds complex...
The complexity is there already. State machines help to *manage* it by
making things explicit. Most programs contain an informal state
machine of some kind. As soon as you need to disallow events, or
handle them differently based on what the app is doing, you've got a
state machine. The only difference in what I'm talking about is that
you design them explicitly rather than setting flags here and there,
disabling event triggers, and using nested SWITCH statements.
Designing the state machine for your program forces you to identify
all the possible states it could be in, what events can occur, and
what you do for each event in each state. All that information is
going to be expressed implicitly in your program anyway.
What makes the "normal" way seem simpler is that we tend to ignore a
lot of the things that can actually happen, so we're handling only a
portion of all the possible cases. This is a great way to keep
complexity at bay, but not a great way to build mission critical
software.
It is always best to express things as simply and directly as
possible. Sometimes the only way to find the best solution is to try
all the ways you can think of and compare them. :)
-- Gregg
[10/11] from: ishtahara:y:ahoo at: 1-Jul-2003 10:11
Very nice, both you and Gregg. Thank you.
In a handful of messages over a few days we have
learned:
- how to change the font of button text
- how to remove highlight of button text
- how to interupt processing with a Cancel button
- techniques for addressing "button down" issues
This is very useful information, is everyone taking
notes? ^_^
The people on this list are great! Thanks to all who
helped. I think your responses help many more than you
are aware.
Happy REBOLing
~D
--- Anton wrote:
[11/11] from: rotenca:telvia:it at: 1-Jul-2003 19:33
> > Maybe the following could work:
> > - Set button text to gray
<<quoted lines omitted: 5>>
> process events, then it is ignored by view's
> event system.
It only works if you return to the event handling system.
To kill events you can use one of functions in eat.r:
http://www.reboltech.com/library/scripts/eat.r
see it in
http://www.reboltech.com/library/html/eat.html
---
Ciao
Romano
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted