I'm trying to modifty the Flex Tree control to allow a user to select multiple items by just clicking each of the desired elements (ie I don't want them to have to press Ctrl or Shift). If the user clicks a selected item a 2nd time, it will deselect it. Can anyone help me out?
Thanks!
I just had to do this with a datagrid, since they are both based on list it will work for you too
How can I get a datagrid to behave like the ctrl key is active?
You can create a simple custom component of ur own. Here is the code:
package com
{
import flash.events.MouseEvent;
import mx.controls.Tree;
public class ForceCtrlTree extends Tree
{
override protected function mouseClickHandler(event:MouseEvent):void
{
event.ctrlKey = true;
super.mouseClickHandler(event);
}
override protected function mouseDownHandler(event:MouseEvent):void
{
event.ctrlKey = true;
super.mouseDownHandler(event);
}
}
}
Import this package into your project.
Then declare the tree component as follows:
Now you need not click ctrl to select multiple objects.
Related
I need to implement multi character type ahead functionality on a DropDownList. Im using spark components Flex 4.5.1.
I wish the long list to for example if I type bl
It will go to Blue not to the first B then the first L
Its a common requirement and all browsers now support it, hope its something that already exists or someone has customized a version.
Why wouldn't you use the Flex Spark ComboBox, which has the type ahead feature built right in?
You can probably customize one of the many autocompletes. I posted the following snippet in another question on how to do an autocomplete.
package autoCompleteExample
{
import mx.collections.ICollectionView;
import mx.collections.IList;
import spark.components.ComboBox;
import spark.events.TextOperationEvent;
public class AutoCompleteExample extends ComboBox
{
override protected function textInput_changeHandler(event:TextOperationEvent):void{
super.textInput_changeHandler(event);
ICollectionView(dataProvider).refresh();
}
override public function set dataProvider(value:IList):void{
ICollectionView(value).filterFunction = defaultFilterFunction;
super.dataProvider = value;
}
private function defaultFilterFunction(item:Object):Boolean{
return (textInput.text.toLowerCase() == String(item[labelField].toLowerCase()).substr( 0, textInput.text.length ));
}
}
}
You can probably just change the text operation handler to select the first item AFTER the refresh. Not sure how well it would work.
I have a custom class that extends List which I am using as a container. However, the scroll speed is too fast on the mouse wheel, as in it scrolls loads even if you only move the wheel a tiny bit. I tried adding an event listener to my list for MouseEvent.MOUSE_WHEEL and setting the value of event.delta but this has had no effect. Does anyone know how I can make it slower?
My custom class is nothing special, I just created it so I could have a different itemRenders for different item types. It looks like:
public class MultipleRenderersList extends List
{
override public function createItemRenderer(data:Object):IListItemRenderer
{
if (data is IRenderable)
{
return data.getDiaryRenderer();
}
else if (data is Array)
{
if (data.length > 0)
{
if (data[0] is IRenderable)
{
return data[0].getDiaryRenderer(data);
}
}
}
return null;
}
}
The List class has a mouseWheelHandler function that you can override. Just override the function, update the delta property of the mouseevent, and call super. This example will quarter the delta, reducing the speed substantially:
package
{
import flash.events.Event;
import flash.events.MouseEvent;
import mx.controls.Alert;
import mx.controls.List;
public class MyList extends List
{
override protected function mouseWheelHandler(event:MouseEvent):void {
event.delta = event.delta/4;
super.mouseWheelHandler(event);
}
}
}
However, in many cases the scroll speed / delta will be driven off of a system preference, so doing this may cause unexpected behavior for some users. The reason that adding the handler and updating the delta failed to work is that by that point mouseWheelHandler had already been called.
A very simple way to modify this is to change the verticalLineScrollSize property. This is a property of all containers and it defaults to 5. (for flex 3)
Actually, what HandOfCode said isn't relevant here. Because he made the same mistake as i did, which is to think that a List component or TileList component are containers. They aren't. So, they don't have verticalLineScrollSize property.
Sean solution is the only one that worked for my case. I would add that event.delta may have a positive or negative value depending of the direction of the wheel action. So you better do something like this if you plan to scroll, for example one line at a time :
override protected function mouseWheelHandler(event:MouseEvent):void
{
event.delta = (event.delta > 0) ? 1:-1;
super.mouseWheelHandler(event);
}
I want my data grid to behave by default as if the user is holding the control key down. So when an item is clicked, then another item they are both part of the selection, clicking them again removes them from the selection.
I already have allowMultipleSelection = true but I can't seem to find any setting that does this. I'm working on the itemclick event in the meantime, but it seems like there might be an easy to use setting I'm missing.
Any thoughts?
You could also extend DataGrid and override the selectItem method like so:
override protected function selectItem(item:IListItemRenderer, shiftKey:Boolean, ctrlKey:Boolean, transition:Boolean = true):Boolean
{
return super.selectItem(item, shiftKey, true, transition )
}
Less code and less likely to have impact on other elements that might be listening for that MouseEvent.
You could try adding event listeners to the grid for MouseEvents (UP and/or DOWN) with the highest priority, stopping propagation, and redispatching a new MouseEvent with the same properties on the original event.target but this time with ctrlKey=true.
I'm not sure if it'll cause 10,000 other things to break.
I tried Nalandial's idea but had no luck...can't really intercept those events, but it got me going in the right direction. Worked a lot on this then found that the solution was a lot simpler than I was making it. I just needed to extend the dataGrid class and override two functions (mouseDownHandler and mouseClickHandler) adding the ctrlKey = true there then calling the rest of the function workes perfectly. In case you want to implement it, here's the code:
package com{
import flash.events.MouseEvent;
import mx.controls.DataGrid;
public class ForceCtrlDataGrid extends DataGrid{
public function ForceCtrlDataGrid(){
super();
}
override protected function mouseClickHandler(event:MouseEvent):void{
event.ctrlKey = true;
super.mouseClickHandler(event);
}
override protected function mouseDownHandler(event:MouseEvent):void{
event.ctrlKey = true;
super.mouseDownHandler(event);
}
}
}
I have a List component that has drop-in CheckBox itemEditor that also serves as the itemRenderer. It displays each item as a simple CheckBox with a label.
However, the itemEditEnd Event does not get triggered until I click on something outside of the List. I want it triggered once the CheckBox is checked or unchecked.
I was thinking of manually dispatching the ListEvent.ITEM_EDIT_END in a CLICK Event handler, but then the itemEditEnd Event would get dispatched twice. There's gotta be a better way to do this.
Any ideas?
Thanks.
Here is the solution I came up with. I changed my List to use the component as an itemRenderer only, not as a itemRenderer and itemEditor. I then added a MouseEvent.CLICK handler to call a function in the List from the itemRenderer to perform the necessary actions:
My List Component:
package
{
import mx.controls.List;
import mx.core.ClassFactory;
public class CustomCheckBoxList extends List
{
public function CustomCheckBoxList()
{
super();
itemRenderer = new ClassFactory(CheckBoxRenderer);
}
public function dispatchSelectionEvent(item:Object, selected:Boolean):void
{
// Take action here...
}
}
}
My ItemRenderer:
package
{
import flash.events.MouseEvent;
import mx.controls.CheckBox;
public class CheckBoxRenderer extends CheckBox
{
public function CheckBoxRenderer()
{
super();
}
override protected function clickHandler(event:MouseEvent):void
{
super.clickHandler(event);
CustomCheckBoxList(listData.owner).dispatchSelectionEvent(data, selected);
}
}
}
I've just run into this. I'm using a custom component rather than the drop-in approach, and this works when using the renderer as the editor.
Note that the Flex folks evidently came up with the notion that users would want to toggle their checkboxes a few times before settling on the state to commit to...at which point they'd hit the Enter key. How obvious!
My solution is to synthesize a keyboard event that is equivalent to hitting Enter. The tricky part is that one must use the callLater() method to dispatch the event because the list control won't have registered its keyboard listener on the editor until after the checkbox's click handler gets called. Here's my click handler for the checkbox in my custom renderer/editor component:
private function onClick(value:Object):void {
newValue = value;
var list:ListBase = ListBase(owner);
list.callLater(dispatchEvent, [new KeyboardEvent(KeyboardEvent.KEY_DOWN, true, false, Keyboard.ENTER, Keyboard.ENTER)]);
}
I have a button bar inf flex along with several other input controls, I have set the tabIndex property for each control and all goes well until I tab to the ButtonBar.
The ButtonBar has 3 buttons but tabbing to it, only the first button gets focus, tab again and the focus goes back to the top control...
How can I make tabbing go through ALL buttons in a Flex Button bar? Is there a way to do this or do I need to create individual buttons for this?
This seems like a possible bug to me...
The component is written so the user must press the left/right arrow keys when focus is within the bar to traverse the buttons--this is a fairly standard GUI behavior (you also see this in other places like radio button groups). If you look into the SDK source for ButtonBar, you can see where they've explicitly disabled tab focus for each child button as it's created:
override protected function createNavItem(
label:String,
icon:Class = null):IFlexDisplayObject
{
var newButton:Button = Button(navItemFactory.newInstance());
// Set tabEnabled to false so individual buttons don't get focus.
newButton.focusEnabled = false;
...
If you really want to change this behavior, you can make a subclass to do it, something like this:
package {
import mx.controls.Button;
import mx.controls.ButtonBar;
import mx.core.IFlexDisplayObject;
public class FocusableButtonBar extends ButtonBar {
public function FocusableButtonBar()
{
super();
this.focusEnabled = false;
}
override protected function createNavItem(
label:String, icon:Class=null):IFlexDisplayObject
{
var btn:Button = Button(super.createNavItem(label, icon));
btn.focusEnabled = true;
return btn;
}
}
}