Using 2 distinct mouse events in flex - apache-flex

Am working on a flex project
I am looking to provide some UI functionality using the mouse- I have two distinct UI events to be achieved via mouse
a) change value
b) delete object
I don't seem to have sufficient mouseclick events for both. I am avoiding using the right click as it has some default options(whose signing off will affect the whole project- not just this). I have mouse click used for change value- how do I use the doubleclick as the single-click events seems to get invoked prior?
Any thoughts?

private var doubleClickOccurred:Boolean = false;
private var timer:Timer = new Timer(100, 1);
protected function application1_creationCompleteHandler(event:FlexEvent):void
{
myLabel.addEventListener(MouseEvent.CLICK, checkSingleOrDoubleClick);
myLabel.addEventListener(MouseEvent.DOUBLE_CLICK, checkSingleOrDoubleClick);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, handleClick);
}
private function checkSingleOrDoubleClick(event:MouseEvent):void
{
if(event.target == myLabel && event.type == MouseEvent.DOUBLE_CLICK)
{
// set the flag and let the timer complete event
// take care of the click handling
doubleClickOccurred = true;
trace(" double clicked");
}
else if( event.type == MouseEvent.CLICK)
{
// start timer to wait till the double click event
// gets called
timer.start();
trace("Starting timer");
}
}
private function handleClick(event:Event):void
{
if(doubleClickOccurred)
{
// handle double click event
trace("Yes");
}
else
{
// handle single click
trace("No");
}
// reset flag for capturing future events
doubleClickOccurred = false;
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:Label id="myLabel" text="Click Me" doubleClickEnabled="true" />
Output:
1) If a there is a single mouse click on the Label, the Single click login i.e trace("No") is invoked
2) In case of double click on the Label, the trace("yes") is invoked.
I hope this piece of code answers your question about handling single and double click on Flex components.

Can't say too much without knowing what you're editing, what the values are, etc.
A common idiom is to show an "X" icon, say, on the edge of a selected item, with clicks only on that icon triggering delete.

Related

how to stop getting mouse click events in flex

I have made a hierarchy in which there is a main page, using add element i have attached a component mxml of type group. There is a single button on main page when clicked it should add children of type group in that group type mxml component along with two buttons. Now using one of buttons i am attaching another component mxml type group. the problem is even they overlap i can still excess the children groups of first group component mxml. how can i stop this mouse events to happen.
I think those kind of events usually bubble up to parent components.
You can try using the following code in your mouse click event listener to stop further propagation:
private function onMouseClicked(event: MouseEvent): void {
event.stopPropagation();
... do whatever you wanted when smth was clicked ...
}
By setting enabled, mouseChildren, mouseEnabled to false, you will disable the entire component and it's children. example below
private var myPreviousGroupComponent:Group = null;
function addNewGroup():void
{
if(myPreviousGroupComponent != null)
{
myPreviousGroupComponent.enabled = false;
myPreviousGroupComponent.mouseChildren = false;
myPreviousGroupComponent.mouseEnabled = false;
}
var newGroup:Group = new Group();
addElement(newGroup);
myPreviousGroupComponent = newGroup;
}

Flexlib scheduleViewer.. how to handle clicks on items

