Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 50 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
50
Dung lượng
213,86 KB
Nội dung
170 | Chapter 8: Framework Utilities and Advanced Component Concepts You’ll notice that in this example, both data grids have dropEnabled and dragEnabled set to true. This in and of itself allows the user to copy contents from one data grid to the other. However, as shown in Example 8-8, this does not ensure the type of behavior required in this case. To achieve the move-only behavior, each data grid also listens for dragComplete events. The dragCompleteHandler( ) method handles the events by either dismissing the event if the event action is set to none, or deleting the element from the drag initiator’s data provider. Custom Drag and Drop Operations The built-in drag and drop functionality will work for many use cases. However, there are also many use cases in which you will want to employ drag and drop func- tionality not supported by the standard, built-in features of the handful of drag and drop-enabled components. For these cases, you can create custom drag and drop elements. You can create custom drag and drop elements using the events discussed in the pre- ceding section in conjunction with mx.managers.DragManager. The DragManager class has several static methods you can use to handle drag and drop functionality. The doDrag( ) method allows you to start a drag and drop operation. The doDrag( ) method requires that you specify the following parameters: the drag initiator, a DragSource object specifying the data to copy from the initiator, and the mouse event used to start the drag operation. In addition, in most cases you’ll need to pass it a ref- erence to an object to use as the drag proxy image (the object that actually drags). Before we look at an example using doDrag( ) let’s first discuss the details of working with DragSource. The DragSource object you pass to doDrag( ) is what is passed along to event handlers for drag events. This object contains data that you can use when copying, moving, or comparing. That means you should generally store whatever data you want to pass along to the drag event handlers in the DragSource object. DragSource objects allow you to save many groups of data, each with a unique key (a string value) called a format. You can use the addData( ) method to add data to a DragSource object. The first parameter is the data to store, and the second parameter is the format, which is an arbitrary string: var dragSource:DragSource = new DragSource( ); dragSource.addData(initiator.dataProvider.getItemAt(index), "item"); The DragManager class also dictates the behavior of the drag proxy image when the user moves it over the drop target and when the user drops the object. Normally the </mx:VBox> </mx:HBox> </mx:Application> Example 8-9. Using ActionScript for drag and drop behavior (continued) Drag and Drop | 171 proxy indicates that it cannot be dropped successfully by displaying a small red circle with a white X. You can remove that icon by calling DragManager.acceptDragDrop( ) and passing it a reference to the drop target on which the user can drop the object. Typically you call this method in response to a dragEnter event. Example 8-10 illustrates how to create custom drag and drop elements. This simple application uses a column of colored canvases and a grid of canvases with the same colors. The canvases from the column are draggable. When the user drops one can- vas over the other with the same color in the grid, the canvas is removed from the column, and the canvas in the grid is lowered in opacity. Example 8-10. A customized drag and drop application <?xml version="1.0"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:Script> <![CDATA[ import mx.core.DragSource; import mx.containers.Canvas; import mx.events.DragEvent; import mx.managers.DragManager; private function beginDragAndDrop(event:MouseEvent):void { var canvas:Canvas = Canvas(event.currentTarget); var dragSource:DragSource = new DragSource( ); var color:uint = canvas.getStyle("backgroundColor"); dragSource.addData(color, "backgroundColor"); var proxy:Canvas = new Canvas( ); proxy.width = 50; proxy.height = 50; proxy.setStyle("backgroundColor", color); DragManager.doDrag(canvas, dragSource, event, proxy); } private function dragEnterHandler(event:DragEvent):void { var target:Canvas = Canvas(event.currentTarget); var initiator:Canvas = Canvas(event.dragInitiator); if(matches(target, initiator)) { DragManager.acceptDragDrop(target); } } private function dragDropHandler(event:DragEvent):void { var target:Canvas = Canvas(event.currentTarget); var initiator:Canvas = Canvas(event.dragInitiator); if(matches(target, initiator)) { vbox.removeChild(initiator); target.alpha = .25; } } private function matches(a:Canvas, b:Canvas):Boolean { 172 | Chapter 8: Framework Utilities and Advanced Component Concepts Customizing List-Based Controls List-based controls such as lists, data grids, and trees have standard ways in which they display data. For example, a list displays one column of text, data grids display one or more columns of text, and trees display a hierarchical view of data. For many if not most applications, the default ways in which these controls display data are return a.getStyle("backgroundColor") == b.getStyle("backgroundColor"); } ]]> </mx:Script> <mx:HBox width="100%"> <mx:VBox id="vbox" height="100%"> <mx:Canvas width="50" height="50" backgroundColor="#00ff80" mouseDown="beginDragAndDrop(event)" /> <mx:Canvas width="50" height="50" backgroundColor="#ff8040" mouseDown="beginDragAndDrop(event)" /> <mx:Canvas width="50" height="50" backgroundColor="#80ffff" mouseDown="beginDragAndDrop(event)" /> <mx:Canvas width="50" height="50" backgroundColor="#ffff80" mouseDown="beginDragAndDrop(event)" /> </mx:VBox> <mx:VRule height="213"/> <mx:Grid> <mx:GridRow width="100%" height="100%"> <mx:GridItem width="100%" height="100%"> <mx:Canvas width="50" height="50" backgroundColor="#00ff80" dragEnter="dragEnterHandler(event)" dragDrop="dragDropHandler(event)" /> </mx:GridItem> <mx:GridItem width="100%" height="100%"> <mx:Canvas width="50" height="50" backgroundColor="#ff8040" dragEnter="dragEnterHandler(event)" dragDrop="dragDropHandler(event)" /> </mx:GridItem> </mx:GridRow> <mx:GridRow width="100%" height="100%"> <mx:GridItem width="100%" height="100%"> <mx:Canvas width="50" height="50" backgroundColor="#80ffff" dragEnter="dragEnterHandler(event)" dragDrop="dragDropHandler(event)" /> </mx:GridItem> <mx:GridItem width="100%" height="100%"> <mx:Canvas width="50" height="50" backgroundColor="#ffff80" dragEnter="dragEnterHandler(event)" dragDrop="dragDropHandler(event)" /> </mx:GridItem> </mx:GridRow> </mx:Grid> </mx:HBox> </mx:Application> Example 8-10. A customized drag and drop application (continued) Customizing List-Based Controls | 173 perfectly sufficient. However, there are cases in which you need to alter the displays in one way or another. For example, you may want to display a checkbox in a data grid column rather than standard text. When you want to customize the way in which a list-based component displays ele- ments, you can use what is called an item renderer. Item renderers allow you to spec- ify what component to use in place of the standard text or text and icon that appear in the component, thus customizing the appearance of the elements in the compo- nent. The following components support custom item renderers: List, HorizontalList, DataGrid, Menu, TileList, and Tree. There are two basic ways to use custom item renderers: Drop-in item renderers These are the simplest types of item renderers to implement. With a drop-in item renderer, you simply specify a standard UI component to use in a particu- lar column. For example, you can use a checkbox as a drop-in item renderer. Inline item renderers These types of item renderers are still rather simple to implement, but they allow you to exert more control over the component. For example, with a drop-in item renderer, you cannot specify the property settings for the component, but with an inline item renderer you can. You can use standard or custom components as item renderers with either of these approaches. Drop-In Item Renderers Drop-in item renderers are extremely simple to implement. All you need to do is set the itemRenderer property of the component for which you want to customize the item views. The itemRenderer property should be a reference to a component class you want to use. For example, the following creates a list component that uses a date field component for each item: <mx:Script> <![CDATA[ import mx.collections.ArrayCollection; [Bindable] private var dataSet:ArrayCollection = new ArrayCollection([new Date(2010, 1, 1), new Date(2010, 4, 15)]); ]]> </mx:Script> <mx:List itemRenderer="mx.controls.DateField" dataProvider="{dataSet}" /> The results of this are shown in Figure 8-1. 174 | Chapter 8: Framework Utilities and Advanced Component Concepts All the list-based components that allow you to use item renderers allow you to set the itemRenderer property for the component itself, except in the case of the data grid, which requires that you set the itemRenderer property at the column level. Example 8-11 sets one of the columns of a data grid to display a checkbox. Figure 8-1. A date field used as an item renderer in a list component Example 8-11. Using a drop-in item renderer <?xml version="1.0"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:VBox> <mx:DataGrid editable="false"> <mx:columns> <mx:DataGridColumn headerText="Song Title" dataField="title"/> <mx:DataGridColumn headerText="Artist" dataField="artist"/> <mx:DataGridColumn headerText="In Favorites" dataField="inFavorites" itemRenderer="mx.controls.CheckBox" /> </mx:columns> <mx:dataProvider> <mx:ArrayCollection> <mx:Array> <mx:Object songId="0" title="Astronaut" artist="David Byrne" rating="5" inFavorites="true" /> <mx:Object songId="1" title="Rio" artist="Duran Duran" rating="3" /> <mx:Object songId="2" title="Enjoy the Silence" artist="Depeche Mode" rating="4" /> <mx:Object songId="3" title="Mesopotamia" artist="B-52s" rating="5" inFavorites="true" /> </mx:Array> </mx:ArrayCollection> </mx:dataProvider> </mx:DataGrid> </mx:VBox> </mx:Application> Customizing List-Based Controls | 175 Drop-in item renderers are ideal when you want to use a simple type of item ren- derer. However, they have several major limitations: • You can use only a handful of standard UI components as drop-in item render- ers. Those components you can use are listed in Table 8-2. • The data value for an item always corresponds to one property of the item ren- derer. In other words, a list-based component is a view for the data model assigned to the dataProvider property. For example, the item value is always assigned to the value of a numeric stepper used as an item renderer. You cannot specify that the item value should be assigned to the maximum property of the numeric stepper. • You cannot customize the components used as item renderers. Inline Item Renderers Although drop-in item renderers are extremely simple to implement, they are also quite limited in terms of how you can configure them. For instance, in Example 8-11 you can display the checkbox in the data grid columns, but you cannot change any of the properties of the components used as item renderers. Inline item renderers are a slight step up from drop-in item renderers in that you can configure the settings of the component used as the item renderer. For example, you can use an inline item renderer to set the enabled property of the checkbox to dis- able it so that the user cannot check or uncheck the box. Inline item renderers require that you specify the itemRenderer value using nested MXML tags rather than attributes. You must then nest within the itemRenderer tag a Component tag with a nested tag to create the type of component you want to use as an item renderer. Example 8-12 specifies the checkbox item renderer as an inline item renderer. It also applies a label to the checkbox, and it disables the checkbox so that the user cannot select or deselect it. Table 8-2. Drop-in components Component Property set by the item value Button selected CheckBox selected DateField selectedDate Image source Label text NumericStepper value Text text TextArea text TextInput text 176 | Chapter 8: Framework Utilities and Advanced Component Concepts The Component tag is a powerful MXML tag. It creates an entirely new scope within the MXML document. The code within the Component tag is essentially an MXML component, and the rules that apply to MXML components generally apply to the code within the Component tag. You can have just one root node, and within that root node you can use Style, Script, and all standard MXML tags used in an MXML component document. Because the Component tag creates its own scope, you don’t have to worry about conflicts within the Component tag and the document within which the Component tag exists. However, this also means that you cannot reference data from the MXML document within the Component tag. For example, the follow- ing will cause a compile error: <mx:Script> <![CDATA[ private var maximumCount:uint = 5; ]]> </mx:Script> <mx:List> <mx:itemRenderer> Example 8-12. Using inline item renderers <?xml version="1.0"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:VBox> <mx:DataGrid editable="false"> <mx:columns> <mx:DataGridColumn headerText="Song Title" dataField="title"/> <mx:DataGridColumn headerText="Artist" dataField="artist"/> <mx:DataGridColumn headerText="In Favorites" dataField="inFavorites"> <mx:itemRenderer> <mx:Component> <mx:CheckBox label="Song in favorites" enabled="false" /> </mx:Component> </mx:itemRenderer> </mx:DataGridColumn> </mx:columns> <mx:dataProvider> <mx:ArrayCollection> <mx:Array> <mx:Object songId="0" title="Astronaut" artist="David Byrne" rating="5" inFavorites="true" /> <mx:Object songId="1" title="Rio" artist="Duran Duran" rating="3" /> <mx:Object songId="2" title="Enjoy the Silence" artist="Depeche Mode" rating="4" /> <mx:Object songId="3" title="Mesopotamia" artist="B-52s" rating="5" inFavorites="true" /> </mx:Array> </mx:ArrayCollection> </mx:dataProvider> </mx:DataGrid> </mx:VBox> </mx:Application> Customizing List-Based Controls | 177 <mx:Component> <mx:NumericStepper maximum="{maximumCount}" /> </mx:Component> </mx:itemRenderer> </mx:List> The error occurs because maximumCount is defined in the MXML document, but it is referenced within the Component tag, which has a different scope. Although the Component tag is powerful, we strongly recommend that you use it only to the extent illustrated by Example 8-12 which sets the label and enabled properties of the checkbox. If you need to create more sophisticated item renderers, it is far bet- ter to define them as MXML or ActionScript components. We’ll look at how to do that in the next section. You can use a property called outerDocument within a Component tag to reference the MXML document containing the Component tag. You can then reference any public or internal properties, as in the following example: <?xml version="1.0"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:Script> <![CDATA[ internal var maximumCount:uint = 5; ]]> </mx:Script> <mx:List> <mx:itemRenderer> <mx:Component> <mx:NumericStepper maximum= "{outerDocument.maximumCount}" /> </mx:Component> </mx:itemRenderer> </mx:List> </mx:Application> However, while this is possible, it is generally not recommended because it is much clearer to break out sophisticated item renderers into new custom components, as discussed next. Custom Components as Item Renderers In order to exert the most control over item renderers you can use a custom compo- nent. Using a custom component (either MXML or ActionScript) you can create extremely sophisticated item renderers. For example, you can create an item ren- derer that displays a rating using colored shapes, as we’ll do in this section. A component must implement certain interfaces to work as an item renderer. There are three basic interfaces for item renderers: IListItemRenderer, IDropInListItemRenderer, and IDataRenderer. All item renderers must implement 178 | Chapter 8: Framework Utilities and Advanced Component Concepts IListItemRenderer and IDataRenderer. Because IListItemRenderer extends IDataRenderer, you simply need to implement IListItemRenderer in most cases. The IListItemRenderer interface requires many getter/setter methods and public meth- ods, and the best way to implement the interface is simply to extend a class that already implements the interface. The following classes already implement the inter- face: Button, ComboBox, Container, DataGridItemRenderer, DateField, Image, Label, ListBase, ListItemRenderer, MenuBarItem, MenuItemRenderer, NumericStepper, TextArea, TextInput, TileListItemRenderer, and TreeItemRenderer. Because Container implements the interface, you can extend any type of container. The IDataRenderer interface requires that the implementing class defines a data get- ter and setter of type Object. The data setter is automatically called every time the data provider is updated and the item renderer needs to update. The data setter is always passed the data provider element corresponding to the item. For example, in a data grid the data is the object representing the row. Even though your custom item renderer component is likely to inherit the data implementation, you’ll gener- ally want to override that implementation. Example 8-13 is saved in an MXML document called Rating.mxml, and it draws five squares using 10-by-10 canvases. The squares are blue by default, and they are col- ored red if they are activated by the value of the rating property from the data passed to the component. Notice that this component overrides the data getter and setter. The setter retrieves the rating value, and it draws the canvases with the appropriate colors based on the rating value. Example 8-13. A custom component for use as an item renderer <?xml version="1.0" encoding="utf-8"?> <mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:Script> <![CDATA[ import mx.containers.Canvas; private var _data:Object; override public function set data(value:Object):void { _data = value; var rating:uint = uint(value.rating); removeAllChildren( ); var canvas:Canvas; for(var i:uint = 0; i < 5; i++) { canvas = new Canvas( ); canvas.setStyle("backgroundColor", i < rating ? 0xFF0000 : 0x0000FF); canvas.width = 10; canvas.height = 10; addChild(canvas); } Customizing List-Based Controls | 179 The MXML application document in Example 8-14 uses the custom component as an item renderer in a data grid using drop-in syntax. Note that if the item renderer MXML or ActionScript class is in a package, you would specify the fully qualified path to the MXML doc- ument or class in the itemRenderer property value. } override public function get data( ):Object { return _data; } ]]> </mx:Script> </mx:HBox> Example 8-14. Using a custom component as an item renderer <?xml version="1.0"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:VBox> <mx:DataGrid editable="false"> <mx:columns> <mx:DataGridColumn headerText="Song Title" dataField="title"/> <mx:DataGridColumn headerText="Artist" dataField="artist"/> <mx:DataGridColumn headerText="Rating" dataField="rating" itemRenderer="Rating" /> </mx:columns> <mx:dataProvider> <mx:ArrayCollection> <mx:Array> <mx:Object songId="0" title="Astronaut" artist="David Byrne" rating="5" inFavorites="true" /> <mx:Object songId="1" title="Rio" artist="Duran Duran" rating="3" /> <mx:Object songId="2" title="Enjoy the Silence" artist="Depeche Mode" rating="4" /> <mx:Object songId="3" title="Mesopotamia" artist="B-52s" rating="5" inFavorites="true" /> </mx:Array> </mx:ArrayCollection> </mx:dataProvider> </mx:DataGrid> </mx:VBox> </mx:Application> Example 8-13. A custom component for use as an item renderer (continued) [...]... width= "20 0" labelField="rating"> 1 82 | Chapter 8: Framework Utilities and Advanced Component Concepts Example 8-16 Using a custom item editor (continued) "20 0" labelField="rating" itemEditor="mx.controls.NumericStepper" editorDataField="value"> . width=" ;50 " height=" ;50 " backgroundColor="#00ff80" mouseDown="beginDragAndDrop(event)" /> <mx:Canvas width=" ;50 " height=" ;50 " backgroundColor="#ff8040" mouseDown="beginDragAndDrop(event)". width=" ;50 " height=" ;50 " backgroundColor="#80ffff" mouseDown="beginDragAndDrop(event)" /> <mx:Canvas width=" ;50 " height=" ;50 " backgroundColor="#ffff80" mouseDown="beginDragAndDrop(event)". initiator)) { vbox.removeChild(initiator); target.alpha = . 25 ; } } private function matches(a:Canvas, b:Canvas):Boolean { 1 72 | Chapter 8: Framework Utilities and Advanced Component Concepts Customizing