There is an entry on this blog that answers questions like “How do I put check boxes inside a datagrid?” and “How do I enable multiple check box selections?”, which is one of the popular entries on this blog. The entry is in Japanese, but I recently found out in an English forum that they seem to be universal questions. Thinking the entry might help a few more people, I tried some web page translation tools on the entry, but I couldn’t figure out any of what I was trying to say by reading the translated stuff, so I decided to translate the entry into English myself.
Well, so much for the introductory remarks. Here it is.
Data manipulation is a basic aspect of business applications, so it is probably safe to assume that a GUI-providing programming language has functions and components that deal with data manipulation like listing, sorting, etc. ActionScript 3.0 does, too.
In this entry, I will explain how to put check boxes in such data lists by adding few functions to code samples in Adobe’s online documents. Let’s assume that you are making a course registration application. By using the method explained in this entry, you can change the status of multiple students in one step by ticking multiple check boxes. Some components allow you to select multiple lines by clicking on them while holding down the Ctrl key, but if you think that method is not so user-friendly, then check boxes may be the solution.
Data manipulation components are commonly made with a pattern using a data grid, a data provider and a renderer. ActionScript 3.0 uses the same pattern, and provides
fl.controls.DataGrid that displays data in a grid of rows and columns, fl.data.DataProvider that provides data to a DataGrid, and fl.controls.listClasses.CellRenderer that tells the grid how to display the provided data. By default ActionScript 3.0 provides a CellRenderer class that displays the data in text.
To change one of the columns in a DataGrid to display a check box, 1) you make a new class that inherits the fl.controls.CheckBox class and implements the fl.controls.listClasses.ICellRenderer interface, and 2) specify the new class in the cellRenderer property of the subject column. The details are explained in the “Define a custom CellRenderer class” section of “Work with a CellRenderer” page on the ActionScript 3.0 Components manual. However, the code listed on this page results in an error, so for a samples code, the one listed in the comments section on fl.controls.dataGridClasses.DataGridCell is much more useful. If you are making a CellRenderer class for the very first time, I’d recommend you to just try this sample code first. This sample code is hereafter referred to as “the sample code” in this entry.
One point that I found inconvenient with the sample code was that each check box represents the selection status of a line in the grid. So, let’s take a step forward and make the check boxes independent of the selection status by going through the modifications that need to be made to the sample code.
First, we modify the function set selected()
. In the sample code, the CheckBox’s status is set here, which presents two problems:
- This method is called when a line in the DataGrid is selected, so the status of a CheckBox always reflects the selection status of the containing row in the DataGrid; i.e a CheckBox is ticked when a row is selected, making it not appropriate for applications like shopping carts and the aforementioned course registration program. Instead, it should toggle its status when you click on it.
- This method is not called when the DataGrid is first displayed, so the cell values are not reflected to the CheckBox status, making the CheckBox unchecked by default no matter what the cell value is. It is only when a row is clicked (selected) that a cell value is reflected to the corresponding CheckBox.
In order to solve these problems, a part of the logic in set selected()
is moved to functions set listData()
and toggleSelected()
both of which will be described later. The line that sets the _rowSelected
attribute remains in set selected()
so that visual attributes of the DataGrid object (e.g. colors) can be changed when a row is selected.
|
override public function set selected(value:Boolean):void { _rowSelected = value; } |
To solve problem #1, we will modify the function toggleSelected()
, for which the sample code says “don’t set selected or dispatch change event”, but for the above mentioned reasons, the selected
attribute is set here. (Please note that this is only a suggestion, so please use this at your own risk. For the rest of the usual caveats, please read our “Terms of Use”.)
|
override protected function toggleSelected(event:MouseEvent):void { var dg:DataGrid = this.parent.parent.parent as DataGrid; var fName:String = dg.getColumnAt(_listData.column).dataField; var newStatus:Boolean = (_data[fName] == true || _data[fName] == "true" || _data[fName] == 1); super.selected = _data[fName] = newStatus; } |
Now we have a CheckBox that behaves like a CheckBox; i.e. if you click on it it toggles its check mark status regardless of the selection status of the DataGrid.
In order to solve problem #2, we will take a look at set listData()
. set listData()
is called 1) when a DataProvider is set to a DataGrid, and 2) when something is changed in a DataGrid (when DataGrid.selectable = true
). We are taking advantage of the former timing, so we are moving the logic that had been implemented in set selected()
down here.
|
public function set listData(ld:ListData):void { _listData = ld; var dg:DataGrid = this.parent.parent.parent as DataGrid; var fName:String = dg.getColumnAt(_listData.column).dataField; var newStatus:Boolean = (_data[fName] == true || _data[fName] == "true" || _data[fName] == 1); super.selected = newStatus; } |
By implementing this, a CheckBox will appropriately reflect the cell value when a DataGrid is filled with values specified in a DataProvider.
By setting the newly implemented CellRenderer to a column in a DataGrid, you will start seeing check boxes instead of “true” and “false” strings.
You can use the CellRenderer like this, but if your application handles ListEvent.ITEM_CLICK events, there is one more modification to make, which is to stop CheckBox’s CLICK events to be transformed to ListEvent.ITEM_CLICKED events, because we are making check boxes that behave independently of DataGrid’s selection status, and clicking on a check box does not mean selecting the corresponding row in a DataGrid.
|
public function CheckBoxCellRenderer() { super(); this.addEventListener(MouseEvent.CLICK, handleClick, false, 0, true); } private function handleClick(ev:Event):void { ev.stopImmediatePropagation(); } |
So, there you have it – a Checkbox in a DataGrid that behaves like a CheckBox!
A few last comments — This code is one implementation method that I derived after much trial and error, which is listed here for your reference. Please read our “Terms of Use” before using the code.
This code is being used in application that we develop, and is subject for future modifications and bug fixes.