Flash Quirk: Disabled buttons still broadcast click

| 9 Comments

The official status on this one is "Not a Bug." This behavior was done by design, but it's a little bit counter-intuitive and not consistent with what I've experienced in other languages. I wanted to mention it here as another example of a Flash Quirk.

Consider the following code: (drag a v2 button onto the stage and give it an instance name of "testBtn")

import mx.controls.Button;
import mx.utils.Delegate;

var testBtn:Button;
var onClick:Function = function():Void {
	trace("testBtn clicked!");
}

// call onClick whenever testBtn is pressed
testBtn.addEventListener("click", Delegate.create(this, onClick));

// "press" the button programmatically
testBtn.onRelease();

When the movie is tested, you'll see this code work perfectly. The button press is simulated via ActionScript, and we get the expected trace outpout. Why would you want to simulate a button press through code? The classic example is implementing keyboard shorcuts that invoke button methods.

Now, add this line BEFORE the onRelease call:

// disable the button
testBtn.enabled = false;

Now run the modified code and notice the results. The button was still pressed, even though it was disabled.

Whenever I disable a JButton in Java or a Button in C# and attempt to programmatically press the button (doClick or PerformClick, respectively), the "click" event is not generated. I expected the same behavior out of Flash, but we all know Flash is a very different beast and somehow I'm not surprised.

The workaround is simple, just change the onRelease call to this:

// "press" the button programmatically, but only if it's enabled
if (testBtn.enabled) testBtn.onRelease();

Still though, that just feels wrong to me.

What do you think - is this a bug, or just another quirk? To me, it's a bug since it's unexpected behavior. However, it's officially not a bug (which makes it a quirk) and I don't think Macromedia is going to do anything about it.

9 Comments

That's got to be a quirk just because there may be a mad zaney reason for needing to detect the button click, trying to think of one.....

User feedback? I know they say prevention is better than constant user feedback, but there may be a case for novice users where they would need to be prompted that "you can only click this button when registered"?

Interesting point though, makes a bit of a mess with the extra if(btn.enabled)'s :(

Rich

i don't think its a bug - or a quirk. You have prevented user interaction with the button by normal means (actual click), but I feel that via code, just about anything should be possible. You have called the function onRelease... via code. At that point I don't see how the button would know to prevent a function called on it.

If I make a mc,_visible = false
and then use draw API and created a bunch of stuff, should the API display since it became invisible for a time during the draw API? Its not the same thing, but in the same ballpark. I make a mc visible = false and then play with alpha... should it auto become visible to allow me to see the alpha changes? i mean the mc should have known right? Thats my take on this one.

that's definately a bug.
moreover, if u set disabled button as defaultPushButton via FocusManager onClick handler will be executed when u hit Enter key even you have this button disabled.

Bug... since if a button is disabled, it should be disabled ie. non functional... else the propety shouldnt be called 'enabled'

also when a button is disabled, it implies its not usable/functional...

either way if MM wants it to behave like this, the documentation should indicate the inconsistant behavior (as compared to other languages) in the enabled propety help page...

nik

BUG.

if you set enabled=false, it should not be enabled, no matter what method you use to try to activate it. It's an issue of consistency.

EricD's point that 'anything should be possible in code' is true, and it still would be if the button worked correctly, you'd just need to set enabled=true before calling the press handler. On press the button should simply check it's own enabled property and ignore a click if it is not enabled.

BUT...I've just checked and traditional flash buttons also work this odd way, so I guess we all got this far without noticing.... :)

I think you're talking about two different things here. The onRelease function, which is simply that, generates the event. The event is 'click'. It should be the responsibility of the event handler to check if the button is enabled, and react accordingly.

Which would cover keyboard shortcuts, etc, and not litter your code with if( myBtn.enabled ) myBtn.onRelease().

To be honest, though, I'm not sure why you would call the onRelease through code, as opposed to from the user action. If you need to do something, do it outside the onRelease, and have the onRelease call that. Keyboard shortcuts shouldn't just call Button onReleases - they should have their own listeners/events that propagate the action.

At which point you're no longer talking about the button being enabled or disabled, but about whether a specific action is enabled or disabled.

Interesting comments Jason.

> The onRelease function, which is simply that,
> generates the event. The event is 'click'. It
> should be the responsibility of the event
> handler to check if the button is enabled, and
> react accordingly.

