I have a morph that I want to have "flash" its border color in blue for a couple of seconds and then restore itself to its prior state.
I know how to change the border color. I know how to achieve a delay. Everything works if I "do something" to interrupt the method at the point of the color change. But if I let it run, the display seems to be caching the state of the display in such a way that I never see the color change.
After the color change I'm trying sending the morph layoutChanged, sending its owner layoutChanged, even going so far as to try Project current world restoreDisplay -- nothing works. Sigh.
There has to be a simple way to do this. How do you tell a morph to show itself "right now" in its current condition -- in mid-method?
-Thanks, Jim
--- Jim Rosenberg http://www.well.com/user/jer/ WELL: jer Internet: jr@amanue.com
On Mon, 27 Dec 2004 19:39:09 -0500, Jim Rosenberg jr@amanue.com wrote:
There has to be a simple way to do this. How do you tell a morph to show itself "right now" in its current condition -- in mid-method?
I think you can do:
Display forceDisplayUpdate.
Later, Jon
-------------------------------------------------------------- Jon Hylands Jon@huv.com http://www.huv.com/jon
Project: Micro Seeker (Micro Autonomous Underwater Vehicle) http://www.huv.com
--On Monday, December 27, 2004 7:51 PM -0500 Jon Hylands jon@huv.com wrote:
There has to be a simple way to do this. How do you tell a morph to show itself "right now" in its current condition -- in mid-method?
I think you can do:
Display forceDisplayUpdate.
Well, I just tried this, and am still not seeing the color change.
--- Jim Rosenberg http://www.well.com/user/jer/ WELL: jer Internet: jr@amanue.com
Hi Jim,
How are you trying to do the delay that you mentioned? With a "Delay forDuration:" kind of call? If you are doing that it won't work because that Delay will block the UI events processing.
The only way I know to make timed things on Morphic is with the stepping mechanism. If you don't know how it works just check the following methods on your image: #step, #stepTime, #startStepping and #stopStepping. Take into account that with #step you wont be able to do the flashing effect in only one method as you were describing. But that is because Morphic wasn't intended to be used in that way.
If you don't want to use the stepping mechanism then you will be doomed to do the UI events processing yourself. Instead of using Delay you should make a while loop with something like this:
[done] whileFalse: [ self world ifNotNil: [self outermostWorldMorph doOneCycle]. "check the elapsed time and set done accordingly" ]
Hope it helps.
Regards, Hernán
Jim Rosenberg wrote:
--On Monday, December 27, 2004 7:51 PM -0500 Jon Hylands jon@huv.com wrote:
There has to be a simple way to do this. How do you tell a morph to show itself "right now" in its current condition -- in mid-method?
I think you can do:
Display forceDisplayUpdate.
Well, I just tried this, and am still not seeing the color change.
Jim Rosenberg http://www.well.com/user/jer/ WELL: jer Internet: jr@amanue.com
--On Monday, December 27, 2004 11:12 PM -0300 Hernan Tylim htylim@yahoo.com.ar wrote:
How are you trying to do the delay that you mentioned? With a "Delay
forDuration:" kind of call? If you are doing that it won't work because that Delay will block the UI events processing.
Yeah,
(Delay forSeconds: 2) wait.
But this is *after* the color change. I'm hoping for something to update the display state before this happens.
-Thanks, Jim
--- Jim Rosenberg http://www.well.com/user/jer/ WELL: jer Internet: jr@amanue.com
Jim Rosenberg wrote:
--On Monday, December 27, 2004 11:12 PM -0300 Hernan Tylim htylim@yahoo.com.ar wrote:
How are you trying to do the delay that you mentioned? With a "Delay
forDuration:" kind of call? If you are doing that it won't work because that Delay will block the UI events processing.
Yeah,
(Delay forSeconds: 2) wait.
But this is *after* the color change. I'm hoping for something to update the display state before this happens.
Morphic doesn't inmediately draw changes on the display, rather it caches all the ones produced in a cycle and process them at the end of the loop. That is to avoid unnecessary draws.
In your code you are doing a color change, but then if you call Delay you are blocking the UI events processing and the color will never get changed. Moreover the whole UI will get unresponsive during the Delay. Your code and the UI event loop is on the same thread, you shouldn't do anything that blocks inside the morphic thread. If you want to do a delay you need to do it as I show you on my previous mail. With the #step methods, or doing the event loop yourself. This last one is done in several places on the image to make modal dialogs, check senders of #doOneCycle.
Regards, Hernán
On Mon, 27 Dec 2004 19:59:18 -0500, Jim Rosenberg jr@amanue.com wrote:
Well, I just tried this, and am still not seeing the color change.
You need to do the following:
aMorph changeBorderColor; changed. Display forceDisplayUpdate. 100 timesRepeat: [ (Delay forMilliseconds: 20) wait. aMorph world doOneCycle]. aMorph restoreBorderColor; changed. "The following line is optional, and probably not needed." Display forceDisplayUpdate.
To force the morph to redraw, you need to send #changed to it. After that, you need to force the redraw to the display. The delay as implemented above is just a simpler way of keeping the UI running while you're pausing.
Later, Jon
-------------------------------------------------------------- Jon Hylands Jon@huv.com http://www.huv.com/jon
Project: Micro Seeker (Micro Autonomous Underwater Vehicle) http://www.huv.com
Hi Jon, the #changed call is not really neccessary. It needs to only do the doOneCycle thing.
try this on a workspace:
m := Morph new. m openInWorld. m color: Color yellow. (Delay forSeconds: 2) wait. m color: Color blue.
select all and evaluate it. This code won´t work. But if you do:
m := Morph new. m openInWorld. m outermostWorldMorph doOneCycle. m color: Color yellow. m outermostWorldMorph doOneCycle. (Delay forSeconds: 2) wait. m color: Color blue.
it will.
Take into account that the 2 seconds delay is a no no. The way to do the delay is how you did it with the loop.
Regards, Hernán
Jon Hylands wrote:
On Mon, 27 Dec 2004 19:59:18 -0500, Jim Rosenberg jr@amanue.com wrote:
Well, I just tried this, and am still not seeing the color change.
You need to do the following:
aMorph changeBorderColor; changed. Display forceDisplayUpdate. 100 timesRepeat: [ (Delay forMilliseconds: 20) wait. aMorph world doOneCycle]. aMorph restoreBorderColor; changed. "The following line is optional, and probably not needed." Display forceDisplayUpdate.
To force the morph to redraw, you need to send #changed to it. After that, you need to force the redraw to the display. The delay as implemented above is just a simpler way of keeping the UI running while you're pausing.
Later, Jon
Jon Hylands Jon@huv.com http://www.huv.com/jon
Project: Micro Seeker (Micro Autonomous Underwater Vehicle) http://www.huv.com
On Tue, 28 Dec 2004 11:03:36 -0300, Hernan Tylim htylim@yahoo.com.ar wrote:
the #changed call is not really neccessary. It needs to only do the doOneCycle thing.
Well, that depends on what you're doing. If you are changing some attribute of the morph that doesn't automatically update the morph, you absolutely need to call it.
The only reason your code works is because #color: calls #changed itself.
Later, Jon
-------------------------------------------------------------- Jon Hylands Jon@huv.com http://www.huv.com/jon
Project: Micro Seeker (Micro Autonomous Underwater Vehicle) http://www.huv.com
You are right. I stay corrected.
Regards, Hernán
Jon Hylands wrote:
On Tue, 28 Dec 2004 11:03:36 -0300, Hernan Tylim htylim@yahoo.com.ar wrote:
the #changed call is not really neccessary. It needs to only do the doOneCycle thing.
Well, that depends on what you're doing. If you are changing some attribute of the morph that doesn't automatically update the morph, you absolutely need to call it.
The only reason your code works is because #color: calls #changed itself.
Later, Jon
Jon Hylands Jon@huv.com http://www.huv.com/jon
Project: Micro Seeker (Micro Autonomous Underwater Vehicle) http://www.huv.com
On Tue, 28 Dec 2004 09:16:20 -0500, Jon Hylands jon@huv.com wrote:
The only reason your code works is because #color: calls #changed itself.
Note that #borderColor: also calls #changed, so the original poster does not need to send #changed.
Most of the stuff I do is with custom morphs, and I generally never make my morphs auto-redraw, so I always end up sending #changed after I have made all the changes I need to.
Later, Jon
-------------------------------------------------------------- Jon Hylands Jon@huv.com http://www.huv.com/jon
Project: Micro Seeker (Micro Autonomous Underwater Vehicle) http://www.huv.com
Thanks everyone for all the help on this -- it's now working exactly the way I want it to. The specific line of code I'm using to get the display to redraw is:
Project current world doOneCycle.
-Thanks again, Jim
A more elegant solution would be to use the alarm handling methods:
flashBorder | oldBorderColor | oldBorderColor := self borderColor. self borderColor: Color blue. self addAlarm: #borderColor: with: oldBorderColor after: 3000. "reset the border color after 3 seconds"
You only have to be careful not to call this method while the border color is set to blue - otherwise the change will be permanent...
Cheers, Hans-Martin
Just so you know, the polite approach is to send #changed and let the system redraw itself naturally. That's just how Morphic works, and is what is expecting to deal with.
If you are wanting to do some sort of animation, then the polite approach is to use things like #step and #addDeferredUIMessage:. It's a little more work, but it means that your morph plays by the rules that morphic is expecting. As one example, if you play polite, then all the other morphs on the screen will still get to animate and respond to events while your animation is happening.
That said, carry on. It's your image, of course!
-Lex
squeak-dev@lists.squeakfoundation.org