I'm trying to use a flexlib schedule viewer in my application.
I want to have it so that when I click on a scheduled event, it calls a function in my main app (that will allow me to edit the event). But there doesn't seem to be any specific function for anything like this built into the class ie no event dispatched when I click on an event.
I can use the 'click' function to detect that the item has been clicked on.. and have tried something like this:
private function exerciseClickHandler(event:MouseEvent):void{
if (exerciseSeries.selectedItem != null){
//code
}
}
<code:ScheduleViewer id="exerciseSeries" click="exerciseClickHandler(event)" />
This method isn't very reliable because if it only works the first time.. once an item is selected, it stays selected so all following clicks on the item fulfills the condition.
Is there any way to determine whether an event was being clicked on?
Or do I have to extend the component and add some sort of clickEvent when an event is clicked on.
Since exerciseClickHandler is firing up when you click on the component, wouldn't this work?
Instead of
private function exerciseClickHandler(event:MouseEvent):void{
if (exerciseSeries.selectedItem != null){
//code
}
}
write
private function exerciseClickHandler(event:MouseEvent):void{
switch (exerciseSeries.selectedItem)
{
//code
case xy:
break;
}
}
or
private function exerciseClickHandler(event:MouseEvent):void{
//do something with exerciseSeries.selectedItem
}
What I mean is that you wrote that everything stops after the first element is clicked. And according to the code you provided it has to stop, beacuse after the first click exerciseSeries.selectedItem won't be null anymore, since it's selected. So remove the conditional you wrote and use the instance.
I'd suggest you set up a ChangeWatcher to keep an eye on the selectedItem (or selectedItems if you are going to allow multiple selection at some point). Example:
protected exerciseSeriesCreationCompleteHandler(event:FlexEvent):void{
ChangeWatcher.watch(this,['exerciseSeries','selectedItem'], handleChange_SelectedItem);
}
protected function handleChange_SelectedItem(event:PropertyChangeEvent):void{
// Either
dispatchedEvent(//some custom event);
// Or
someDirectMethodCall();
}
An alternative would be to search for an instance of the the event class in the view hierarchy under the mouse coordinates whenever a user clicks.
//Attach this click handler to the component
private function handleClick(event : MouseEvent) : void {
var obj : *EventClass*= null;
var applicationStage : Stage = FlexGlobals.topLevelApplication.stage as Stage;
var mousePoint : Point = new Point(applicationStage.mouseX, applicationStage.mouseY);
var objects : Array = applicationStage.getObjectsUnderPoint(mousePoint);
for (var i : int = objects.length - 1; i >= 0; i--) {
if (objects[i] is *EventClass*) {
obj = objects[i] as *EventClass*;
break;
}
}
if(obj is *EventClass*){
//Dispatch some custom event with obj being the item that was clicked on.
}
}
Where EventClass is the class of the objects that represent events
I have had similar problems and sometimes you can get by with wrapping the object with a Box and putting the click event on the Box. If you have not already tried that, it's a cheap, easy fix (if it works for you).
<mx:Box click="exerciseClickHandler(event)">
<code:ScheduleViewer id="exerciseSeries" />
</mx:Box>

FLEX button to trigger event continiously when pressed... not once!

I'm wondering if there's a way to configure a FLEX button so it behaves like a push button...
<mx:Button buttonDown="trace('ankur')" autoRepeat="true"/>
to make a flex button to receive contiuous event happening, use the autoRepeat property with buttonDown event, note the click property will no work,
put this tag in ur application, run it,
i hope , this is wht u were luking for
thanx
Ankur Sharma
If you just need it to toggle (which is how a pushbutton behaves), set its toggle property to true.
<mx:Button label="Button Test" toggle="true"/>
If this is not what you mean, be more specific in your question.
EDIT: Since you refined your question, I would suggest you make a handler for the mouseDown event of the button, which starts a method running, and make a mouseUp handler that stops the method from running. Or better yet, have it set or unset a variable, which is tested in the updateDisplayList() method. Like so:
private var _runButtonStuff:Boolean = false;
override protected function updateDisplayList(width:Number, height:number) : void {
super.updateDisplayList(width,height);
if (_runButtonStuff) {
doStuff();
}
}
private function doStuff() : void {
// do some stuff
}
private function buttonIsDown() : void {
_runButtonStuff = true;
}
private function buttonIsUp() : void {
_runButtonStuff = false;
}
and the button looks like this:
<mx:Button text="Run Something" mouseDown="buttonIsDown()" mouseUp="buttonIsUp()"/>
<mx:Button label="Button Test" toggle="true" click="yourMethodName()"/>
public function yourMethodName():void {
var evt:someEventName = new someEventName(someEventName.TYPE);
dispatchEvent(evt);
}
Now when you listen to this event again, call the same method name again through addEventListner. It will keep on firing the same event for ever.
I have a question, on what scenario you want to apply this. You can either go by EventDispatcher or some ActionScript code which will keep on firing the same method name until the equation is solved.
Depending upon your requirement you can go. I would suggest event driven, as it would be easier to manage.

Flex Slider: How to differentiate between programmatic versus user change

I am using HSlider to implement a one-thumb slider control. The thumb position is updated by a timer. However, the user can also update the thumb position by either clicking on a position in the slider track, or by dragging the thumb.
Judging by the Flex documentation, I figured all I needed to do was write a handler for the change event. The docs say:
change Event Event Object Type:
mx.events.SliderEvent property
SliderEvent.type =
mx.events.SliderEvent.CHANGE
Dispatched when the slider changes
value due to mouse or keyboard
interaction.
I wrote my code as follows:
<mx:HSlider thumbPress="handleThumbPress(event)" change="handleUserChange(event)"
showTrackHighlight="true" buttonMode="true" useHandCursor="true" minimum="0"
maximum="{_max}" snapInterval="1" enabled="true" width="100%" id="mySlider"
liveDragging="false" showDataTip="true" verticalCenter="0" horizontalCenter="0"
trackSkin="{SliderTrack}" trackHighlightSkin="{TrackHighlightConfigurable}"
sliderThumbClass="{MySliderThumb}" thumbSkin="#Embed('../imgempty.png')"
dataTipFormatFunction="dataToolTipFormat"/>
What I observe is that my change handler, which is only supposed to be invoked in response to user interaction keeps getting invoked whenever my timer sets the value of the slider. The timer code sets the values quite simply as:
private function updateValue( newValue : Number ) : void
{
mySlider.value = newValue;
}
Am I making an obvious mistake? Is there a better way to distinguish between user versus programmatic change of Flex Slider?
Thanks.
-Raj
Change event is not fired if you change value programmatically. When you change value of thumb beyond minimum or maximum value of slider the event is fired. Event also gets fired if you change Minimum or maximum of slider. Is this happening in your code ?
You could just put a boolean wrapping when you set the value programmatically:
private var inputByUser:Boolean = false;
private function updateValue( newValue : Number ) : void
{
if (!inputByUser)
mySlider.value = newValue;
}
I don't know your exact code so I couldn't solve it explicitly, but something along those lines is what I'd do. You'd set that inputByUser in your change handler, like so:
private function changeHandler() : void
{
inputByUser = true;
updateValue(mySlider.value + 10); // however you're doing it
inputByUser = false;
}
Hope that helps,
Lance

How does one cancel/unaccept a drag-and-drop operation in Flex 3?

Goal:
Allow the user to delete a record by dragging a row from an AdvancedDataGrid, dropping it onto a trash-can icon and verify the user meant to do that via a popup alert with "OK" and "Cancel" buttons.
What is working:
Dragging/Dropping a row onto the trash icon.
If the user clicks the "OK" button, the record is deleted.
If the user clicks the "Cancel" button, the operation is canceled.
Problem:
After the user clicks the "Cancel" button and the popup alert closes, no rows in the ADG can be dragged. I've discovered that after sorting the ADG, by clicking on a column header, the user can begin dragging rows again.
Code: (changed from original post)
<mx:Image source="{trashImage}" buttonMode="true"
toolTip="drag a participant here to delete them from the project"
dragDrop="deleteParticipantDrop(event)" dragEnter="deleteParticipantEnter(event)"
dragExit="deleteParticipantDragExit(event)" top="4" right="122" id="image2" />
// trashImage Event Handlers:
private function deleteParticipantEnter(event:DragEvent):void
{
var component:IUIComponent = IUIComponent(event.currentTarget);
dragComponent = component;
DragManager.acceptDragDrop(component);
DragManager.showFeedback(DragManager.MOVE);
deleteParticipantDragEvent = event;
}
private function deleteParticipantDrop(event:DragEvent):void
{
var selectedKitNum:String = memberRpt.selectedItem.KitNum;
var selectedName:String = memberRpt.selectedItem.ParticipantName;
var component:IUIComponent = IUIComponent(event.currentTarget);
dragComponent = component;
DragManager.acceptDragDrop(component);
isEditingParticipantInfo = false;
isDeletingParticipant = true;
deleteParticipantDropEvent = event;
event.stopImmediatePropagation(); // Added as per mrm
alert.confirm("Are you sure you want to delete this participant, Kit #" + memberRpt.selectedItem.KitNum + " (" +
memberRpt.selectedItem.ParticipantName + ") from the project? This cannot be reversed!! An email will be " +
"sent to notify this participant and you will receive a copy of it for your records.", confirmRemoveParticipant);
}
private function deleteParticipantDragExit(event:DragEvent):void
{
var component:IUIComponent = IUIComponent(event.currentTarget);
dragComponent = component;
DragManager.acceptDragDrop(component);
DragManager.showFeedback(DragManager.NONE);
}
private function confirmRemoveParticipant(event:CloseEvent):void
{
if (event.detail == Alert.YES)
{
deleteReason = DeleteParticipantTitleWindow(PopUpManager.createPopUp( this, DeleteParticipantTitleWindow , true));
dispatchEvent(deleteParticipantDropEvent); // Added as per mrm
PopUpManager.centerPopUp(deleteReason);
deleteReason.showCloseButton = true;
deleteReason.title = "Reason for removal from project";
deleteReason.addEventListener("close", cleanupRemoveParticipant);
deleteReason["cancelButton"].addEventListener("click", cleanupRemoveParticipant);
deleteReason["okButton"].addEventListener("click", finalizeDeleteParticipant);
isDeletingParticipant = false;
}
else
{
cleanupRemoveParticipant();
}
}
private function cleanupRemoveParticipant(event:Event = null):void
{
memberRpt.invalidateDisplayList();
memberRpt.executeBindings();
if (deleteReason != null)
{
PopUpManager.removePopUp(deleteReason);
deleteReason = null;
}
}
public function finalizeDeleteParticipant(event:Event):void
{
if (deleteReason.reason.text != null)
{
selectedReportItem = memberRpt.selectedItem;
selectedReportItemIndex = memberRpt.selectedIndex;
memberReportData.removeItemAt(selectedReportItemIndex);
}
else
{
alert.info("You must provide a reason for removing a participant from your project!!");
}
cleanupRemoveParticipant();
}
Thanks in advance for all helpful suggestions.
Have you tried running the validateNow() method on the ADG after the cancel event?
Here is some more information on the validateNow() method.
Why you need to know about validateNow...
I really do think this is what you're looking for! Please let us know if that is the case...
Try refreshing the data bindings on the datagrid using executeBindings and/or invalidateDisplayList in the enclosing control.
To be honest this sounds a bit like a bug. Have you posted this on flexcoders? The Adobe guys hang out on there (probably here too, but definitely there)
Hang on... just spotted that between the drop event and the cancel button of the popup there is an asynchronous web service call which appears to be handled by GetParticipantOrderInformation. Is that correct?
If yes, then have you tried offering a simpler dialog for Cancel before you do that? I wonder whether the combination of layers of events is causing a problem.
I didn't have any success with refreshing the data bindings on the datagrid via the executeBindings and invalidateDisplayList methods. I also didn't have any luck by showing the confirmation alert before making the webservice call. In fact, I discovered that making the webservice call was completely unnecessary and removed it. So now the code flows like this:
Drag/drop ADG row onto trash icon.
Display confirmation Alert box.
If user clicked "Cancel" button, redisplay the ADG.
But the same problem persists. I'll update the Code section with the latest code.
Here's an idea:
- Just before you create the alert window, stop the DragEvent
event.stopImmediatePropagation();
store the event so we can resume if the user clicks the Yes button
queuedEvent = event as DragEvent;
show the alert window
if the user clicks the yes button, resume the queued event
dispatchEvent(queuedEvent);
DragManager.showFeedback(DragManager.NONE);

Resources