No disrespect, but I don't agree with that, which is why I labeled this behavior as a quirk. If the button is disabled, the onRelease function should not generate the event at all. I expect a disabled button to be disabled, period. Both Java and C# have this behavior.

Additionally, this isn't just v2 component button behavior, as pointed out by Adam above.

> To be honest, though, I'm not sure why you would
> call the onRelease through code, as opposed to
> from the user action. If you need to do
> something, do it outside the onRelease, and have
> the onRelease call that. Keyboard shortcuts
> shouldn't just call Button onReleases - they
> should have their own listeners/events that
> propagate the action.

Where this came from was that the button click event had multiple listeners. I wanted to provide a keyboard shortcut for the button (to trigger all of listeners), so I simply intercepted the keyboard event and had it fire off the button release.

Really, this was more or less copying Java's JButton.setMnemonic function to associate a keyboard event with a button.

I should clarify - I agree that this is a 'quirk', but not a bug. Keeping in mind that what you've done is gone over the intent of onRelease, which is that it is fired when the button is clicked by a user. Instead of leaving it at that, you've taken it over and called it in a place where, for all intents, was never it's purpose. I would think that architecting it such that the button generates a click event that is handled by the application it resides in, which then propagates the event out, would put you in a better place to handle keyboard shortcuts, instead of taking the shortcut of having the keyboard shortcut raise the onRelease.

As for the button having multiple listeners, it comes down to the same thing: should the button click be doing the work? Which of course will depend on the application. I would say, though, that since you have multiple methods for starting a single action (mouse click/keyboard shortcut), that generating the action directly off the mouse click doesn't make sense. For example: what if the behaviour needs to change based on whether the call was made from a keyboard shortcut vs. the button? Could that change the functionality? Your way, all listeners must be aware of that - but they would never know the difference.

I'm probably not being all too coherent, though. So, just to clarify:

Definitely quirky. But, following with the general AS framework, not surprising: consider that if the enabled property disallowed any method calls on an object, you'd be in trouble. I think the intent of (dis)enabled in AS is simply that the user is unable to interact the (visual) object in question. Anything beyond that is up to the developer.

Considering onRelease is more or less a band-aid for on (release), allowing you to attach code to a frame rather than a button, I agree that perhaps I'm going beyond what the method was intended for. However, I still think it is a bug.

We need a way to programmatically "press" a button (onRelease is the logical choice here) - and when a button is disabled it shouldn't be able to be pressed. Calling onRelease via code should not result in the onRelease function actually executing if the button is disabled.

In regards to the other comments - I think we define "keyboard shortcut" differently. To me, a keyboard shortcut is tightly coupled with a button (i.e. press Ctrl+I to click the "I am a button" button). They both perform the same action - the one invoked by the button itself - and the keyboard is a quick way to get to that action. Again, I'm thinking along the lines of JButton.setMnemonic.

Because Flash doesn't support setMnemonic to implement keyboard shortcuts for buttons, you have to implement them with a key listener instead. I want the keyboard shorcut and the button to perform the same action or series of actions. The easiest way to do that is to just intercept the key event and press the button programatically.

Even though the keyboard shortcut is implemented as a separate entity through a key listener, it is really just the button press in disguise, and results in the exact same action.

In Java you assign an action to a button, and set the mnenomic for that button. Both the shortcut and the button perform the same action then, and a keyboard listner is set up behind the scenes to trigger the button's action event. My implementation in Flash follows the same logic, but in Flash I need to code it explicitly. Again, the keyboard listener looks like a separate entity, but it's really just a different way to press the button and invoke it's click action.

Of course, there are million and one ways to do the same thing in programming. You can have the button perform an aciton, and have the shortcut perform the same action rather than have the shortcut invoke the button's action. I choose the latter because it reminds me of Java's implementation, and the shortcut and the button are tightly coupled - if the action or series of actions change for the button press, I only want to change code in one place (where it is defined for the button). By having the keyboard "press" the button, I don't have duplicate code.

There will never be a situation where the shortcut for the button and the button itself do different things (again, they are tightly coupled, by definition). If that arises, I'll simply change the shortcut's pressing the button with it's own unique action.

Hopefully that made sense. :-)

Leave a comment



About this Entry

This page contains a single entry by darron published on August 10, 2004 8:35 PM.

Feedback on CFC-Based Security System was the previous entry in this blog.

ColdFusion struct properties converted to uppercase when using Flash Remoting is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.

Archives

OpenID accepted here Learn more about OpenID
Powered by Movable Type 5.02