247 3 6MB
English Pages 720 [723] Year 2007
Professional
Adobe®Flex 2 TM
Rich Tretola Simon Barber Renaun Erickson
Professional
Adobe®Flex 2 TM
Professional
Adobe®Flex 2 TM
Rich Tretola Simon Barber Renaun Erickson
Professional Adobe®Flex 2 TM
Published by Wiley Publishing, Inc. 10475 Crosspoint Boulevard Indianapolis, IN 46256 www.wiley.com Copyright © 2007 by Wiley Publishing, Inc., Indianapolis, Indiana Published simultaneously in Canada ISBN: 978-0-470- 10267-1 Manufactured in the United States of America 10 9 8 7 6 5 4 3 2 1 Library of Congress Cataloging-in-Publication Data Tretola, Rich, 1971Professional Adobe Flex 2 / Rich Tretola, Simon Barber, Renaun Erickson. p. cm. Includes index. ISBN 978-0-470-10267-1 (pbk.) 1. Internet programming. 2. Application software--Development. 3. Web site development--Computer programs. 4. Flex (Computer file) I. Barber, Simon, 1980- II. Erickson, Renaun, 1977- III. Title. IV. Title: Professional Adobe Flex Two. QA76.625.T74 2007 005.2'768--dc22 2007008855 No part of this publication may be reproduced, stored in a retrieval system or transmitted in any form or by any means, electronic, mechanical, photocopying, recording, scanning or otherwise, except as permitted under Sections 107 or 108 of the 1976 United States Copyright Act, without either the prior written permission of the Publisher, or authorization through payment of the appropriate per-copy fee to the Copyright Clearance Center, 222 Rosewood Drive, Danvers, MA 01923, (978) 750-8400, fax (978) 646-8600. Requests to the Publisher for permission should be addressed to the Legal Department, Wiley Publishing, Inc., 10475 Crosspoint Blvd., Indianapolis, IN 46256, (317) 572-3447, fax (317) 572-4355, or online at http://www.wiley.com/go/permissions. LIMIT OF LIABILITY/DISCLAIMER OF WARRANTY: THE PUBLISHER AND THE AUTHOR MAKE NO REPRESENTATIONS OR WARRANTIES WITH RESPECT TO THE ACCURACY OR COMPLETENESS OF THE CONTENTS OF THIS WORK AND SPECIFICALLY DISCLAIM ALL WARRANTIES, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE. NO WARRANTY MAY BE CREATED OR EXTENDED BY SALES OR PROMOTIONAL MATERIALS. THE ADVICE AND STRATEGIES CONTAINED HEREIN MAY NOT BE SUITABLE FOR EVERY SITUATION. THIS WORK IS SOLD WITH THE UNDERSTANDING THAT THE PUBLISHER IS NOT ENGAGED IN RENDERING LEGAL, ACCOUNTING, OR OTHER PROFESSIONAL SERVICES. IF PROFESSIONAL ASSISTANCE IS REQUIRED, THE SERVICES OF A COMPETENT PROFESSIONAL PERSON SHOULD BE SOUGHT. NEITHER THE PUBLISHER NOR THE AUTHOR SHALL BE LIABLE FOR DAMAGES ARISING HEREFROM. THE FACT THAT AN ORGANIZATION OR WEBSITE IS REFERRED TO IN THIS WORK AS A CITATION AND/OR A POTENTIAL SOURCE OF FURTHER INFORMATION DOES NOT MEAN THAT THE AUTHOR OR THE PUBLISHER ENDORSES THE INFORMATION THE ORGANIZATION OR WEBSITE MAY PROVIDE OR RECOMMENDATIONS IT MAY MAKE. FURTHER, READERS SHOULD BE AWARE THAT INTERNET WEBSITES LISTED IN THIS WORK MAY HAVE CHANGED OR DISAPPEARED BETWEEN WHEN THIS WORK WAS WRITTEN AND WHEN IT IS READ. For general information on our other products and services please contact our Customer Care Department within the United States at (800) 762-2974, outside the United States at (317) 572-3993 or fax (317) 572-4002. Trademarks: Wiley, the Wiley logo, Wrox, the Wrox logo, Programmer to Programmer, and related trade dress are trademarks or registered trademarks of John Wiley & Sons, Inc. and/or its affiliates, in the United States and other countries, and may not be used without written permission. Microsoft and Excel are registered trademarks of Microsoft Corporation in the United States and/or other countries. All other trademarks are the property of their respective owners. Wiley Publishing, Inc., is not associated with any product or vendor mentioned in this book. Wiley also publishes its books in a variety of electronic formats. Some content that appears in print may not be available in electronic books.
To the love of my life, Kim, and my beautiful daughters, Skye and Coral. — Rich Tretola The work on this book is dedicated to my family and friends, most notably Phil, Tina, Joanna, and Kimberley. — Simon Barber The book for Einar and Ranel, my love to Eve and the boys. — Renaun Erickson
Credits Contributing Writers
Production Manager
Marco Casario Marc Leuchner Andrew Muller
Tim Tate
Vice President and Executive Group Publisher Richard Swadley
Executive Editor Chris Webb
Vice President and Executive Publisher Joseph B. Wikert
Development Editor Kevin Shafer
Compositor Laurie Stewart, Happenstance Type-O-Rama
Technical Editors Charles Freedman Andy McIntosh Drew McLean Clint Modien Josh Tynjala
Project Coordinator
Production Editor
Indexer
Christine O’Connor
Robert Swanson
Copy Editor
Anniversary Logo Design
Kim Cofer
Richard Pacifico
Editorial Manager Mary Beth Wakefield
Hether Kolter
Proofreader James Brook, Word One
Acknowledgments This book would not have been possible without the hard work of my co-authors Simon and Renaun, and I want to thank them both for their contributions. I would also like to thank the Acquisitions Editor, Chris Webb, and the Development Editor, Kevin Shafer, for their commitment to getting the project completed through many challenges. Special thanks to the members of the Internet Services team at Herff Jones, including Michael McKellip, Jeff Titus, Bill Davis, Tim Johnson, Rob Schimp, Brent Johnson, and my manager, Jeff Patrick. The support of these team members and management has enabled me to transition my development career to be focused on Rich Internet Application development. Most importantly, I would thank my wife, Kim. She has given me two beautiful daughters, Skye and Coral, and is my best friend. Without her support, it would not have been possible for me to transform my career path to software development. She has supported me through good times and bad, and has always believed in me, and for this I am eternally grateful. Aloha no au ia 'oe. — Rich Tretola Thank you to my co-authors, Rich and Renaun; without you this would never have been possible. Also, I would like to thank Chris Webb, the Acquisition Editor, for all his hard work in making this book a success. Many thanks go out to my family, co-workers, and friends, without whom this would not have been possible. — Simon Barber I would like to first thank Chris Webb for helping me become a part of this project. I would like to thank Rich and Simon for the opportunity to contribute as an author on the project. All the hard work of the editor Kevin Shafer and other technical editors is an experience I’ll never forget — thank you. — Renaun Erickson
Contents Acknowledgments Introduction
ix xxvii
Part I: Getting Started
1
Chapter 1: Introducing Flex 2.0
3
Rich Internet Applications OpenLaszlo Ajax XUL Windows Presentation Foundation History of RIA Benefits of RIA
Overview of Flex Flex 2 Flash Player 9 Flex Builder 2 Flex Free SDK 2 Flex Data Services (FDS) Flex Charting
Summary
Chapter 2: Introducing Flex Builder 2.0 Flex Builder 2.0 Eclipse Standalone and Plugin Creating a Flex Project Flex Builder Perspectives The Development Perspective Source Mode The Development Perspective Design Mode The Debugging Perspective Debugging Your Application Starting the Debugger
Compiling Your Application Running Your Application Summary
3 3 4 4 4 4 4
5 5 5 6 6 7 8
8
9 10 10 14 14 15 19 19 22
23 24 24
Contents Chapter 3: Flex 2.0 Basics
25
Flex 2 Programming Model
25
MXML ActionScript Flex Class Library
Flex Charting Components
25 27 30
31
Charting Types
31
Flex Data Services
32
Data Management Service Messaging Service Publish-Subscribe Messaging Data Push RPC Services FDS Alternatives
Summary
Chapter 4: Using Flex Builder 2.0
32 33 33 34 34 34
34
35
Getting Started with Flex Builder
35
Learning Flex Builder Flex Builder Workbench Basics
36 40
Flex Builder Basics Working with Projects Running Applications Navigating and Customizing the Flex Builder Workbench
Developing with Design Mode Building a Flex User Interface Adding View States and Transitions Adding Interactivity with Behaviors
Programming Flex Applications Code Editing in Flex Builder
Summary
44 44 50 52
54 54 56 56
57 57
58
Part II: Developing in Flex 2.0
59
Chapter 5: Programming Languages
61
Developing MXML Applications UI Layout Using Containers UI Controls XML Namespaces
xii
61 61 63 63
Contents Data Binding with Components RPC Services Data Validation Data Formatting Cascading Style Sheet (CSS) Skins Adding Effects Custom MXML Components
MXML Basic MXML Syntax MXML Naming Conventions
ActionScript Flex Components Separating ActionScript from MXML Developing ActionScript Components Performing Reflection
Handling Events Event Flow Event Class EventDispatcher Class Event Usage Propagation Priorities Subclassing Events Keyboard Events
Summary
Chapter 6: Building User Interfaces Visual Components Class Hierarchy UIComponent Class Component Sizing Event Handling Styling Components Adding Behaviors Applying Skins Modifying Components at Run-time Extending Components
Data Providers and Collections Data Providers Collections
64 65 67 68 69 70 72 73
74 74 74
75 75 78 79 80
84 84 85 85 86 88 90 91 92
93
95 95 95 96 97 98 101 103 104 104 105
106 106 109
xiii
Contents IList Interface ICollectionView Collection Change Events Hierarchical Data Providers Remote Data Providers
111 112 115 117 119
Positioning and Sizing Components
120
Layout of Components Component Sizing Component Positioning and Layout Constraint-based Layout
120 121 122 123
Getting Familiar with Flex Controls Summary
124 125
Chapter 7: Customizing the User Interface Applying Behaviors Using Behaviors
Applying Styles Using Styles Using Local, Application, and Global Selectors
Applying Fonts Device Fonts Embedded Fonts FlashType Fonts
Skinning the Application Graphical Skins Programmatic Skins
Item Renderers Building Custom Item Renderers and Item Editors
Item Editors Overview of Cell Editing Process Editable Cell Returning Data from an Item Editor Sizing and Positioning an Item Editor Cell Editing Events
Tooltips Creating Tooltips ToolTipManager Class
Cursor Manager Adding and Removing Cursors Busy Cursor
Summary
xiv
127 127 128
131 132 133
134 134 135 136
140 140 141
143 144
147 147 147 148 148 149
152 153 155
157 157 158
159
Contents Chapter 8: Flex UI Topics Repeaters and Containers Using the Repeater Component Repeater Component Execution Process
Using View States Using Transitions Transitions Applied to View States Transition Event Handling Transition Action Effects Effects and Filters
Using the Drag-and-Drop Manager List Control Drag-and-Drop Functions Adding Drag-and-Drop Support to Other Components
Embedding Assets Images Fonts SWF and Sound Files
Using the History Manager Components with Built-in History Management Adding History Management to Components
Flex Printing Basic Printing Printing Multiple Pages Printing Grid Data
Communicating with the Wrapper Flex to JavaScript, JavaScript to Flex Verifying that JavaScript Has Loaded
Working with Shared Objects Saving and Reloading Data from Shared Objects
Designing Accessible Applications Enabling Accessibility in Your Application Components with Built-in Accessibility Customizing Your Components for Accessibility
Summary
Chapter 9: Flex Data Data Binding Using Binding to Variables with [Bindable] Binding Directly to Component Properties Data Modeling with Flex
161 161 161 162
165 167 167 169 170 170
171 171 172
175 175 176 176
177 177 177
180 181 181 182
183 183 185
187 187
189 189 189 189
190
191 191 191 192 193 194
xv
Contents A Basic Data Model Using an External XML File Binding a Data Model to a Custom Component Binding Data to a Data Model
Validating Data Flex Built-in Validators Validating a Data Model Simple Data Validation Using errorString Testing Validation Events Validating with ActionScript
Formatting Data Flex Built-in Formatters Formatter Errors
Summary
Chapter 10: Flex Charting Flex Chart Examples Area Chart Bar Chart Bubble Chart Column Chart Line Chart Pie Chart Plot Chart Candlestick Chart HighLowOpenClose (HLOC) Chart
Charting Classes
194 195 196 198
200 200 201 203 204 207
208 208 210
211
213 213 215 216 218 220 222 223 225 226 228
229
Axis Label Axis Title Axis Renderer Grid Lines Axis Types ChartItem ChartItemEvent Hit Data Legend
229 230 230 231 231 232 232 232 232
Advanced Charting
232
Chart Events Drill-Down Charts Mixed Series Types
232 234 236
xvi
Contents Multiple-Axis Charts Axis Rotation
Charting Effects SeriesInterpolate SeriesSlide SeriesZoom
237 239
240 240 240 240
Chart Style Examples Summary
241 244
Chapter 11: Data Access
245
Server-side Data
245
Flex Data Access RPC Services Data Management Service Messaging Service
245 246 247 248
Data Services Configuration
248
Service Configuration Files Message Channels Data Serialization Destinations and Security Configuring Logging Software Clustering Custom Error Handling
248 249 250 258 259 261 262
RPC Service Components
263
Defining RPC Components Calling a Service and Handling Results
263 264
RPC Services Configuration
265
Destination Configuration Destination Properties
265 266
Flex Messaging
267
The Basics of Flex Messaging Flex Messaging Architecture Producer Components Consumer Components
267 268 269 272
Message Service Configuration
274
Message Service Configuration Message Service Destination Configuration Building a Custom Message Service Adapter
Data Management Services Data Management Service vs. RPC Features
274 275 277
278 278
xvii
Contents Data Management Service Data Flow Data Synchronization Conflicts
Distributed Data Distributed Data Application Class Mappings Data Synchronization Handling
Data Management Service Configuration Data Management Service Destination Configuration Data Push from Servers to Client
Summary
Part III: Creating and Extending Flex Components Chapter 12: Creating MXML Components Creating Simple MXML Components Scoping Your Components Styling Your Components Advanced MXML Components Adding Custom Properties and Methods to a Component
279 279
280 280 281 283
284 284 286
286
287 289 289 291 292 293 293
Creating Composite Components Template Components
295 297
Creating a Template Component Using a Template Component
297 298
MXML Interfaces Creating Interfaces Using Interfaces
Using IMXMLObject Summary
Chapter 13: Flex Component Properties Elements of a Component The package Statement import Statements Defining the Class Name The Default Constructor Defining Properties Defining Methods Overriding Methods Using super
xviii
302 302 302
303 304
305 305 305 306 306 306 307 309 311
Contents Creating a Simple ActionScript Component Implementing and Overriding UIComponent Methods Creating Advanced Components in ActionScript Summary
313 314 315 318
Chapter 14: Flex Components
319
Custom Events in Components
319
Dispatching Custom Events
Using Metadata Tags in Components [ArrayElementType] [Bindable] [DefaultProperty] [Embed] [Event] [Effect] [IconFile] [Inspectable] [InstanceType] [NonCommittingChangeEvent] [RemoteClass] [Style]
Compiling Components Compiling Components with Flex SDK Compiling Components with Flex Builder Deploying Components
Summary
Chapter 15: Custom Formatter, Validator, and Effect Components Custom Formatters Customizing the SwitchSymbolFormatter Class Extending the Formatter Class Custom Formatter Example Formatter Errors
Custom Validators Creating Effects Extending the Effect Class Extending the EffectInstance Class Custom Effect Example Extending the TweenEffect Class
319
321 321 321 324 324 325 326 327 327 328 328 330 330
332 332 332 338
340
341 341 341 344 345 346
347 349 349 350 350 353
xix
Contents Extending the TweenEffectInstance Class Custom TweenEffect Example Custom Effect Triggers
Summary
Part IV: Programming ActionScript 3.0 Chapter 16: Overview of ActionScript Programming Introduction to ActionScript What’s New in ActionScript 3.0 Compatibility with Previous Versions
Getting Started with ActionScript ActionScript 3.0 Is More than Flex ActionScript 3.0 Coding Considerations Running ActionScript Applications
Display Programming Understanding the Display Architecture Working with Display Objects Using the Core Display Classes
Summary
Chapter 17: Data Types and Classes Value Types Primitive Data Types Complex Data Types
Dates and Times Creating Calendar Dates and Times Retrieving Time Values by Unit Date Manipulation
Strings Length Property Characters in Strings String Comparison Obtaining String Representations of Objects Concatenation Patterns and Substrings Uppercase and Lowercase Conversion
Arrays Index Arrays
xx
353 354 357
359
361 363 363 364 366
367 367 372 373
374 374 376 381
387
389 389 390 390
391 391 392 393
395 395 395 396 396 397 397 399
399 399
Contents Associative Arrays Multidimensional Arrays Cloning Arrays
Error Handling Error Types Custom Error Classes Exception Handling
Regular Expressions Regular Expressions and Strings Using the RegExp Class Using Groups
XML Introduction to XML E4X Introduction E4X Classes
Summary
Part V: Building and Deploying Flex 2.0 Applications Chapter 18: Building and Deploying Flex Applications Flex Framework and Application Directory Structure Flex and Flash Player Security and Technology Concerns Network Security Concerns Open Technology Concerns Flash Player Security Features
Building and Deploying Applications Building for Flex 2 SDK Building for Flex Data Services 2 Compiling an Application Deployment Directory Structure
Applying Flex Security Flex Security Features
403 407 408
408 408 411 414
415 415 416 417
418 418 420 420
426
427 429 429 432 432 433 434
435 436 437 439 442
445 445
Improving Startup Performance
447
Startup Order Using Deferred Creation Deferring Component Creation Using Ordered Creation Using the callLater() Method
447 449 452 455 458
Summary
460
xxi
Contents Chapter 19: Debugging and Testing Logging Overview
461 461
Flash Debug Player Logging API Compiler Logging Web-tier Logging
462 463 464 464
Client-side Logging
464
Using the Logging API Custom Logger
Flex Builder Debugging Tools Invoking Configuring Breakpoints and Stepping
465 465
471 472 472 475
Command-line Debugger
475
Invoking Configuring Debugger Commands
475 476 477
Summary
Chapter 20: Deploying Flex Applications Deployment Considerations Server-side and Client-side Caching Deployment Options RSL Deployment Flash Player Sandbox and Cross-Domain Consideration
Deploying a Flex 2 SDK Application that Uses RSL Compiling for Deployment Troubleshooting Tips and Common Deployment Problems
478
479 479 481 485 485 487
488 493 497
Asset and Dependent Files Run-time Data Access Proxy Server Accessing Server-side Resources from Different Domains
497 498 498 499
Deploying a Flex Data Service Application Under Tomcat Configuring for FDS Creating a Wrapper
500 506 508
Migrating and Transferring Files Defining Features mxmlc Compiler
xxii
509 510 511
Contents Adding Features to the Wrapper Creating a Wrapper that Supports Web Standards and
512 514 518
Using Express Install Editing Your Wrapper Configuring Express Install on Flex Data Services Upgrading Without Express Install Summary
520 521 525 526 527
Part VI: Advanced Flex 2.0 Chapter 21: Using the Cairngorm Framework
529 531
The Cairngorm Framework Understanding Frameworks
531 532
Application Frameworks Architectural Frameworks
532 532
Building an Application Using the Cairngorm Framework Value Object and Model Locator Pattern The View The Front Controller, Cairngorm Event Broadcaster, and Command Patterns Business Delegate and Service Locator
Summary
Chapter 22: Using the Flex-Ajax Bridge Why Use Flex with JavaScript? Requirements for the FA Bridge Memory-Consumption Issues Flex-Ajax Bridge Samples Using Flex Validators from JavaScript Create Flex Components Using JavaScript
Summary
Chapter 23: Using the ActionScript 3.0 Libraries Types of Libraries How to Include the SWC in Your Application Building a Simple Application Using One of the Libraries Summary
533 534 537 541 545
547
549 549 550 551 551 551 555
559
561 562 562 565 571
xxiii
Contents Chapter 24: Using ColdFusion/Flex Connectivity Using the Flash Remoting Update Using the Flex Messaging Event Gateway The Structure of Messages
Using the ColdFusion Event Gateway Adapter Using the Flex Data Service Assembler Configuring ColdFusion Value Object CFC EmployeeAssembler.cfc The DAO.cfc
ColdFusion Extensions for Flex Builder 2 Eclipse RDS Support Plugin Installation Create CFC Wizard ActionScript to CFC Wizard CFC to ActionScript Wizard Services Browser
Summary
Part VII: Integration Techniques Chapter 25: Rich Media Integration Integration Audio Video Using the Camera
Building an Application with Rich Media Integration The Inner Workings of the Application
Summary
Chapter 26: Integration with External Applications Using the External API
573 573 583 585
587 591 591 594 595 596
597 597 601 604 605 605 606
606
607 609 610 610 610 612
613 617
620
621 621
AVM1 and AVM2 SWF Communication
622
ExternalInterface and LocalConnection Building Custom Tracing Utility
625 626
Flash Player Process Structure Using LocalConnection and C# .NET Windows Application
Summary
xxiv
626 627
641
Contents Appendix A: Flex 2.0.1
643
Run-time CSS Support ASDoc Tool
643 647
ASDoc Tags and Syntax Documenting the Logger Classes Using the ASDoc Compiler Documenting the Logger Classes – Continued
647 648 649 650
Building Modular Flex Applications Summary
657 663
Index
665
xxv
Introduction The Flex product line was originally released by Macromedia in 2003, then followed up by Flex 1.5, and now Flex 2 by Adobe in 2006. Flex 2 marks a milestone for the Rich Internet Applications (RIAs) development community because it has developed into a mature product with excellent development tools and resources. Although previous versions were expensive and targeted large corporations, this has changed with Flex 2 because the new pricing model puts the power of Flex into the hands of all developers and companies for as little as free. Developers worldwide rejoiced when Adobe announced that it would be releasing portions of Flex at no charge, as well as a very reasonably priced development environment for those who choose to use it. Flex applications run within the Flash Player, which is the single-most downloaded piece of software in the history of the Internet. Because so many people already have the Flash Player and the Flash Player is so easily upgraded, Flex applications being built today will be available to run on a large section of the population’s computers. There is a growing wave of excitement around Flex, and we find ourselves in the early stages of a revolution of the Internet. Flex will play a large part in reshaping the Internet from the 1990s into a new, richer, more interactive Internet, sometimes referred to as Web 2.0. A great opportunity exists to make your mark on Web 2.0 by using Flex technologies, and this book will help you get there.
Who This Book Is For If you have been using Flex since its version 1 release (or you are someone who is starting with Flex), this book will provide valuable information for handling just about any possible request during the development of your applications. It will also prove itself to be an invaluable resource as a reference manual. The examples provided throughout this book are concise and very easy to understand. Code samples within this book have been carefully written so that they can be easily applied to real-world applications. If you are someone who wants to start building Flex applications (or is already doing so), this book will help you take your applications to a higher level.
What This Book Covers This book covers all aspects of Flex 2, including the Software Development Kit (SDK), Flex Data Services (FDS), Flex Builder 2 Integrated Development Environment (IDE), Flex Charting, and much more. You will learn about MXML (which is a tag-based programming language), as well as ActionScript 3 (which is the companion scripting language), and where to use each. This book will also show you how to use Flex components and how to create your own custom components. You will see how to structure your applications with frameworks and best practices.
Introduction
How This Book Is Str uctured This book has been broken down into seven sections, each covering specific areas of Flex. These sections are as follows: ❑
Getting Started — This section introduces Flex and Flex Builder. It covers some of the Flex basics and demonstrates how to use Flex Builder.
❑
Developing in Flex 2.0 — This section focuses on building user interfaces, customizing those interfaces, accessing data from your Flex application, and Flex charting components.
❑
Creating and Extending Flex Components — This section shows you how to create components using both MXML and ActionScript, as well as how to customize them.
❑
Programming ActionScript 3.0 — This section discusses programming and data typing ActionScript classes.
❑
Building and Deploying Flex 2.0 Applications — This section focuses on building, debugging, and deploying Flex applications. It also covers the configuration of the integrated JRun server.
❑
Advanced Flex 2.0 — This section discusses the usage of the Cairngorm Framework, the Flex-Ajax Bridge, ActionScript 3.0 libraries, and ColdFusion/Flex connectivity.
❑
Flex 2.0 Integration Techniques — The last section covers integration with rich media and external applications.
Appendix A also includes an overview of Flex 2.0.1, and discusses what is new with this updated release of Flex 2.
What You Need to Use This Book Although all of the examples in this book were created using the Windows operating system, almost all will also run perfectly on the other operating systems supported by Adobe. For the best results, you should use Flex Builder to compile the examples in the book. However, if you are a non-GUI kind of person, you can certainly compile them using the free Flex SDK.
Conventions To help you get the most from the text and keep track of what’s happening, a number of conventions have been used throughout the book.
Boxes like this one hold important, not-to-be forgotten information that is directly relevant to the surrounding text.
Tips, hints, tricks, and asides to the current discussion are offset like this.
xxviii
Introduction As for styles in the text: ❑
Important new terms and important words are highlighted when they are introduced.
❑
Keyboard strokes are shown like this: Ctrl+A.
❑
Filenames, URLs, and code within the text are shown like this: persistence.properties.
❑
Code is presented in the following two ways:
In code examples, new and important code is highlighted with a gray background. The gray highlighting is not used for code that’s less important in the present context, or has been shown before.
Source Code As you work through the examples in this book, you may choose either to type in all the code manually, or use the source code files that accompany the book. All of the source code used in this book is available for download at http://www.wrox.com. Once at the site, simply locate the book’s title (either by using the Search box or by using one of the title lists), and click the Download Code link on the book’s detail page to obtain all the source code for the book. Because many books have similar titles, you may find it easiest to search by ISBN; for this book the ISBN is 978-0-470-10267-1. Once you download the code, just decompress it with your favorite compression tool. Alternatively, you can go to the main Wrox code download page at http://www.wrox.com/dynamic/books/download .aspx to see the code available for this book and all other Wrox books.
Errata We make every effort to ensure that there are no errors in the text or in the code. However, no one is perfect, and mistakes do occur. If you find an error in one of our books (such as a spelling mistake or faulty piece of code), we would be very grateful for your feedback. By sending in errata you may save another reader hours of frustration and at the same time you will be helping us provide even higher quality information. To find the errata page for this book, go to http://www.wrox.com and locate the title using the Search box or one of the title lists. Then, on the book details page, click the Book Errata link. On this page, you can view all errata that has been submitted for this book and posted by Wrox editors. A complete book list including links to each book’s errata is also available at www.wrox.com/miscpages/booklist.shtml.
If you don’t spot “your” error on the Book Errata page, go to www.wrox.com/contact/techsupport .shtml and complete the form there to send us the error you have found. We’ll check the information and, if appropriate, post a message to the book’s errata page and fix the problem in subsequent editions of the book.
xxix
Introduction
p2p.wrox.com For author and peer discussion, join the P2P forums at p2p.wrox.com. The forums are a Web-based system for you to post messages relating to Wrox books and related technologies and to interact with other readers and technology users. The forums offer a subscription feature to email you topics of interest of your choosing when new posts are made to the forums. Wrox authors, editors, other industry experts, and your fellow readers are present on these forums. At http://p2p.wrox.com you will find a number of different forums that will help you not only as you read this book, but also as you develop your own applications. To join the forums, just follow these steps:
1. 2. 3.
Go to p2p.wrox.com and click the Register link.
4.
You will receive an e-mail with information describing how to verify your account and complete the joining process.
Read the terms of use and click Agree. Complete the required information to join, as well as any optional information you wish to provide, and click Submit.
You can read messages in the forums without joining P2P, but in order to post your own messages, you must join. Once you join, you can post new messages and respond to messages other users post. You can read messages at any time on the Web. If you would like to have new messages from a particular forum e-mailed to you, click the Subscribe to this Forum icon by the forum name in the forum listing. For more information about how to use the Wrox P2P, be sure to read the P2P FAQs for answers to questions about how the forum software works, as well as many common questions specific to P2P and Wrox books. To read the FAQs, click the FAQ link on any P2P page.
xxx
Part I: Getting Started Chapter 1: Introducing Flex 2.0 Chapter 2: Introducing Flex Builder 2.0 Chapter 3: Flex 2.0 Basics Chapter 4: Using Flex Builder 2.0
Introducing Flex 2.0 Flex 2.0 is arguably the most important new Internet development tool set released to date. It will help speed the migration of the Internet to the Web 2.0 that we have been promised for so long now. Not only has Adobe introduced an extremely easy-to-use development environment in Flex Builder 2.0, but it has also released an SDK allowing for Flex Rich Internet Applications to be developed with absolutely no fees. So what are Rich Internet Applications? Let’s start with a definition.
Rich Internet Applications A Rich Internet Application (RIA) is an application that runs in the traditional browser but utilizes an intermediate layer that can bypass the traditional page refresh that has been a standard of most current Web applications. The most common tools that can achieve this intermediate layer include JavaScript used in Asynchronous JavaScript and XML (Ajax) applications, as well as Flex or Flash using the Flash Player. Other RIA solutions include OpenLaszlo (which utilizes the Flash Player as well as Ajax), XUL (which is dependent on a Mozilla-compatible browser), and the Windows Presentation Foundation (which is part of the Microsoft .NET Framework 3.0).
OpenLaszlo Like Flex, OpenLaszlo can compile to SWF and, because it is open source, it is also free for developers to use. OpenLaszlo applications are built using JavaScript, as well as an Extensible Markup Language (XML) based programming language named LZX, and compiled to SWF. It is very similar to Flex, and because it was available for free, it garnered a larger amount of attention during the days of Flex 1.5. Because OpenLaszlo compiles to SWF, it enjoys the same write-once-run-anywhere feature that is synonymous with Flex and Flash applications. The one advantage to OpenLaszlo over Flex is that the next version of OpenLaszlo (code-named legals) will allow write-once-and-compile to either an SWF or a dynamic HTML (DHTML), or Ajax, application. The major disadvantages of OpenLaszlo are that it has a smaller set of built-in components than Flex, and it has always been at least one full version behind in optimization for the most current Flash Player.
Part I: Getting Started
Ajax Ajax is a combination of HTML or Extensible HTML (XHTML), Cascading Style Sheets (CSS), and JavaScript to create an application-type feel from a standard Web page request. CSS and JavaScript can be used to trigger updates to the visual aspect of the page, and XMLHttpRequests can be used to fetch data in the background of the page. The combination of these techniques allows a single Web page to change its appearance and update its data without any additional page requests from the server. There are many limitations to this type of RIA, including compatibility issues with browser versions, as well as differences in (or lack of) JavaScript support necessary for the RIA to perform as expected.
XUL XML User Interface Language (XUL) is an XML-based language developed by the Mozilla project. It is a tag-based language that contains many predefined widgets (buttons, radio buttons, and so on) that will be rendered only by a Mozilla-compatible browser such as Firefox. Although it can also be used in the creation of RIAs, XUL has been most widely used in the creation of Mozilla applications and extensions.
Windows Presentation Foundation Windows Presentation Foundation (WPF) consists of an engine and a framework that will be preinstalled in Windows Vista, and introduces Extensible Application Markup Language (XAML) as a new tag-based language. XAML is very similar to MXML because it is a tag-based XML language with attributes whereby each tag creates an object model class. XAML tags are fully extendable, allowing developers to create custom classes. XAML, along with C# (which is the programming language), would correspond to MXML and ActionScript 3 in Adobe Flex. WPF is used for both traditional desktop applications and browser-based RIAs. With Microsoft’s backing, WPF and XAML are sure to make a large contribution to Web 2.0 and RIA. Microsoft has stated that it will also introduce Windows Presentation Server Everywhere (WPF/E), which will provide support for other browsers and platforms. One major advantage of WPF is that it will support three dimensions out of the box, which is something that has been lacking in the Flash Player. A disadvantage of WPF is that it does not run within the Flash Player, and it will be a long time before Microsoft can expect the same penetration of its runtime as the Flash Player.
History of RIA Although the concept of a Web application that performs more in line with the traditional desktop application has been around for years, RIAs were first introduced by Macromedia in March 2002.
Benefits of RIA RIAs offer many benefits over traditional Web applications. Following are a few of the many advantages of RIAs:
4
❑
RIAs offer a richer interface that provides a more engaging user experience without the need for page reloads.
❑
RIAs offer real-time feedback and validation to the user, triggered by user events.
Chapter 1: Introducing Flex 2.0 ❑
The look and feel of a traditional desktop application can be accomplished with an RIA.
❑
RIAs also can include a full multimedia experience, including audio and video.
❑
RIAs have capabilities such as real-time chat and collaboration that are either very difficult or simply impossible with traditional Web applications.
Over view of Flex Flex was developed to create a development environment that more closely resembled the traditional development environment utilized by other programming languages. The goal was to take the already tremendously successful Flash visual development environment and open it up to programmers who are more comfortable with a code-based model. In 2004, Macromedia released Flex 1.0, which caused a buzz in the world of RIAs because it was the first time that it was possible to compile Flash SWF files from code. In 2005, Flex 1.5 was released, which was a big improvement over Flex 1.0 and included many new features. A few of the notable new features included new charting components, updates to the datagrid component, and new component-skinning techniques for more control over the look and feel of Flex 1.5 applications. Flex 1.5 was very successful, but was still targeted to the mid- to large-size company, and it was priced that way. For smaller companies and developers, Flex 1.5 was simply out of reach because of Macromedia’s pricing model. In 2006, Adobe released Flex 2.0 and announced that it was now possible to create and distribute Flex 2.0 applications absolutely free. This has created a large influx of developers into the Flex community, and shows tremendous growth potential.
Flex 2 Flex 2 is a tremendous upgrade over its predecessor. It includes a new version of the MXML tag-based language, as well as a new version of ActionScript. Adobe has built the Flex 2 Framework to be fully extendable, allowing developers to create custom components that extend or combine base components using either MXML or ActionScript 3. Flex 2 is built to run within the all-new Flash 9 Player, which in itself includes huge performance increases over previous versions. Flex 2 includes a new development environment built on the Open Source Eclipse integrated development environment (IDE) named Flex Builder 2, the free Flex 2 SDK, as well as the new Flex Data Services (FDS) application server. Flex 2 also offers a new set of charting components that are not part of the basic free versions of the Flex SDK but can be purchased separately or as part of a Flex Builder package.
Flash Player 9 In May 1996, a small company named FutureWave Software released a product that it called FutureSplash Animator. FutureSplash was released as a browser extension using the new plug-in API from Netscape. Ironically, FutureWave attempted to sell its technology to Adobe, but at the time, Adobe wasn’t interested. Macromedia was interested in FutureSplash, and, in December 1996, acquired FutureWave Software. Macromedia renamed FutureSplash as Flash Player 1.0.
5
Part I: Getting Started Following is a timeline of key events in this history of the Flash player: ❑
1997 — FutureSplash is renamed and released as Macromedia Flash 1.0.
❑
1997 — Flash 2 adds buttons, the Library, sound support, and color tweens.
❑
1998 — Flash 3 adds new animations and alpha transparency.
❑
1999 — Flash 4 adds MP3 audion streaming and motion tweens.
❑
1999 — 100-millionth download of the Flash Player.
❑
2000 — Flash 5 adds ActionScript 1.
❑
2000 — Flash Player installs reach the 92 percent penetration mark.
❑
2002 — Flash Player 6 adds support for Flash remoting, Web services, video, shared libraries, and components.
❑
2003 — Flash Player 7 introduces ActionScript 2.0 and streaming audio and video.
❑
2005 — Flash Player 8 adds filter effects, GIF and PNG images, bitmap caching, new video codec (On2 VP6), file upload and downloading, and FlashType.
❑
2006 — Flash Player 9 is released and introduces ActionScript 3, E4X XML parsing, regular expressions, and binary sockets.
The introduction of Flash Player 9 in 2006 represents the most significant release of any Flash Player to date. The incorporation of ActionScript 3 brings true object-oriented programming to Flex 2 and the upcoming Flash 9 authoring tool. Flash Player 9 boasts performance increases of up to ten times over Flash Player 8. Flash Player 9 is based on the ECMAScript standard and adds new features, including ECMAScript for XML (E4X), regular expressions, a standardized event model, and binary sockets. Flash Player 9 also includes better memory utilization, improved application initiation speed, as well as improvements in the debugger and error reporting.
Flex Builder 2 Flex Builder 2 is the new development tool that (although it is not necessary for Flex development because any text editor can be used) offers the most complete development environment for rapidly creating Flex applications. Because Flex Builder 2 has been built on top of the mature Eclipse IDE, it will be very familiar to developers who have already been developing software in other languages using Eclipse as their tool of choice. Eclipse is a development environment that was built with extendability in mind, and this can also work to the benefit of Flex developers because it can be customized to suit the needs of the Flex developer. Chapter 2 provides a more comprehensive look into Flex Builder 2.
Flex Free SDK 2 The Flex Software Development Kit (SDK) is a free download from Adobe and includes the Flex framework (component class library), compiler, and debugger. Using the text editor of your choice, you can create the ActionScript and MXML files for your application, and then compile to SWF using the SDK. The SDK allows for data communication via Web services, HTTP services, and Flash remoting with ColdFusion as the back-end server.
6
Chapter 1: Introducing Flex 2.0
Flex Data Services (FDS) FDS is the server version of Flex that must be installed under any Java 2 Enterprise Edition (J2EE) server. FDS is essentially the next generation of Flex 1.5, which was sold only as a server. As well as a full commercial edition, the FDS server is available in an Express edition, which is free and available for commercial use (but is limited to one CPU without clustering). FDS is made up of several components and capabilities, including the following: ❑
Flex Messaging Services (FMS)
❑
Publish-subscribe messaging
❑
Data push
❑
RPC services
Flex Messaging Services FMS is one of the pieces that make up FDS, and it allows for the creation of applications that support real-time messaging, as well as collaboration. The messaging service has support for Java Message Service (JMS), as well as other existing messaging services, allowing for the creation of cross-platform chat applications.
Publish-Subscribe Messaging FMS uses the producer/consumer publish-subscribe metaphor, which allows for the creation of co-browsing applications. To understand what is meant by a co-browser application, imagine a company’s customer service representative being able to make edits to a form on the user’s screen in real time while the user watches.
Data Push Data push is the capability for the server to push data changes to the client without any user interaction or polling of the servers. This can be critical when an application has hundreds or thousands of users connected, and they can all see changes to business-critical data in real time. This is a feature that is available only when using the FDS server.
RPC Services Remote procedure call (RPC) services are the suite of services used to connect to external data. They include the following: ❑
WebService — The WebService component can be used to access any Web service that complies
with the WSDL 1.1 standard and returns data formatted as Simple Object Access Protocol (SOAP) messages over HTTP. ❑
HTTPService — The HTTPService component can send HTTP GET, POST, HEAD, OPTIONS, PUT, TRACE, or DELETE requests. It does not support multipart requests.
❑
RemoteObjects — The RemoteObject component uses Action Message Format (AMF) to
transfer data that is a binary format and is the fastest of the RPC services. It is an ideal way to interact with server-side Java objects that are within the FDS server’s source path. It can also be
7
Part I: Getting Started used to connect to local or even remote ColdFusion servers. Both Java objects and ColdFusion components can be mapped to ActionScript objects, allowing for seamless integration between the server-side and client-side objects. The WebService and HTTPService components are included for free with the Flex SDK, whereas the RemoteObject component is available only for use with the FDS server (Commercial or Free Express Edition) or ColdFusion 7.02.
Flex Charting The Flex charting components are a set of rich charting components that enable easy development of professional dashboard and business intelligence (BI) systems. The charting components are sold as a stand-alone product or bundled with Flex Builder 2. A free trial of the charting components is available from Adobe. You can learn more about the charting components in Chapter 10.
Summar y This chapter defined RIA and gave some examples of the benefits of RIA, as well as the software options available for creating RIAs. It also provided an overview of Flex and its history, as well as the pieces that make up Flex. Most of the information on Flex covered in this chapter is covered in more depth later in this book. Chapter 2 introduces the all-new Flex Builder 2 built on top of Eclipse.
8
Introducing Flex Builder 2.0 One of the most significant pieces of the new Flex 2 product family is the all-new Flex Builder 2. The original Flex Builder was built on top of Dreamweaver, and, to put it bluntly, the community was not shy about letting Macromedia (now Adobe) know just how bad Flex Builder 1 actually was. Fortunately for the Flex development community, Macromedia acknowledged this, decided to scrap it completely, and started over using Eclipse as the base for Flex Builder 2. Flex Builder 2 is light years ahead of the original, and most developers now use it as the tool of choice for doing Flex MXML and ActionScript development. Most modern systems will not have any problems running Flex Builder 2. Following are the official requirements from Adobe for Flex Builder on Windows: ❑
Intel Pentium 4 processor
❑
Microsoft Windows XP with Service Pack 2, Windows XP Professional, Windows 2000 Server, Windows 2000 Pro, or Windows Server 2003
❑
512MB of RAM (1GB recommended)
❑
300MB of available hard-disk space
❑
Java Virtual Machine: Sun JRE 1.4.2, Sun JRE 1.5, IBM JRE 1.4.2
Following are the official requirements for Mac (as of this writing, the Mac version is still in beta): ❑
PowerPC or Mactel (1GHz or greater)
❑
Mac OS X 10.4.7
❑
1GB of RAM recommended
❑
300MB of available hard-disk space
❑
Java Virtual Machine: Sun JRE 1.5
❑
Eclipse 3.2 (plugin configuration only)
Part I: Getting Started
Flex Builder 2.0 Eclipse Standalone and Plugin Flex Builder 2 is available in two different distributions. The standalone version operates exactly the same as the plugin version, but is a lighter-weight application. The standalone version runs on top of a strippeddown version of Eclipse, which makes it a smaller install and a smaller memory footprint. However, for those who have already been using the full version of Eclipse for other development (such as Java, ColdFusion, and so on), Flex Builder comes as a plugin that installs into Eclipse, just like the many other Eclipse plugins. If you are using the Eclipse standalone version with a previous ActionScript plugin, it is recommended that you uninstall it before installing the Flex 2 plugin to avoid any conflicts with file associations.
Creating a Flex Project To create a Flex project, simply choose New and then Flex Project from the File menu, as shown in Figure 2-1.
Figure 2-1: Creating a new Flex project
10
Chapter 2: Introducing Flex Builder 2.0 Choose the way you want your application to access data and how it should be compiled, as shown in Figure 2-2. Selecting Basic will automatically compile your application each time you save a file within Flex Builder. If you choose Flex Data Services (FDS) as your method for accessing data, you also have the option to compile your application using the FDS server at run-time. Next, as shown in Figure 2-3, enter a project name and either browse to a location or choose the default location for your project file storage.
Figure 2-2: Selecting the type of project
Figure 2-3: Defining the storage location of project files
11
Part I: Getting Started Next, you will need to name the main file for your application. Figure 2-4 shows this step with the main application file being named Index.mxml. Note that you should not name the main file of your application the same as an existing component or a component you intend to build. This could create bizarre, non-verbose conflicts in the project. At this point, you can switch to the Library Path tab to add SWC libraries to your project. You can also choose to add SWC files to your project after it has been created. Choose either the Add SWC Folder or Add SWC button to add the library to the project (Figure 2-5). To add a library to an existing project, simply right-click the project name within the Navigator window and choose Properties. Next, select Flex Build Path and then choose the Library Path tab (Figure 2-5). Choose either the Add SWC Folder or Add SWC button to add the library to the project. For more information on SWC files, see Chapter 14.
Figure 2-4: Naming the main application file
12
Chapter 2: Introducing Flex Builder 2.0
Figure 2-5: Adding a library during project creation
Figure 2-6: Adding a library to an existing project
13
Part I: Getting Started
Flex Builder Perspectives Flex Builder has multiple perspectives. A perspective defines a set of editors and view panels that are useful to the task at hand. For example, Flex Builder will switch to a different perspective if you are debugging an application. Switching to a perspective will alter the views and editors that show within the Eclipse application. Switching perspectives will happen automatically in some situations. The default perspective is the Development perspective, and it includes a Source mode (Figure 2-7) and a Design mode. The other perspective is the Debugging perspective.
Figure 2-7: The Development perspective in Source mode
The Development Perspective Source Mode The Source mode is a basic code editor that will include code hints, code completion, syntax coloring, and real-time error reporting for both MXML and ActionScript code. Figure 2-8 shows the Development perspective with the Outline view of the Source mode enabled. The Outline view shows the hierarchy of your MXML code when editing an MXML file, or the properties and methods of your class files when editing an ActionScript class. Either way, you can go directly to a line of code by clicking the entry in the Outline views.
14
Chapter 2: Introducing Flex Builder 2.0
Figure 2-8: Outline view of Development perspective in Source mode
The Development Perspective Design Mode As shown in Figure 2-9, switching to the Design mode makes available two panels on the right-side screen: the States panel and Components panel. The Editor panel located in the middle of the screen changes to become a visual editor, allowing the drag-and-drop positioning of components, as well as drag-and-drop of components from the Components panel. The States panel allows you to create new states that can be designed visually as well. For more information on how to use states, see Chapter 8. Note that you cannot switch to Design mode when editing an ActionScript file. It is only available for editing MXML files. Note that, by default, the Components panel appears in the same pane as the Outline view on the left of the screen, and the States and Properties appear on the right. Another part of Design mode, the Properties view, has multiple sections, as well as the following property view options: ❑
Standard property view options — There are three separate sections within the Standard view of the Properties view: ❑
Common section — This allows for editing of the component properties, as shown in Figure 2-10.
15
Part I: Getting Started
Figure 2-9: The Development perspective in Design mode
Figure 2-10: The Common section of the Properties view
16
Chapter 2: Introducing Flex Builder 2.0 ❑
Style section — As shown in Figure 2-11, this makes use of color selectors, sliders, combo boxes, and buttons to allow for easy editing of the selected component’s style properties. The changes are reflected in real time within the design editor.
❑
Layout section — This is the area where you make changes to layout properties, including width and height when working in directional layouts. It also includes x, y, and the layout constraints when working within an absolute layout. Use the checkboxes within the constraint options section to anchor the selected component to one or more corners of the parent container. Figure 2-12 shows the Layout section with a component anchored to the bottom-right corner of the parent container. Any changes made will be reflected in the design editor in real time.
❑
Category property view options — The Category view shown in Figure 2-13 is a tree layout of the available properties. They can be edited by updating the text fields next to each property. Some of the text fields will include visual editors to make editing of colors and known property options easier.
❑
Alphabetical property view options — As shown in Figure 2-14, the Alphabetical view includes all of the same properties shown in the Category view, but in a simple alphabetical list, rather than a tree layout.
To use the Properties view to make changes to your components, simply click a component within the design editor, which will update the Properties panel to show the options available for the selected component.
Figure 2-11: The Style section of the Properties view
17
Part I: Getting Started
Figure 2-12: The Layout section of the Properties view (note that the controls shown will not be available if the application is not using absolute layout)
Figure 2-13: The Category view of the Properties view
18
Chapter 2: Introducing Flex Builder 2.0
Figure 2-14: The Alphabetical view of the Properties view
The Debugging Perspective Switching to the Debugging perspective allows you to run the Flex debugger, set breakpoints, watch variables, and step through your code. To switch to the debugging perspective, simply choose Flex Debugging perspective from the perspectives menu at the top-right corner of the editor, as shown in Figure 2-15. The Flex Debugging perspective will not be available as shown in Figure 2-15, unless it has been opened at least once before. To show it for the first time, you must either click the Open Perspective button in the top right or navigate to Window ➪ Perspective ➪ Flex Debugging.
Debugging Your Application Flex Builder 2 offers debugging capabilities that allow you to find bugs within your application. A debugger allows you to stop and start the application to find problems, or to examine or substitute values for variables. To debug your application, you must first switch your perspective to the Flex Debugging perspective using the buttons within the tabs at the top of the editor window, as shown earlier in Figure 2-15. Once you are in the Flex Debugging perspective, you can set breakpoints by right-clicking the line of code you wish to break on, and selecting Toggle Breakpoint from the context menu, as shown in Figure 2-16. You can also simply double-click the line of code to toggle on and off a breakpoint. Note that the Debugging perspective is automatically opened when a breakpoint is encountered, or when a run-time error is thrown.
19
Part I: Getting Started
Figure 2-15: Switching to Flex Debugging perspective
Figure 2-16: Adding a breakpoint
20
Chapter 2: Introducing Flex Builder 2.0 The Debugging perspective also includes views to read, edit, and watch variables, manage breakpoints, and watch expressions. These include the Console view, the Variables view, the Breakpoints view, and the Expressions view.
Console View The Console view displays any trace statements that are within your source code while your application is running within a debug session. This view will become one of your best friends while debugging your Flex applications. The Console view also displays run-time errors.
Variables View The Variables view of the debugger allows you to easily copy, find, change, and watch your variables while debugging your application. To do so, simply right-click a variable name, and then use the context menu shown in Figure 2-17 to perform any of the aforementioned functions. Selecting Watch from the context menu will add the variable to the Expressions view (discussed shortly).
Figure 2-17: Variables view of the Debugging perspective
The Variables view contains many icons and symbols that can be a bit confusing. The following table provides definitions for the various symbols. Symbols
Definition
Red Square
Defines a private variable
Green Circle
Defines a public variable
Yellow Diamond
Defines a protected variable
Blue Diamond
Defines an internal variable
Orange Box (Package)
Defines a variable scoped to a user-defined namespace
21
Part I: Getting Started The following table provides definitions for the various icons. Icons
Definition
C icon
Defines a constant variable
D icon
Defines a dynamic variable
S icon
Defines a static variable
Getter Icon
Indicates that the variable has a getters
Breakpoints View The Breakpoints view is an easy place to manage your breakpoints while in a debugging session. As shown in Figure 2-18, you can right-click a breakpoint and use the context menu to change the status, or to remove a breakpoint. You can also use the breakpoints toolbar for additional functionality, including jumping to the breakpoint within the source code, skipping all breakpoints, as well as expanding and collapsing the breakpoint tree.
Figure 2-18: Breakpoints view of the Debugging perspective
Expressions View Use the Expressions view to add and edit expressions on the variables you are watching. You can also choose to re-evaluate the expressions you are watching because the data may have changed as you proceeded through the debug session. As shown in Figure 2-19, you can right-click an expression and use the context menu.
Starting the Debugger To run the debugger and start a debugging session, click the arrow next to the bug button on the toolbar, and then select the application you wish to debug. If the application is not listed, choose Debug As and select Flex Application, as shown in Figure 2-20. Chapter 19 provides more information on debugging.
22
Chapter 2: Introducing Flex Builder 2.0
Figure 2-19: Expressions view of the Debugging perspective
Figure 2-20: Running an application in debug mode
Compiling Your Application Flex Builder 2 will compile your application as you build it, unless you specifically tell it not to by unchecking Build Automatically in the Project menu. Each time you save a file, Flex Builder will compile the SWF file, as well as generate the wrapper files and supporting files for running, debugging, and history management. By default, these files are compiled to the bin directory within your project, although this can be changed within the Flex Build Path section of the project properties.
23
Part I: Getting Started
Running Your Application To run your application, you must simply select the down arrow next to the green arrow button on the toolbar, and then select the application you wish to run from the list (Figure 2-21). If the application is not yet in the list, choose Run As and select Flex Application. To run the same application again, you can simply select the button with the green arrow.
Figure 2-21: Running an application
Summar y This chapter discussed the all-new Flex Builder 2 IDE. After reading this chapter, you should be able to create a project, edit it in either Source or Design view, and then run the application. This chapter also examined the tools available to use Flex Builder to debug your Flex application. Chapter 3 introduces the pieces that make up Flex. This includes the programming model, examples of MXML and ActionScript, the Flex class library, charting components, data services, and messaging services.
24
Flex 2.0 Basics The first two chapters of this book introduced you to the Flex 2 product line and the concepts of Rich Internet Applications (RIA). This chapter explains how to build a Flex 2 application using the Application Model. First, before you build anything, you are introduced to the XML markup language (MXML) and ActionScript. The following section, “Flex 2 Programming Model,” explains what the different elements are when developing your applications. The elements described are MXML, ActionScript, and the Flex 2 Framework.
Flex 2 Programming Model The Flex 2 Programming Model consists of MXML, ActionScript, and the Flex class library. To build a full-fledged application, you must have a good knowledge of all these technologies. To start off, you are introduced to the basics of MXML. Then you are shown how ActionScript and MXML work together to create powerful, rich user interfaces. The third element of the programming model is the Flex 2 Framework, which contains Flex components, managers, and behaviors. This component-based development model allows developers to incorporate pre-built components, extend the component library by creating new components, or combine pre-built components to create composite components.
MXML The first element of the programming model, MXML, is an XML language that defines the user interface for an application. MXML is also used to define non-visual aspects such as server-side data sources and bindings between the user interface and the server side.
Part I: Getting Started To write a Flex application, you must be able to write MXML and ActionScript. As mentioned earlier, MXML is an XML language that is used to lay out your user interface. MXML is very similar to HTML in that it provides tags for user interface elements. If you have worked with HTML, then MXML should be very familiar to you. MXML has a much broader tag set than HTML, and defines visual components such as data grids, buttons, combo boxes, trees, tab navigators, and menus, as well as non-visual components, Web service connections, data binding, and effects. The biggest difference between HTML and MXML is the MXML-defined file that is compiled into a Shockwave file (SWF) and rendered by the Flash Player. MXML can be written in a single file or in multiple files. MXML requires that you close off every tag that you declare in your Flex application. Otherwise, the Flex compiler will throw an error.
Example Application Using MXML One of the great things about MXML is that it can be written in a wide range of integrated development environments (IDEs) that support text editing because it’s a plain XML file. The following example shows the mandatory “Hello World” application. It consists of an tag and two children, the and tag.
The tag is always the root tag of a Flex application. The tag defines a Panel container that includes a title, title bar, status message, border, and an area for its children (that is, the control). The tag is a Label control that simply displays text. Figure 3-1 shows the “Hello World” application rendered in the Flash Player.
Figure 3-1: “Hello World” application rendered in the Flash Player
26
Chapter 3: Flex 2.0 Basics
ActionScript The second element of the programming model, ActionScript, extends the functionality of a Flex application. ActionScript provides control and object-manipulation features that are not available in strict MXML. The ActionScript programming language is used in Adobe’s Flash Player. Included are built-in objects and functions that allow you to create your own objects and functions like many object-oriented programming (OOP) languages. ActionScript 3.0 offers a robust programming model that is more familiar to developers with basic knowledge of OOP. ActionScript is executed by the ActionScript Virtual Machine (AVM), which is part of the Flash Player. The code is compiled into a bytecode format by the compiler, such as the one built into Flex Builder 2. ActionScript and JavaScript are very similar, so being familiar with JavaScript will make your life easier when using ActionScript. JavaScript is derived from The European Computers Manufacturers Association (ECMA) document ECMA-262, which is the international standard for the JavaScript language. ActionScript is based upon the ECMA-262 Edition 4 specification, so this is where the similarities come in between the two languages. ActionScript 3.0 contains a lot of new features, such as run-time exceptions, run-time types, sealed classes, method closures, ECMAScript for XML (E4X), regular expressions, namespaces, and new primitive types. All these new features allow the developer to speed up the development process. One important point to note is that Flex Builder 2 converts all MXML files into ActionScript before the code is compiled into bytecode for use with the AVM.
ActionScript in MXML Flex developers will find that ActionScript extends the capabilities of Flex when developing applications. In ActionScript, you can define event listeners, create new classes, handle callback functions, and define getters and setters, packages, and components. Following are some of the ways that ActionScript can be used in Flex applications: ❑
ActionScript is inserted between the tags. This code can be comprised of new functions, error handling, or events, and can perform any other tasks your Flex application may require.
❑
Create new components in ActionScript.
❑
Create new components and compile into SWC files (which are external components compiled to be reused in many applications).
❑
Extend existing components with ActionScript classes.
❑
Take advantage of ActionScript support for OOP concepts such as code reuse, inheritance, encapsulation, and polymorphism.
❑
Use global ActionScript functions that are available in any part of an SWF file where ActionScript is used, or in any user-defined class.
❑
Use the standard Flex components that comprise the Flex Class Libraries. All the components and libraries are written in ActionScript.
27
Part I: Getting Started Overview of ActionScript Compilation Process A Flex application can consist of MXML files, ActionScript classes, SWF files, and SWC files. The Flex compiler transforms the main MXML file and its children into a single ActionScript class linking in all the reference-imported classes. Once the transformation is complete, the end result is a single SWF file that can be deployed on the server. Every time you make changes to your application, a new SWF file is generated. You may find it more convenient to remove the reusable components and compile those into SWC files, which can be included in a library path for your application.
ActionScript Code in MXML ActionScript code is only allowed to be declared in between the following tag in MXML files:
Statements and expressions must be wrapped in functions; otherwise, you will receive a compiler error. Also, you cannot define classes or interfaces in the tag, because the MXML file you have defined is a class in itself. You may have noticed the odd CDATA construct. This is used to tell the compiler not to interpret the script block as XML, but rather as ActionScript. The tag must be located at the top-level component tag of the MXML file. Multiple tags can be defined, but for readability, it’s recommended to have them in one location. The following example shows ActionScript being defined in an MXML file:
28
Chapter 3: Flex 2.0 Basics In MXML, you can use ActionScript to refer to visual or non-visual components. You do this by specifying the id property of the component in MXML. Then you use id to refer to the component in ActionScript. The following example shows how this is achieved:
If you want to access the control, you must refer to the id property in ActionScript. To do this, the following code must be used: var str:String = lbl1.text;
The code gets the value from the Label control named lbl1.
Import and Include There is a noticeable difference between the terms “importing” and “including” in reference to ActionScript. Importing is adding a reference to a class file or package so that you can access the objects and properties of the external classes, as shown in the following example: import mx.controls.TextInput;
Including ActionScript is copying the lines of code of an external ActionScript file into another. This can either be done in the tag using the include directive, or the tag to add the ActionScript into your Flex applications. The following example is using the include directive within the tag:
Introduction to ActionScript Components This section provides a brief overview of how to create reusable components using ActionScript. Later in this book, you will build more complex components using MXML and ActionScript. Custom components can contain graphical elements, define some kind of business logic, or extend existing components in the Flex framework. Defining your own components in ActionScript has several advantages: ❑
Divide your application into individual models that can be developed and maintained separately.
❑
Implement commonly used logic within the components.
❑
Build a collection of components that can be reused among all your Flex applications.
29
Part I: Getting Started When creating custom components, you may find it useful to extend the component from the Flex class hierarchy. This allows you to inherit functionality already built into the Flex components. As shown in the following example, you can define a custom TextInput and derive it from the Flex TextInput control: package myComponents { public class MyTextInput extends TextInput { public function MyTextInput() { ... } ... } }
The filename of the control MyTextInput must be in a filename called MyTextInput.as and stored at the root of your Flex application in a subdirectory name myComponents. As you may have already picked up, the package name reflects the location of the component, myComponents. To use the custom component in your Flex application, you will need to write the following MXML:
The code xmlns:components=”myComponents.*” defines a namespace called components that points to the subdirectory myComponents. You can then reference the component as an MXML tag using the namespace prefix.
Flex Class Library The Flex 2 Framework contains Flex managers, components, and behaviors. The component-based model allows developers to incorporate pre-built components, create new ones, or combine components into composite components. Later in this book, you are introduced to more of the Flex 2 Framework. The following lists some of the common packages that you will use in your Flex application:
30
❑
mx.controls — Flex user interface controls
❑
mx.collections — Flex collection components
Chapter 3: Flex 2.0 Basics ❑
mx.charts — Flex charting components
❑
mx.utils — Flex utility classes
❑
flash.events — Flex event classes
❑
flash.net — Flex classes for sending and receiving from the network, such as URL downloading
and Flash Remoting There are many more packages in the Flex Framework, and listing them would be out of the scope of this chapter.
Flex Char ting Components The visual aspect that Flex charting offers over a simple table of numeric data is much easier for your Flex application users to comprehend. The Flex charting components are not included in the free Flex 2 SDK, and must be downloaded separately to use them inside your Flex application.
Charting Types Charts come in many different types, including the following: ❑
Area charts — The AreaChart control is used to represent data that emphasizes a change in values by filling in the portion of the graph beneath the line connecting various data points. The chart allows for an icon or symbol to represent each data point along the line or a simple line without any icons or symbols. These custom symbols are part of the built-in data series renderer functionality, which you learn about in future chapters.
❑
Bar charts — The BarChart control is used to represent data across categories, and is ideal for showing the variations in the value of an item over time, or for showing the values of several items at a single point in time. It is essentially a column chart rotated 90 degrees to the right.
❑
Column charts — The ColumnChart control is used to represent data using vertical bars (called columns) to display different values of one or more items. They are used to compare values across categories. They are ideal for showing the variations in the value of an item over time.
❑
Bubble charts — The BubbleChart control is used to represent data with three values for each data point. A bubble chart is a type of xy (scatter) chart. The first of the three values determines the position along the x-axis, the second value determines the position along the y-axis, and the third value determines the size of the bubble symbol.
❑
Candlestick charts — The CandlestickChart control is used to represent data that contains open, high, low, and close values for each time period you want to display. The hollow or filled portions of the candlestick are called the body. The long thin lines above and below the body represent the high/low range and are called shadows. The high is marked by the top of the upper shadow, and the low by the bottom of the lower shadow.
❑
Line charts — The LineChart control is used to represent data over time or categories as a series of points using coordinates. Icons and symbols can be used at each data point along the line with visual markers.
31
Part I: Getting Started ❑
Pie charts — The PieChart control shows the size of items that make up a data series proportional to the sum of the items. It always shows only one data series, and is useful when you want to emphasize a significant element in the data.
❑
Plot charts — The PlotChart control is used to represent data in Cartesian coordinates with one data point being along the x-axis and the other data point along the y-axis.
❑
HighLowOpenClose (HLOC) charts — The HLOCChart control is most often used to represent data for stock prices, but can also be used for scientific data (for example, to indicate temperature changes). The HLOCChart control does not require the data point that represents the opening value.
Chapter 10 provides more detail about the charting capabilities of Flex.
Flex Data Ser vices Flex Data Services (FDS for short) allows developers to build applications deployed on standard Java 2 Enterprise Edition (J2EE) servers. FDS provides connectivity with existing server-side data and business logic to create powerful business applications. FDS offers many great features, including the following: ❑
A robust messaging architecture that provides services that automatically synchronize data between client and server
❑
Real-time data push and publish-subscribe messaging
❑
Collaborative and disconnected applications
When developing an application, some consideration must be taken regarding how your data will flow from the client to the server and vice versa. FDS could be a viable option if you need the following features.
Data Management Service Developing RIAs requires more powerful data management compared to the traditional request/response model. Creating a richer and more powerful experience will require data-intensive applications, and with this, new challenges arise. This is where data management services make things simple when working with distributed data. Data Management Service adds functionality to provide data synchronization, data replication, and occasionally disconnected application services.
Data Synchronization This process is managed by FDS, and it removes the complexity and room for error by providing a highperformance data synchronization engine between client and server. Existing solutions can be integrated with data synchronization to provide an end-to-end solution.
32
Chapter 3: Flex 2.0 Basics Data Paging FDS takes care of paging large datasets, which allows you to focus your knowledge on application business logic instead of worrying about basic data management.
Messaging Service The Flex Messaging Service is comprised of the basic messaging functionality in the form of publishsubscribe API for Flex applications. This allows Flex and Flash clients to use publish-subscribe messaging to integrate with back ends that use Java Messaging Service (JMS) systems. Messages are sent asynchronously by passing packets of data (called messages) to and from a message service. A message is usually comprised of a header and a body, where the header contains the routing information and the body contains the application data. In the jargon of the world of messaging, an application that sends messages is called a producer and an application that receives messages is called a consumer. The producer and consumer need not know anything about each other, because the producer sends messages to a messaging destination and the messaging service routes it to the appropriate consumers. Figure 3-2 shows the flow of data from message producer to message consumer.
Data
Message producer
Channel
Destination
Message data flow
Channel
Data
Message consumer
Figure 3-2: Flow of data from message producer to message consumer
Publish-Subscribe Messaging Publish-subscribe messaging has been around for a while, and works asynchronously. The way it works is a producer creates a message and sends it to some predetermined destination. At the same time, a consumer attaches itself to the destination and listens for the sent messages. Producers and consumers (also known as message agents) collaborate by exchanging messages through a common gateway (which is the destination). Examples of applications that would benefit from the use of publish-subscribe messaging are stock trading services, inventory control, visualization tools, and any application that requires messages to be sent to multiple subscribers. Figure 3-3 shows a simple publish-subscribe message flow.
33
Part I: Getting Started
Producer/ Publisher
Message
Channel
Channel
Message
Consumer/ Subscriber
Channel
Message
Consumer/ Subscriber
Destination
Figure 3-3: Publish-subscribe message flow
Data Push In FDS, you can push data changes from the server to the client without polling the server. This is robust and highly scalable to allow pushing of data to thousands of concurrent users.
RPC Services You can develop a Remote Procedure Call (RPC) application without the use of FDS by using either HTTP services or Web services, and no server-side proxy service. To get the RPC service to work, it should either be in the same domain as the server hosting your application, or have a crossdomain.xml file on the remote server hosting your RPC service. FDS RPC functionality allows you to develop enterprise functionality into your applications, including servicing data from different domains, a white list of permitted RPC services, server-side logging, localization support, and client authentication. The RemoteObject component is used to access remote Java objects using Action Message Format (AMF), without exposing them as compliant Web services.
FDS Alternatives As of this writing, a company called Midnight Coders has an alternative solution to FDS called WebORB. It is a platform enabling development, deployment, and run-time execution of RIAs. The product allows connectivity between rich clients created with Flex, Flash, and Ajax, as well as server-side applications developed with .NET, Java, Ruby on Rails, and PHP. Most of these products will have an implementation of FDS in their commercial editions.
Summar y This chapter is just an overview of what’s to come in the world of Rich Internet Applications using Adobe Flex 2. Some of these topics may be a little over your head, such as the Flex Data Services, but you will quickly learn to integrate these technologies into your applications. Chapter 4, “Using Flex Builder,” is where all the fun starts. Flex Builder is something you will need to get familiar with quickly to enter the world of RIA development.
34
Using Flex Builder 2.0 Learning how to use the full potential of the Adobe Flex Builder 2 makes developing Flex applications easier and quite enjoyable. In the end, every application consists of text files, MXML, and ActionScript, which are compiled into a binary SWF file. The Flex Builder is the tool to help organize, visualize, create, and run commands on the application code. This chapter teaches you how to learn more about the Flex Builder from within the Flex Builder. It covers basic layout and workbench areas, as well as how to customize the workbench experience. Finally, you learn about Flex Builder’s ability to build applications with both the Design and Source views.
Getting Star ted with Flex Builder The Flex Builder is a fully integrated development environment (IDE). It provides tools to assist you in creating, debugging, packaging, and compiling code into SWF applications. Following are the included feature sets: ❑
Text editor — Flex Builder 2 provides separate editors for MXML, ActionScript, and CSS code. You do not need to keep track of which editor is for which file type. This is because the Flex Builder automatically handles it for you. The editors also provide features that are discussed in this chapter, including code hinting, navigation, formatting, commenting, and others.
❑
Design editor — The Design view editor is specific to the MXML editor. It provides a collection of views to help create components and applications visually by placing user-interface and data-access controls on the design mode stage.
Part I: Getting Started ❑
Navigation features — The Navigator and the Outline views provide the ability to navigate not only projects, but also components. Flex Builder also provides the functionality to open code through definition links and view editors with line numbers to help locate specific code.
❑
Build tools — The mxmlc compiler does all compiling of the applications, but what Flex Builder does is provide the ability to manage the process. You can configure projects to build automatically as you write code and save the file, or be built manually. Configuration settings are also set per project to give you full control of the compilation and deployment process.
❑
Integrated debugger — Flex Builder integrates the mxmlc compile-time errors with the Console view for easy access to error locations. Run-time debugging is handled through the Flex Debugging perspective and the associated Console, Debug, Variables, Breakpoints, and Expressions views.
❑
Integrated Adobe Flex 2 Help — The Flex Builder help system provides eight main categories, from how Flex works to the Flex 2 language reference. It also provides a list of links to other online Flex resources. The Dynamic Help view provides in real time contextual help as you write your code. Another help item is the Key Assist popup list, containing a quick view to all the shortcuts.
❑
Eclipse plugins and third-party tools — Eclipse provides a plugin architecture embraced by the community with many well-done projects to support other development requirements. Most common are development and version control plugins such as Ant, Tomcat, CVS, Subversion, and ColdFusion. Along with the plugin architecture, Eclipse allows you to configure external tools from within the Flex Builder.
If you have built applications with other comparable development environments, you will find that the Flex Builder and Eclipse platform provides extensive capabilities. Flex Builder 2 comes in two installation options. The first is the stand-alone Flex Builder with the prepackaged Eclipse environment included. The second option is to install Flex Builder as an Eclipse plugin into an existing Eclipse installation. Although this chapter uses the stand-alone Flex Builder in its examples, the information is still pertinent to the plugin edition as well. When installing the Flex Builder Eclipse plugin into an installation with other ActionScript or MXML plugins, you must resolve editor conflicts through the Eclipse preferences window.
Learning Flex Builder One of the most overlooked places to start learning about Flex Builder is the Flex Start Page. If you are like most developers, you probably vaguely remember seeing it the first time you opened up Flex Builder. Do not worry if you did skipped over it; you can bring the Flex Start Page back up by selecting Help ➪ Flex Start Page. The result is shown in Figure 4-1. The next step to finding extensive information on Adobe Flex 2 and related technologies is Flex Help itself. Figure 4-2 shows the Flex Builder Help system, which opens as a separate application outside of Eclipse when you select Help ➪ Help Contents from the Flex Builder menu system.
36
Chapter 4: Using Flex Builder 2.0
Figure 4-1: Flex Start Page
Figure 4-2: Flex Help application
37
Part I: Getting Started Figure 4-2 also shows the name of the eight main titles in the Flex Help library. The library is quite extensive, and many times you’ll want to narrow your search to specific sections of the library. You do this by clicking the blue “Search scope” link found on the top middle area of Figure 4-2. The search mechanism uses groups of topics as named search lists that can be selected as the current search scope. Figure 4-3 shows the two dialog windows used to create and select a search list for just the “Using Flex Builder 2” section of the Flex library. The selection of scope will now filter all search results to only pull information from the “Using Flex Builder 2” help section. The search scope not only affects the external help system, but also affects the Help view search mode available inside Flex Builder. You can see that in Figure 4-4, which demonstrates a search result on the term “debugging.” The search returns the same filtered results as the Help view search mode shown in Figure 4-5. The ability to use the external help application or the internal Help view search mode demonstrates the flexibility of Flex Builder’s options. One of the nice help features is called Dynamic Help. It uses the same help view area as the Help view search mode. Open the Dynamic Help view, shown in Figure 4-6, by selecting Help ➪ Dynamic Help.
Figure 4-3: Dialog windows used to create and select a search list
38
Chapter 4: Using Flex Builder 2.0
Figure 4-4: Search result on the term “debugging”
Figure 4-5: Help view search mode
39
Part I: Getting Started
Figure 4-6: Dynamic Help view
The Dynamic Help works as you select or move the editor cursor over key words. The Dynamic Help view shown in Figure 4-6 displays the reference link to mx.logging.Log in connection to the Log class in CustomLoggerMain.mxml source editor being highlighted. The Go To section in Figures 4-5 and 4-6 is another way to switch between the different modes of the Help view. Related Topics is another definition given to the Dynamic Help view mode. The bookmarks option displays a list of bookmarked help pages. You bookmark the current help page by clicking the Bookmark Document icon located in the top-right section of the help page. There it is — the power to pull information from the Flex library as you continue learning about Flex Builder from within the Flex Builder itself.
Flex Builder Workbench Basics The Flex Builder workbench is made up of perspectives, editors, and views. The following table provides definitions to better explain the basics of the Flex Builder workbench and other related topics.
40
Term
Definition
Perspective
A group of views and editors in a workbench.
Editor
Specific functionality to edit files of specific types.
Chapter 4: Using Flex Builder 2.0 Term
Definition
View
Container for functionality, also as known as panels.
Workspace
Defines an area of the file system that contains project resources.
Perspectives, Editors, and Views The grouping of views and editors related to what current development actions are taking place are organized in perspectives. Adobe Flex Builder 2 provides two default perspectives: one for development and one for debugging. Flex Builder provides hooks into the IDE to change perspectives automatically, depending on the task at hand. For example, when you create a new project and are not presently in the Flex Development perspective, a prompt will ask if you would like to switch perspectives, as shown in Figure 4-7.
Figure 4-7: Prompt asking if you would like to switch perspectives
The Flex Development perspective includes two modes that are dependent on the MXML editor. The first mode is Source mode, which also defines the layout for the perspective when an ActionScript or CSS editor is in use. The MXML editor in Design mode is the second mode of the Flex Development perspective. The following table shows the default development view configuration, as well as which Flex Development perspective mode the view appears in. The specific list of views in each perspective described here defines the default configuration layout. You can customize any perspective for your specific development environment needs. Chapter 2 introduces the basic views and provides figures for most of the views discussed here. View Name
Group
Typical Layout Area
Navigator
Source/Design
Left Side
Outline
Source/Design
Left Side
Editor
Source/Design
Middle
Continued
41
Part I: Getting Started View Name
Group
Typical Layout Area
Problems
Source/Design
Bottom
Components
Design
Left Side
States
Design
Right-Top
Properties
Design
Right-Bottom
The following table shows the default debugging view configuration, as well as which Flex Development perspective mode the view appears in. View Name
Group
Typical Layout Area
Navigator
Debugging
Left Side
Debug
Debugging
Middle-Top
Editor
Debugging
Middle
Variables
Debugging
Right-Top
Breakpoints
Debugging
Right-Top
Expressions
Debugging
Right-Top
Console
Debugging
Bottom
The following table shows the default optional views, as well as what groups and which Flex Development perspective mode the view appears in. View Name
Group
Typical Layout Area
Search
Any
Bottom
Console
Any
Bottom
Tasks
Any
Bottom
To open any view in the current perspective, select Window ➪ Other Views…, and a popup of all the available views will open. Figure 4-8 shows the dialog window that pop ups upon selecting the Other Views menu item.
42
Chapter 4: Using Flex Builder 2.0
Figure 4-8: Dialog window that pop ups when selecting other views
Later in this chapter, you learn how to navigate and customize the views in the Flex Builder workbench.
Workspace Workspaces are larger than perspectives, and allow you to organize resource and configuration groupings on the same machine. Each workspace must have a separate location on the file system. The process of creating new workspaces and retrieving old ones is called switching workspaces. You will find the menu item under File ➪ Switch Workspace…, as shown in Figure 4-9. Figure 4-10 shows the workspace switch dialog box. To select a new workspace you can browse or type in a new location on the file system.
Figure 4-9: Switching workspaces
43
Part I: Getting Started
Figure 4-10: Workspace switch dialog box
Switching to different workspaces makes sense if you work in different environments with many clients or separate projects. For example, an author of a book can create a workspace specific for the example projects needed to be published, but also keep a workspace for other clients or personal projects. Each workspace will reference different projects and can configure the layout of perspectives and views differently. If you have used other Adobe products, such as Flash 8 Professional or Dreamweaver, workspaces work similarly to the workspace layout feature found in those products.
Flex Builder Basics With the workbench and the basic parts explained in the previous sections, let’s examine how to use the workbench. The project is the most basic organizational unit used by the Flex Builder workbench. Managing and navigating the project and its resources make up a big part of a developer’s daily tasks.
Working with Projects There are three project types defined by the Flex Builder: Flex Project, ActionScript Project, and Flex Library Project. Figure 4-11 shows the three Flex Builder project types, along with the some other Eclipse basic projects. The icons next to the specific project wizard found in Figure 4-11 also show up in other places of the workbench, in particular the Navigator view. New projects can be created a few different ways:
44
❑
You can select a wizard by right-clicking in the Navigator view and selecting New ➪ Project..., or from the main menu’s File ➪ New ➪ Other….
❑
You can choose a specific project wizard type straight from the main menu by selecting File ➪ New ➪ , or from the context menu in the Navigator view New ➪ . The specific type options are Flex Project, ActionScript Project, or Flex Library Project.
❑
You can import a previous project by selecting from the main menu File ➪ Import…, or by selecting Import… from the context menu in the Navigator view. This method is not covered in the book, but is noted here for reference.
Chapter 4: Using Flex Builder 2.0
Figure 4-11: Three Flex Builder project types
Each project type has a specific wizard for creating a project. The wizard for creating a new Flex project walks you through the application data access setup, project file location, and the build path setup dialog windows. In particular, Figures 2-2 through 2-6 in Chapter 2 show the wizard dialog windows for creating a new Flex Project. The ActionScript Project is used for creating applications with ActionScript code that does not use any of the Flex Framework. The DrawCircles.as class introduced in the next section, “Multiple Applications,” is an example of an ActionScript application. The DrawCircles.as code is defined in Listing 4-1 later in this chapter. The non-Flex Framework application only needs to extend the Sprite class, and can be run just like a typical Flex application. The Flex Library Project is covered in the “Compiling Components with Flex Builder” section of Chapter 14. After creating the project, there are few things to learn about how to add and manage resources within the project. Projects can have multiple applications, link to external resources, be built automatically or manually, and publish source code.
Multiple Applications When you create a project, it creates a default MXML application file. There a multiple ways to add more applications to a project. The default MXML application file receives the same name as the project, unless the project name contains spaces or special characters. If the latter is the case, the filename is defaulted to main.mxml. Create a Flex Project with basic data access called Chapter4. You should see a Chapter4.mxml file as shown in Figure 4-12.
45
Part I: Getting Started
Figure 4-12: Chapter4.mxml file The following steps outline the first of two methods on how to add multiple applications to the project:
1.
Create a new MXML application by selecting Flex ➪ New ➪ MXML Application, or by selecting New ➪ MXML Application from the right-click context menu from the Navigator view.
2.
Type MyApp into the filename input box located on the New MXML Application dialog window shown in Figure 4-13.
The first approach is quite simple, and creates the MXML application file for you, as well as assigning the application to the project. The green sideways triangle located over the top-left area of the MXML file icon indicates the file is a runnable application for the project, as shown in Figure 4-14. The blue circle over the bottom-right area of the MXML file icon indicates which application is the default runnable application.
Figure 4-13: New MXML Application dialog window
Figure 4-14: Sideways triangle located over the top-left area of the MXML file icon
46
Chapter 4: Using Flex Builder 2.0 The following steps outline the second approach to add an application to the project:
1. 2. 3.
Create a new MXML or ActionScript file. For example, select File ➪ New ➪ File. Name the file DrawCircles.as. Open the DrawCircles.as file and add the source code shown in Listing 4-1 to the file.
Listing 4-1: DrawCircles.as package { import import import import import
flash.display.Graphics; flash.display.Shape; flash.display.Sprite; flash.display.StageScaleMode; flash.display.StageAlign;
public class DrawCircles extends Sprite { private var childCount:int = 0; public function DrawCircles() { stage.scaleMode = StageScaleMode.NO_SCALE; stage.align = StageAlign.TOP_LEFT; doDrawCircle( 0x336699 ); doDrawCircle( 0x993333 ); doDrawCircle( 0x339933 ); } private function doDrawCircle( color:uint ):void { var child:Shape = new Shape(); child.graphics.beginFill( color ); child.graphics.lineStyle( 2, 0xCCCCCC ); child.graphics.drawCircle( 30, 40, 30); child.graphics.endFill(); child.x = (childCount * 65) + 10; child.y = 0; addChild(child); childCount++; } } }
4.
Right-click the DrawCircles.as file and select Set as Default Application. Or you can rightclick the Chapter4 project name and select Properties.
Note that the Set as Default Application menu item is disabled for ActionScript files in non-ActionScript typed projects in Flex Builder 2.0.1. You must change the nature of the project or create a new project of ActionScript project nature. Or you could manually set the default application through the project’s Properties window.
47
Part I: Getting Started 5. 6. 7.
Select Flex Applications, as shown in Figure 4-15. Click the Add… button and select the DrawCircles.as file, as shown in Figure 4-16. Click OK and go back to the workbench.
Now, DrawCircles.as will have an icon indicator showing that it is a runnable application. Click the DrawCircles.as file and run the application. The DrawCircles application is shown in Figure 4-17. You can now add MXML or ActionScript applications to any project you want to and know how to run it. A lot of the examples in the Flex language reference documentation are ActionScript applications, just like DrawCircles.as. Therefore, it’s important to understand how to run ActionScript applications.
Figure 4-15: Selecting Flex applications
Figure 4-16: Selecting the DrawCircles.as file
Figure 4-17: Running the DrawCircles application
48
Chapter 4: Using Flex Builder 2.0 Linking External Resources A linked folder on the file system links external resources in a project. Select File ➪ New ➪ Folder to activate the New Folder Wizard. Name the folder myPictures, click the Advanced ➪ button, and check the “Link to folder in the file system” checkbox, as shown in Figure 4-18. Click the Finish button and a folder pointing to the My Pictures folder is created in the project. This can be used for quick access to other resources from within the Flex Builder to save the developer from using an operating system file explorer application.
Figure 4-18: New Folder Wizard
Building Applications Automatically and Manually To set a project to build automatically, first click inside the Navigator view on the project name or a file in the project. Then, select Project ➪ Build Automatically. There are situations where manually building is warranted (for example, when you want the build script to run unit tests, move files, or manipulate other resources outside the Flex compiler). The most common methods of doing advanced manual builds use Apache Ant, which is out of the scope of this book. An important feature for any build process is the Clean command. To clean a project, select Project ➪ Clean… with the project you want cleaned selected in the Navigator view. The Clean command forces the build scripts to delete all cache and output files, and then compile all source files from scratch. This single feature can resolve a lot of build project compile issues, especially if you are changing large chunks of files within a project.
Publishing Source The project feature makes it easy to publish the source of your application. Figure 4-19 shows the wizard that opens by selecting Project ➪ Publish Application Source… from the main menu system.
49
Part I: Getting Started This feature works only for Flex applications. ActionScript applications will not have the View Source menu option on the right-click context menu. Running this feature inserts a value into the viewSourceURL property of the default MXML application tag. To access the published source, run the application and select the View Source context menu item when you right-click the SWF. Figure 4-20 shows what the generated publish source application looks like.
Figure 4-19: Publish Application Source Wizard
Figure 4-20: Generated publish source application
Running Applications After building your applications, you can run or debug them a couple of different ways from within Flex Builder. The content covered in this section does not discuss debugging, but many of the launch configuration options apply to debugging as well. In-depth information about debugging applications is covered in
50
Chapter 4: Using Flex Builder 2.0 Chapter 19. The simplest method of running an application is by pressing the green Run button, or by selecting Run ➪ Run . Applications can be configured to be run through a browser, or through the stand-alone player. The configuration option for running or debugging applications is called the launch configuration. Figure 4-21 shows the toolbar icon that allows you to open a specific application’s launch configuration for any applications in the currently selected project in the Navigator view. The Create, Manage, and Run Configurations dialog box provides three tabs with configuration options: Main, Source, and Common. To configure an application to run in a stand-alone Flash Player, uncheck the “Use defaults” checkbox in the Main tab. Then select the Run (or Debug) browse button, and select the application SWF file instead of the default HTML file, as shown in Figure 4-22.
Figure 4-21: Opening the launch configuration
Figure 4-22: Main tab of the Create, Manage, and Run Configurations dialog box
51
Part I: Getting Started Clicking the Run command launches the application in the stand-alone Flash Player. Other standard preferences located in the Windows ➪ Preferences ➪ Web Browser allow for the default browser used to run the application to be changed.
Navigating and Customizing the Flex Builder Workbench Customizing the workbench to your specific development needs revolves around the understanding of the topics from previous chapters. To change perspectives, you can click the perspective-specific button, or select the perspective from the drop-down list, as shown in Figure 4-23.
Figure 4-23: Changing perspectives
Also shown in Figure 4-23 is the ability to select the Other… option that allows adding other perspectives to the perspective toolbar. To create a new perspective, select the Window ➪ Perspective ➪ Save Perspective As… menu item. A dialog box will appear, where you fill in the new perspective name and click OK. The steps to delete a Flex Builder perspective are to go to Windows ➪ Preferences ➪ Perspectives, select the perspective, and click the Delete button. The current state of each view is saved for the current perspective automatically. There are a couple options to customize the layout of your views in a perspective. Each view can be minimized, restored, and maximized. A quick way to maximize and minimize views or editors is to double-click the view/editor tab containing the name of the specific workbench item. To move or dock a workbench item, view, or editor, click the tab area with the name and drag it to the new location. As you drag the workbench item over potential areas, a dotted line will appear, indicating the potential layout placement. If you want a particular view to live outside the Flex Builder’s layout constraints, you can right-click the view and toggle the Detached menu item. Detaching the view from Flex Builder then opens up a new window, which is not the layout constraint for the view. You can dock workbench items on the left, right, top, bottom, in layers, tiled, or many other ways. Figure 4-24 shows views and editors in various docking positions. A special layout feature in Flex Builder is called fast views. You can drag any view down into the fast view’s default lower left-hand corner location. The fast view places the view’s icon into a toolbar-like container, allowing for toggle-style visible views. The fast view toolbar can also be customized to be docked on the left, bottom, or right side of the Flex Builder.
52
Chapter 4: Using Flex Builder 2.0
Figure 4-24: Views and editors in various docking positions
Moving around the workbench can be greatly enhanced by learning more about the common keyboard shortcuts. You can view a quick list of the available shortcuts by selecting the Help ➪ Key Assist… menu item. All actions in the Flex Builder can be assigned new keyboard shortcuts through the Windows ➪ Preferences ➪ Keys configuration tabs. Moving around the code files is a very common task when using the Flex Builder. There a few good methods that help developers move around the files efficiently. The first is the open definition feature. To use this feature, click any property or object in a code file and press F3. For example, open up the DrawCircles.as file and select the doDrawCircle method on line 13, and press F3. The open definition action takes you to the declaration point of doDrawCircle. This works on methods, properties, and classes, including Flex Framework source files found in the Flex 2 SDK installation folder. The outline view is a very powerful tool to very quickly move around a class structurally. The outline view provides a tree structure of the class and its elements. By clicking a node in the outline tree, the editor updates to the correlating line in the code. The Navigation view has a specific feature called working sets, which can be defined to contain different resource items across projects. The set of commands to create, edit, and select working sets is found in the Menu icon on the Navigation view toolbar.
53
Part I: Getting Started The last navigation feature discussed here is the search functionality in the Flex Builder. To bring up the global search functionality, select the Edit ➪ Find in Files… menu item. The action will open a dialog box, shown in Figure 4-25, providing a search input box, filename filtering, and scope settings.
Figure 4-25: Search dialog box
Developing with Design Mode Flex Builder’s Design mode and supporting views provide the features to create applications visually. The Flex Framework visual components contain the following characteristics: ❑
Size
❑
Events
❑
Styles
❑
Behaviors
❑
Skins
The Design mode’s development workflow capabilities relate directly to manipulating the visual component’s characteristics. This is demonstrated in the following sections.
Building a Flex User Interface Follow these steps to create a basic application using Components view and Flex Properties view:
1. 2. 3. 54
Open the Chapter4.mxml file located in the Chapter4 project. Click the Design mode button. Drag a Label control from the Components view onto the stage area.
Chapter 4: Using Flex Builder 2.0 4.
5. 6.
Click the Label instance and then, in the Flex Properties view, change the following properties: ❑
ID — txtTitle
❑
Text — Professional Flex 2 by Wrox
❑
Constraint checkboxes — Left 20 and Top 20
Drag a Button control from the Components view onto the stage area. Click the Button instance and then, in the Flex Properties view, change the following properties: ❑
ID — txtSwitch
❑
Label — Switch
❑
Constraint checkboxes — Left 20 and Top 45
Figure 4-26 shows the proper layout of the controls on the stage, and the Flex Properties view displays the values for the Label control. Before continuing to the next part of the example, this is a good time to point out two icons on the Design mode editor toolbar. These two icons are the Refresh and Show Surrounding Containers (F4) icons located after the Design mode button and before the States combo box. You can also change the design stage size to a common resolution size, or change it to some custom values for your specific project needs. The Flex Properties category and alphabetical views both are methods of viewing the properties for controls or components currently selected.
Figure 4-26: Proper layout of the controls on the stage and Flex Properties view
55
Part I: Getting Started
Adding View States and Transitions The next step in developing the example application visually is to create states of the application. Each Flex application has a default state that all child states relate to. You can nest states relatively in a tree hierarchy structure. The hierarchical structure constrains the application state changes, but does not restrict how the states can be navigated. The example application will have a switchBottom state that moves the label and button to the bottom of the application.
1. 2. 3. 4.
Open the States view and right-click the (start).
5. 6. 7. 8. 9.
Select the Label control and change the Top property to Bottom property with the same value.
Select the New State… context menu item. Name it switchBottom and click OK. Select the switchBottom state. The States combo box located in the Design mode editor’s toolbar can also be used to switch between states.
Select the Button control and change the Top property to Bottom property with the same value. Select the Button control and add currentState = “”; to the On Click property. Select the . Select the Button control and add currentState = “switchBottom”; to the On Click property.
Run the application. When you click the button, it will move the button and label to the bottom of the application. States can be used for many purposes. For example, a good usage might be for forms having a large number of fields that might not be filled out by everyone. You can have the base state show a form of all the required input form items, and an optional state that opens up to show all the other fields. A good rule of thumb to know when a specific usage of states might be less optimal is to ask yourself if the states cover the same data and/or user logic.
Adding Interactivity with Behaviors States changes can look very rigid when large layout changes are taking place on the page. To alleviate this, you can use different effects or behaviors. The Design mode supports behavior development through the Flex Properties view.
1.
Click the Label control and select the Flex Properties view, along with changing it to the Category view.
2.
Open up the Effects folder node.
3.
❑
Set mouseDownEffect property to WipeRight.
❑
Set moveEffect property to Fade.
Open up the Events property folder node. ❑
Set mouseDown to txtTitle.text = (txtTitle.text == “Is Great” ) ? “Professional Flex 2 by Wrox” : “Is Great”;
56
Chapter 4: Using Flex Builder 2.0 4.
Click the Button control and select the Flex Properties view, along with changing it to the Category view.
5.
Open up the Effects folder node. ❑
Set moveEffect property to Fade.
From changing states, text, and adding effects to the controls of the Flex application, the Design mode is a powerful visual tool. You do not have to touch any source code to make complex applications, or change simple component properties and behaviors.
Programming Flex Applications Although visually creating applications has many benefits, most likely the development process will require changing source MXML, ActionScript, and CSS files. Flex Builder provides the normal code-editing features usually found in IDEs.
Code Editing in Flex Builder The code assistance or code hinting is not only for MXML files, but is also available in ActionScript and CSS source files. As you use the code assistance, Flex Builder will also automatically insert any package import dependencies. There are also other tag, method, and syntax completion benefits derived from using the code assistance tool that help the developer be more productive. The CSS code assistance provides a list of valid values with dash-separated values. It is still valid to name the style properties in camel-case notation (that is, background-color and backgroundColor are valid CSS properties, even though code assistance only displays background-color). Flex Builder supports code folding to help you organize and view source code. The code folding icons show up as blue circles in the left gutter of the code with either minus or plus signs. Another, lesser-known source code navigation feature of Flex Builder is creating bookmarks. Any line of code can be bookmarked for viewing and link access through the Bookmark view. To add a bookmark to a line of code, you first select the line of code, then right-click in the left gutter, and select the Bookmark… context menu item. It will be placed in the Bookmark view’s list, where each bookmark can be double-clicked to return to the specific source file and line number. To delete bookmarks, open up the Bookmark view and right-click the bookmark to be deleted. Select the Delete button from the context menu. Just as with Bookmarks, you can also assign tasks manually in the same process. The Task view allows for simple to-do list functionality to be used while working with many source files.
57
Part I: Getting Started The part of making your development life easy while editing source files is to learn the shortcuts. The following table lists a few of the more useful shortcuts defaulted in Flex Builder. Shortcut Keys
Name
Description
Ctrl+Shift+T
Open Type
Opens a full list of types dialog box.
F3/Ctrl+click
Go to Definition
Jumps to identifier’s declaration code.
Ctrl+O
Quick Outliner
Pop ups outline view with filtering ability.
Shift+F2
Find in Language Reference
Opens context-sensitive help.
Ctrl+Space
Content Assist
Opens code-hinting popup window.
Right-click in gutter
Folding
Code folding features.
Summar y In this chapter, you have learned how to use Flex Builder. You learned the basic definitions of what Flex Builder is and how the workbench works. This chapter also provided a good overview of how to work with projects by setting up custom workbenches, and learning how to navigate through projects. Finally, you learned about the skills to develop an application through the Design mode, as well as about the Source mode. Chapter 5 discusses the building of your first Flex applications. You not only learn the basic components that make up your Flex applications, but you explore a list of Flex application capabilities such as CSS, skinning, custom components, basic data access, and handling events.
58
Part II: Developing in Flex 2.0 Chapter 5: Programming Languages Chapter 6: Building User Interfaces Chapter 7: Customizing the User Interface Chapter 8: Flex UI Topics Chapter 9: Flex Data Chapter 10: Flex Charting Chapter 11: Data Access
Programming Languages Chapter 3 introduced you to MXML and ActionScript, and how they work together to build rich client applications in Flex. This chapter goes into more detail regarding Flex’s programming languages.
Developing MXML Applications The process of developing using MXML allows you as the developer to separate application logic from the user interface. This is great because you can lay out all or most of the user interface before writing a single line of code. You may find this useful when showing clients what the application may look like initially. Obviously, the interface will change over time as more and more users use the application, but at least you can visualize what it may look like when it is finished. MXML allows developers to build applications from the end user’s perspective, because it is the user interface to the business and data access logic.
UI Layout Using Containers MXML supports two kinds of user interface components: controls and containers. Controls are buttons, combo boxes, text inputs, and date fields. Containers, on the other hand, are rectangular boxes that contain the controls and/or other containers. When laying out controls, you may find it useful to use containers such as the HBox, VBox, and Grid. The HBox container lays out child components horizontally. The VBox container lays them out vertically, and the Grid container is used to lay out child components in columns and rows.
Part II: Developing in Flex 2.0 Flex also has navigator containers that are used to control user navigation through the application. Following are examples of navigator containers: ❑
The ViewStack navigator container is the same as the TabNavigator and Accordion containers in that only one child container is visible at a time, but the ViewStack does not have any way to navigate between them by default.
❑
The TabNavigator container contains a collection of child containers in which only one child is visible at a time. Flex automatically creates a TabBar container at the top of the TabNavigator container, with a tab corresponding to each child container. Each tab can have its own label and icon. When the user clicks a tab, the corresponding child container becomes visible as the selected child of the TabNavigator container.
❑
The Accordion container has a collection of child containers, but only one is visible at a time (like the TabNavigator). The difference is that the Accordion has navigator buttons called accordion headers, which you use to navigate between the children.
There are ways to associate a navigation control with a ViewStack container to navigate between the children. This is done by assigning the ViewStack container’s id property to the navigation control’s dataProvider property. You can associate a LinkBar, TabBar, or ToggleButtonBar container with a ViewStack container to provide a navigation interface.
In this code example, the control’s dataProvider property is assigned to the container id property . To label each button in the LinkBar control, you must assign a name to the label property of the ViewStack container’s children. Figure 5-1 shows what the preceding code looks like when compiled into an SWF file.
62
Chapter 5: Programming Languages
Figure 5-1: A ViewStack container and LinkBar navigator
UI Controls Flex has a variety of user interface controls, such as TextInput, ComboBox, Button, and LinkButton. These controls are usually added to the interface once you have the layout and navigation of your application defined. The following example contains a VBox (vertical box) container with two child components, a TextInput control and a Button control:
XML Namespaces In a typical XML document, tags are associated with a namespace. This allows you to refer to more than one set of tags in the same XML document: Some Text
63
Part II: Developing in Flex 2.0 In MXML, you define an XML namespace using the xmlns property within the root tag of your application or component. Do not specify a prefix if you want to use the default namespace. To add additional tags, you will need to specify a tag prefix and a namespace. In the main file of your Flex application within the tag, you will notice an xmlns property that indicates the tags in the MXML namespace use the prefix of mx: and a namespace of http://www.adobe.com/2006/mxml:
The XML namespace allows you to use custom tags that are not found within the MXML namespace. This will come in handy when you need to define your custom components that are located outside the default namespace. The following component is located in the subdirectory [applicationroot]/mycomponents/ view. To access the MXML component (MyComponent.mxml) you need to define a namespace xmlns:mycomponent?view=”mycomponents.view.*“. The namespace mycomponentview can be allocated any name of your choice as long as it’s one word and without punctuation marks.
To be able to define this component outside of the mycomponents.view.* namespace, you will need to add a namespace to the root tag of the MXML file:
This is done by adding the property xmlns:view=”mycomponents.view.*” to the root tag, which, in this case, happens to be the Application tag. Now all you need to do is instantiate the component by adding the tag .
Data Binding with Components Data binding is a powerful feature of Flex that allows you to tie data in one object to another. This feature lets you pass data between client-side objects in your application. Binding automatically copies the value of a property in the source object to a property in the destination object when the source property changes.
64
Chapter 5: Programming Languages This allows you to pass data between different layers of the application, such as the UI, data models, and data services. Flex provides three ways to use data binding: ❑
The curly braces {} syntax
❑
The tag in MXML
❑
The BindingUtils static methods in ActionScript
Even though data binding is a powerful feature, it may not always be appropriate for all situations. You may find that a piece of data only needs to be updated occasionally, or you need strict timing when updating your user interface. The requirements for data binding are a source property, a destination property, and an event that triggers to indicate when to copy the data from the source to the destination. The following example shows the Label control with its text property bound to the TextInput control’s text property. When you type, the TextInput control’s text property (the source property) is copied to the Label control’s text property (the destination property).
Chapter 9 provides more information about data binding.
RPC Services A Remote Procedure Call (RPC) lets your applications interact with remote servers to provide data to your applications or send data to a server. Flex has several types of RPC services that allow access to local and remote server-side or business logic. Your applications can connect to a Web service using the Simple Object Access Protocol (SOAP), a Java object residing on the server using Action Message Format (AMF), or an HTTP URL that returns data in a custom format (such as XML or JSON). Flex provides components for all three RPC services, which can be defined in MXML or ActionScript: ❑
WebService component, which provides access to the SOAP-based Web services.
❑
HTTPService component, which provides access to HTTP URLs that return custom data.
❑
RemoteObject component, which provides access to Java, PHP, and .NET objects using the AMF protocol. With the RemoteObject component, you can access methods of server-side
objects, such as Java objects, without manually configuring the objects as Web services. You need to configure the objects that you want to access as Remote Service destinations in the Flex services configuration file, which is part of Flex Data Services.
65
Part II: Developing in Flex 2.0 The following example shows an application using the HTTPService component to call a Flickr service that returns a list of recent photos. The application binds to srv.lastResult.rsp.photos.photo, which is the HTTPService component’s id property (srv) and the result of the last invocation (lastResult property). Flickr will return the result in XML and, by default, the HTTPService component will serialize the data into an object. This allows you to access the list of photo objects using the syntax srv.lastResult .rsp.photos.photo. You may have noticed in the TileList control that there are two new tags: and . These are used to define custom inline item renderers for the TileList control. You learn more about item renderers in later chapters, but for now, all it does is replace the current item renderer with a custom Image control to show the thumbnails from Flickr.
Figure 5-2 shows the application rendered in a Web browser. The thumbnails are displayed within the TileList control, and the data was extracted from Flickr using the HTTPService component.
66
Chapter 5: Programming Languages
Figure 5-2: Photos retrieved from Flickr
Data Validation In Flex, you can use the validator components to validate data stored in a data model or a user-interface component. There is a set of standard validator components that comes with the Flex SDK, and you can also build your own by extending the Validator class. The following example uses the CreditcardValidator component to validate the credit card number in the TextInput control. The ComboBox control contains the different card types (for example, American Express, Mastercard, and Visa).
{cardTypeCombo.selectedItem.data} {creditCardInput.text}
Figure 5-3 shows the application rendered in a Web browser. As you can see, a border around the TextInput control is visible and a tooltip is displayed to inform the user that the validation has failed. If the validation is successful, an Alert control is displayed to inform the user that the credit card number is valid. Chapter 9 provides more information about validating data.
Figure 5-3: Data validation application
Data Formatting Formatter components are used to convert raw data into a formatted string. Each formatter implements a format method that takes in an Object and returns a formatted string depending on the value of the formatString property. A DateFormatter component, for example, may have a formatString of DD/MM/YYYY and, when passed into the format method, the result would be 29/08/2006.
68
Chapter 5: Programming Languages To create a custom formatter, you must extend the Formatter class in the package mx.formatters and override the format method with your own functionality. The following example uses a DateFormatter component to format the date from the DateField control and display it in the TextInput control. The formatString in this case is “EEEE, MMM. D, YYYY at H:NN A”, which determines what the output of the format will look like.
Figure 5-4 shows the application rendered in a Web browser. Chapter 9 provides more information about formatting data.
Figure 5-4: Data formatting application
Cascading Style Sheet (CSS) A Cascading Style Sheet (CSS) allows you to style your Flex application in a similar manner to an HTML Web page. You can either declare your styles within the inline MXML tag, or reference an external file that contains the styles. To use the tag, it is must be a second-level child tag of the root tag in the MXML file and it can be used only in MXML applications and not MXML components. There are two different types of selectors when applying styles to components. The first is the class selector, which can be applied to an individual component. The second is the type selector, which is applied to all components of a certain type.
69
Part II: Developing in Flex 2.0 The following example shows a class selector and a type selector using the inline method within an MXML file. Both styles are applied to the same control.
.myLabel /* class selector */ { fontSize: 20; } Label /* type selector */ { color: #0000FF; }
Figure 5-5 shows the application rendered in a Web browser.
Figure 5-5: CSS application
Skins Skinning is the process of changing the appearance of a component by modifying or replacing its visual elements. These elements can be made up of images, SWF files, or class files that contain drawing API methods. Flex components can be reskinned without changing their functionality. Skins can be applied to components with various states (for example, the Button control, which has many skins for various states). Skins are defined using the downSkin, upSkin, and overSkin style properties to represent the way the Button control appears when it is down, up, and when the mouse is over the control. Refer to the Flex 2 documentation for all skins regarding the Button control. You can define style properties in a few ways: either inline using the tag, the setStyle() method, or Cascading Style Sheets (CSS). You can add skins to Flex components either graphically or programmatically.
70
Chapter 5: Programming Languages Graphical Skins You need to embed image files into your Flex application to use graphical skins. The graphical skins replace the existing skins when you define the files as style properties. The main advantage of graphical skinning is that designers can use tools such as Adobe Photoshop to create the skins as images with no knowledge of ActionScript. However, graphical skins may take up more memory and increase the file size because the external images or SWF files are embedded within the Flex application. Another disadvantage when using graphical skins is that they may distort if you resize the component. The solution to this problem would be to use a technique called Scale-9 to create your skins. This will allow your components to resize without distorting skins. The following code example shows the styles defined inline between the tag. The overSkin, upSkin, and downSkin style properties point to the image files.
Button { overSkin: Embed(“assets/images/over_skin.png”); upSkin: Embed(“assets/images/up_skin.png”); downSkin: Embed(“assets/images/down_skin.png”); }
Programmatic Skins Programmatic skins are drawn using ActionScript and are declared in class files. Knowledge of the Flash drawing API is needed to successfully apply skins to your Flex controls. This is a disadvantage because developers are required to create the skins, and not the designers. This means that the developer must translate the designer’s designs into code. One advantage of using programmatic skins is that you have much more control over your styles. If you wanted to control the radius of the Button control’s corners, this is possible using programmatic skins. They also use less memory because they are compiled without any reference to external files, such as images or SWF files. The following code example is a typical outline of a programmatic skin class that could be used to skin a Button control: package { // Import necessary classes here. import flash.display.Graphics; import mx.skins.Border; import mx.skins.ProgrammaticSkin; import mx.styles.StyleManager;
71
Part II: Developing in Flex 2.0 public class MySkin extends ProgrammaticSkin { public function MySkin() { // Set default values here. } override protected function updateDisplayList(w:Number, h:Number):void { // Add styleable properties here. // Add logic to detect component’s state and set properties here. // Add drawing methods here. } } }
Adding Effects An effect is a change to a component that occurs over a specified period of time. Examples include fading, resizing, and moving a component. Effects are initialized using a trigger (such as a mouse click), receiving focus on a component, or a component becoming visible. All these triggers are used to form behaviors. Behaviors let you animate, add motion, and add sound to your application in response to some user or programmatic action. For example, if you move your mouse cursor over a Button control, it may inform you by resizing slightly. To create a behavior, you define an effect with an id property and bind it to the trigger (mouseUpEffect). The following example has two effects defined, each with their own id property to distinguish them from each other. The one effect enlarges the component, while the other effect reverts it back to ts original size. These effects are assigned using their id property to the mouseDownEffect and mouseUpEffect triggers of the Button control.
72
Chapter 5: Programming Languages
Custom MXML Components In Flex, the ideal way to build your applications is using multiple MXML and ActionScript files. The reason for this is that the architecture promotes modular design and code reuse, and lets multiple developers work on the same project without much hassle. MXML components are MXML files that you create and use as custom MXML tags within other MXML files. The name of the MXML file becomes the class name, which you can reference in another MXML file. You will find the main use of MXML components is to extend the current functionality found in existing Flex components. A simple example of using a custom MXML component would be to have a ComboBox control with a list of states. It would be a pain to create and initialize a ComboBox component with the list of states every time you needed one in your application. The solution would be to create a custom MXML component that extends the ComboBox control and have the list of states defined in there. So anytime you need a state selector in your application, you could use the custom MXML component. The name of this example file is StateSelector.mxml, which extends the ComboBox control and adds an array of objects containing the list of states:
The following MXML code shows you how to use the StateSelector.mxml in your Flex application:
The StateSelector.mxml is in the same subdirectory as the main application MXML file. So no namespace is required when defining the custom MXML component.
73
Part II: Developing in Flex 2.0
MXML This section describes the basics of the MXML syntax, which, as you may know, is used to build your user interfaces.
Basic MXML Syntax You will find that most MXML tags correspond to ActionScript 3.0 classes or properties of those classes. The Flex compiler parses the MXML tags and compiles them into one SWF file that contains the SWF byte code. You have already seen many examples so far using MXML syntax. Let’s start off with an easy example, such as defining a Button control:
As you can see, the id property of the Button control has been set to myButton, which needs to be unique for each control in the MXML file. The label property sets the text that is shown inside the Button control. The following example shows a complete Flex application with one Button control defined:
MXML Naming Conventions When you create new MXML files, there are naming conventions you must adhere to: ❑
Filenames can only start with a letter or an underscore (_), and they can only contain alphanumeric and underscore characters after that.
❑
Filenames cannot be the same name as ActionScript class names, component id values, or the word “application.“ Also, do not use filenames that match MXML tags in the mx namespace.
❑
All filenames are required to end with the lowercase .mxml file extension.
A lot of MXML tags correspond to ActionScript classes. When defining the tags, you use the same naming conventions as the ActionScript class. In other words, the class begins with a capital letter, and each capital letter separates the words in the class name. Also, the properties and events also correspond to the ActionScript class.
74
Chapter 5: Programming Languages
ActionScript ActionScript is the reason Flex developers exist. Without it, your application would have no logic, and all it would be is a useless user interface. Flex developers need ActionScript to be able to extend the functionality of their applications. The language provides control and object manipulation that is not available in MXML.
Flex Components As a Flex developer, you will find that ActionScript’s primary use will be working with visual controls and containers in your application. In this section, you learn how to reference a Flex control and manipulate the properties in ActionScript.
Referring to a Control in ActionScript Before you write any ActionScript, you must define a control in MXML and assign an id property to it. This allows you to reference the Flex control in ActionScript.
The id property is optional and is only required when referencing the component. The MXML compiler creates a variable called myTextInput that contains a reference to the TextInput object. You can access all the public methods and properties using the dot notation in ActionScript. To access the control in ActionScript, you must reference the id property. The following example shows you how this is done:
75
Part II: Developing in Flex 2.0 The getText() method returns a string, refers to the TextInput control’s id property (myTextInput) and accesses the text property of the object. One thing to note is that the ids for all tags in an MXML component, even deeply nested, generate public variables in the component being defined. In other words, all id properties must be unique within the document. If the id property of a Flex component is not defined, you can use the methods of the component’s container, namely, getChildAt() and getChildByName():
This example casts the getChildAt(0) to type TextInput to access the name property and assigns the value to the variable name. The variable name is passed into the childChildByName(name) method and cast to type TextInput to allow access to the text property, which is assigned to variable text. The this keyword is another way to reference components in a document using ActionScript. To access the object, you use the keyword, followed by the square brackets, passing in a string between them. The following code example has the same functionality as the previous one, except it uses the this keyword to reference the TextInput control:
Component Method Invocation In ActionScript, you can invoke a method on a component using the standard dot-notation syntax, as shown here: myTextInput.setSelection(0, 5);
The myTextInput is the id property of the TextInput control, which, as you know, is a variable. Using the dot notation, the setSelection() method is called with the required parameters. If you need to invoke a method from a child document (such as an MXML component), you can use the parentApplication, parentDocument, or Application.application properties. With these methods, you can access parent document public methods and properties. An example of where this may come in useful is when you need to call a method on the parent document from a popup window.
Using ActionScript to Create Visual Components To create visual components at run-time, you must use the new operator. This is the same way you create instances of an ActionScript class. When the component is instantiated, all its default properties are available, but it does not have a parent or any children. Also, you will not be able to see the component, because it is not yet in the display list of the Flash Player. This is the most appropriate time to set any properties on the component before it is added to the display list. Once you have all the necessary properties set, you must add the new component to a container by using the container’s addChild() or addChildAt() method. This will put the component into the Flash Player’s display list, and the component’s children are then created. The children are created late so that you can set the properties that affect the children as they are created. The following piece of code creates a TextInput control using the container’s addChild() method. If you want to add a control to a specific index in the display list, you can use the addChildAt() method.
77
Part II: Developing in Flex 2.0
To remove a control at run-time, you can use the removeChild() method or removeChildAt() method. There is also a method called removeAllChildren() that will remove all the children from the container. One thing to remember when using these methods is they do not actually delete the objects from memory. Some time in the future of the application cycle, the Flash Player will include the objects in the garbage collector, unless you have a reference to the child on some other object. The addChild() method can only take a parameter of type DisplayObject. If you create a new object that is not a subclass of flash.display.DisplayObject, you must wrap it in a DisplayObject before attaching it to a container.
Separating ActionScript from MXML This section shows you several different methods of separating ActionScript from MXML. The first method is having one MXML file with the event-handling logic in the event attribute:
The second method is another MXML document, but instead putting the event-handling code in the block:
Lastly, the third method is an MXML document again, but with the event-handling code in a separate ActionScipt file:
The thirdsample.as file contains the following code: public function setLabel():void { myLabel.text = “Third method”; }
Developing ActionScript Components In ActionScript, you can create reusable components and reference them in MXML as tags. You can create your own components from scratch, or extend existing components within the Flex Framework. Developing your own components in ActionScript allows you to modularize the application and maintain your code separately. This is great when you have many developers working on the same application. Each Flex developer can write a component (or a separate part of a component), and from there, you will eventually have a full suite that can be reused between applications.
79
Part II: Developing in Flex 2.0 When developing components, you may consider basing them off the current Flex components because there will most likely be logic you can reuse within your own custom components. For example, you may want to create a masked TextInput control and, instead of starting from the beginning, you can extend the existing Flex TextInput control. The following piece of code is a custom component called MaskedTextInput derived from the TextInput control and the package name is com.mycompany.components: package com.mycompany.components { import mx.controls.TextInput; public class MaskedTextInput extends TextInput { public function MaskedTextInput() { super(); } } }
To reference your custom component in your application, you must define a namespace components (this can be any name) that points to the directory of the MaskedTextInput.as file:
Types of Components In ActionScript, you can create the following types of custom components: ❑
User-interface (UI) components are Button, TextInput, and ComboBox controls plus VBox, HBox, and Canvas containers that a user can interact with using the mouse and keyboard. A typical custom visual component extends the UIComponent class or other Flex visual components.
❑
Non-visual components are Flex components that have no visual elements, such as the HTTPService, Web service, and DateFormatter components. These components do not extend the UIComponent class and provide greater efficiency at run-time.
Performing Reflection Reflection is the process by which an application can be modified in the process of being executed, in a manner that depends on abstract features of its code and its run-time behavior. In other words, the program has the ability to “observe” and possibly modify its own structure and behavior.
80
Chapter 5: Programming Languages The following is an example in Java using the java.lang.reflect package. If you are familiar with Java, and have used the java.lang.reflect package, this should be easy to understand. // Java code to illustrate how reflection works // Without reflection Person person = new Person(); person.walk(); // With reflection Class cl = Class.forName(“Person”); Method method = cl.getMethod(“walk”, null); method.invoke(cl.newInstance(), null);
Both code fragments create an instance of a class Person and call its walk() method. The difference is, in the first fragment, the names of the class and method are hard-coded. It is not possible to use a class of another name. In the second fragment, the names of the class and method can easily be made to vary at run-time. In ActionScript, the introspection API (discussed shortly) is not as advanced as the Java equivalent, but does allow you to read the methods and properties, and invoke methods of an object at run-time. Reflection is an activity that allows an object to have information about the structure. The programming paradigm driven by reflection is called reflective programming. In ActionScript 3, reflection is referred to as object introspection. There are two ways to do introspection in ActionScript: ❑
Using the for…in loops
❑
Using the introspection API
For…in Loops The for…in loop does not enumerate over declared variables and methods of classes but only dynamically added properties. So, in other words, most of the ActionScript API classes would not display any properties. The following code example creates an instance of the Object class and adds properties to that instance. The Object class is dynamic, which means you can add or change properties at run-time.
The output of the trace statement would look like this: firstname: Simon emailaddress: [email protected] lastname: Barber
There is a toString() method in the mx.utils.ObjectUtil class that will print all the dynamically added properties of an object: public function dump(o:Object) { trace(ObjectUtil.toString(o)); }
Introspection API In the previous section, you were shown how to use the for…in loop and ObjectUtil class’s toString() method to print out dynamic properties of an object. The introspection API in ActionScript allows you to list all the public properties and methods of a non-dynamic (sealed) class or class instance using the describeType() method. The method is in the flash.utils package and returns an E4X XML object that contains an XML description of the object’s type. To return information about the non-static members of a class, use describeType (this), with this meaning any object instance or ActionScript primitive types. If you want to return information about the static members of a class, use describeType(getDefinitionByName(“MyClass”)). The following examples traces out the variables of the TextInput control instance textInput:
82
Chapter 5: Programming Languages
The output displays the variables of the TextInput control: Variable isPopUp = false (Boolean) Variable states = (Array) Variable transitions = (Array)
One more other useful method for introspection is the ObjectUtil’s getClassInfo() method, which returns an Object with the name and properties of the object. The following example traces the object out using the toString() method of the ObjectUtil’s class:
Handling Events Being able to handle events in Flex is very important because you will most likely need to use them to interact with Flex controls, custom controls, and components. This section provides you with basic information about the event model in Flex 2, and describes the Event object, its subclasses, and the event dispatching model. Events inform a developer that something has happened within a Flex application. They can be generated when the visual appearance of a component changes, when the component is created and destroyed, and by using user devices such as the mouse and keyboard. In other words, any user interaction will most likely trigger an event, or even data that is returned from the server may trigger an event. This happens without any user interaction. The developer can listen for these events by adding event listeners, which are functions used to respond to the triggered events. They are commonly referred to as event handlers. To give you an example, a user clicks a button that downloads data from the server. An event handler listens for an event to be triggered once the data has been fully downloaded. The event is fired, which, in turn, calls the event-handler function and parses the data into some meaningful information to be used in a DataGrid control, for example. All or most components in Flex have built-in events that can be handled in ActionScript in your MXML applications.
Event Flow The event model allows developers to listen for any events being dispatched by another control. The flow of an event starts when the Event object is dispatched. It then makes a journey from the root of the display list to the target node, checking for registered listeners. The target node is the node where the event originated from (for example, a user clicks a Button control named Button1). The Event object’s target node holds a reference to Button1. There are three parts to the way event flow works: ❑
84
Capturing phase — This phase comprises of all the nodes from the root node to the parent of the target node. Once this phase is in execution, the Flash Player starting at the root examines each node to see if there is a listener registered to handle the event. If it finds registered listeners, it will set the values of the Event object and then call the listener function. The Flash Player stops after it has reached the target node’s parent and called the registered event listeners.
Chapter 5: Programming Languages ❑
Targeting phase — This phase consists only of the target node. The Flash Player sets the values on the Event object, looks at the target node for any registered event listeners, and then calls those listeners.
❑
Bubbling phase — This phase consists of all the nodes from the target node’s parent to the root node. It begins at the target node’s parent where the Flash Player sets the values on the Event object and then calls the event listeners on each of these nodes. The Flash Player will stop after any listeners on the root node are called.
These phases are examined in more detail later in this chapter.
Event Class The flash.events.Event class is the base class for all events in your application. Any time an event occurs in Flex, this class is implicitly created when it is dispatched. It contains properties with information about the event that occurred. The event listeners can access the details that were passed with the event’s properties, such as the event type and the target that dispatched the event. However, passing an Event object to the event listener is optional. The Event object is created only once on every dispatch. During the bubbling and capturing phases, the values on the Event object change as it moves up or down the display list. This is much more efficient than creating a new Event object for each node.
Subclassing Events There are two packages that house all the major event classes that extend the flash.events.Event class. They are mx.events and flash.events. The mx.events.* packages contains all the events that are specific to the Flex controls, such as the DropDownEvent and ItemClickEvent classes. The other package, flash.events, contains all the events that are defined by the Flash Player, such as the TextEvent and MouseEvent classes. When developing Flex applications, you must create your own events that extend the Event class. These custom events will contain additional unique properties that hold vital information that the Event class does not contain. For example, the TextEvent class extends the Event class and has a text property that contains a character or sequence of characters entered by the user.
EventDispatcher Class The EventDispatcher class allows any object that inherits from it to participate in the Flex event model. All objects in the Flash Player’s display list inherit the functionality of the EventDispatcher class. The reason for this is that all objects in the display list inherit from the DisplayObject class, which, in turn, extends the EventDispatcher class. Although you may think the EventDispatcher only allows you to dispatch or send events, you would be mistaken. This class gives you the functionality to register for events, check for event listeners, and remove
85
Part II: Developing in Flex 2.0 event listeners. The most common method used in the EventDispatcher is the addEventListener() method, which you use to register an event listener. More advanced programmers and component developers will use the dispatchEvent() method to manually dispatch or send events a custom Event object into the event flow. One other method to mention is the hasEventListener() method, which checks for an event listener of a specific event type on a particular display object and returns true if it is found.
Event Usage To use events in Flex, you must first define an event listener or event handler. This is a function or class method that responds to an event when it is dispatched. The signature of the function can optionally include an argument that specifies the event type. The following example is a basic event listener function that traces a string to the console:
Secondly, you must register the event listener or function with a display list object by using the EventDispatcher class addEventListener() method: btn1.addEventListener(MouseEvent.CLICK, eventListenerFunction);
There is a simpler method to listener registration for Flex controls in MXML. You define the click event, which references the listener function on the Button control using an attribute:
This is the same as using the addEventListener() method to register the listener in the previous code example. However, it is better practice to use the addEventListener() method because it gives you greater control and you can configure the priority and capture settings, and use event constants. With event constants, you can ensure that the event type is valid at compile time. Any time an event is dispatched, Flex creates an Event object containing information about the event, such as the type and a reference to the control that fired it. To have access to the Event object, it must be passed into the event listener function, as this following code example shows: public function eventListenerFunction(event:Event):void { trace(“Event type: “ + event.type); }
86
Chapter 5: Programming Languages To do the same within MXML using an inline event, you must explicitly pass the event into the listener:
The event model allows you to register multiple event listeners with a single event. This may be useful when you want two things to happen when a user clicks a Button control. The following example shows multiple event listeners registered to a single instance of a button in MXML and ActionScript: // MXML
// ActionScript public function initUI():void { btn1.addEventListener(MouseEvent.CLICK, eventListenerFunction1); btn1.addEventListener(MouseEvent.CLICK, eventListenerFunction2); }
To set the order in which the event listeners are called, you must specify the priority parameter of the addeEventListener() method. This obviously cannot be done using the inline method in MXML. The opposite also works by registering a single event listener with multiple components. The following example again shows the registration of a single event listener with multiple components in MXML and ActionScript: //MXML
//ActionScript public function initUI():void { btn1.addEventListener(MouseEvent.CLICK, eventListenerFunction); btn2.addEventListener(MouseEvent.CLICK, eventListenerFunction); }
The Target Property of the Event Class As mentioned earlier, the Event object contains a reference to the object dispatching the event. In essence, you can access all the public methods and properties of the instance within the event listener. The following example accesses the currentTarget.name property of the UIComponent: public function eventListenerFunction(event:Event):void { trace(“The button instances name is “ + event.currentTarget.name); }
To call methods and access properties on the current target within the event listener, you must cast the currentTarget property to a DisplayObject. If you need to access the properties of a specific control (such as the Button control), the currentTarget property must be cast to type Button.
87
Part II: Developing in Flex 2.0 The following example sets the label of the Button control to “Label Changed”: import mx.controls.Button; public function eventListenerFunction(event:Event):void { Button(event.currentTarget).label = “Label Changed”; }
Propagation There are three phases during which Flex looks for event listeners when events are triggered. The phases occur in the following order:
1. 2. 3.
Capturing phase Targeting phase Bubbling phase
In this section, you learn more about how event propagation is handled in Flex, and learn more about each phase.
Difference Between the Target and currentTarget Properties All Event objects have a target and currentTarget property, which keeps track of where it is in the propagation process. The target property references the dispatcher of the event, and the currentTarget property references the current node that is being examined for event listeners. When a user clicks a control, the target property often refers to a subcomponent such as a UITextField (which renders the label) in a Button control. In other words, when the Flash Player dispatches the event, it might be triggered from the internal subcomponent and not the Button control. Most likely, you will have the Button control listen for the event, and the target property of the event listener might refer to the UITextField or subcomponent of the control. The MouseEvent will bubble up the chain within the control, but the target property (which might be the UITextField) will stay the same. The currentTarget property will be set to each level as it moves up the chain, and eventually reference the Button instance. So, for this reason, you should use the event.currentTarget property rather than the event.target property.
Capturing Phase As mentioned, the capturing phase is when Flex examines an event’s ancestors in the hierarchy for registered event listeners. It starts at the root ancestor, and carries on down the display list until it reaches the parent’s target. Figure 5-6 shows the structure of a basic application. The capturing phase starts at the Application object and moves through to the Panel (parent of the target).
88
Chapter 5: Programming Languages Application
VBox
Panel
TextInput
Figure 5-6: Capturing phase
The currentTarget property will change on the Event object to the node of the listener being called during the capturing phase. The target property will remain the same, referring to the dispatcher of the event. The useCapture property of the addEventListener() method defaults to false and has to be explicitly set to true. Adding an event listener using MXML will result in the argument being set to false, and there is no way to override it.
Targeting Phase The targeting phase is when Flex invokes only the event dispatcher’s listeners. So, no other nodes in the display list are looked at during this phase, and the currentTarget and target properties remain.
Bubbling Phase The bubbling phase is very similar to the capturing phase, except it looks for event listeners in reverse. In other words, it starts at the dispatcher’s parent and carries on up the display list to the root application. Figure 5-7 shows the same structure of a basic application as the capturing phase. The bubbling phase starts at the parent of the dispatcher and moves through to the root of the application. The events will only bubble and process the event bubbling phase if the bubbles property is set to true. Keyboard and mouse events bubble by default, but it can be dangerous to set all your events to bubble by default. The reason for this is that if you are listening for different events, but the event type is the same, all those listeners will trigger. This can be difficult to debug, and it is recommended not to bubble your events unless it’s really necessary.
89
Part II: Developing in Flex 2.0 Application
VBox
Panel
TextInput
Figure 5-7: Bubbling phase
There is one more thing to remember. If you set the useCapture property to true, the bubbling phase will not process. If you want both phases to be processed, you have to call the addEventListener() method twice, once with useCapture set to true and the other with useCapture set to false.
Priorities Event priority is really used when there are many event listeners registered with a single event. The event listeners are called depending on the order in which the addEventListener() methods are defined. Using MXML to register the events results in an unpredictable order. To change the order in which the event listeners are called, you specify the priority property parameter in the addEventListener() method. The priority works from highest to lowest. The listener2() method will be called first because it has the highest priority of 2, and the listener1() method will be called next. public function initUI():void { btn1.addEventListener(MouseEvent.CLICK, listener1, false, 1); btn1.addEventListener(MouseEvent.CLICK, listener2, false, 2); }
If all the event listeners have the same priority, they will be executed in the order they are defined. The priority can be either positive or negative, and the default value is 0. To change the priority of the event listener, the removeEventListener() method must be called to remove the event listener. You will then need to register the event listener again with a different priority.
90
Chapter 5: Programming Languages An important point to remember is that there is no guarantee that the listener will finish executing before the next one in the priority list is called. In other words, you should ensure that listeners do not rely on other listeners to complete before calling the next one. The Flash Player does not necessarily wait for the first handler to finish executing before proceeding to the next one.
Subclassing Events In Flex, there are many subclasses that are based off the Event class. They contain specific information about the event that is not available in the Event class, such as the DragEvent class. Flex controls generate an Event object that is a specific event type (for example, when you drag a row from one List control to another). If you specify the event type as a parameter in the event listener functions, you can access all the subclass’s properties. The following is an event listener that listens for the dragComplete event to be dispatched. You can define the event parameter as a basic Event class, but you will have to cast it in the event listener to access the properties specific to the subclassed event. This way it can use less memory, but it is best practice to declare the type. private function doDragComplete(event:DragEvent):void { trace(“dragComplete triggered: “ + event.type); }
While developing Flex applications, you will need to create custom events that carry specific information not found on the Event class. To accomplish this, create a custom class that extends the Event class, as the following example shows: package com.mycompany.events { import flash.events.Event; import com.mycompany.vo.UserVO; public class LoginEvent extends Event { public function LoginEvent(type:String, userVO:UserVO, bubbles:Boolean=false, cancelable:Boolean=false) { super(type, bubbles, cancelable); this.userVO = userVO; } public var userVO:UserVO; } }
The LoginEvent class extends the Event class and adds an extra property called userVO. This contains a reference to another custom class called UserVO, which has all the properties associated with a user of the application. The userVO property is set in the constructor of the LoginEvent class. This can be set as optional by specifying the property to be equaled null. public function CustomEvent(type:String, userVO:UserVO=null, bubbles:Boolean=false, cancelable:Boolean=false)
91
Part II: Developing in Flex 2.0 { super(type, bubbles, cancelable); this.userVO = userVO; }
Keyboard Events As you may already know, or may have gathered, the Flash Player supports all the basic functionality using keyboard combinations from the operating system. You can also trap or override any key or combination of keys to perform an action. You may find that you want to trap keys globally so that wherever a user is in the application, the keystrokes are identified and the necessary action is performed. No matter where the mouse is in an application, Flex recognizes the global keyboard events. The most common way to handle keyboard events is to create an event listener. If you want to trap any key when it is pressed, you can add an event listener to the stage object, as the following example shows: private function addKeyboardListeners():void { stage.addEventListener(KeyboardEvent.KEY_DOWN, trapKeys); }
As you can see, every time a user presses a key, the trapKeys() method is called to process any logic that the developer has defined. The following example shows what the trapKeys() method looks like for this basic example. The function traces out the event.charCode and event.keyCode to the console. private function trapKeys(event:KeyboardEvent):void { trace(“charCode: “ + String(event.charCode) + “ | keyCode: “ + String(event.keyCode)); }
To accomplish the same task in MXML using the inline method, you can define the keyDown event of a UIComponent and reference the trapKeys() method:
Keys can only be trapped on components that can have focus. You should avoid trying to trap keys on containers that cannot have focus, such as the Box containers. Instead, if a container has children that accept focus and keyboard input from the user, you can set the event handler on the container and assume it will bubble up.
Precedence on KeyboardEvent Registering event listeners for keyboard events with regard to order does not work the same way as explained earlier in the chapter. Defining the keyUp and keyDown event listeners for the parent and control will result in each component dispatching the same event twice, because the event bubbles. This will result in the target property changing.
92
Chapter 5: Programming Languages In the following example, the keyDown event is registered in the application, Panel container, and the TextArea control: private function addKeyboardListeners():void { application.addEventListener(KeyboardEvent.KEY_DOWN, trapKeys); panel1.addEventListener(KeyboardEvent.KEY_DOWN, trapKeys); textarea1.addEventListener(KeyboardEvent.KEY_DOWN, trapKeys); }
The order in which the keyboard events are dispatched is the child controls are first before any of their parents. In this example, the TextArea control event is dispatched first, then the Panel control, followed by the Application.
MouseEvents The MouseEvent class and all its subclasses have extra properties that determine if a specific key was held down when clicking the mouse button: ❑
altKey — Set to true if the Alt key is held down when the user pressed the mouse button.
❑
ctrlKey — Set to true if the Ctrl key is held down when the user pressed the mouse button.
❑
shiftKey — Set to true if the Shift key is held down when the user pressed the mouse button.
You may want the user to be able to open a popup window by holding down the Alt key and Shift key together while pressing the mouse button anywhere within application.
Summar y This chapter provided the insight and knowledge to build your first Flex application. You learned about the MXML syntax and using ActionScript to provide flow control and object manipulation that is not available in MXML. Lastly, you learned about one of the most important features in Flex — handling events within your applications. Chapter 6 describes how to improve the user experience by adding functionality to your application and customizing the user interface. You learn about styles, fonts, skins, and item renderers, and how to localize your applications.
93
Building User Interfaces This chapter describes how to use Flex 2 components to build user interfaces for your applications. Flex 2, as you know, has many built-in components that make life a lot easier when it comes to building the interface. You are introduced to Flex controls, data providers, and collections, and how to lay out controls using containers. Flex makes it very easy to lay out your user interfaces using MXML.
V isual Components The component-based development model Flex provides allows you to develop applications that are architecturally sound, achieving great scalability and reliability. The pre-built visual components in Flex allow you to build interfaces faster without having to create your own components. That said, Flex includes a well-thought-out component architecture that allows you (as the developer) to build your own components, either by extending existing ones, or creating your own. You have a lot of power at your fingertips when using visual components in Flex. They are extremely flexible and provide a great deal of control over their appearance (the font and size of the text in any component, the sizing of components), as well as their response to user interactions. This section provides an overview of the characteristics of visual components such as size, events, styles, behaviors, and skins.
Class Hierarchy All visual components in Flex generally extend the UIComponent class. This is the base class for all visual components in Flex, both interactive and non-interactive. When creating custom components, you should extend the UIComponent class because it contains functionality for width, height, handling double-clicks, id property, style names, and x and y properties. Figure 6-1 shows the class hierarchy from the Object class through to all visual components in Flex.
Part II: Developing in Flex 2.0 Object
EventDispatcher
DisplayObject
InteractiveObject
DisplayObjectContainer
Sprite
UIComponent
All Visual Components
Figure 6-1: Class hierarchy from the Object class through to all visual components in Flex
UIComponent Class The UIComponent class has many properties and methods that are accessible when extending the class. The most commonly used properties are listed in the following table.
96
Property
Type
Description
doubleClickEnabled
Boolean
Specifies whether the UIComponent object receives doubleClick events
enabled
Boolean
Whether the component can accept user interaction
height
Number
Number that specifies the height of the component, in pixels, in the parent’s coordinates
id
String
ID of the component so that you can refer to it using ActionScript
Chapter 6: Building User Interfaces Property
Type
Description
percentageWidth
Number
Number that specifies the height of a component as a percentage of its parent’s size
percentageHeight
Number
Number that specifies the width of a component as a percentage of its parent’s size
styleName
String
The class style used by this component. Very similar to the way CSS works in HTML
toolTip
String
Text to display in the tooltip
visible
Boolean
Controls the visibility of the UIComponent
width
Number
Number that specifies the width of the component, in pixels, in the parent’s coordinates
x
Number
Number that specifies the component’s horizontal position, in pixels, within its parent container
y
Number
Number that specifies the component’s vertical position, in pixels, within its parent container
Component Sizing The Flex SDK has layout and sizing functionality that allows you to control the size of your visual components. You can determine the size of your components (explicit sizing), or let Flex do it for you (default sizing). To use default sizing, you do not specify the width and height of the component. Explicit sizing, on the other hand, requires you to specify the width and height of the visual component, as the following example shows:
You may find explicit sizing to be too precise. You can, instead, define the size of the component as a percentage. In Flex, this is called percentage-based sizing. The following example shows percentage-based sizing on a Panel control:
97
Part II: Developing in Flex 2.0 To specify the percentage-based sizing in ActionScript, you must access the percentageWidth and percentageHeight properties of the control. The following example will reset the Panel control’s width to 50 percent of the parent container: panel1.percentageWidth = 50;
The layout of your components is very important. Flex has a mechanism called constraint-based layout that allows you to control the size and position by anchoring the sides, or centering the components within their containers by specifying the top, bottom, left, right, verticalCenter, and horizontalCenter properties. The following example shows a VBox container defining constraint-based layouts:
You can mix the sizing and layout properties as long as they are done appropriately. You must not specify the width and percentageWidth of a control, because you can use only one or the other.
Event Handling A user interacts with a component such as clicking a button that, in turn, fires an event. You can write code to process the click event that may pop up an Alert control, informing the user that something important has occurred. As you may know, Flex applications are event-driven, and this makes it a very powerful platform to develop your Rich Internet Applications (RIA). The basic cycle of event handling starts when events are dispatched. The objects that have registered listeners are notified for that event. Event handlers (or event listeners) are defined to process the event in ActionScript. You register event listeners in either ActionScript or the MXML declaration of the component. The following example registers an event listener in MXML that is processed when the Button control is clicked:
98
Chapter 6: Building User Interfaces This example passes in the event object when declaring the click event handler handleClickEvent (event). The event handler in this example does not make use of the event, but you will need to do so in many of the applications you build. You do not have to pass in the event object, as long as it is not defined as a parameter in the event handler. The following example shows the event object being accessed within the event handler. The List control contains the names of the three authors. The event handler is registered to the change event. Any time a user selects an item in the List control, the Alert control pops up and shows the name of the selected author through the selectedItem property.
Component Instantiation Component instantiation works as a sequence of steps that occur when you create a component instance from an ActionScript component class. The easiest way to create an instance of a component is declaring it in MXML. On the other hand, you can do the same process in ActionScript. The following example creates a Button control in ActionScript and adds it to the display list of the Flash Player: import import import import
mx.effects.easing.Back; mx.controls.Button; mx.containers.VBox; mx.core.Container;
99
Part II: Developing in Flex 2.0 private function initUI():void { var vboxContainer:VBox = new VBox(); addChild(vboxContainer); var buttonControl:Button = new Button(); buttonControl.label = “Click”; vboxContainer.addChild(buttonControl); }
The following steps occur when this code is executed:
1. 2. 3. 4. 5.
The constructor of the vboxContainer instance is called. The addChild() method is called to add the vboxContainer instance to the display list. The constructor of the buttonControl instance is called. The buttonControl instance label property is set to the string “Click”. The vboxContainer instance addChild() method is called to add the buttonControl instance to the display list or stage. The following actions are performed internally when the button instance is added to the stage:
6.
a.
The parent property of the component is set to reference its parent container.
b.
The style settings of the component are processed.
c.
The add event for the button is dispatched.
d.
The childAdd event for the parent container is dispatched.
e.
The preinitialize event of the component is dispatched. The component is currently in a very raw state, and the control creates internal child components. For example, the Button control creates the UITextField to show the label text.
f.
The component’s children are created and initialized, including the internal children.
g.
The initialize event is dispatched on the component, of which, at this stage, all children have been initialized, but the component is not fully processed. No sizing or layout has been executed yet.
A render event is dispatched to display the application, and Flex does the following: a.
All the processing is completed to display the component, including layout of the component.
b.
The visible property is set to true to show the component.
c.
The creationComplete event is dispatched and the component’s size and layout has been processed, including all the properties.
d.
The updateComplete event is dispatched. This event is dispatched whenever the position, size, or other visual characteristics of the component changes.
If you were to remove the component using the removeChild() method, the child’s parent property would be set to null. The Flash Player will delete the component from memory using the garbage
100
Chapter 6: Building User Interfaces collector if there are no references to the component. This happens at an undetermined time when the Flash Player does a sweep to remove objects from memory. Figure 6-2 shows the following major events that are dispatched in a component’s creation life cycle: ❑
The preinitialize event occurs very early in the life cycle of a component to do any initialization. In rare situations, it may come in handy when you must set the properties on a parent before the children are created.
❑
The initialize event is useful to configure a component before Flex has determined the visual appearance. So, in other words, use this to set properties that affect its appearance (such as width and height).
❑
The creationComplete event should be used to set accurate values on the component (such as the size or position). Using this event to perform actions that change the visual appearance will require Flex to recalculate its layout, which creates unnecessary processing overhead.
❑
The updateComplete event should be used to perform actions each time the characteristics of the component change. preinitialize
initialize
creationComplete
updateComplete
Figure 6-2: Major events that are dispatched in a component’s creation life cycle
Styling Components Styling in Flex is defined using Cascading Style Sheets (CSS), which allow you to set the characteristics of components (such as fonts, padding, and alignment). All visual components can define their own styles, but, by default, they are inherited from its superclass. You may notice that some styles are inherited not by the subclass but from the superclass. To find out more about which styles are supported in the visual component, refer to the Adobe Flex 2 documentation. Styles can be defined in MXML as tag attributes, such as setting the padding between borders of a container or defining the font weight of a TextInput control.
101
Part II: Developing in Flex 2.0 The following example shows a Label control with the fontWeight and fontSize style attributes defined in MXML:
Styles can also be defined using the tag in MXML or ActionScript using the setStyle() method. The setStyle() method takes two parameters: the style name (as a String) and the value. This example uses the ActionScript setStyle() method to set the Label control’s fontWeight and fontSize styles:
This example uses MXML and the tag. The styles are set using CSS syntax inline, or using an external file that contains style declarations. The style declaration is referenced in MXML using the styleName tag attribute on the visual component:
.myLabelStyle { font-weight: bold; font-size: 20; }
102
Chapter 6: Building User Interfaces
The .myLabelStyle is a CSS class selector style definition that applies only to visual components that have referenced it using the styleName attribute. A type selector applies to all instances of the component type, such as shown in the following example:
Label { font-weight: bold; font-size: 20; }
Adding Behaviors In Flex, a trigger combined with an effect is called a behavior. A trigger is an action similar to an event, and an effect is a visible change to a component of a specified period of time in milliseconds. Effects are fading, resizing, zooming, or moving a component around the stage. Multiple effects can be defined for a single trigger either in parallel or in sequence. Triggers are implemented as CSS styles, which means that you can set them as tag attributes in MXML using the tag or in ActionScript using the setStyle() method. Behaviors allow you to add animation, sound, and/or motion to your application in response to user or programmatic action. To create a behavior, you declare a specific effect with a unique id and bind it to the trigger. The following example declares a Fade effect with an id of fadeInstance, which is bound to the creationCompleteEffect trigger of the Button control. The Fade effect has an alphaFrom property, which is the initial transparency level between 0.0 and 1.0, where 0.0 means transparent and 1.0 means fully opaque. The alphaTo property is the final transparency level, and also takes a value between 0.0 and 1.0. The duration property is how long the effect takes to finish in milliseconds.
103
Part II: Developing in Flex 2.0
Applying Skins Chapter 7 provides more details about skinning in Flex, but for now, this discussion will serve as an introduction. Skins are graphical style elements that dictate the look of visual components. Many components have many skins. For example, the Button control has eight, one for each button state (such as Up, Down, Disabled, Selected, Focus, Over, and so on). All these elements can be made up of images, SWF files, or class files that use the drawing API methods to achieve the effect. There are two ways to add skins to a Flex component: graphically and programmatically. Figure 6-3 shows three Button controls: one with the upSkin, another with the overSkin, and, lastly, one with the downSkin.
Button
Button
Button
upSkin
overSkin
downSkin
Figure 6-3: Three Button controls
Modifying Components at Run-time In most languages such as Java or .NET, you can modify the look, size, or position of a component at run-time. Flex also allows you to do the same. You achieve this by using the component properties, styles, or ActionScript methods, including the x and y properties, and width and height properties, and by using the setStyle(stylename:String, value:Object) method. To use the x and y properties of a component, the parent container of the child must make use of absolute positioning. The Canvas container allows for absolute positioning by default, but the Application, Box, and Panel containers must set the layout property to absolute. With the x and y properties, you could reposition a TextInput control 10 pixels to the right and 10 pixels down when a user clicks a Button control. The following example shows how this is achieved:
104
Chapter 6: Building User Interfaces
The width and height properties are useful if you want to resize a component at run-time. In Flex, each component is set to a standard width and height if none are explicitly provided. The following example resizes a TextInput control by 10 pixels using the width and height properties:
One thing to remember about the width and height properties is that they are always set in pixels, regardless of whether they were originally fixed values, percentages, or not set at all.
Extending Components In Flex 2, you can create custom components that extend existing or custom components. When you extend existing components, you inherit all the functionality of the base component, plus you can add new properties and methods to it. The following example is a custom MXML component with a DateField control and TextInput control inside an HBox container. The TextInput control’s text property is bound to the DateField control’s selectedDate property. The filename for this component is MyCustomComponent.mxm, and it is located in a same directory as the application file.
105
Part II: Developing in Flex 2.0 To use the custom MXML component in your application, you must specify its filename as an MXML tag, as shown in the following example:
In this example, the custom component is in the same directory as the application file, which maps to the local namespace indicated by the asterisk. There are two ways to create custom components in Flex. The method you take depends on your application requirements of the component. ❑
Create custom components as MXML files that provide an easy way to extend existing components, modify the behavior, or add basic features to an existing component.
❑
Create custom components as ActionScript files by extending the UIComponent class or any of is subclasses. Using ActionScript to create custom components provides greater customization for visual or non-visual components.
For more information regarding creating MXML and ActionScript components, see Chapter 12, “Creating MXML Components,” and Chapter 13, “Flex Component Properties.”
Data Providers and Collections Many Flex controls use a data provider such as an array or ArrayCollection (for example, the ComboBox control, which reads in a data provider to define the options in the drop-down list). Collection classes are used to represent data providers in Flex, which is a group of objects with a set of methods to access, sort, filter, and modify items in the collection. This section describes data providers and collection classes, including an introduction to using data providers in controls. Also, you learn how to use collection classes to access and manipulate data.
Data Providers All List-based controls represent data using a data provider that is an object required by the control to make it function correctly. For example, the DataGrid control requires a data provider to determine the row of items to display to the user. The following are all the components that use data providers:
106
❑
Tree control
❑
DataGrid control
❑
ComboBox control
❑
List control
❑
TileList control
Chapter 6: Building User Interfaces ❑
Menu control
❑
MenuBar control
❑
ButtonBar control
❑
LinkBar control
❑
TabBar control
❑
ToggleButtonBar control
❑
LineChart control
❑
ColorPicker control
❑
PopUpMenuButton control
❑
HorizontalList control
❑
Repeater component
❑
DateField control
The easiest way to use a data provider with a control is declare an Array of strings or objects, which is then bound to the control’s dataProvider property. Using a raw data object has its limitations as a data provider, and you should use the collection classes if you have data that changes. Raw objects do not have the functionality to notify the control when changes to the base object occur. Therefore, the control does not get updated, unless it is redrawn or the data provider is reassigned. Another downside to using raw objects is that they do not provide functionality for accessing, sorting, or filtering data. The following example shows the difference between using an Array (raw object) and an ArrayCollection, with both of them bound to separate List controls. There are two Button controls: one calls the addCountryToArray()method, and the other one calls the addCountryToCollection() method. These two methods take the value from the TextInput control and add them to the relevant data providers.
You will see that the first List control does not reflect the changes when the Button control labeled Add Country to Array is clicked. However, when the Button control labeled Add Country to Collection is clicked, the List control below reflects the changes. The reason for this is that collections notify the control when changes are made to its data. Collections in Flex provide functionality to ensure data synchronization, simple and yet very sophisticated data access, and manipulation tools. They provide a consistent interface for managing and accessing data of many different types. Flex supports two basic types of data providers: ❑
Linear or listed-based data providers are one-dimensional, and are sometimes referred to as flat data consisting of a number of objects.
❑
Hierarchical data providers consist of tree-like structures, with the data source usually being an XML object. Controls that support hierarchical data are the Tree, Menu, MenuBar, and PopUpMenuButton.
The structure defined in hierarchical data providers matches the layout of a tree or cascading menu. A tree usually contains a root node with one or more branches or child nodes, which, in turn, contain branch nodes or children with an ending leaf node. Controls that support hierarchical data use the data descriptor interfaces to access and manipulate the data providers. You can write your own custom data descriptor if your hierarchical data does not support the format described by the DefaultDataDescriptor class. Once you have successfully
108
Chapter 6: Building User Interfaces implemented all the interfaces in your custom data descriptor, you can specify them in the hierarchical control’s dataDescriptor property. The ArrayCollection or XMLListCollection class and the ICollectionView or IList interface can be used to access or manipulate hierarchical data dynamically.
Collections Collections are more robust than plain Arrays because they provide functionality that includes adding and removing objects, as well as sorting and filtering the data. They also support change notification, which keeps data synchronized across an application. Collection interfaces provide the following features: ❑
They ensure that the control is updated properly when underlying data changes.
❑
They provide handling of paged data coming from remote data providers that may not initially be available.
❑
They contain a set of operations for handling data that is independent of those found in raw data providers such as an Array.
❑
The collections that implement the ICollectionView interface provide a view of the data that can be sorted or filtered by a custom method. These features affect the collection’s view and not the underlying data.
❑
Multiple components can use the same collection as their data provider.
❑
Collections can be modified so that changes are reflected by all the components that use the data provider.
The following example shows you how to define a collection in MXML:
United States South Africa United Kingdom
You can do the same in ActionScript as long as you import the mx.collections.ArrayCollection class. To initialize the ArrayCollection with data, you must pass an Array into the constructor, as shown in the following example: import mx.collections.ArrayCollection; [Bindable] public var myCollection:ArrayCollection = new ArrayCollection([“United States”, “South Africa”, “United Kingdom”]);
109
Part II: Developing in Flex 2.0 If an instance of the ArrayCollection is created without passing in an Array to the constructor, you can set it to the source property at a later stage. var myArray:Array = [“United States”, “South Africa”, “United Kingdom”]; myCollection.source = myArray; ArrayCollections can be bound to a chart control and updated in real time because collections support
notification changes. The following example does exactly this. A timer is set to run every 1000 milliseconds, which, in turn, adds a new object to the ArrayCollection, which reflects in the ColumnChart control. The object’s number property is set to a random number between 0 and 100.
import import import import
mx.utils.UIDUtil; flash.utils.Timer; flash.events.TimerEvent; mx.collections.ArrayCollection;
[Bindable] public var myCollection:ArrayCollection = new ArrayCollection(); public function initTimer():void { var myTimer:Timer = new Timer(1000, 0); myTimer.addEventListener(“timer”, timerHandler); myTimer.start(); } public function timerHandler(event:TimerEvent):void { var o:Object = new Object(); //o.uid = UIDUtil.createUID(); o.number = Math.random() * 400; myCollection.addItem(o); }
110
Chapter 6: Building User Interfaces
Collection Interfaces In the Flex Framework, the collection model uses the following interfaces to define how collections represent data, provide access to it, and manipulate them: ❑
IList — A collection of items organized in an ordinal fashion. Provides access and manipula-
tion methods based on the index. The interface does not provide sorting, filtering, or cursor functionality. ❑
ICollectionView — A view onto a collection of data. It can be modified to show the data
sorted according to certain criteria, or be reduced by filters without modifying the underlying data. The interface provides access to an IViewCursor object to access the items. ❑
IViewCursor — The interface for enumerating over a collection view bidirectionally. The cursor provides find, seek, and bookmarking functionality.
IList and ICollectionView interfaces allow developers access to two alternative methods for accessing and manipulating data. The IList interface is a simple interface that provides adding, setting, getting, and removing operations on linear data.
The ICollectionView interface, however, provides more complex functionality than the IList interface, and is appropriate if the underlying data is organized in a non-linear fashion. The collection that implements the ICollectionView interface can represent a subset of data by using the sort or filtering operations. The ArrayCollection and XMLListCollections classes implement both the IList and ICollectionView interfaces.
IList Interface The IList interface contains simple methods for linear data access using an index. Anything you change in the collection changes the data provider. For example, inserting an item at an index of two will also reflect as the second item in the underlying data source. The following can be achieved with the IList interface: ❑
Get, set, add, or remove an item at a specific index from the collection.
❑
Add an item at the end of the collection.
❑
Get an index of an item in the collection.
❑
Get the amount of items in the collection.
❑
Remove all the items from the collection.
111
Part II: Developing in Flex 2.0
ICollectionView The ICollectionView is a view of the underlying data source that represents a collection of items. The interface is more complex than that of the IList interface. The following can be achieved with the ICollectionView interface: ❑
Modify the view to show data in a sorted order, or show only a subset of the items using the filtering capabilities without changing the underlying data.
❑
Move through the collection, use bookmarks to save locations in the collection, and add and remove items by accessing the data using a cursor.
❑
Represent remote data that might not initially be available yet, or the dataset that may become available at different times.
Sorting Collections The Sort class allows you to sort on data in collections. Multiple fields are supported when sorting data, and require that the entries be unique. A custom comparison function can be used to order the sorted output, and the Sort class can also search for item in the collection. If you apply a sort instance to the collection, you are required to call the refresh() method of the collection to apply the changes. The SortField class is used to specify the fields to use in the sort. You create an instance of the SortField class and add it to the fields array property of the Sort class instance. All the SortField instances of the collection must be unique. The following example sorts an ArrayCollection in descending order. The primary sort is on the label field of the collection, case-sensitive, and in descending order.
import mx.collections.SortField; import mx.collections.Sort; import mx.collections.ArrayCollection; [Bindable] public var myCollection:ArrayCollection = new ArrayCollection([{label: “A”}, {label: “B”}, {label: “C”}, {label: “D”}, {label: “E”}]); public function sortCollection():void { var sort:Sort = new Sort(); sort.fields = [new SortField(“label”, true, true)]; myCollection.sort = sort; myCollection.refresh(); }
112
Chapter 6: Building User Interfaces
Filtering Collections Filtering limits the ICollectionView to a subset of the data provider’s underlying data. You define a function that takes a single Object parameter and returns a Boolean value to specify whether to include the item in the view. The same step applies with sorting as it does with filtering. You must call the refresh() method of the collection when you set the filter function. The following example uses both filtering and sorting of an ArrayCollection. There are two Button controls to apply the sort and filtering, respectively, and one to reset the view to its original state.
= “A” && item.label < “N”; } public function resetCollection():void { myCollection.filterFunction = null; myCollection.sort = null; myCollection.refresh(); } ]]>
113
Part II: Developing in Flex 2.0
IViewCursor Interface The IViewCursor interface defines the functionality to enumerate over a collection view. The ICollectionView interface contains a createCursor() method that returns an IViewCursor object referred to as a cursor. The cursor is used to transverse the items in the view, as well as to access and manipulate data. It is a position indicator that points to a particular item in the collection. The IViewCursor interface has the following methods and properties to perform the following operations: ❑
Move the cursor backward and forward.
❑
Move it to specific items.
❑
Get the item at a cursor location.
❑
Add, remove, and change items.
❑
Save the cursor as a bookmark so that you can return to it at a later stage.
To use the ICollectionView interface, you must access it by calling the method of a collection instance, as shown in the following code snippet: public var myArrayCollection:IViewCursor; public var myCursor:IViewCursor; public function getCursor():void { myCursor = myArrayCollection.createCursor(); }
The moveNext() and movePrevious() methods are used to move the cursor forward and backward by one item at a time. To check whether you have reached the bounds of the collection, use the beforeFirst and afterLast properties.
114
Chapter 6: Building User Interfaces To search within the collection, you can use the findAny(), findFirst(), and findLast() methods that match the parameter, but you must apply a Sort to the ICollectionView instance. It is important to note that if you do not need to find the first or last occurrence of an item in the collection, the findAny() method is more efficient than the findFirst() and findLast() methods. To find the last occurrence of an item in the collection, you must apply a Sort, as the following example shows: var sort:Sort = new Sort(); // the null parameter on the SortField constructor specifies a collection of simple objects (String, Boolean or numeric) sort.fields = [new SortField(null, true)]; myCollection.sort = sort; myCollection.refresh(); myCursor.firstLast(“NY”);
You can search for a complex object using the findLast() method on multiple sort fields. However, you cannot skip fields in any of the find methods. If the object has three fields, you can specify the combinations 1 or 1, 2 or 1, 2, 3 as a parameter, but not 1, 3. The following code will find the last object with a label field “NY” and a data field “New York”: myCursor.firstLast({label: “NY”, data: “New York”});
The seek() method moves the cursor to a location at an offset from the specified bookmark. You can move to the first and last element in the collection, or to the last bookmark you saved. The IViewCursor interface has methods and properties to access and manipulate data. The current property is a reference to the item at the current cursor location. The insert() method adds an item before the cursor’s current position, and the remove() method removes the current item and returns a reference to it. When inserting an item using the insert() method of the IViewCursor interface and the collection view is sorted, the inserted item will move to the sorted location and not the cursor location.
Collection Change Events Collections have a mechanism that provides feedback to the developer whenever changes occur to the data within the collection. Any class that implements the IList or ICollectionView interface dispatches a CollectionEvent class event whenever the collection changes. The CollectionEvent class contains a kind property that indicates the way in which the collection has changed. To determine this, you compare the kind property to the value of the CollectionEventKind class constants, such as CollectionEventKind.ADD. The CollectionEvent class contains another useful property, items, which is an Array of objects whose type varies depending on the event kind property. If it is the ADD and REMOVE event, the array contains the added or removed items. If it is the UPDATE event, the items property contains an Array of PropertyChangeEvent event objects. This object contains the type of change and the property value before and after the change.
115
Part II: Developing in Flex 2.0 The PropertyChangeEvent class kind property indicates the way in which the property changed. This is determined by the comparing the kind property value with the PropertyChangeEventKind constants. The constants can either be UPDATE or DELETE. The collection events are used to monitor changes to the collection, which, in turn, is used to update the display. If you have a custom control that uses a collection as its data provider, you can listen for the change events on the collection and update the custom control accordingly. The following example lets you add, remove, and replace items in a list control. An event handler is registered to the collectionChange event of the ArrayCollection instance. Any time an item is added, removed, or replaced, a message is logged in the TextArea control.
Hierarchical Data Providers The structure of hierarchical data providers is more advanced than your typical linear data providers (such as an Array). They display data in a nested hierarchy of nodes and subnodes like a tree with branches and leaves. In Flex, there are a few controls that accept hierarchical data providers, including the Menu, MenuBar, PopUpMenuButton, and Tree controls. Your typical hierarchical data sources are XML, which can be Strings containing well-formed XML, or XML, XMLList, or XMLCollection objects. Objects that have nested objects (including Arrays or ArrayCollection objects) are also considered hierarchical data sources. The structure must have the children in the children field of the data source. Otherwise, you must create your own custom data descriptor class. This will allow you to support other hierarchical data provider structures with custom field names other than the children field.
Data Descriptors A data descriptor class is used to parse the hierarchical data used in Tree- and Menu-based controls. It provides an interface between the hierarchical control and the data provider object. Flex has two types of data descriptor interfaces for hierarchical controls. The ITreeDataDescriptor is used by the Tree controls, and the IMenuDataDescriptor is used for the Menu, MenuBar, and PopUpMenuButton controls. Flex provides a DefaultDataDescriptor class that implements both of the interfaces just mentioned. You can specify a custom data descriptor by assigning a new one to the dataDescriptor property of the hierarchical controls. The only reason you would want to define a custom data descriptor is if your data models do not conform to the default descriptor structure.
XML Data Provider In most cases, the data for a Tree control is retrieved from a server in the form of XML, but can also be defined within the tag. The or tag can be used to define an XML or XMLList object in MXML, and lets you use binding expressions in the XML nodes.
117
Part II: Developing in Flex 2.0 The following example shows MXML binding in an tag:
If your data provider for a hierarchical control is going to be dynamic, you should use the XMLListCollection object instead of the XML or XMLList object. This ensures that your component will represent any changes made to the data provider. The XMLListCollection class supports the IList and ICollectionView interface methods for manipulating data at run-time. The following example uses two Tree controls, two XMLListCollection objects, and a Button control to copy an object in the one XMLListCollection object to the other:
Remote Data Providers The Remote Procedure Call (RPC) components provide Flex with the functionality to call remote servers to retrieve data for use in your application. The components that are provided with Flex are the HTTPService, WebService, and RemoteObject components. The following example is a basic application that uses the HTTPService component to download the list of featured videos from the video-sharing site, YouTube:
119
Part II: Developing in Flex 2.0
Positioning and Sizing Components In Flex, the controls are laid out using a set of rules that are a combination of sizing rules for individual components, and sizing and positioning rules for containers. Automatic layout is supported in Flex, which lets you concentrate on building the logic for your application; if need be, you can always adjust the dimensions at a later stage. Many controls and containers have default layout rules, but you can use the component’s properties and methods to customize it yourself. Every Flex component has several properties (such as width and height) to adjust the size of the component. Containers also have properties and styles that you can use to configure their layout, including the verticalAlign and horizontalAlign properties to set the alignment of their children. Flex also allows you to position children using the x and y properties of the container. Only containers that support absolute positioning (including the Canvas container) allow for this.
Layout of Components The Layout Manager has the job of controlling the layout in Flex. The manager has a three-step process in which it sizes and lays out components in the application:
120
1.
Commitment pass — Determines the properties of the application components. During this pass, the Layout Manager causes each component to execute its commitProperties() method, which determines the property values.
2.
Measurement pass — Calculates the default size of every component in the application. This starts from the most deeply nested components and works its way out toward the Application container. During this pass, the Layout Manager causes each component to execute its measureSizes() method, which calls the measure() method to determine its default size.
Chapter 6: Building User Interfaces 3.
Layout pass — This pass lays out your application, including resizing and moving of any components. This starts from the outermost container and moves to the innermost container, determining the actual size and placement of each component. During this pass, the Layout Manager causes each component to execute its updateDisplayList() method to lay out the component’s children.
Component Sizing The layout phase and measurement determine a component’s width and height, and you can retrieve these dimensions by using the width and height properties. The following properties (and others not listed here) are used to control the sizing of components: ❑
Default sizing — The size of the controls and containers are determined automatically.
❑
Explicit sizing — You set the width and height properties to an absolute value.
❑
Percentage-based sizing — You specify the component size as a percentage of its container size.
❑
Constraint-based layout — You control the size and position by anchoring the component sides to the container.
There are several ways to control the size of components. This section describes the basic sizing properties, how to determine component sizes, how to use automatic, explicit, and percentage-based sizing, and various techniques for controlling component size.
Sizing Properties You will find that there are several properties affecting the size of components in Flex. The general rule is that you only need to use a few properties for most applications, but a knowledge of these properties can help you understand how the underlying sizing mechanism works in Flex. If you are not creating custom components, you would use the following basic properties to specify how a component is sized: ❑
The width, height, percentWidth, and percentHeight properties specify the width and height of a component. Using the MXML tags, you can use the width and height properties to specify the dimensions in pixels and as a percentage of the parent container. When using ActionScript, you use the width and height properties to specify the dimensions in pixels, and use the percentWidth and percentHeight properties to specify the dimensions as a percentage of the parent container.
❑
The minWidth, minHeight, maxWidth, and maxHeight properties specify the minimum and maximum dimensions that a component can have in Flex. If you explicitly set the width and height properties, these properties have no effect.
Default Sizing As a rule of thumb, you should determine whether a component’s default size is appropriate for your application. If you decide that default sizing is sufficient, you do not have to specify an explicit or percentage-based size.
121
Part II: Developing in Flex 2.0 The following example uses default sizing for the Button control:
Explicit Sizing To use explicit sizing, you specify the width and height properties of a component to set its size:
You may notice that the VBox container is smaller than the Button control. Flex will clip the Button control to the container’s boundary and display a scroll bar so that you can scroll the container to view the clipped content. The scroll bars will not be visible if you specify the verticalScrollPolicy and horizontalScrollPolicy properties of the container to off.
Component Positioning and Layout During the initialization phase, Flex will position the components appropriately, and also perform a layout pass to position or reposition components in the application. Flex provides two mechanisms regarding the positioning and layout of controls: ❑
Automatic positioning — Flex automatically positions the children within the container according to a set of container- and component-specific rules.
❑
Absolute positioning — The children’s x and y properties are set by the developer, or you can use a constraint-based layout that specifies the gap between each child in the container. This type of positioning is occasionally referred to as absolute layout.
There are three containers that support absolute layout or positioning. The Application and Panel containers use automatic positioning by default, but you can set the layout property to absolute. The third one is the Canvas container, which always uses absolute positioning.
Layout Rules Flex has a set of rules that are used to perform the layout of components. You should be able to understand the details of Flex layout if you can remember these rules. These rules will give you an understanding of
122
Chapter 6: Building User Interfaces why Flex lays out your application the way it does. This will help you when you need to modify the appearance of your application. ❑
Flex first determines all components’ measured or explicitly set sizes, up from the innermost child controls to the outermost Application control. This is all done in the measurement pass.
❑
After the measurement pass, Flex determines all percentage-based sizes and lays out components down from the outermost container to the innermost controls. This is done in the layout pass.
❑
Sizes that you set to a pixel value are mandatory and fixed, and override any maximum or minimum size specifications that you set for the component.
❑
The default sizes determined in the measurement pass specify the sizes of components that do not have explicit or percentage-based sizes (or use constraint-based layout), and are fixed.
❑
Percentage-based size specifications are advisory. The layout algorithms satisfy the request if possible, and use the percentage values to determine proportional sizes. However, the actual sizes can be less than the requested sizes. Percentage-based sizes are always within the component’s maximum and minimum sizes, and, subject to those bounds, don’t cause a container’s children to exceed the container size.
Forcing Layout Manually In rare instances, you may need to programmatically force Flex to lay out components again. Usually, Flex will delay processing of properties that require substantial computation until the scripts that caused them to be set finish executing. For example, if you set the width property of a component or container, it will be delayed because Flex prevents it from happening multiple times. Sometimes you may want to force the layout before the script has completed. To force the layout, you need to call the validateNow() method of the component. This will cause Flex to validate the properties, sizes, and layout of the object and all of its children. This method is processor-intensive and should be used cautiously if it is needed.
Constraint-based Layout Constraint-based layout allows you to anchor sides or the center of the component to a position relative to the viewable region of the component’s container. With constraint-based layout, you can anchor one or more corners of a component at a specific pixel offset from the container’s corresponding edge. The anchored child stays at the specific pixel offset even if the container is resized. If the anchor is set to top and bottom, then when the container resizes, the component will resize with it. To use constraint-based layout in your application, you must adhere to the following rules: ❑
Place the component inside a container that supports absolute layout (such as a Canvas container) or inside an Application or Panel container with the layout property set to absolute.
❑
Any component that extends the UIComponent class also supports constraint-based layout.
❑
Specify the top, bottom, left, right, verticalCenter, or horizontalCenter styles.
123
Part II: Developing in Flex 2.0 ❑
Do not specify a top or bottom style with a verticalCenter style, because the verticalCenter style overrides the other properties. The same applies to the left or right styles with a horizontalCenter style.
❑
Using constraint-based layout will override an explicit or percentage-based sizing. Specifying the top and bottom constraints will override any height or percentHeight properties.
The following basic example shows a Button control anchored 10 pixels from the bottom of the VBox container:
Getting Familiar with Flex Controls In Flex, controls are referred to as user interface (UI) components such as Button, TextInput, and ComboBox controls. There are two types of controls in Flex: ❑
Basic controls (such as a Button)
❑
Data provider–based controls (such as a List)
Controls are typically placed into containers, which are components that provide a hierarchical structure for controls. The tag is the root of your Flex application. This represents a base container that covers the entire Flash Player drawing area. You can place controls or containers directly onto this area. Controls have the following characteristics. ❑
Declare the control in MXML and specify its properties and events.
❑
Use the ActionScript API to call the control’s methods and set its properties at run-time.
❑
Customize the visual appearance by using the styles, skins, and fonts of the controls.
The easiest way to add a control to your Flex application is using the MXML API. To achieve this, you must specify the control’s MXML tag, as the following example shows:
124
Chapter 6: Building User Interfaces
Summar y In this chapter, you learned about the most important elements in creating rich user interfaces for your Flex applications. The most interesting topics were visual components, data providers and collections, sizing and positioning of components, and constraint-based layout. These topics will stand you in good stead on the road to developing Rich Internet Applications using Flex 2. Chapter 7 discusses improving the user experience by adding functionality to your applications. The topics covered are behaviors, styles, fonts, skinning, item renderers and editors, tooltips, and the Cursor Manager.
125
Customizing the User Interface This chapter discusses how to improve the user experience by adding functionality to your application and, more importantly, the user interface (UI). You are introduced to effects and behaviors, styles and themes, fonts, skins, item renderers and editors, tooltips, and cursor management.
Applying Behaviors A combination of a trigger paired with an effect is called a behavior. A trigger is an action such as a mouse click on a button, or a component receiving focus or becoming visible. An effect is a visible change to a component that occurs within a specific duration measured in milliseconds. Fading, moving, or zooming a component are examples of various effects. Behaviors allow you to add animation and motion to your application in response to user or programmatic action. For example, you could create a menu similar to the Apple Mac OS X Dock, which grows in size if your mouse gets close to the icons. You can define multiple effects to play in response to a single user or programmatic action. A good example of this would be the Apple Mac OS X Dock in hide mode. When you move your mouse close to the Dock, it appears and the icons grow depending on your mouse position. Flex components do not play an effect when a trigger occurs, but some components do indirectly, as when the ComboBox control’s drop-down list slides down when you click it. Note that triggers are not the same as events, because if you look at the properties of a Button control, for example, it contains a mouseUp event and a mouseUpEffect trigger. The mouseUpEffect trigger is associated with an effect, so that when the mouseUp event occurs, an effect is run.
Part II: Developing in Flex 2.0
Using Behaviors In MXML, you use the name of the effect to assign it to the trigger property of the component:
This code example declares two effects, one fading from fully opaque to fully transparent, and the other effect in reverse. So, when a user clicks the button, it disappears and reappears when the mouse button is released. In MXML, all properties that are effect triggers are implemented in Cascading Style Sheets (CSS) styles. Therefore, you can apply the effect using the tag. The following code example is the same as the preceding example, but it uses CSS styles, instead:
Button { mouseDownEffect: myFadeOut; mouseUpEffect: myFadeIn; }
You could also use the setStyle() and getStyle() methods to manipulate triggers and their associated effects. In ActionScript, you can declare play effects often as part of an event listener. To invoke the effect, you call the play() method. The following example resizes a Panel container:
128
Chapter 7: Customizing the User Interface
Instead of specifying the target property of the Resize effect, you could pass in the myPanel instance as an array into the play() method of the resize effect instance: myResize.play([myPanel]);
Embedded Fonts with Effects The Fade, Dissolve, and Rotate effects work only with text that is rendered using embedded fonts. Nothing will happen to the text if system fonts are used. Embedded fonts are discussed in more detail later in this chapter. When applying a Zoom effect to text rendered with system fonts, Flex will scale the text between whole point sizes. In essence, you do not have to use embedded fonts with the Zoom effect, but it will appear smoother if you do.
Composite Effects You can combine or composite effects either by using the Parallel or Sequence effect. The Parallel effect plays the child effects at the same time, and the Sequence effect plays them sequentially. The following example defines Parallel and Sequence effects with the same child effects. The Parallel effect resizes the Panel container and blurs it at the same time, whereas the Sequence effect resizes the Panel container and, once that is finished, removes the blur.
129
Part II: Developing in Flex 2.0
Easing Functions In Flex, you can change the speed of an animation by defining an easing function for an effect. This allows you to create a more realistic rate of acceleration and deceleration. The easing function also includes the functionality to make objects look like they are bouncing. The following code shows the basic format of an easing function: function myEasingFunction(t:Number, b:Number, c:Number, d:Number):Number {}
Note the following: ❑
The t specifies time.
❑
The b specifies the initial position of a component.
❑
The c specifies the total change in position of the component.
❑
The d specifies the duration of the effect in milliseconds.
Easing functions can be found in the mx.effects.easing.* package. The following example is the same as the last code example regarding composite effects, except an easing function has been applied to the Resize effect by setting the easingFunction property:
You can also apply easing functions to controls such as the ComboBox control by specifying the openEasingFunction and/or closingEasingFunction. The following example shows how this is done:
Applying Styles Styles are useful for defining the look and feel of your Flex application. You use them to change the appearance of a single component, or across all components by using Cascading Style Sheets (CSS). To modify the appearance of components, you use style properties similar to those in CSS. These properties define the size of a font, background color, or the size of the border in a Panel container. Some styles are inherited from parent containers to their children, and across style types and classes. This allows you to define a style once that then applies to all controls of a single type or set of controls. Also, you can override individual properties for each control at a local, component, or a global level, leaving you with greater flexibility in the appearance of your application. Flex does not allow you to control all aspects of your component layout with CSS. Properties such as width, height, x, and y are not styles of the UIComponent class. As you may remember, the UIComponent class is the base class for all visual components in Flex.
131
Part II: Developing in Flex 2.0
Using Styles You use CSS to apply styles to a document or across an entire application. The one way to apply styles is by referring to an external style sheet, or including them inline within the MXML document. The following example applies an external style sheet myStyleSheet.css to the current document:
If you prefer to use styles inside the document or inline, use the tag. This will apply the styles to your current document and its children. The following example defines a new style and applies it only to that instance of a Label control:
.myLabel { font-size: 16; font-family: Arial; font-weight: bold; color: #FFCC00; }
This example defines a new style that applies to all instances of a Label control:
Label { font-size: 16; font-family: Arial; font-weight: bold; color: #FFCC00; }
132
Chapter 7: Customizing the User Interface You can use the setStyle() and getStyle() methods of a control to manipulate style properties. Using these methods does require more processing power on the client than using style sheets, but it provides greater control over how you apply styles. myLabel.setStyle(“fontWeight”, “bold”);
Lastly, you can use attributes of MXML tags to apply styles inline and apply only to the instance of the control. This is the most efficient method of applying instance properties because no ActionScript code blocks or method calls are required. The following example sets the fontWeight style of the myLabel instance to bold:
Note that you must use the camel-case version of the style property in an MXML tag. For example, you must use fontSize and not font-size. You can also bind inline style properties to values.
Using Local, Application, and Global Selectors The tag contains style sheet definitions that adhere to the CSS 2.0 syntax and apply to the current document and all of its children in the current document. To define a local style, you would use the class selector. Any component that wants to use the style must refer to it in its styleName property. The following example defines a type and class selector in the tag:
.myClass /* class selector */ { font-size: 16; font-family: Verdana; font-weight: bold; color: #FFCC00; } Label /* type selector */ { font-size: 16; font-family: Verdana; font-weight: bold; color: #FFCC00; }
Application Type Selector The Application container is the root of your Flex application and is the top-most document. Any styles defined in the Application type selector are inherited by all the container’s children, as well as the container’s subclasses. Styles that are not inheritable are applied only to the Application container and not its children.
133
Part II: Developing in Flex 2.0 Styles applied in the Application type selector that are not inherited by the Application object’s children are not inheritable. Use the global type selector to apply a non-inheritable style globally. Defining styles in the Application type selector are not required to declare a style for each component, because the components are children of these classes and inherit the Application type selector styles. The following example defines various styles in the Application type selector:
Application { background-color: #FFFFFF; padding-top: 10; }
Global Type Selector Flex provides a global type selector that you can use to apply styles to all controls. Any properties defined by a global type selector apply to all controls, unless that control explicitly overrides it. The global selector is like a type selector, and so you do not have to preface it with a period in CSS. The following example defines the fontFamily and fontSize property to the global selector:
global { font-family: Verdana; font-size: 10; }
Applying Fonts Flex has two types of fonts: device fonts and embedded fonts. Embedded fonts are smoother, and you can apply special effects to text-based controls such as rotating and fading. There are many ways to embed fonts in your application, such as using CSS syntax to embed FlashType fonts into the SWF files. The application stores the names of the fonts that you used to create the text. The Flash Player uses the font names to locate identical or similar fonts on the user’s system when the application runs. Using embedded fonts means that they are used regardless of whether the client system contains the fonts because they are embedded within the SWF file.
Device Fonts Device fonts do not export their outline information and are not embedded in the SWF or application. The Flash Player uses whatever fonts it can find on the client computer that closely resemble the device fonts.
134
Chapter 7: Customizing the User Interface The following example specifies three device fonts. The Flash Player looks for the first font, the second font, and so on.
Application { font-family: Arial, Helvetica, Verdana; font-size: 10; color: Blue; font-weight: bold; }
The Flash Player supports the following three device fonts: ❑
_sans — The _sans device font is a sans-serif typeface (for example, Arial).
❑
_serif — The _serif device font is a serif typeface (for example, Times Roman).
❑
_typewriter — The _typewriter device font is a monospace font (for example, Courier).
When using device fonts, the size of the SWF does not increase. However, using device fonts can impact performance of the application because it requires the Flash Player to interact with the local operating system. If you are using device fonts, you are limited to three fonts.
Embedded Fonts You can embed TrueType Font (TTF) families in your Flex application rather than relying on a client machine to have the specific fonts. The font will always be the same when running your application, and you do not have to worry about missing fonts. Embedded fonts have the following benefits: ❑
The font does not need to be installed on the system.
❑
Embedded fonts are anti-aliased, meaning their edges are smoothed for easier readability (especially when the text size is larger).
❑
Embedded fonts can be partially or fully transparent and be rotated.
❑
Embedded fonts provide smoother playback when zooming.
❑
Text appears as you would expect when using embedded fonts.
The following are downsides to using embedded fonts: ❑
You can only embed TrueType fonts.
❑
Embedded fonts increase the size of your application because it must contain the outlines for the text.
❑
Embedded fonts decrease readability of text at sizes smaller than 10 points.
135
Part II: Developing in Flex 2.0 To use embedded fonts in your application, you would typically use CSS syntax. The @font-face declaration specifies the source of the embedded font, and then defines the name of the font by using the fontFamily property. Each font face from the same family must be specified using the @font-face declaration. Note the font licenses before attempting to embed fonts into your Flex application. Some fonts might have licensing restrictions that do not allow them to be stored as vector information.
Embedded fonts can be TTF files on your file system or an SWF file that is created in Adobe Flash. Fonts embedded using Flash take advantage of the FlashType technology, which makes them more readable at smaller sizes. The following example embeds the font Verdana located at c:\Windows\Fonts\Verdana.ttf:
@font-face { src:url(“c:\\Windows\\Fonts\\Verdana.ttf”); fontFamily: myFontFace; }
After you have embedded the font, you can use the fontFamily name or alias in a type or class selector. The following example uses the myFontFace as a type selector for all Button controls: Button { fontFamily: myFontFace; }
FlashType Fonts FlashType is a new rendering engine included in Flash Player 8 and above that provides clear, high-quality text rendering in SWF files. It greatly improves the readability of text, especially when rendered at smaller font sizes. To use FlashType fonts in Flex, you create an SWF file in Adobe Flash 8 that contains the fonts you require in your application. You then reference that SWF file’s font contents so that it gets embedded into your application. Using FlashType fonts in your application may cause a slight delay when loading the application. The more you use, the slower the startup time of your application. It can also increase the memory usage by quite a bit. Embedding FlashType fonts in your application is the same as other embedded fonts. They are anti-aliased, and you can rotate them or make them fully or partially transparent.
136
Chapter 7: Customizing the User Interface A good practice is to include the four primary typefaces for each font that you want to embed (that is, plain, bold, italic, and bold italic). The reason for this is that some Flex controls use one of the non-plain typefaces. An example of this would be a label on the Button control that uses a bold typeface of the font. Embedding a plain typeface to use on a Button will likely not work, because it requires a bold typeface.
Creating an SWF to Embed FlashType Fonts The first step in embedding FlashType fonts in your application is to create an SWF using Adobe Flash 8 that contains those fonts. Once you have completed this part, you must embed them into your Flex application.
1. 2. 3.
Open Adobe Flash 8 and create a new document.
4.
In the Properties panel, select Dynamic Text from the drop-down list.
Select the Text Tool and create a text field on the Stage. Enter at least one character of text into the text field. If it is easier, you may want to type out the name of each typeface, as shown in Figure 7-1.
Figure 7-1: Entering text into the text field
137
Part II: Developing in Flex 2.0 5.
In the Properties panel, click the Embed button, and the Character Embedding dialog box shown in Figure 7-2 will appear.
6.
Then, select the ranges of glyphs you would like to embed. Only select all if you feel it is absolutely necessary. Selecting all the glyphs will make the file size fairly large, so rather, select only what you really need.
7. 8.
Create three more text fields, one for each typeface, such as bold, italic, and bold italic (Figure 7-3). Export your movie by pressing Ctrl+Enter to create an SWF file for use within your Flex application.
Figure 7-2: Character Embedding dialog box
Embedding FlashType Fonts After you have created your SWF file with the appropriate fonts, it is time to embed them into your Flex application using CSS.
1.
Embed each typeface with a @font-face declaration:
@font-face { src:url(myfonts.swf); fontFamily: Verdana; fontStyle: italic; fontWeight: bold; }
2.
Now, define a style for each embedded typeface. This can be done in an external style sheet or in the tag.
.myStyle1 { fontFamily: Verdana; fontSize: 11; }
138
Chapter 7: Customizing the User Interface
Figure 7-3: Three more text fields for each typeface
You must specify the fontFamily property and it must match the fontFamily property set in the @font-face declaration. The value of the fontFamily property stays the same, regardless of which typeface you are defining (in other words, if the typeface is bold, you do not specify Verdana Bold, but just Verdana). Remember that you must specify all the typeface properties like you did in the @font-face declaration. If the typeface is bold italic, define the fontWeight and fontStyle properties to match it. .myStyle2 { fontFamily: Verdana; fontSize: 11; fontStyle: italic; fontWeight: bold; }
139
Part II: Developing in Flex 2.0 3.
Apply the new style to your Flex controls:
You can also specify the styles inline instead of defining them in a style sheet. The only problem with this approach is that if you need to edit the styles, it will not be in one central place. There is one more way to embed FlashType fonts without using the @font-face declaration: by using the [Embed] metadata keyword. The following example embeds a Verdana font’s italic typeface: [Embed(source=”verdana_fonts.swf”, fontName=”Verdana”, fontWeight=”italic”)] public static var italicFont:Class;
Ensure that you are using the latest SWF file that contains your fonts. Otherwise, recompile the SWF file, if necessary.
Skinning the Application The process of changing the appearance of a component by modifying or replacing its visual elements is called skinning. The elements can be made up of images, SWF files, or a class that implements the drawing API methods.
Graphical Skins Image files embedded into your application that represent a state of a component are called graphical skins. Each image may be a different state of a component, such as the downSkin of a Button control. The following example shows the upSkin, overSkin, and downSkin style properties defined as new graphical skins. These style properties point to the different images for each state of the control. Figure 7-4 shows the graphical skins used in the following code example:
Button { upSkin: Embed(“/skins/upSkin.png”); overSkin: Embed(“/skins/overSkin.png”); downSkin: Embed(“/skins/downSkin.png”); }
140
Chapter 7: Customizing the User Interface
Figure 7-4: Graphical skins Skins are actually a class, and when you are changing the reference from a current skin to a new one, it is just a new class. Flex wraps each embedded asset as a class within the current document’s class. Note that if you change any graphical skins, you must recompile the application because they are embedded into the SWF file. You can define skin properties either using CSS, inline, or by using the setStyle() method of the control you are skinning. The one downside to using graphical skins or images is that resizing the component will create distortion. You can use a technique called Scale-9 to create skins that do not become distorted. The technique lets you define nine sections of an image that scale independently.
Programmatic Skins In Flex you can write programmatic skins as ActionScript classes that use the Drawing API of the Flash Player. The methods for drawing at run-time are in the flash.display.Graphics package. The best way to learn how to create programmatic skins is to look at the ones that come with Flex and then either extend them or create your own. The programmatic skin recipe is a basic template that you can use to implement a skin for a component. The following code example is a programmatic skin class. You can use this class as a template to create new skins. package { import import import import
flash.display.Graphics; mx.skins.Border; mx.skins.ProgrammaticSkin; mx.styles.StyleManager;
public class MyCustomSkin extends ProgrammaticSkin { // Constructor. public function MyCustomSkin() { // Set default values here. } override protected function updateDisplayList(w:Number, h:Number):void { // Add styleable properties here. // Add logic to detect component’s state and set properties here. // Add drawing methods here. } } }
141
Part II: Developing in Flex 2.0 Programmatic skins define the appearance of a skin in multiple states of a control, such as the upSkin, downSkin, and overSkin of a Button control. These states refer to the default state, when the button is pressed, and when the mouse is over the button but has not been pressed.
Choosing a Superclass The first step in creating a programmatic skin is to select a superclass for the skin. You can extend the abstract base classes in the mx.skins package or the mx.skins.halo package, but the former gives you more control over the look and feel of your skins. The latter is fine if you use the default behavior of the Flex controls but want to add extra styling. Most skins extend the mx.skins.ProgrammaticSkin class, but any of the following classes can be used: ❑
The ProgrammaticSkin class implements all the necessary interfaces to make it easier for you to define skins for your components. It is also the most common superclass to use.
❑
The Border class extends the ProgrammaticSkin class and adds a property called borderMetrics that allows you to get the thickness of the border.
❑
The RectangularBorder class extends the Border class and adds a style property called backgroundImage so that you can set the background image of the component.
Note that a programmatic skin must implement the IFlexDisplayObject, IInvalidating, and ILayoutManagerClient interfaces. It must also implement the ISimpleStyleClient interface if it depends on the values of CSS styles. The superclass of a skin can be a subclass of the DisplayObject class as long as you implement all of those interfaces. The updateDisplayList() method is used to define the look of your skin. It is called after the skin’s constructor is called and then every time the skin is resized, restyled, moved, or interacted with in some way. In the updateDisplayList() method, you use the drawing methods to draw the programmatic skin. When implementing the updateDisplayList() method, remember to use the override keyword to override the superclass’s implementation, set the return type to void, and declare the method as protected. The method also takes the width and height of the component as arguments. The following code example draws a square with a border: override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void graphics.clear(); graphics.lineStyle(2, 0x000000, 1.0, true, LineScaleMode.NORMAL, CapsStyle.SQUARE, JointStyle.MITER); graphics.beginFill(0xFFFFFF, 0); graphics.drawRect(0, 0, unscaledWidth, unscaledHeight); graphics.endFill(); }
142
Chapter 7: Customizing the User Interface The following example applies a programmatic skin to a specific state of the control: Button { upSkin:ClassReference(‘MyCustomSkin’); }
Note that if you subclass the RectangularBorder class, you must also call the super.updateDisplayList() inside of your implementation of the updateDisplayList().
Item Renderers In Flex, there are several controls that represent a list of items. You can scroll through the list of items and select one or more from the list. They are all derived from the ListBase class, and the following controls are included: List, TileList, Menu, Tree, DataGrid, and HorizontalList. A list control uses a data provider for its data, which is a collection of objects. The data provider creates a layer of abstraction between the Flex list controls and the data that populates them. You can think of the data provider as the model and the Flex list control as the view onto the data. Every list control has a default view to display the data, and Flex lets you override this mechanism. To do this, you must create an item renderer. The simplest item renderer is the DataGridItemRenderer, which is the default item renderer for the DataGrid control. It contains the functionality to display text. The following example is a List control using the default item renderer to display a list of three different fruits:
Apples Oranges Pears
If you wanted to display more than just text for each item in the list control, you must create your own custom item renderer. Custom item renderers and item editors provide you with the following benefits: ❑
Replace the display of text with a richer appearance.
❑
Combine multiple elements in a single list item such as an image and a label.
❑
Allow you to control the display of the item programmatically.
Figure 7-5 is a list control with a custom item renderer containing an Image control and a Label control inside of an HBox container.
143
Part II: Developing in Flex 2.0
Figure 7-5: List control with a custom item renderer
Building Custom Item Renderers and Item Editors There are several ways to use item renderers in your application, such as using the drop-in method or using the inline method or as reusable components. ❑
The drop-in method inserts a single component as an item renderer by defining it in the list control’s itemRenderer property.
❑
The inline method defines the item renderer as one or more components using the child tags of the list control.
❑
Using a custom component as an item renderer is more efficient and promotes reuse. This means that you can reuse it in more than one place or application.
The Drop-in Method If you only need to drop in single components (such as a DateField or Numerical Stepper control), the drop-in item renderer is perfect. In other words, you define an existing Flex component as an item renderer for the list control. The following example has a DataGrid control with a CheckBox control as the item renderer of the second column:
144
Chapter 7: Customizing the User Interface
Flex automatically uses the data property to populate the CheckBox control with the current value of the column because the dataField of that column is set to the selected object property.
The Inline Method The drop-in method shows you how easy it is to use an item renderer in a list control. The only problem is that you cannot configure them the way you might want to. For more flexibility, you create an item renderer as an inline component. The following example is from the drop-in example, but instead uses the inline method:
145
Part II: Developing in Flex 2.0 In this example, an inline item renderer was used that allows you to center the CheckBox control vertically and horizontally within the cell.
A Component as an Item Renderer The advantage of using a component as an item renderer is that you can reuse it all over the application and in different applications, too. Using this method, you can create more complex item renderers because you will create a separate document or class for them. The following example is a custom item renderer called MyCustomItemRenderer.mxml:
To show you the power of item renderers, this custom reusable component has three Flex controls contained inside an HBox container. If you click the button, an Alert control pops up with current selected fruit and date values. These are passed into the item renderer via the data property. This example is the main application with the item renderer defined in the List control using the itemRenderer property:
146
Chapter 7: Customizing the User Interface You may find several areas in your application where the MyCustomItemRenderer may come in handy. This exact example merely demonstrates how powerful item renderers are. Information passed to an item renderer or item editor is done so through the data property of the item renderer or item editor. The ListData class defines the data type of the listData property implemented by drop-in item renderers or drop-in item editors for the List control.
Item Editors Item editors let you modify the value of the cell in a list control. The List, DataGrid, and Tree controls support item editors. This allows the user of your application to be able to edit rows of data inline without having to pop up a dialog box or bind it to a form below.
Overview of Cell Editing Process The specific process that occurs when a cell in a list control is edited is as follows:
1. 2.
The user releases the mouse button over the cell, or tabs to a cell.
3.
The itemEditBegin event is dispatched to open the item editor, and can be used to modify the data passed to the item editor.
4. 5.
The user then edits the cell.
6.
The itemEditEnd event is dispatched to close the item editor and update the cell with new data. You can modify the data returned to the cell via the event, validate the new data, or return the data in a different format.
7.
The new data appears in the cell.
The itemEditBeginning event is dispatched, which you can use to disable editing of a specific cell or cells.
The user then ends the editing session and the cell editing session quits when the user removes focus.
Editable Cell The Flex list controls, such as the List, Tree, and DataGrid, include an editable property that can be set to true so that users can edit the contents of the control. The editable property is set to false by default. Setting the editable property to true on a DataGrid control means all columns are editable. If you do not want every column editable, set the DatagridColumn.editable property to false. In the Flex list controls, you can use the default item editor (the TextInput control), a custom item editor, or a custom item renderer as an editor. If you want the item renderer to be the editor, set the rendererIsEditor property of the list control to true. If you set the rendererIsEditor property to true, Flex will ignore the itemEditor property and use the item renderer as the item editor.
147
Part II: Developing in Flex 2.0
Returning Data from an Item Editor By default, Flex expects an item editor to return a single value to the list control. The editorDataField property of the list control specifies the property of the item editor that contains the new data. The value is converted to the appropriate data type for the cell. The default value of the editorDataField property is text that corresponds to the default item editor of a list control, the TextInput control. If you changed the default item editor to a DateField control, you must set the editorDataField property to the selectedDate property, as the following example shows:
In the preceding example, a DateField control is the item editor and, therefore, the editorDataField property is set to selectedDate, the property of the DateField control that contains the new cell data.
Sizing and Positioning an Item Editor You may notice that when you click in a cell, a popup control appears above the selected cell of the list control. The list control also hides the current value of the cell. Four properties can be used to size and position item editors within list controls: ❑
148
editorHeightOffset — Specifies the height of the item editor in pixels, relative to the size of the cell for a DataGridColumn control, or the text field of a Tree control
Chapter 7: Customizing the User Interface ❑
editorWidthOffset — Specifies the width of the item editor in pixels, relative to the size of the cell for a DataGridColumn control, or the text field of a Tree control
❑
editorXOffset — Specifies the x location of the upper-left corner of the item editor in pixels, relative to the upper-left corner of the cell for a DataGridColumn control, or the upper-left corner of the text field of a Tree control
❑
editorYOffset — Specifies the y location of the upper-left corner of the item editor in pixels, relative to the upper-left corner of the cell for a DataGridColumn control, or the upper-left corner of the text field of a Tree control
The following example sets the editorXOffset property of the DataGridColumn control to 10 pixels. This will offset the DateField control 10 pixels from the left.
Cell Editing Events The cell editing process of a list component dispatches three events: itemEditBeginning, itemEditBegin, and itemEditEnd. This was mentioned earlier in this chapter. There are default event listeners defined for these three events, but you can implement your own event listeners that will execute before the default ones. In your implementations, you can modify the data passed to or returned from an item editor. If you modified the data in the event listener for the itemEditBeginning
149
Part II: Developing in Flex 2.0 event, that code would execute first, then the default event listener would run to continue the editing process. You can replace the default event listener with your own implementation. To prevent the default one from executing, call the event.preventDefault() method from anywhere in your event listener. Each editable list control has a corresponding event class that defines the event object for the cell editing events. The DataGrid control uses the DataGridEvent class; the List and Tree controls use the ListEvent class. The following example defines an event listener, but with no implementation for the List control: public function myCellBeginEvent(event:ListEvent):void { // implement the event listener. }
Accessing Cell Data When a user edits a cell, you can access the current value, the new value entered by the user, or the item editor used to edit the cell. To access the current value of a cell, use the editedItemRenderer property of the list control. The data provider element is accessible in Tree and List controls, and the element for the whole row in a DataGrid control. Use the itemEditorInstance property if you need to access the new cell value of the item editor. Note that the itemEditorInstance is not initialized until the cellBeginEvent has executed, and would typically only access it within the event listener of the itemEditEnd event. The following example contains an event listener defined on a DataGrid control for the itemEditEnd event:
In the preceding example, you get the item editor (which is a TextInput control) by casting it to the relevant type. If it were a custom item editor, you would need to cast it to that type. Now that you have a reference to the item editor, you can access the old value and new value.
Preventing a Cell from Being Edited To prevent a cell from being edited, you can call the event.preventDefault() method in the event listener of the itemEditBeginning event. The following example calls the preventDefault() method of the event passed in for the itemEditBeginning event:
151
Part II: Developing in Flex 2.0
The preceding example uses the rowIndex property of the event, but, in essence, you can use any property of the DataGrid to stop a cell being edited. If you try to edit the three rows of the DataGrid, it will not work.
Tooltips Tooltips, as you may already know, are a method of providing useful information to the user. When a user moves the mouse over a specific area, a tooltip pops up with the relevant information. Tooltips can be used to help your users work through your application, or you can use them to add extra functionality. You will find that tooltips are in many desktop applications written for Windows or Linux. They add extra information when a user moves the mouse pointer over an onscreen element. Figure 7-6 shows a tooltip that appears when the user’s mouse pointer hovers over the TextInput control. The tooltip will eventually disappear, even though the user’s mouse pointer remains over the component. You can set the time it takes for the tooltip to appear and disappear.
152
Chapter 7: Customizing the User Interface
Figure 7-6: Tooltip for TextInput control Tooltips support style sheets and dynamic loading of the text, but do not support embedded HTML. Tooltips are the basis for the accessibility implementation, and all controls that support accessibility do so by making their tooltip text readable by screen readers.
Creating Tooltips All visual components that extend the UIComponent class support a toolTip property. You set the toolTip property to a text string and then, when a mouse pointer hovers over the component, the string appears in the tooltip. The following example shows a TextInput control with the toolTip property defined:
To do the same in ActionScript, set the toolTip property of the component instance to text string, as the following example shows:
With regard to children in containers, if you do not define a tooltip on the child of a container, the tooltip of the parent container is displayed, instead. For example, if you add a TextInput control to a Panel container that has a tooltip, the user sees the Panel container’s tooltip text when the mouse pointer is over the Panel. To clear the child’s tooltip text, set the toolTip property to a blank string. So, in other words, the children inherit the tooltip from the parent container.
153
Part II: Developing in Flex 2.0 Using Styles with Tooltips Tooltip text and tooltip box appearance can be changed using CSS syntax or the StyleManager class. Changes to the tooltip’s styles are reflected in the whole application. To change the styles of a tooltip, use the tag with a type selector to override the default one. The following example sets the styles of the tooltip using CSS:
ToolTip { fontFamily: “Arial”; fontSize: 20; fontStyle: “bold”; color: #FFCC00; backgroundColor: #999999; }
To use the StyleManager class to apply styles to tooltips, use the setStyle() method on the tooltip type selector, as the following examples shows:
Tooltip Events Tooltips have many events that are dispatched during their life cycle. The types of events are contained in the ToolTipEvent class. The usual properties type and target are available, but there is also a property called toolTip that references the tooltip itself. With this reference, you can add the tooltip’s text property inside the event handler. The following example gets a reference to the tooltip and sets its text to the myLabel instance text property:
ToolTipManager Class The ToolTipManager class allows you to customize the tooltip functionality, such as enabling and disabling tooltips, or setting the display delay. The ToolTipManager class contains a reference to the current tooltip in the currentToolTip property.
Enabling and Disabling Tooltips To enable or disable a tooltip, set the ToolTipManager.enabled or ToolTipManager.disabled properties. The following example has two Button controls, one for enabling and one for disabling tooltips:
155
Part II: Developing in Flex 2.0 Delay Times for Tooltips The delay time is the amount of time that passes before something happens. If you move your mouse pointer over a component and tooltips are enabled, there is a brief delay by default before the tooltip appears. This is great if a user is not looking for the tooltip to appear. The ToolTipManager class allows you to set the length of time that passes before a tooltip appears, and how long the tooltip remains onscreen. There are three properties the ToolTipManager class exposes regarding delay times of tooltips: ❑
showDelay — The length of time (in milliseconds) that passes before Flex displays a tooltip
❑
hideDelay — The length of time (in milliseconds) that passes before Flex hides the tooltip
❑
scrubDelay — The length of time (in milliseconds) that a user can take when moving the mouse between components before Flex waits for the duration of the showDelay to display
the tooltip
Tooltip Effects Tooltips can use custom or standard Flex effects, by setting the showEffect or hideEffect property of the ToolTipManager class. The following example uses Blur and Fade effects when the tooltip appears. This is achieved by using the Parallel effect.
Fonts used in this example do not fade, because you must use embedded fonts to achieve this effect.
Cursor Manager The Cursor Manager allows you to customize the cursor in your Flex application. You can use this to provide visual feedback to the user, such as waiting for processing to complete. The cursor image can be a JPEG, PNG, GIF, or SVG file, or a Sprite object or an SWF file. The default cursor in Flex is the system cursor used in your operating system. The Cursor Manager lets your control the functionality and appearance of the cursor. You may want different cursors, depending on the context of your application. The Cursor Manager contains a list of cursors with priorities. The one with the highest priority is currently visible. You might have two cursors with the same priority, and Flex will use the most recent one.
Adding and Removing Cursors To create a new cursor, use the setCursor() static method of the CursorManager class. The new cursor will be added to the list. There is an optional priority property that can be specified so that the Cursor Manager knows what the priority of the new cursor is. If the priority is higher than any of the others in the list, that cursor is shown immediately; otherwise, the one with the highest priority must be removed to show another cursor. To remove the cursor, use the removeCursor() static method of the CursorManager class. If the cursor is removed that is currently being displayed, the cursor with the next-highest priority is shown immediately. The following example loads an external image. While it loads, the cursor is set to busy.jpg, and reverts back once the image has fully loaded into the Flash Player.
Busy Cursor Flex defines a busy cursor that is used to indicate to the user that your application is processing, such as calling a remote server and waiting for a response. The default busy cursor is an animated clock. The CursorManager has two static methods that can be used to control the busy cursor. The setBusyCursor() method obviously displays the busy cursor, and the removeBusyCursor() method removes it from the cursor list. The following example contains two Button controls; one shows the busy cursor and the other hides it:
When the busy cursor is shown, you can still interact with the entire application, unless you have disabled something such as a Panel and all its children. If you do not want the user to interact with your application when the busy cursor is showing, set the Application.application.enabled property to false.
158
Chapter 7: Customizing the User Interface
Summar y Being able to customize a Flex application’s user interface is very important when building a successful product. Flex allows your designers to customize the look and feel of the application to fit the user’s needs. At the end of the day, your imagination is your only limit. Chapter 8 carries on from here to show you more advanced topics, such as view states, transitions, drag and drop, embedding assets, Flex printing, talking to JavaScript, and using shared objects.
159
Flex UI Topics This chapter examines a variety of topics, including dynamic layout controls, states and transitions, embedded assets, local data storage using shared objects, communication with the browser, history management, and accessibility.
Repeaters and Containers The Repeater control is a layout control that allows the interface to be drawn dynamically by looping through its dataProvider. Each object in the dataProvider can be accessed within the repeater by binding to “repeater id”.currentItem.
Using the Repeater Component The basic example in Listing 8-1 shows a simple Repeater with a horizontal layout accessing the label property of the objects within ArrayCollection dp.
Listing 8-1: Basic Repeater
When the application is initialized, the repeater will execute and loop through its dataProvider four times (the length of the ArrayCollection), drawing four buttons horizontally. Figure 8-1 shows the results, and Figure 8-2 shows the results after setting the repeater’s layout property to vertical.
Figure 8-1: Using the Repeater control
Figure 8-2: Vertical Repeater control
Repeater Component Execution Process The Repeater component will execute initially when it is created, and then it will re-execute whenever there is a change to its dataProvider, startingIndex, or count. If any of these properties change, the Repeater will re-execute, destroy all of its children, then re-create the children, and automatically
162
Chapter 8: Flex UI Topics redraw the screen. This allows the developer a great deal of flexibility because the user interface can be drawn and redrawn by simply changing the dataProvider. The advanced Repeater example shown in Listing 8-2 uses a custom component and Tile control to show a real-world example of how a Repeater control could be used to represent multiple categories in a sample e-commerce application.
Listing 8-2: Advanced Repeater
Figure 8-3 shows how the code shown in Listing 8-2 will execute when the application initializes. The Repeater will loop through the category1 ArrayCollection creating the six product custom components. (For more information on custom components, see Chapter 13.) Figure 8-4 shows how the Repeater re-executes after the dataProvider changes when the Category 2 button is clicked.
163
Part II: Developing in Flex 2.0
Figure 8-3: Code execution when application initializes
Figure 8-4: Re-execution of the Repeater control when the Category 2 button is selected
Following is the custom component Product.mxml used in Listing 8-2:
164
Chapter 8: Flex UI Topics
Using V iew States View states enable developers to alter the appearance of the application view by simply adding code to add children, remove children, or change component properties. After defining the base state (all MXML files are created in the base state), the developer can create a new state using the Design view of Flex Builder, or by simply adding a code block like this:
Using this code, when you change view state to “newState”, the application will add a Button component to the view and position it before the hbox1 component. The Button would then show either to the left of hbox1 or above hbox1, depending on whether the application is a horizontal or vertical layout. To switch between states, you set the currentState property of the component or application. To go back to the base state, simply set the currentState property to an empty string. Listing 8-3 shows a sample application with a two-state view of a simple product.
Listing 8-3: Two-State View
Figure 8-5 shows the application in its base state, and Figure 8-6 shows the application in the “Description” state, after the user has clicked the Open Description button.
Figure 8-5: Application in base state
Figure 8-6: Application after user clicks the Open Description button
166
Chapter 8: Flex UI Topics
Using Transitions The preceding example accomplishes multiple states of a product view, but the application jumps from one state to the next rather abruptly. Luckily, Flex offers very simple ways to make the application change more gracefully. Flex calls these transitions.
Transitions Applied to View States A transition is a way to make a smoother change between states. A transition can be a single effect, or a group of effects run in sequence or in parallel. Using the simple state example, you can add a Resize effect by simply adding the following code right after the mx:Application tag:
This code block adds a Resize effect that plays for a duration of 500 (half a second) when switching from the ““ (base state) to the “Description” state, and then again when switching from the “Description” state back to the ““ (base state). Transitions allow you to apply more than one effect either in parallel or in sequence. The advanced transitions example shown in Listing 8-4 is a navigation system using state management to move between panels with a smooth transition. Each state sets the size and position of the three panels.
Listing 8-4: Advanced Transitions Example
167
Part II: Developing in Flex 2.0
168
Chapter 8: Flex UI Topics The transition is accomplished by using a sequence of a Move, followed by Rotate of 360 degrees, and finally a Resize. Because the transition is set to run when changing fromState * (all) to State *, it will run all state changes. The sequence is also set to target all panels, which means it will affect every panel on every state change, which is obvious when the Rotate effect plays (as shown in Figure 8-7). If you were to remove the Rotate effect, you would only see the effect on the panel that is growing and the panel (if any) that is shrinking.
Figure 8-7: Effect of Rotate
Transition Event Handling When Flex is changing states, there is a defined process order. There are two events dispatched along the way. The first event dispatch (currentStateChanging) occurs when the current state is changing, and the second occurs when the state has completed the change. The following seven steps (as defined in the Flex 2 documentation) show the official process Flex uses when changing from one state to another:
1. 2. 3. 4. 5. 6. 7.
You set the currentState property to the destination view state. Flex dispatches the currentStateChanging event. Flex examines the list of transitions to determine the one that matches the change of the view state. Flex examines the components to determine the one that matches the change of the view state. Flex applies the destination view state to the application. Flex dispatches the currentStateChange event. Flex plays the effect you defined in the transition.
It is important to know that if the currentState property is changed again, before Flex completes the current transition, Flex will skip to the end of the transition and start the cycle over again as listed in the previous steps.
169
Part II: Developing in Flex 2.0
Transition Action Effects To control the order that Flex uses to apply transitions, you can apply action effects. Action effects can be applied to the view state properties to gain additional control over the each property. There are four action effects that correspond to four view state properties. The following table shows the four action effects and their corresponding view state properties. Action Effect
View State Property
SetPropertyAction
SetProperty
SetStyleAction
SetStyle
AddChildAction
AddChild
RemoveChildAction
RemoveChild
Each action effect will play when the corresponding view state property occurs. Let’s go back to the basic state example in Listing 8-4 and change the transitions block to the following:
When running the application, you will now notice that the product description text does not appear until after the resize has occurred. The visible property has been given a startDelay of 500 to exaggerate the point. Action effects can give you that fine touch you need to really refine your transitions to be exactly the way you want them to perform.
Effects and Filters Transitions also support filters, which allow the developer to make sure certain effects run only on some of the targets in the Sequence, rather than all of the targets (which is the default behavior). Using the preceding code sample, simply add filter=“move” to the Rotate effect, and you will now notice that only the panels that are moving will have the Rotate effect applied. Transitions and states are one of the
170
Chapter 8: Flex UI Topics coolest features of Flex 2. Experiment by changing from Sequence to Parallel, or by using other effects (Blur, Dissolve, Zoom, and so on).
Using the Drag-and-Drop Manager The Flex DragManager class allows assets to be dragged and dropped for either purely visual reasons or for moving data between components.
List Control Drag-and-Drop Functions List controls have drag-and-drop functionality built in and are very easy to set up and use. The example shown in Listing 8-5 uses three simple List components — one original List to drag from and two additional List components to accept the drag item. The setup is as simple as setting dragEnabled=“true” on the List component that contains the drag data, and setting dropEnabled=“true” on the List components that will accept the data. Figure 8-8 shows the rotation transition. Figure 8-9 and Figure 8-10 show Listing 8-5 in action.
Listing 8-5: List Control Drag and Drop
171
Part II: Developing in Flex 2.0
Figure 8-8: The rotation transition
Figure 8-9: A valid drop when over a target
Figure 8-10: An invalid drop when not over a target
Adding Drag-and-Drop Support to Other Components Non–list-based controls (or containers) must explicitly add support by using a series of events and classes that must be implemented. The DragManager class and its doDrag() method manage the start of the drag.
172
Chapter 8: Flex UI Topics The DragSource class holds the data that is being dragged. In Listing 8-6, the data would be the name and price of the baseball hats. The DragEvent class dispatches events when the drag is in operation.
Listing 8-6: Custom Drag-and-Drop Operation
Figure 8-11 shows the results of the custom drag-and-drop operation.
Figure 8-11: The compiled results of Listing 8-6
Events that will be broadcast include dragEnter, dragOver, and dragComplete. Their definitions are described in the following table.
174
Chapter 8: Flex UI Topics Event
Description
dragEnter
The dragEnter event is dispatched when the drag item moves across the drop target. This allows you to alert the user that the item is over the target by programming a visual alert to the drop target. This could be a color change, a green border, and so on.
dragOver
The dragOver event is dispatched while the drag item is over the target and occurs after the dragEnter event. This would be a good time to validate that the item is going to be accepted by the target before it is dropped.
dragDrop
This is the dragDrop when the drag item is released over the target.
dragComplete
The dragComplete event broadcasts when the user releases the drag item, whether or not it is on the drop target.
dragExit
The dragExit event is broadcast when the drag item is dragged outside of the drop target, but is not dropped on the drop target.
Embedding Assets Flex supports the embedding of images, movies, sound files, and fonts. Embedding the assets will compile the image or font into the generated SWF file. Although you can load assets at run-time using relative paths, embedding the assets means that they are available as soon as the application initializes. It also means that you can distribute your application as a single SWF file. Another reason to embed assets is that there are some areas such as icons where only embedded assets are allowed by Flex.
Images There are several ways to embed an image asset. Here are two methods of embedding an image file to be used as a Button’s icon: ❑
Embed inline:
❑
Bind with ActionScript:
175
Part II: Developing in Flex 2.0
Fonts There are multiple benefits to embedding a font as an asset. Embedded fonts can be rotated, which is often necessary when labeling chart data. Embedded fonts can also show transparency, and show better results when using a Zoom effect. Another key feature of embedded fonts is that the developer can be sure that the fonts will appear the same on all machines because there is no need to rely on the machines’ installed fonts. Only fonts that are TrueType Font (TTF) files or fonts that have been embedded in an SWF file can be embedded. There are several ways to embed and apply a font: ❑
Embedding a font (Sample 1):
@font-face { src:url(“HELVETIB.TTF”); fontWeight: bold; fontFamily: myHelveticaBold; }
❑
Embedding a font (Sample 2):
❑
Using an embedded font via a Cascading Style Sheet (CSS):
Label { fontFamily: myHelveticaBold; fontWeight: bold; }
❑
Using an embedded font inline:
SWF and Sound Files SWF and sound files can be embedded as classes in the same way as image files.
Using the Histor y Manager History management in Flex is achieved when the application is embedded within a Web page. The page will contain a hidden HTML frame that contains a history SWF, which stores and retrieves information on the application’s current state. This enables the user to use the browser’s Back and Forward buttons to navigate within the application.
Components with Built-in History Management Components such as TabNavigator and Accordion have history management enabled by default. ViewStacks can also utilize history management, but it must be enabled by setting its historyManagementEnabled property to true. You can also turn off history management in the TabNavigator and Accordion by setting this property to false.
Adding History Management to Components It is also possible to add history management to other components by implementing mx.managers .IHistoryManagerClient and supplying the saveState and loadState methods, which are required by the interface. The following sample code extends the ToggleButtonBar and adds history management:
Note that history management will only work when all of the necessary JavaScript and SWF files are available in the application’s root folder, and the application’s HTML wrapper has the necessary code to include the needed files and create the hidden frame. Flex Builder 2 will generate the wrapper page and all necessary files within the project’s bin folder. You can also get these files from your SDK install. Listing 8-7 is a sample of the wrapper HTML page.
Listing 8-7: Sample Wrapper HTML Page
Filtering Messages Use the selector property of the Consumer component to filter out messages that the component should receive. A selector property uses a string formatted in SQL92 syntax. The Consumer component receives only messages with the headers that match the selector property’s criteria.
273
Part II: Developing in Flex 2.0 The following code example defines the selector property of the Consumer component:
10” />
In this example, the selector property is set to an expression of “property1 > 10”. This means that the consumer will process only messages containing a header of property1 with a value that is greater than 10. You may wonder where these headers are defined. Well, before a producer sends a message to a destination, you can define multiple headers in the AsyncMessage headers array property, as the following example shows: private function sendMessage():void { var message:AsyncMessage = new AsyncMessage(); message.headers = new Array(); message.headers[“property1”] = 11; message.body = input.text; producer.send(message); }
This message will be accepted by the consumer because the headers array property of the AsyncMessage instance contains a property1 value of 11.
Message Ser vice Configuration To get messaging to work, you must declare a connection to the server-side destination in the and tags. A Message Service destination is the endpoint that you send messages to and receive messages from when performing publish-subscribe or point-topoint messaging.
Message Service Configuration Common tasks that you will perform in configuring the Message Service are defining message destinations, adding security to message destinations, and modifying logging settings. Message Service destinations can be configured in the FDS configuration file, or a file that is included by reference. The following example shows a basic Message Service configuration file:
274
Chapter 11: Data Access
0
1000 0 true
flex.messaging.durability.FileStoreManager
Message Service Destination Configuration Channels are used to transport messages to and from a destination. A destination can reference one or more channels that are defined in the FDS configuration file. Only one channel can be used to conduct a destination. The following example shows two channels being referenced in a destination:
A destination can contain network properties for defining client-server messaging behavior. The following example shows the network properties defined within a destination:
0
275
Part II: Developing in Flex 2.0 Message Service destinations use the network properties shown in the following table. Property
Description
session-timeout
Idle time in minutes before a subscriber is unsubscribed. When the value is set to 0, subscribers are not forced to unsubscribe automatically.
throttle-inbound
The max-frequency attribute controls how many messages per second the server can receive. The policy attribute indicates what to do when the message limit is reached. A policy value of ERROR indicates that an error should be returned if the limit is reached. A policy value of IGNORE indicates that no error should be returned if the limit is reached.
throttle-outbound
The max-frequency attribute controls how many messages per second the server can send. The policy attribute indicates what to do when the message limit is reached. A policy value of ERROR indicates that an error should be returned if the limit is reached. A policy value of IGNORE indicates that no error should be returned if the limit is reached. A policy value of REPLACE indicates that the previous message should be replaced when the limit is reached.
A destination can contain server-related properties for controlling server-related parameters. The following example shows the network-related properties defined within a destination:
1000 0 true
flex.messaging.durability.FileStoreManager
Message Service destinations use the service-related properties shown in the following table.
276
Property
Description
max-cache-size
Maximum number of messages to maintain in memory cache.
message-time-to-live
This is how many milliseconds a message is kept on the server. A value of 0 means the message lasts forever.
Chapter 11: Data Access Property
Description
Durable
Boolean value that indicates whether messages should be saved in a durable message store to ensure that they survive connection outages and reach destination subscribers.
durable-store-manager
Durable store manager class to use when not using the JMS adapter. By default, the flex.messaging.durability.FileStoreManager, included with FDS, stores messages in files in the /WEB-INF/flex/ message_store/DESTINATION_NAME of your Flex Web application. You can change this location by setting the file-store-root property.
batch-write-size
(Optional) Number of message files to write in each batch.
file-store-root
(Optional) Location for storing message files.
max-file-size
(Optional) Maximum file size in kilobytes for message files.
In Message Service, you can specify an adapter to use (such as ActionScript, JMS, or ColdFusion Event Gateway adapter). You reference the adapter in the destination definition, or use the default configured adapter. The following example shows two adapter definitions referenced inside a destination:
Building a Custom Message Service Adapter If you find that the standard adapter does not provide the desired functionality, you can create a custom Message Service adapter. The custom adapter must extend the Flex Message Service Adapter class. The primary method of any Message Service adapter is the invoke() method. This method is called when a client sends a message to a destination. In the invoke() method, you can include code to send to all the subscribing clients or consumers, or to specify clients by evaluating the selector statements included in the message.
277
Part II: Developing in Flex 2.0 The MessageService.PushMessagesToClients() method is used to send messages in the invoke() method. This method takes a Message object as a parameter. The second parameter is of type Boolean and indicates whether to evaluate the message selector statements. The MessageService .PushMessagesToPeer() method in the invoke() method is used to broadcast messages to peer server nodes in a clustered environment. package custompackagename; import import import import
flex.messaging.services.ServiceAdapter; flex.messaging.services.MessageService; flex.messaging.messages.Message; flex.messaging.Destination;
public class SimpleCustomAdapter extends ServiceAdapter { public Object invoke(Message message) { MessageService msgService = (MessageService)service; msgService.pushMessageToClients(message, true); msgService.sendPushMessageFromPeer(message, true); return null; } }
If you want the Message Service adapter to manage its own subscriptions, override the ServiceAdapter .HandleSubscriptions() method. You must also override the ServiceAdapter.Manage() method, which is passed command Messages for subscribe and unsubscribe operations. To use the custom adapter class, you specify it in the adapter-definition element in the FDS configuration. The following example shows this:
Data Management Ser vices The Data Management Service feature uses client-side and server-side functionality to distribute data among multiple clients and server tiers. The client-side contains the DataService component in ActionScript that works in conjunction with the server-side Data Management Service to provide distributed data. The Data Service component manages data on the client, while the server-side Data Management Service manages the distribution of data among multiple clients and server-side data resources.
Data Management Service vs. RPC Features The Data Management Service employs a different approach to data than the RPC approach. Data Management Service supports automatic and manual synchronization of a common set of data on multiple clients and server-side data. It also supports offline client-side data persistence for occasionally connected clients.
278
Chapter 11: Data Access RPC components invoke operations on a remote service that return static results that you bind into an object. Data Management Service is different. The set of data is replicated to multiple clients from the Data Management Service and data is changed. The changes are automatically set to the Data Management Service, which updates the data resource and client applications.
Data Management Service Data Flow A Data Management Service application uses the Flex messaging framework, discussed earlier in this chapter. Instead of having a client application as the producer and another client application as a consumer, Data Management Services client applications act as both producers and consumers. Figure 11-4 shows the flow of data between the server-side data resource and an Array Collection object. A Data Management Service uses an adapter to update a data store. If data in one or more clients changes, the Data Management Service automatically synchronizes all client and server versions of the data. Any changes to database or directories do not automatically propagate back into the Data Management Service and client applications. The Data Management Service also provides functionality for server-side and client-side conflict resolution (APIs for handling data synchronization conflicts). Flex client application DataService component
Network tier fill () gets data from server.
Server tier
Network endpoint
Data Management Service Adapter
Data messages Managed ArrayCollection
commit () sends updates to server.
Remote data resource
Figure 11-4: Flow of data between the server-side data resource and an Array Collection object
Data Synchronization Conflicts When one or more clients change the same piece of data at the same time, data synchronization conflicts can occur. There is an API for detecting and handling data synchronization conflicts, and ensuring the integrity of distributed data by limiting any further changes until conflicts are resolved. The Data Management Service can detect when a data update from a client is out-of-date and inform the client of the conflict.
279
Part II: Developing in Flex 2.0
Distributed Data As you know by now, Data Management Service allows you to distribute and synchronize data among multiple clients. This section describes how to create client-side Flex applications that can show and distribute data.
Distributed Data Application A Flex application uses a Data Service component to receive data and send data to the server-side Data Management Service. The data travels over a protocol-specific message channel to and from the Data Management Service. You can manage an ArrayCollection object on multiple clients by using a Data Service component. Any changes made to the data synchronize with the rest of the clients. The following example creates and fills an ArrayCollection object in ActionScript. The fill() method populates the Array Collection object with data from the Data Management Service destination.
The following example shows a manual update of an item in an Array Collection object. The commit() method of the Data Service object sends the changes to the Data Management Service destination. var users:ArrayCollection = new ArrayCollection(); var userDS:DataService = new DataService(“myUserDestination”); userDS.autoCommit = false; var user:User = users.getItemAt(10); user.firstname = “Simon”; userDS.fill(users); userDS.commit();
280
Chapter 11: Data Access Call the DataService.disconnect() method to disconnect connected clients. The Data Service component keeps a copy of its managed data and will resubscribe to pick the changes when you reconnect.
Class Mappings To map a server-side Java object to a client-side ActionScript object, you use the [RemoteClass(alias=” “)] metadata tag. You must specify the package and class name of the Java object in the alias value. This is the same technique used when you map client and Java objects using RemoteObject components. If you do not want to map the ActionScript object to the Java object, but do want it mapped from the server to client, just specify the [RemoteClass] metadata tag without the alias value. The following example shows an ActionScript object that is mapped to a Java object called com.mycompany .vo.User: package com.learningpc.livecourse.vo { [Bindable] [RemoteClass(alias=”com.mycompany.vo.UserVO”)] public class UserVO { public var id:Number; public var sessionkey:String; public var username:String; public var password:String; public var firstname:String; public var middlename:String; public var lastname:String; public var photo:String; public var emailaddress:String; public var logincount:Number; public var lastlogindate:Date; public var lastlogoutdate:Date; public var homepage:String; public var usertype:String; public var lastIp:String; public var active:Number; } }
The following shows the corresponding Java object contact: package com.learningpc.livecourse.vo; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 4832904328320999999L; private int id; private String username; private String password;
281
Part II: Developing in Flex 2.0 private String firstname; private String lastname; private String emailaddress; public static long getSerialVersionUID() { return serialVersionUID; } public String getEmailaddress() { return emailaddress; } public void setEmailaddress(String emailaddress) { this.emailaddress = emailaddress; } public String getFirstname() { return firstname; } public void setFirstname(String firstname) { this.firstname = firstname; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getLastname() { return lastname; } public void setLastname(String lastname) { this.lastname = lastname; } public String getPassword() { return password; }
282
Chapter 11: Data Access public void setPassword(String password) { this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String toString() { StringBuffer sb = new StringBuffer(); sb.append(username); sb.append(“ “); sb.append(password); sb.append(“ “); sb.append(firstname); sb.append(“ “); sb.append(lastname); return sb.toString(); } }
Data Synchronization Handling When working with distribution data, there are often times that clients try to make changes already made. The following example displays an Alert box when a client conflict occurs:
Data Management Ser vice Configuration To connect to Data Management Service using the tag, you must configure a destination in your service-config.xml file. The section describes how to configure the destinations and data adapters they use, and also how to push data to clients.
Data Management Service Destination Configuration As mentioned previously, messages are transported over message channels. You can define one or more message channels for a destination definition. If one channel cannot be reached, the next one in the list is tried. The following example shows a destination definition with two message channels defined:
dev.contacts.ContactAssembler
284
Chapter 11: Data Access application true
20
loadContacts
loadContacts java.lang.String
syncContacts
Configure Network-Related Properties The network-related properties are the same as configuring the Flex Message Service, except that there are two additional properties, cluster and paging, as shown in the following table. Element
Description
cluster
The ref attribute of the cluster element references the name of a software cluster, which is configured in the clusters section of the services-config.xml file. For information about clusters, see the earlier section, “Software Clustering.”
paging
The enabled attribute of the paging element indicates whether data paging is enabled for the destination. When you enable paging, the pageSize attribute indicates the number of records to be sent to the client when the client-side DataService.fill() method is called. This element is optional; the default value is false.
Transactions All client changes are handled as one unit and, if the value cannot be changed, all changes are rolled back. Your J2EE server must support J2EE transactions (JTA) for distributed transactions to work.
285
Part II: Developing in Flex 2.0 The following defines the use of transactions within a destination definition:
Item Caching The default setting in Data Management Service is set to true for items returned from fill() and getitem() calls. This means a complete copy of the managed state of all active clients is kept in each server’s memory. The following example turns off the cache of items in the destination definition:
false
Data Push from Servers to Client To push data from server to client, you use the Flex.data.DataServiceTransactions Java class. The object is used on the server-side to push changes to managed code stored on clients that have the AutoSyncEnabled property of the DataService component set to true. The Data Management Service creates an instance of the DataServiceTransaction class when you make changes to a sync method. With the instance, you can call the getcurrentDataServiceTransaction(), deleteitem(), and createitem() methods to trigger additional changes. If the current transaction is rolled back, these changes are not pushed to clients. Note that when you compile code that uses the FDS Java APIs, you must include the messaging JAR and flex-messaging-common.jar files in your class path.
Summar y FDS adds a new dimension to Rich Internet Applications with publish-subscribe messaging, data synchronization, being able to push data to clients, and much more. With these features, you can build enterpriseclass applications that take full advantage of the rich presentation layer provided by Adobe Flex. Chapter 12 discusses creating MXML components in your Flex applications. MXML components are MXML files or documents that are referenced using MXML tags within your other MXML files. Chapter 12 teaches you about creating MXML components to reuse in your Flex applications.
286
Part III: Creating and Extending Flex Components Chapter 12: Creating MXML Components Chapter 13: Flex Component Properties Chapter 14: Flex Components Chapter 15: Custom Frontmatter, Validator, and Effect Components
Creating MXML Components Creating components is one of the most important features of Flex because it allows for the reuse of code created either by you or by other developers. Once a component is created, it can be reused by simply including it within your application. This chapter shows you how to create simple, composite, and advanced components. You learn how to scope and style your components, as well as how to create interfaces and template components.
Creating Simple MXML Components To create a component, you simply create a new MXML file and add a visual component as the root tag. Ensure that you add the mx namespace to the root tag. If you are using Flex Builder, you can accomplish this by selecting File ➪ New ➪ MXML Component. Simply give it a unique name and choose a Based On tag and you should end up with something like this:
Now, add anything you want to the custom component and use it within your application. To use a custom component, you will need to add it as an xml namespace in the parent’s root tag. Assuming the component created is named Test.mxml and is in a folder named components, this is what the main application file would look like when the component is added:
Part III: Creating and Extending Flex Components Take a look at a real-world example of where you may want to use a very simple custom component. Imagine that you are building an application where the user needs to select his or her birthday and you want the user to choose the month from a ComboBox rather than allowing him or her to free-type the value (which will result in inconsistent data). You could add a ComboBox to your application and create an array of months as the dataProvider, or you could create a very simple custom component that could then be reused within the same application or any application you will build in the future. Selecting the ComboBox to base the component on is the same as extending ComboBox. It just makes it easier to extend a ComboBox, rather than creating a composite component with a ComboBox and its data wrapped in a Canvas. The component would look something like that shown in Listing 12-1.
Listing 12-1: SimpleMonths.mxml
January February March April May June July August September October November December
Listing 12-2 shows the new component being included in the application.
Listing 12-2: SimpleMonthsMain.mxml
Figure 12-1 shows the SimpleMonths component.
290
Chapter 12: Creating MXML Components
Figure 12-1: The SimpleMonths component
Scoping Your Components Scoping within a Flex application refers to the value that will be returned from the this keyword. When this is accessed from within the application’s main file, it will be returned as the reference that Flex has assigned to mx.core.Application.application. When this is accessed from any Flex component, it will be returned as the full path from the root of your application to the component. In other words, this will always refer to the file you are working within. Take a look at Listing 12-3 and Listing 12-4.
Listing 12-3: Index.mxml
Listing 12-4: MyHBox.mxml
In these examples, this is being accessed from the Index.mxml file (Listing 12-3) within the Label component, and this is also being accessed within the Label component of the MyHBox custom component (Listing 12-4). The results can be seen in Figure 12-2. Notice that when this is called from the custom component, the ID of the component is returned. If there is no ID supplied, Flex assigns an ID.
291
Part III: Creating and Extending Flex Components
Figure 12-2: The this being accessed in multiple ways
Styling Your Components Components are self-contained and can be styled individually, or they can simply accept the style properties defined by the parent application’s style settings. Components can be styled inline by adjusting the style properties within the MXML code. They can be styled using CSS within an tag, or they can be skinned. Listing 12-5 shows SimpleStyledMonths.mxml. In the example shown in Figure 12-3, the properties of the MXML root tag were updated to take on a purple style and square corners. Figure 12-3 shows the original custom component, as well as the styled version.
Listing 12-5: SimpleStyledMonths.mxml
January February March April May June July August September October November December
292
Chapter 12: Creating MXML Components
Figure 12-3: SimpleMonths and SimpleStyledMonths components
Advanced MXML Components The SimpleMonths example was a very basic implementation of a custom component. More advanced components include custom properties, methods, and even additional components combined together to create what is known as a composite component.
Adding Custom Properties and Methods to a Component The SimpleMonths example created previously is limited to showing only the name of the month. But what if the application calls for the display to show only the number or the abbreviation of the months? Should you then create new components called MonthsByName, MonthsByNumber, and MonthsByAbr? he answer is no, because you can very easily build this functionality into one simple component. This can be accomplished by adding properties to your component, which can be set when the component is included in the parent document. The example shown in Listing 12-6 adds a property named labelFieldVar to determine what value to show within the ComboBox. The values that can be set are full, abr, and num, which will display the full month name, the month’s three-letter abbreviation, or the month’s number (1–12), respectively.
Listing 12-6: AdvancedMonths.mxml
Notice that labelFieldVar is set as a public property. This is important because only public variables and methods can be accessed from the parent, and only public properties can be set from within the custom MXML tag that is used to add the component to the parent. The labelFieldVar is also set to be bindable, which allows the property to be bound to the component root tag’s labelField property. Also notice that, when the variable is bound, it is accessed by scoping the variable name with this using dot notation. It is not necessary to scope it, because it is a local property, but it is a best practice to do so. If you do not use this, the variable is scoped to this by default. To set the labelFieldVar, simply add the property to the new MXML tag. Following is an example showing all three versions of this component within a single application. Figure 12-4 shows all three versions of the AdvancedMonths component.
294
Chapter 12: Creating MXML Components The AdvancedMonths component also has a public function added to demonstrate how methods can be added to component. In this example, the method will be called when the component’s change event occurs, passing in the type of month that should be returned. An Alert will show the current value of the component. Although this example may not have any use in the real world, it is simply meant to show the process of calling a method within a component. In the next section, you see the value of calling methods on components within a more detailed example. Figure 12-5 shows the custom component’s method being called from the parent.
Figure 12-4: All three versions of the AdvancedMonths component
Figure 12-5: The custom component’s method being called from the parent
Creating Composite Components A composite component is a component that is made up of multiple components. In the example shown in Listing 12-7 and Listing 12-8, a composite component has been created to capture a user’s birth date.
Listing 12-7: Birthdate.mxml
Listing 12-8: BirthdateMain.mxml
The component consists of an HBox as the root element with three nested ComboBox components representing the month, day, and year of a birth date. The new component reuses the AdvancedMonths component that was created earlier in this chapter to represent the birth date month. It contains its own labelFieldVar
296
Chapter 12: Creating MXML Components property, which is passed along to the AdvancedMonths labelFieldVar property. Two new Arrays were added to create the dataProviders for the new ComboBox elements. The new component also contains a public method named getBirthdate that returns a Date object representing the current values of the month, day, and year. The results of this component can be seen in Figure 12-6.
Figure 12-6: The results of the Birthdate component’s getBirthdate method
Template Components Template components are a unique type of component where the variables are typed in a more general way, allowing for flexibility in design. By creating a template component, you can control the layout of the component but still give another developer who implements your template component the freedom to use whatever UI components are desired. The following example illustrates this.
Creating a Template Component To create a template component, you must first create properties to act as placeholders for the components. In Listing 12-9, four properties are created. They are header, menu, and footer (all of which are typed as UIComponent), and content (which is an Array of UIComponents). Next, run the init function, which adds the components into whatever order and layout you would like.
Listing 12-9: TemplateLayoutComp.mxml Template Component
In this particular example, the header is added to the root VBox. An HBox named body is created to hold the menu and the mainContent, which is a VBox that was created to hold the contents of the content Array. The mainContent is created by looping over the content Array and adding each component as a child of mainContent. Finally, the footer is added to the root VBox, and the function is complete.
Using a Template Component To use a template component, you must add it to your MXML file (just as you would add any other custom component) and then define the content sections by name, scoped with the component namespace.
298
Chapter 12: Creating MXML Components Take a look at the examples shown in Listing 12-10 and Listing 12-11. Both use the TemplateLayoutComp that was defined earlier in this section. The namespace is defined as comps, so this is what is used to scope the inclusion of the TemplateLayoutComp. Nested within this component tag are the definitions of the component properties.
Listing 12-10: UseTemplate1.mxml
299
Part III: Creating and Extending Flex Components Listing 12-11: UseTemplate2.mxml
Notice that the first example header is defined as a Canvas with a Label nested within. Looking further, you will see the menu defined as a LinkBar, the content defined as a ViewStack with nested Label and Canvas components, and, finally, a footer defined as a Label. The results of this example can be seen in Figure 12-7. Now, take a look at the second example using the same TemplateLayoutComp and you will see that the header has been replaced by an Image, the menu has changed from a LinkBar to a ToggleButtonBar, and one of the Label components in the content section has been changed to a TextInput. These changes are all valid because they still meet the requirements of the TemplateLayoutComp, which had all of these areas typed as UIComponent. The results of the second example can be seen in Figure 12-8.
300
Chapter 12: Creating MXML Components
Figure 12-7: The results of UseTemplate1.mxml
Figure 12-8: The results of UseTemplate2.mxml
301
Part III: Creating and Extending Flex Components
MXML Interfaces As in most object-oriented languages, MXML allows the use of interfaces to define component functionality. Interfaces are a great way to decouple function definitions from implementations. Interfaces are created to act as a blueprint for any object that implements them. The interface declares public method and property definitions that must be included in the class that implements the interface.
Creating Interfaces To create a Flex interface, you must simply create a new ActionScript file and define it as an interface. You can also create an interface in Flex Builder. Click File ➪ New ➪ ActionScript Interface. A dialog box will ask for the package, interface name, and whether it extends any other interface. The basic syntax for an interface looks like Listing 12-12.
Listing 12-12: IBirthdate.as Interface Example package { public interface IBirthdate { function getBirthdate():Date; } }
You cannot define interface methods as public or private. Interfaces are typically used only to define methods. However, in the event that you want the interface to enforce a property, you can add implicit getters and setters to an interface. This example shows how a single function must be defined by all classes that implement this interface.
Using Interfaces To use an interface within an MXML component, you simply need to use the implements property of the component’s root tag. You will also need to define the necessary properties and methods that are outlined in the interface. To use the IBirthdate interface shown in Listing 12-12 within the Birthdate custom component that was shown in Listing 12-7, you simply add implements=”IBirthDate” to the component’s root HBox tag. Listing 12-13 shows what it would look like.
Listing 12-13: Birthdate.mxml Component Using IBirthdate as the Interface
302
Chapter 12: Creating MXML Components
Using IMXMLObject When creating custom components, it is often necessary to run a function when the component is initialized to manipulate data or visual components within the component. To do this, you would usually add a call to a function using the component’s initialize or creationComplete properties. However, if you are building a nonvisual component by extending Object (using as the root tag), you will not be able to do this, because these properties are not available for type Object. The solution is to implement mx.core.IMXMLObject. When implementing IMXMLObject, you are required to define a function named initialized. The initialized function will be called automatically after the properties of the component are initialized. The examples in Listing 12-14 and Listing 12-15 show a component implementing IMXMLObject. It has two properties, a and b, that are public, and a private property named total.
Listing 12-14: MyObjectComp.mxml
Listing 12-15: IMXMLObjectExample.mxml
303
Part III: Creating and Extending Flex Components
Figure 12-9: The results of the getTotal method When the component is initialized the function runs and sets the value for total, which is then returned and shown in the Alert. Figure 12-9 shows the results.
Summar y This chapter covered many subtopics, but all had to do with creating MXML components. The ability to extend the built-in Flex components, as well as create composite components, interfaces, and templates, creates limitless possibilities for developers to build components that suit the needs of their projects. It also opens the doors to third-party companies creating new components for Open Source or commercial use to further expand the base that Adobe has provided. The next couple of chapters show additional ways to extend Flex. Chapter 13 examines all of the pieces that make up a component, including the package statement, import statements, the class name, the default constructor, properties, getters and setters, and methods. It also demonstrates how to create simple and advanced components using ActionScript rather than MXML.
304
Flex Component Proper ties This chapter examines the many properties of a custom ActionScript component. The first half of this chapter discusses how to create a full ActionScript component, starting with a package statement and finishing with overriding of methods. The second half of the chapter shows additional examples of ActionScript components.
Elements of a Component ActionScript components are made up of many elements, some of which are required and others of which are optional. The package statement, class name, and constructor are required, whereas the import statements, properties, and methods are optional.
The package Statement The first thing to define in a custom ActionScript class is the package statement. The package statement includes the full folder path from the root of your application to the class, using dot notation to navigate the folder path, as shown here: package com.mydomain.components { // Class definition }
Part III: Creating and Extending Flex Components
import Statements The first section of the class definition includes the import statements. This is the area where you define all of the classes that you will need to import to meet the requirements of your class. To add the import statements, simply use the import keyword, followed by the path to the class you would like to import. Following is an example of importing a single class: package com.mydomain.components { // import statements import mx.controls.Button; }
You can also import a package of classes using the asterisk in place of a single class name. Following is an example of importing a package of classes: package com.mydomain.components { // import statements import mx.controls.*; }
Both of these examples will give access to the Button class. However, the second example will also give you access to all of the classes in the mx.controls package.
Defining the Class Name The next piece of a custom class is the section where you would define the class name. The class name must match the name of the file. For example, if you name your class UCaseTextInput.as, the class name must be defined as UCaseTextInput. Following is an example of naming the class: package com.mydomain.components { // import statements import mx.controls.Button; // class name public class ValidateButton extends Button { } }
The Default Constructor The default constructor is the method that Flex uses when it initializes an instance of the class. It should always be declared as public, and it may contain optional arguments if the class will be initialized using ActionScript. If you intend to initialize your class using MXML, you must have
306
Chapter 13: Flex Component Properties a zero argument constructor. The default constructor should not have a return type and should be named the same as the class name. Although not required, it is good practice to make a call to the super method, which calls the default constructor of the parent class. Following is an example of adding a default constructor: package com.mydomain.components { // import statements import mx.controls.Button; // class name public class ValidateButton extends Button { // default constructor public function ValidateButton(){ // a good practice is to include a call to super(). super(); } } }
Defining Properties Properties are the variables that will be used within the class to hold data. They can be defined as public (which will allow access of their data from outside the class), or they can be defined as protected or private (which restricts their access). Protected properties can be accessed from other classes that extend the custom class, and private properties cannot be accessed from outside the class. Adding getters and setters will allow your private properties to be accessed from outside the class, but you gain the control of how the private data is stored and returned.
Standard Properties Standard properties are defined as [Access type] var [property name]:[property type]. The following example includes two properties, checkIcon and xIcon. Both are defined as private, which means they will only be accessible from within the class itself. package com.mydomain.components { // import statements import mx.controls.Button; // class name public class ValidateButton extends Button { // define properties [Embed(source=”good.png”)] private var checkIcon:Class; [Embed(source=”bad.png”)] private var xIcon:Class;
307
Part III: Creating and Extending Flex Components // default constructor public function ValidateButton (){ // a good practice is to include a call to super(). super(); this.setStyle(“icon”,xIcon); } } }
Getters and Setters A property that is typed as private can only be accessed from within the containing class. To allow this property to be accessed, you will need to add getters and setters. Listing 13-1 has a property named _isValid, which is a private Boolean. Naming the property with a leading underscore will allow you to use implicit getters and setters. Implicit getters and setters allow the variable to be set or retrieved by property name rather than method call. The methods are named with get, followed by a space and then the property name, and set, followed by a space and the property name. The getter returns the class variable (in this case, _isValid), and the setter sets the _isValid variable. Using private properties with get and set methods allows you to have more control over the data.
Listing 13-1: Adding Private Properties with Getters and Setters package com.mydomain.components { // import statements import mx.controls.Button; // class name public class ValidateButton extends Button { // define properties [Embed(source=”good.png”)] private var checkIcon:Class; [Embed(source=”bad.png”)] private var xIcon:Class; private var _isValid:Boolean; // default constructor public function ValidateButton (){ // a good practice is to include a call to super(). super(); this.setStyle(“icon”,xIcon); } // getters and setters public function get isValid():Boolean{ return this._isValid; }
308
Chapter 13: Flex Component Properties public function set isValid(b:Boolean):void{ this._isValid = b; if(b){ this.setStyle(“icon”,checkIcon); }else{ this.setStyle(“icon”,xIcon); } } } }
Listing 13-1 shows that the set isValid method does more than simply set the _isValid property; it also changes the button’s icon to a check or “x” mark. The results of this class in its current state can be seen in Figure 13-1 and Figure 13-2.
Figure 13-1: The ValidateButton component in an invalid state
Figure 13-2: The ValidateButton component in a valid state
Defining Methods You can add private methods to your class to perform operations within the class, public methods that can be called from outside the class, or protected methods that can only be called from child classes. Listing 13-2 now includes a method named getProperties, which returns a few properties of the custom Button component. The results of this new method can be seen in Figure 13-3.
309
Part III: Creating and Extending Flex Components Listing 13-2: Adding a Custom Method package com.mydomain.components { // import statements import mx.controls.Button; // class name public class ValidateButton extends Button { // define properties [Embed(source=”good.png”)] private var checkIcon:Class; [Embed(source=”bad.png”)] private var xIcon:Class; private var _isValid:Boolean; // default constructor public function ValidateButton (){ // a good practice is to include a call to super(). super(); this.setStyle(“icon”,xIcon); } // getters and setters public function get isValid():Boolean{ return this._isValid; } public function set isValid(b:Boolean):void{ this._isValid = b; if(b){ this.setStyle(“icon”,checkIcon); }else{ this.setStyle(“icon”,xIcon); } } // a method to return propeties public function getProperties():String{ var s:String = “Label = “ + this.label + “\n” + “Width = “ + this.width + “\n” + “Height = “ + this.height; return s; } } }
310
Chapter 13: Flex Component Properties
Figure 13-3: An Alert with the results of a call to the getProperties method
Overriding Methods Using super To override a method, you will need to use the keyword override. You can also access the parent’s properties and methods using the super keyword. Listing 13-3 now contains a new function that overrides the label property by overriding the implicit public get label method. The new method adds parentheses before and after the original label, which is accessed using super.label. The results of this class with the added override method can be seen in Figure 13-4.
Listing 13-3: Overriding a Method package com.mydomain.components { // import statements import mx.controls.Button; // class name public class ValidateButton extends Button { // define properties [Embed(source=”good.png”)] private var checkIcon:Class; [Embed(source=”bad.png”)] private var xIcon:Class; private var _isValid:Boolean; // default constructor public function ValidateButton (){ // a good practice is to include a call to super(). super(); this.setStyle(“icon”,xIcon); }
311
Part III: Creating and Extending Flex Components // getters and setters public function get isValid():Boolean{ return this._isValid; } public function set isValid(b:Boolean):void{ this._isValid = b; if(b){ this.setStyle(“icon”,checkIcon); }else{ this.setStyle(“icon”,xIcon); } } // a method to return propeties public function getProperties():String{ var s:String = “Label = “ + this.label + “\n” + “Width = “ + this.width + “\n” + “Height = “ + this.height; return s; } // an override to add parentheses to the label override public function get label():String{ return “(“+super.label+”)”; } } }
Figure 13-4: The button label with the parentheses added by the override method The custom class is now complete, and although it may not be the most useful component, it does demonstrate all of the key elements of an ActionScript component. The following discussion further explores the creation of ActionScript components.
312
Chapter 13: Flex Component Properties
Creating a Simple ActionScript Component Listing 13-4 is an example of a simple ActionScript component. It is a simple example that creates a TextInput component that self-validates the text property for a valid e-mail address.
Listing 13-4: EmailTextInput Component package com.mydomain.components { import mx.controls.TextInput; import mx.events.ValidationResultEvent; import mx.validators.EmailValidator; import flash.events.Event; public class EmailTextInput extends TextInput { private var emailValidator:EmailValidator = new EmailValidator(); private var validator:ValidationResultEvent; public function EmailTextInput(){ super(); this.addEventListener(“change”, this.validate); this.emailValidator.source = this; this.emailValidator.property = “text”; } private function validate(event:Event):void{ validator = emailValidator.validate(); if (validator.type==ValidationResultEvent.VALID){ this.errorString=””; } else { this.errorString = validator.message; } } } }
The class is defined within the com.mydomain.components package and imports the needed classes (including TextInput), as well as the necessary validation and event classes. The class extends TextInput and declares EmailValildator and ValidationResult properties that will be used in the validate function. The default constructor creates a listener that calls the validate function when the text property changes. It also assigns the source and property properties of the emailValidator. Finally, the validate function calls the validate function of the emailValidator and sets the errorString. The results of this component can be seen in Figure 13-5.
313
Part III: Creating and Extending Flex Components
Figure 13-5: The EmailTextInput component in action
Implementing and Overriding UIComponent Methods When creating a custom component, you may find it necessary to override public or protected methods to accomplish your needs. Fortunately, Flex makes this a very simple thing to do. The CircleLabel example shown in Listing 13-5 overrides the updateDisplayList function and uses the graphics class to draw an ellipse around the label’s text property.
Listing 13-5: CircleLabel Component package com.mydomain.components { import mx.controls.Label; public class CircleLabel extends Label { public var circleColor:uint = 0x000000; public function CircleLabel(){ super(); } override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void { super.updateDisplayList(unscaledWidth, unscaledHeight); // Draw a circle around the label text graphics.lineStyle(1, this.circleColor, 1.0); graphics.drawEllipse(-5,-5,this.width+10,this.height+10); } } }
The updateDisplayList function was selected as the function to override because it is called before the component appears onscreen. The results of the CircleLabel component can be seen in Figure 13-6.
314
Chapter 13: Flex Component Properties
Figure 13-6: Two instances of the CircleLabel component
Creating Advanced Components in ActionScript Listing 13-6 shows an example of an advanced ActionScript component that includes many UIComponents, private variables, getters, setters, styles, and events. The class extends Canvas and is named MultiRowTabs. It has several import statements to give access to Flex containers, controls, and collections. There are also import statements to allow the use of the TabSkin and MouseEvent classes.
Listing 13-6: MultiRowTabs.as package com.mydomain.components { import mx.containers.Canvas; import mx.containers.HBox; import mx.containers.ViewStack; import mx.controls.Button; import mx.collections.ArrayCollection; import mx.skins.halo.TabSkin; import flash.events.MouseEvent; public class MultiRowTabs extends Canvas { // declare class properties public var myViewStack:ViewStack; public var tabsPerRow:Number = 4; public var rowHeight:Number = 22; public var tabRows:Array = new Aray(); private var _dp:ArrayCollection; private var buttonArray:ArrayCollection; // default constructor public function MultiRowTabs(){ }
315
Part III: Creating and Extending Flex Components // getters and setters public function get dp():ArrayCollection{ return _dp; } public function set dp(a:ArrayCollection):void{ _dp=a; this.removeAllChildren(); buttonArray = new ArrayCollection(); var start:Number = 0; var end:Number = tabsPerRow; var currentY:Number = 0; // add rows for(var i:Number=0; i
Figure 14-5 shows the results of Listing 14-7 and Listing 14-8.
Figure 14-5: The custom event being dispatched
[Effect] The Effect metadata tag is used to define a custom effect that will be dispatched when an event occurs. This can be easily demonstrated by building on the earlier Event examples. By simply changing a single line to the ButtonLabel class (Listing 14-9), an effect is defined that can be assigned to an Effect instance (Listing 14-10).
326
Chapter 14: Flex Components Listing 14-9: Adding the Effect Metadata Tag ... // Define the custom event [Event(name=”labelChanged”, type=”flash.events.Event”)] [Effect(name=”labelChangedEffect”, event=”labelChanged”)] public class ButtonLabel extends Button { ...
Listing 14-10: Adding labelChangedEffect to the Component Instantiation MXML Tag
[IconFile] IconFile is used to identify the filename of a jpg, gif, or png file that will be used as the icon for your custom class. Whereas the [Embed] metadata tag can be used to embed image files, SWF files, music files, video files, and so on, IconFile is only used to embed a file that will be used as the icon for the custom class. Here is the example of the IconFile syntax: [IconFile(“icon.png”)] public class CustomButton extends Button { }
[Inspectable] The Inspectable metadata tag is used to define the attributes of your custom component that you would like to display within the code hints and property inspector of Flex Builder 2. The example shown in Listing 14-11 defines a variable named ccType that is inspectable. It defines a defaultValue of Visa, a category of Credit Card, and enumeration values of Visa, Mastercard, Discover, and American Express.
Listing 14-11: MyComponent.mxml
327
Part III: Creating and Extending Flex Components Figure 14-6 shows an example of the code hints being displayed as the component is added to an application. Figure 14-7 shows the same example, but this time in Design view, which exposes the property inspector. You can see that the category of properties is Credit Card with the property showing as ccType and the available values within the drop-down list.
Figure 14-6: Code hints
[InstanceType] The InstanceType metadata tag is used to declare the type of object that will be allowed when declaring a variable as IDeferredInstance within a template object. The syntax of InstanceType looks like this: [InstanceType(“package.className”)]
[NonCommittingChangeEvent] The NonCommittingChangeEvent is a metadata tag that will prevent a change from occurring when a specified event occurs. Listing 14-12 demonstrates how this works. A private variable named s of type String is created and bound to the ti2 TextInput component. The other TextInput component
328
Chapter 14: Flex Components
Figure 14-7: Code hints when in Design view
with the id of ti1 sets the value of s equal to the value of its text property whenever the text changes. Additionally, the Binding metadata tag attached to the s variable is set to bind when the triggerBinding event is dispatched. The triggerBinding event is dispatched only when the Enter key is pressed while typing in the ti1 TextInput component.
Listing 14-12: NonCommittingChangeEventSample.mxml
[RemoteClass] RemoteClass is used to bind an ActionScript class to a Java class. This will allow for automatic data type conversions. Following is an example of an ActionScript class named MyClass in package com.mydomain being bound to a Java class named MyClass in package com.mydomain: package com.mydomain { [Bindable] [RemoteClass(alias=”com.mydomain.MyClass”)] public class MyClass { public var id:int; public var myText:String; } }
[Style] The Style metadata tag is used to define custom style properties for your components. Simply add the Style metadata tag or tags to your class definition, and then use the getStyle method to retrieve its value. Listing 14-13 and Listing 14-14 show examples of how to define two styles named borderColor and fillColor, both of which are defined as uint data types. The styles are set within the component tag when the class is instantiated. The updateDisplayList function is overridden and the custom styles are used to draw the circle border and fill.
Listing 14-13: CustomCircle.as package { import mx.core.UIComponent; [Style(name=”borderColor”,type=”uint”,format=”Color”,inherit=”no”)]
330
Chapter 14: Flex Components [Style(name=”fillColor”,type=”uint”,format=”Color”,inherit=”no”)] public class CustomCircle extends UIComponent { public function CustomCircle(){ super(); } override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void { super.updateDisplayList(unscaledWidth, unscaledHeight); graphics.lineStyle(1, getStyle(“borderColor”), 1.0); graphics.beginFill(getStyle(“fillColor”),1.0); graphics.drawEllipse(0,0,100,100); } } }
Listing 14-14: StyleSample.mxml
Figure 14-8 shows the results of Listing 14-13 and Listing 14-14.
Figure 14-8: Using the Style metadata tag
331
Part III: Creating and Extending Flex Components
Compiling Components To allow components to be easily shared between applications and developers, components can be compiled to SWC files and distributed as SWC files or Runtime Shared Libraries (RSLs). Components can be compiled using the free Flex SDK or Flex Builder. The following examples demonstrate how to compile components in these methods, as well as how to use these compiled components.
Compiling Components with Flex SDK The Flex SDK uses the compc compiler to compile your custom components into SWC files.
SWC To create an SWC file with a single class, simply open the compc compiler command window and change directory to the root of your class path. The following command compiles an SWC file named EmailTextInput to c:/jrun4/servers/flex2/flex/WEB-INF/flex/user_classes/ EmailTextInput.swc: compc -source-path . -output c:/swcs/ValidateButton.swc -include-classes com.mydomain.components. ValidateButton
To create an SWC file that contains multiple files, simply add additional –include-classes statements. To include assets, simply add –include-file, followed by the filename and its path. compc -source-path . -output c:/swcs/ValidateButton.swc -include-classes com.mydomain.components.ValidateButton -include-file bad.png com/mydomain/components/bad.png -include-file good.png com/mydomain/components/good.png
RSL To compile the component to a simple library.swf file, you can use the following syntax within the compc compiler. The library.swf within the ValidateButton folder can now be renamed and deployed as an RSL. compc -source-path . -output c:/swcs/ValidateButton -include-classes com.mydomain.components.ValidateButton -directory=true -debug=false
Create a folder named RSLSample at C:\RSLSample and copy the ValidateButton folder to this folder. The example at the end of this chapter demonstrates how to compile your application with this new RSL.
Compiling Components with Flex Builder Flex Builder makes compiling your components to SWC files a very easy procedure. Simply follow the directions here and your SWC will be created automatically.
SWC To compile an SWC file within Flex Builder, you must first create a Flex Library project by selecting File ➪ New ➪ Flex Library Project (Figure 14-9). Next, name your project the same name as you would like your SWC to be named, as shown in Figure 14-10.
332
Chapter 14: Flex Components
Figure 14-9: Creating a Flex library project
Figure 14-10: Naming the project
Once you have named your project, you must either copy your component files into the new project, or link to them as source files. After you have done this, you can add your classes and assets to your build path. You can open this view by right-clicking the Project and selecting Properties, as shown in Figure 14-11 and Figure 14-12.
333
Part III: Creating and Extending Flex Components
Figure 14-11: Adding classes to the library build path
Figure 14-12: Adding assets to the library build path
334
Chapter 14: Flex Components After you have added your classes and assets, the SWC file will be created automatically (assuming you have your project set to build automatically) within the bin folder of your project, as shown in Figure 14-13. You can now distribute your compiled SWC file to other projects or developers. An SWC file is a file that you can open to show its contents. By renaming the SWC as a zip, you can open and see the contents of the SWC, as shown in Figure 14-14.
Figure 14-13: The compiled SWC file in the bin folder
Figure 14-14: The contents of the compiled SWC file
335
Part III: Creating and Extending Flex Components RSL To extract the SWC that was just created to a Runtime Shared Library, simply follow these directions. The first thing you must do is to add the ValidateButton SWC file that was created earlier to the library path of the Flex build path of the project, as shown in Figures 14-15 and 14-16. Next, highlight the RSL URL property and click the Edit button. Change the link type to “Runtime shared library (RSL)” and check “Auto extract to swf to RSL URL,” as shown in Figure 14-17. Because the RSL URL was left as a local reference, this will create a new SWF file named ValidateButton.swf in the bin folder of your project.
Figure 14-15: Adding an SWC file to the project’s library path
336
Chapter 14: Flex Components
Figure 14-16: The SWC file after being added
Figure 14-17: Changing RSL URL properties
337
Part III: Creating and Extending Flex Components You can now include any components within this library file in your application, just as you would when working with components that are in a local folder path. To demonstrate this, copy the ValidateButton Main.mxml file from Chapter 13 into your project and compile it. The results of the compiled SWF from Chapter 13 and the same compiled SWF from this chapter can be seen in Figure 14-18 and Figure 14-19. Notice the large difference in file size of the compiled SWFs. The benefits of RSL are very dramatic. However, they are only useful if you will be using the components compiled within your RSL in multiple applications, because the RSL still must be downloaded. The benefits are only realized when a second application loads using the RSL, and this time it will not need to download the RSL, because it has already cached the RSL it downloaded when running the first application. Another advantage is that the end developer, using an RSL, will always have the latest component when compiling the application.
Figure 14-18: Compiled with the components embedded
Figure 14-19: Compiled using an RSL for the components
Deploying Components Components can be deployed in more than one method. The first method is to simply include the folder path of your component within your project build and compile a single SWF. This is the method that has been demonstrated many times throughout this book. Other methods include deployment as an RSL, or an embedded SWC merged into your code.
338
Chapter 14: Flex Components RSL with SDK If you haven’t already done so, create a folder named RSLSample located at C:\RSLSample, and copy the ValidateButton folder that was compiled earlier in this chapter in the section “Compiling Components with Flex SDK” and the subsection “RSL.” Also copy the ValidateButtonMain.mxml file that was created in Chapter 13 into C:\RSLSample. Your folder structure should now look like Figure 14-20. Open the command window and navigate to C:\RSLSample (using cd C:\RSLSample) and run the following command to compile the ValidateButtonMain.swf with the RSL. The results of this can be seen in Figure 14-21. To include more than one RSL, simply supply a comma-separated list. mxmlc -runtime-shared-libraries=ValidateButton/library.swf -ex ternal-library-path=ValidateButton -file-specs ValidateButtonMain.mxml
Figure 14-20: C:\RSLSample before compiling the ValidateButtonMain with RSL
Figure 14-21: The newly compiled ValidateButtonmain.swf
RSL with Flex Builder If you are using RSLs with Flex Builder as shown earlier in this chapter, the RSL SWF will be automatically created and moved to the bin folder of your project. It will then be deployed along with your application SWF when you run your application from Flex Builder.
339
Part III: Creating and Extending Flex Components SWC with SDK Create a new folder directly under C:\ and name it SWCExample. Copy the ValidateButtonMain.mxml file that was created in Chapter 13 and also used in the earlier RSL examples in this chapter. Open the command window and navigate to the SWCExample folder (using cd C:\SWCExample) and run the following command: mxmlc -library-path+=C:/swcs/ValidateButton.swc --file-specs ValidateButtonMain.mxml
As opposed to the earlier RSL examples, this will compile an SWF file that will include all of the files needed to deploy by itself. You will notice that the file size for this SWF is larger, but you can deploy the SWF as a single file without the need to deploy the SWC file. To include more than one SWC file, simply supply a comma-separated list.
SWC with Flex Builder Compiling an application when using an SWC that has been defined in the library path of the Flex build path of your project and not set to be an RSL will automatically embed all of the files needed in the compiled application SWF. You will be able to deploy the SWF without deploying the SWC file.
Summar y This chapter included information of how to create custom events in components. It provided examples showing custom events being dispatched based on logic within a custom component. It included examples on how to use the [ArrayElementType], [Bindable], [DefaultProperty], [Embed], [Event], [Effect], [IconFile], [Inspectable], [InstanceType], [NonCommittingChangeEvent], [RemoteClass], and [Style] metadata tags. Lastly, this chapter covered creating SWCs and RSLs, using both the free Flex SDK and Flex Builder. It also provided examples on how to deploy your applications using SWCs and RSLs, using both the free Flex SDK and Flex Builder. Chapter 15 discusses nonvisual Flex components. These types of components include custom formatters, custom validators, and custom effects. Examples are provided to show how to use the SwitchSymbolFormatter class, how to extend the Formatter class and create custom formatters, and how to create custom validators, as well as examples of how to extend the Effect class.
340
Custom Formatter, Validator, and Effect Components Flex 2 provides RIA developers with the ability to extend the factory base classes and override functions to create custom classes that fit better with the needs of the application being created. This chapter shows you how to customize some of these factory classes. You learn how to use SwitchSymbolFormatter and also how to create a custom formatter. This chapter also shows you how to create custom validators and custom effects.
Custom Formatters Many built-in formatter classes are used to format phone numbers, dates, currency, and so on. However, there will be occasions when it will be necessary to format a string to a format that is not covered by any of the built-in formatter classes. The way to do this is by creating a custom formatter.
Customizing the SwitchSymbolFormatter Class The SwitchSymbolFormatter class is a very flexible formatter that allows custom format strings as well as custom format characters. Listing 15-1 creates an instance of the SwitchSymbolFormatter on creationComplete as well as on change of the ComboBox component. The formatValue method has two arguments passed in. The first argument is the format string, which, in this example, uses the selected value from the ComboBox. The second argument is the string that will be formatted.
Part III: Creating and Extending Flex Components Listing 15-1: Customizing the SwitchSymbolFormatter Class
#-######## ###-###### ##-###-#### #######-##
By selecting a new value from the ComboBox, you will see that the new format string will be applied that will reformat the string. The default format character is the pound (#) symbol. Wherever Flex encounters a pound symbol, it places the corresponding character form the string being formatted. If there are other characters in the format string (such as –, as in this example), they will be included in the formatValue results. So a string such as 123456789 with a format string of ###-###-### will be formatted to 123456-789, as shown in Figure 15-1.
342
Chapter 15: Custom Formatter, Validator, and Effect Components
Figure 15-1: Formatting a string with the # symbol There will probably be occasions where the results you would like in your formatted string should include the # symbol. The SwitchSymbolFormatter can accommodate this by allowing the format character to be a custom character rather than the default # symbol. Listing 15-2 is the same as Listing 15-1, except that the constructor of the SwitchSymbolFormatter is now being passed the asterisk symbol * as the format character. The format string would now use * symbols instead of # symbols, which allows you to now use # in the format string and it will be included in the newly formatted string.
Listing 15-2: Passing the * Character as the Format Character
343
Part III: Creating and Extending Flex Components
# *-******** # ***-****** # **-***-**** # *******-**
So a string such as 123456789 with a format string of #***-***-*** will result in #123-456-789, as shown in Figure 15-2.
Figure 15-2: Formatting a string with the * character
Extending the Formatter Class Formatters have also been built to be easily extendable, so you have the ability to create custom formatters to meet your needs. To write a custom formatter, you must simply extend the mx.formatters.Formatter class and override the format method.
344
Chapter 15: Custom Formatter, Validator, and Effect Components
Custom Formatter Example Listing 15-3 is admittedly a rather useless example in the real world, but it does demonstrate how easy it is to create a custom formatter. The ReverseFormatter overrides the format method, which accepts an argument of type Object that contains the data to be formatted. It then checks to see if the Object has length and loops over the data and returns it in reverse.
Listing 15-3: Custom Formatter that Will Reverse the Text package { import mx.formatters.Formatter // Custom formatters must extend mx.formatters.Formatter public class ReverseFormatter extends Formatter { public function ReverseFormatter() { super(); } // Custom formatters must override format(). override public function format(formatObj:Object):String { if(formatObj.length == 0) { // return empty string and set error property if string has zero length. error=”Cannot format an empty String”; return “” } else { error=null; var returnString:String = “”; // loop through value and build string in reverse for(var i:Number=formatObj.length; i>=0; i--){ returnString = returnString + formatObj.charAt(i); } return returnString; } } } }
Figure 15-3 shows the ReverseFormatter from Listing 15-4.
Figure 15-3:ReverseFormatter in action
345
Part III: Creating and Extending Flex Components Listing 15-4: Sample Application Running the Custom Formatter
Formatter Errors Formatters also contain an error property that allows you to get information on the status of the formatter. In the ReverseFormatter example shown in Listing 15-3, the error property is being set to “Cannot format an empty String” when the Object coming into the format function has a length of zero. It is set to null when the Object has a length greater than zero. The sample application will show the error property when it is not null as an Alert. You can see the results of this in Figure 15-4.
Figure 15-4: Displaying a formatter error
346
Chapter 15: Custom Formatter, Validator, and Effect Components
Custom Validators Like most of the Flex 2 objects, Validator is extendable. To create your own custom validator you will simply need to extend Validator and override the doValidation method. The class shown in Listing 15-5 is a custom password validator that will apply certain rules to a string to ensure it complies with a predetermined standard. In this example, you are requiring a password to have at least 1 uppercase letter, 1 lowercase letter, 1 number, and a length of between 6 and 10 characters. Looking at the code, you will see a results Array is defined and then appended to when the validation fails. Determining whether the validation passes or fails is handled by the doValidation method. Within the doValidation method, you will see a series of conditional tests that check the length, as well as searching for specific characters. If the condition being tested returns false, a new ValidationResult object is created with a custom errorCode and errorString, which is then appended to the results array and returned.
Listing 15-5: PasswordValidator.as package { import mx.validators.Validator; import mx.validators.ValidationResult; public class PasswordValidator extends Validator { private var results:Array; public function PasswordValidator() { super(); } // Override the doValidation() method. override protected function doValidation(value:Object):Array { results = []; // Call super’s doValidation(). results = super.doValidation(value); // Return if super’s doValidation contains errors (required would be an example). if (results.length > 0){ return results; } // Check for min length var dataString:String = String(value); if (dataString.length < 6){ results.push(new ValidationResult(true, null, “Short”, “Password must be at least 6 characters.”)); return results; } // Check for max length (this can be set in the text component’s maxChars property). if (dataString.length > 10){ results.push(new ValidationResult(true, null, “Long”, “Password must be no larger than 10 characters.”)); return results;
347
Part III: Creating and Extending Flex Components } // Check for at least 1 uppercase letter. if (dataString.search(“[A-Z]”)
The last node manages the loading of the alternative content for the case in which the version of Flash Player installed on the client does not meet the minimum requirements.
Upgrading Without Express Install Though Express Install is user-friendly, it is not the only possibility that a developer of Flex applications has available for managing the updating of Flash Player. Through the properties of the and tags, it is possible to define a path to upgrade and install Flash Player. The tag displays the codebase property that controls the version of the plugin in Internet Explorer. In the tag, two attributes become defined: the classid (which identifies the ActiveX control used by the browser to read the film segment) and the codebase. The classid specifies the base path used to resolve relative URIs specified by the classid, data, and archive attributes:
In this case, the following line of code, aside from indicating the download URL of Flash Player, also establishes the minimum requirements defining the version: codebase=”http://download.macromedia.com/pub/shockwave/cabs/flash/ swflash.cab#version=9,0,0”
526
Chapter 20: Deploying Flex Applications Therefore, the browser loads the Flash-defined film segment from this tag. If, on the client, it does not find version 9 of the Flash Player, it will request that the user perform an upgrade of the plugin. Similarly, for the Firefox, Netscape 8, and all other Mozilla-based browsers, the pluginspace property of the tag functions in the same way:
The only difference with respect to the tag object is that it is not possible to specify a version of the plugin, and, therefore, it can only verify the presence of Flash Player on the client. Using these two methods does not always obtain the desired results. Depending on the type of browser and the version, the user may not be able to load the exact version of Flash Player requested for the Flex application to function. In addition to the Flash Player–detection techniques described here, you can always provide alternative content that displays the version information and contains a link to the Flash Player download page. This content should be put in the block. To examine more detail about the Flash Player detection, Adobe has created the Flash Player Detection Kit (located at http://www.adobe.com/products/flashplayer/download/detection_kit/), which includes the following: ❑
The documentation describing the requirements, methods, and procedures for detecting and updating the end user’s Flash Player version
❑
Client-side detection sample files
❑
ActionScript-based detection sample files
Summar y This chapter provided a comprehensive guide on the different methods of application deployment, as well as the consequences of each. It demonstrated the use of the wrapper file and all of the ways this file can be edited for Web-standard compliance, as well as to suit the individual needs of the application being deployed. The History Manager and Express Install were also discussed, and examples demonstrated how to deploy an application using either or both of these. Chapter 21 is dedicated to the Cairngorm micro-architecture developed by the Adobe Consulting team. Examples on the implementation of Cairngorm and all of the pieces that make up the Cairngorm framework are demonstrated.
527
Part VI: Advanced Flex 2.0 Chapter 21: Using the Cairngorm Framework Chapter 22: Using the Flex-Ajax Bridge Chapter 23: Using the ActionScript 3.0 Libraries Chapter 24: Using ColdFusion/Flex Connectivity
Using the Cairngorm Framewor k Cairngorm is a framework used to develop Rich Internet Applications (RIAs) in Adobe Flex. It was originally developed by iteration::two, which was acquired by Macromedia (now Adobe) in 2005. The framework was released for Flex 1.5 and later updated to version 2 to work in conjunction with the newly released Flex 2.0. The latest version of the Cairngorm Framework, version 2.1, was released at Adobe MAX 2006 in Las Vegas by the Adobe Consulting Team. The example used in this chapter uses Cairngorm 2.1, which is currently as of this writing the latest version of the framework.
The Cairngorm Framewor k The framework is an adaptation of Sun’s core J2EE patterns and was first applied to Flash development and then to Flex. Iteration::two also played a significant role in helping shape the Flex Framework. Over the years, iteration::two developed the Cairngorm Framework through considerable research and development using best-practice techniques from the field of design patterns. The framework was then applied to the emerging technology of RIAs using Flex. At the MAX 2004 conference in New Orleans, iteration::two announced the release of the Cairngorm Framework as an Open Source project for the Flex development community. For more information on the Cairngorm Framework, Steven Webster has a great series of articles on “Developing Flex RIAs with Cairngorm Micro-Architecture.” The series is comprised of the following six parts: ❑
Part 1: Introducing Cairngorm
❑
Part 2: Keeping state on the client
Part VI: Advanced Flex 2.0 ❑
Part 3: Architecting the view
❑
Part 4: Feature-driven development
❑
Part 5: Server-side integration
❑
Part 6: Rapid and consistent development with Cairngorm and Flex
You can find the series of articles at http://www.adobe.com/devnet/flex/architecture.html. It is a must-read if you want to learn more about the Cairngorm Framework and how it works with Adobe Flex. To get to grips with Cairngorm, this chapter takes you through the framework while building a Flex weather application. This seems to be the most efficient way in learning something new.
Understanding Framewor ks It is important to understand what a framework is before you start using one for the first time. The word “framework” is often misunderstood in the software development field. There are two different types of frameworks, one being application frameworks and the other being architectural frameworks. For a more in-depth explanation of frameworks, refer to part 1 of Steven Webster’s series of articles at http://www.adobe.com/devnet/flex/articles/cairngorm_pt1_02.html.
Application Frameworks Application frameworks usually refer to a set of libraries and classes used to implement the standard structure of an application. Flex 2.0 is a great example of an application framework. The Flex 2.0 Framework provides a set of rich class libraries that provide functionality for developers to create custom applications. For example, Flex 2.0 provides a competent framework that allows you to develop custom components to be reused in your Flex applications. Application frameworks have become more popular with the rise of graphical user interfaces (GUIs), which seem to promote a standard structure for applications. Object-oriented programming (OOP) techniques usually are used to implement frameworks such as the unique part of an application that can inherit from preexisting classes in the framework.
Architectural Frameworks Architectural frameworks refer to a set of tools that can be used to provide a structure where the business layer of the application can be defined. In other words, an architectural framework is the internal structure on which an application is built.
532
Chapter 21: Using the Cairngorm Framework
Building an Application Using the Cairngorm Framewor k In the remainder of this chapter, you build an application from the ground up, utilizing the Cairngorm micro-architecture. The Flex Weather application showcases the basics of a Flex application framework, and demonstrates data binding, navigator containers, and controls and effects. The Weather application is a great way for you to become familiar with the Cairngorm Framework. Figure 21-1 shows the completed Flex Weather application using the Cairngorm Framework.
Figure 21-1: Example Weather application using the Cairngorm Framework
533
Part VI: Advanced Flex 2.0
Value Object and Model Locator Pattern Developers who come from a Web application background must change the way they think about RIAs. The reason is because Flex applications are stateful, rather than the stateless HTTP request-and-response model of an HTML Web application. To overcome this, developers require ways to maintain state on the client. This is done by using either cookies or sessions on the server to achieve a stateful client. RIAs work in the same way that desktop applications work in that their state is maintained on the client. So the principles of building Web applications must be changed when designing and developing RIAs.
Value Object When developing applications in Flex (or any enterprise application, for that matter), you should create classes or objects that represent an entity. For example, in the Weather application, the one thing that you must represent is the weather for that location. Each location has a number of weather attributes, such as temperature, date, conditions, longitude, latitude, wind, and so on. Useful structures can be exchanged or transferred between tiers in your application. On the server side, you could run a query in SQL that returns a result set and then converts it into a collection of custom value objects (VOs) to return to the client. Flex can then deserialize each VO in the collection into the corresponding VO on the client. VOs are used to create a layer of business objects that can be transferred between tiers, instead of using records, results sets, and datasets. Using VOs also allows stricter typing on the client. This is great when compiling your Flex applications because any references to properties that do not exist, or types that do not correspond, will throw a compiler error. Listing 21-1 shows a representation of a location’s weather forecast in a VO.
Listing 21-1: WeatherVO.as package com.wiley.proflex2.chapter23.vo { import com.adobe.cairngorm.vo.IValueObject; [Bindable] public class WeatherVO implements IValueObject { public var location:String; public var humidity:Number; public var visibility:Number; public var conditions:String; public var code:String; public var temp:String; public var date:String;
534
Chapter 21: Using the Cairngorm Framework public public public public public public public
var var var var var var var
link:String; sunrise:String; sunset:String; windspeed:String; units:UnitsVO; highTemp:Number; lowTemp:Number;
public function WeatherVO() { units = new UnitsVO(); } } }
Contained inside the WeatherVO is another value object called the UnitsVO, shown in Listing 21-2. This contains all the units for distance, pressure, speed, and temperature. You may find it easier to manage your code by moving some of the properties in one VO into another one, such as in this scenario.
Listing 21-2: UnitsVO.as package com.wiley.proflex2.chapter23.vo { import com.adobe.cairngorm.vo.IValueObject; [Bindable] public class UnitsVO implements IValueObject { public var distance:String; public var pressure:String; public var speed:String; public var temperature:String; } } WeatherVO is simply a set of properties that describes the weather for a specific location. Once the weather data has been downloaded, you set it to an instance of a WeatherVO and store it in the model or state of your application. This means you can access the WeatherVO instance anywhere in your Flex application.
The Model Locator The Model Locator pattern is a singleton and was created purely to be used with Flex application development. In this case, a singleton is a design pattern that allows for only one instance of the Model Locator to be present within your application’s memory. Any data that you think is required to live in the application’s state should be stored inside the Model Locator. The Model Locator creates a central area where all the states can be held in your Flex application. This allows the view components to bind to the model or state of the application and keep everything up to date. Listing 21-3 shows the Model Locator of the Flex Weather application.
535
Part VI: Advanced Flex 2.0 Listing 21-3: ModelLocator.as package com.wiley.proflex2.chapter23.model { import com.adobe.cairngorm.model.ModelLocator; import com.wiley.proflex2.chapter23.vo.WeatherVO; import mx.events.IndexChangedEvent; [Bindable] public class ModelLocator implements com.adobe.cairngorm.model.ModelLocator { private static var modelLocator:com.wiley.proflex2.chapter23.model .ModelLocator; public static function getInstance():com.wiley.proflex2.chapter23.model .ModelLocator { if (modelLocator == null) modelLocator = new com.wiley.proflex2.chapter23.model .ModelLocator(); return modelLocator; } public function ModelLocator() { if ( com.wiley.proflex2.chapter23.model.ModelLocator.modelLocator != null ) throw new Error( “Only one ModelLocator instance should be instantiated” ); } // Store the location id public var location:String; // The current weather for that location id public var weather:WeatherVO; public var showWeatherDetail:Boolean = false; public var backgroundColor:uint = DAYTIME_COLOR; public const DAYTIME_COLOR:uint = 0x93BCF6; public const NIGHTTIME_COLOR:uint = 0xB6B3C1; } }
While reviewing the code for the Model Locator, you will notice two properties: the locationid property and the weather property (which is an instance of the WeatherVO class). These are stored in the state of the client so that the relevant views can bind to those properties.
536
Chapter 21: Using the Cairngorm Framework Later on in this chapter, you will see that the WeatherView component requires the current location’s weather forecast so that it can display the details. The weather property in the Model Locator can be passed in to the WeatherView component, as shown here:
The view is updated accordingly because a reference is passed from the weather instance in the Model Locator to the weather instance in the WeatherView component.
The View The view of your application represents the elements that the user sees and interacts with. You will learn how to create and build the view using the Cairngorm Framework. As mentioned earlier, the Model Locator pattern was designed specifically for Flex development. The main reason for its existence is so that you can use the powerful data-binding capabilities of the Flex Framework to update the view of your application. To use binding, you need a source and a destination. The source is the point where the data comes from and the destination is where the data is sent to. The source property has one or many destinations. Any time the source is updated, one or more destinations that are bound to the source are updated by copying the contents of the source to one or many destinations. This is a very powerful capability that most Flex developers cannot live without. The entry point for the Flex Weather application is the Main.mxml file (shown in Listing 21-4), which contains one other component view, WeatherView.mxml (shown in Listing 21-5). The WeatherView.mxml file contains all the components that make up the view of the application.
Listing 21-4: Main.mxml
Application { backgroundColor: #000000; } Label { fontFamily: Arial; fontSize: 11; }
537
Part VI: Advanced Flex 2.0 Button, ComboBox { highlightAlphas: 0.37, 0.73; fillAlphas: 0.6, 0.53, 0.88, 0.63; borderColor: #EEEEEE; themeColor: #0099cc; cornerRadius: 3; } LinkButton { color: #FFFFFF; borderStyle: solid; borderColor: #FFFFFF; } @font-face { src: url(assets/fonts/arial_fonts.swf); fontFamily: Arial; } @font-face { src: url(assets/fonts/arial_fonts.swf); fontFamily: Arial; fontWeight: bold; }
Listing 21-5: WeatherView.mxml
539
Part VI: Advanced Flex 2.0
In the WeatherView.mxml file, you can view the implementation of the component. As you can see, a lot of Flex visual components are bound to the properties of the weather instance. Any changes to the weather instances held in the Model Locator cause the binding to execute in the instance, updating the weather property of the WeatherView component. Cairngorm ensures that dynamic data displayed in MXML comes from the Model Locator and nowhere else. The Main.mxml file contains the tag, which is the entry point for all Flex applications. The styles for the application are defined inline within the tag. Also contained here are the Service Locator and Front Controller, which are discussed in the next few sections. They are defined here so that the compiler includes them in the application. Otherwise, the Cairngorm Framework would not be able to access them.
540
Chapter 21: Using the Cairngorm Framework
The Front Controller, Cairngorm Event Broadcaster, and Command Patterns In this section, you learn about the design patterns Cairngorm uses to listen to user actions and convert those into something meaningful to the user of the application. You will also come across the most important and innovative patterns in the Cairngorm Framework. The Front Controller, Cairngorm Event Broadcaster, and Command patterns work together to help you develop consistent RIAs using Flex.
The Command Class In the Flex Weather application, you have one feature: retrieving the weather by location. This feature gets executed once the user has filled in the location and clicks the button to retrieve the weather by location. For every feature or use case in your application, a corresponding custom command and event must be created. Each command contains an execute() method that is run by the framework when the user action has been executed. These classes are occasionally referred to as worker classes because they carry out the work for an application. Consider the only feature in the Flex Weather application: being able to retrieve weather for a specific location. To implement this feature, you create a Command class called GetWeatherByLocationCommand. Listing 21-6 shows the GetWeatherByLocationCommand.as file.
Listing 21-6: GetWeatherByLocationCommand.as package com.wiley.proflex2.chapter23.commands { import com.adobe.cairngorm.commands.ICommand; import mx.rpc.IResponder; import com.adobe.cairngorm.control.CairngormEvent; import com.wiley.proflex2.chapter23.business.WeatherDelegate; import com.wiley.proflex2.chapter23.events.GetWeatherByLocationEvent; import mx.utils.ObjectUtil; import mx.controls.Alert; import com.wiley.proflex2.chapter23.model.ModelLocator; import com.wiley.proflex2.chapter23.vo.WeatherVO; public class GetWeatherByLocationCommand implements ICommand, IResponder { public function execute( event : CairngormEvent ) : void { var delegate : WeatherDelegate = new WeatherDelegate( this ); var initialEvent : GetWeatherByLocationEvent = GetWeatherByLocationEvent( event ); delegate.getWeatherByLocation(initialEvent.locationId, initialEvent.unit); }
541
Part VI: Advanced Flex 2.0 //------------------------------------------------------------------------public function result( event : Object ) : void { trace(ObjectUtil.toString(event.result.rss.channel)); var item:Object = event.result.rss.channel; var weather:WeatherVO = new WeatherVO(); weather.location = item.title; weather.sunrise = item.astronomy.sunrise; weather.sunset = item.astronomy.sunset; weather.link = item.link; weather.conditions = item.item.condition.text; weather.date = item.item.condition.date; weather.code = item.item.condition.code; weather.temp = item.item.condition.temp; weather.humidity = item.atmosphere.humidity; weather.visibility = item.atmosphere.visibility; weather.windspeed = item.wind.speed; weather.units.distance = item.units.distance; weather.units.pressure = item.units.pressure; weather.units.speed = item.units.speed; weather.units.temperature = item.units.temperature; weather.highTemp = item.item.forecast[0].high; weather.lowTemp = item.item.forecast[0].low; model.weather = weather; model.showWeatherDetail = true;
} //------------------------------------------------------------------------public function fault( event : Object ) : void { Alert.show(event.fault); } [Bindable] public var model:ModelLocator = ModelLocator.getInstance(); } }
As you can see, the GetWeatherByLocationCommand class implements the ICommand and IResponder interfaces. The ICommand interface means that any class that implements this interface must contain an execute() method to act as an entry point, which allows Cairngorm to execute each and every command. In the execute() method, an instance of the WeatherDelegate class is created and the initialEvent instance is cast from a CairngormEvent to type GetWeatherByLocationEvent. The WeatherDelegate class is a business delegate that creates a mapping between the client and server side. In other words, it is an API that maps to the server-side methods of your application.
542
Chapter 21: Using the Cairngorm Framework The GetWeatherByLocationEvent class extends the CairngormEvent class. The CairngormEvent is a base event class that developers are encouraged to extend to create application-specific events. Each execute() in a command takes a CairngormEvent as a parameter, which you can then cast to your custom-implemented event. Every time you create a command, a corresponding event must be created. The events broadcast using the Cairngorm Event Dispatcher. Listing 21-7 shows the implementation of the GetWeatherByLocationEvent.as.
Listing 21-7: GetWeatherByLocationEvent.as package com.wiley.proflex2.chapter23.events { import com.adobe.cairngorm.control.CairngormEvent; import com.wiley.proflex2.chapter23.control.ApplicationController; public class GetWeatherByLocationEvent extends CairngormEvent { public function GetWeatherByLocationEvent(locationId:String, unit:String) { super( ApplicationController.EVENT_GET_WEATHER ); this.locationId = locationId; this.unit = unit; } public var locationId : String; public var unit : String; } }
The GetWeatherByLocationEvent class contains two properties: locationid and unit. When the event is broadcast, there are two values that must be passed into the constructor of the GetWeatherByLocationEvent. These values are critical in returning the correct weather data to your Flex application. The following example shows this:
Now, let’s go back to the rest of the implementation of the execute() method. The getWeatherByLocation() method of the WeatherDelegate is called and requires two parameters, locationid and unit. These are passed in via the initialEvent instance, which is of type GetWeatherByLocationEvent. The result() and fault() methods are part of the IResponder interface. These methods wait for the asynchronous call to return results from the server. The result() method handles the results if the call was successful, and the fault() method handles the results if they were not successful.
The Front Controller The Front Controller is a central place where all the commands are mapped to the relevant events. Once an event is dispatched, the Front Controller finds the corresponding command to execute. Listing 21-8 shows the Front Controller pattern in the Flex Weather application.
543
Part VI: Advanced Flex 2.0 Listing 21-8: ApplicationController.as package com.wiley.proflex2.chapter23.control { import com.adobe.cairngorm.control.FrontController; import com.wiley.proflex2.chapter23.commands.*; public class ApplicationController extends FrontController { public function ApplicationController() { addCommand( ApplicationController.EVENT_GET_WEATHER_BY_LOCATION, GetWeatherByLocationCommand ); } public static const EVENT_GET_WEATHER_BY_LOCATION : String = “getWeatherByLocation”; } }
First, all the events are named as constants on the ApplicationController instance. This means the compiler can catch any mistyped events at compile time rather than at run-time. In the constructor, the command class is added to the list of commands. In a larger application, there will be many more of these commands. It is important to ensure that they are all added when the Front Controller is first created by adding them in the constructor. The addcommand() method takes the event name as type string and the name of the command of type string: addCommand( ApplicationController.EVENT_GET_WEATHER_BY_LOCATION, GetWeatherByLocationCommand );
You may have noticed that the ApplicationController extends FrontController. This is so that you can create a FrontController specifically for your application’s needs. By extending the FrontController, you have access to the addCommand() method of its superclass. This allows you register events with their corresponding command classes. You create your controller in the base file of your application. In this example, it is the main.mxml file between the tag, as follows:
The JavaScript function createButton is executed when the form button is clicked. This function accepts a form object and builds the ActionScript needed to create a Flex Button. It also sets the Button label, width, and height properties by filling in the form values. Notice that the last line of the newButton string says panel().addChild(btn). The panel() is not actually a Flex function. It is the syntax that is used to access a component within the embedded SWF. The ID of the Panel that the button is being added to is actually named panel, but when accessing it from JavaScript, the parentheses are required. Once the ActionScript String has been created, the JavaScript eval function is run, which creates the button within the embedded SWF. Figure 22-2 shows the page when it loads, and Figure 22-3 shows the page after the createButton method has been run. Figure 22-3 also shows the JavaScript that was created and passed to Flex.
Figure 22-2: Page when it loads
558
Chapter 22: Using the Flex-Ajax Bridge
Figure 22-3: Page after the createButton method has been run
Summar y The Flex-Ajax Bridge will find its way into the development of Web 2.0 applications because it ties the two leading RIA solutions together into a new hybrid application with hundreds of JavaScript and Flex code libraries. This chapter provided an overview of why you would use the Flex-Ajax Bridge, requirements, and installation, as well as demonstrations of how the FA Bridge can be used in different ways. Information on possible memory issues was provided as well. Chapter 23 discusses the ActionScript libraries that are freely available from Adobe Labs. Descriptions are included for all of the available libraries, as well as a fully functioning example showing the YouTube library.
559
Using the ActionScript 3.0 Libraries The ActionScript 3.0 libraries are a free set of libraries that Adobe’s Developer Relations Team has released to the public. These libraries help developers get started when building Flex 2.0 applications. The libraries are split up into seven separate projects with their own distinctive functionalities. The libraries are available on Adobe Labs, which is a Web site that provides you with the opportunity to experience and evaluate new and emerging technologies and products from Adobe. At Adobe Labs, you have access to resources such as the following: ❑
Prerelease software and technologies
❑
Code samples
❑
Early versions of products and documentation
❑
Forums and wiki-based content to help you interact with like-minded developers
Part VI: Advanced Flex 2.0
Types of Libraries The following is list of libraries that have been updated to work with the final release of Flex Builder 2.0 and MXMLC. Note that these libraries are of beta quality and that Adobe does not officially support them. ❑
Corelib — The Corelib library consists of several basic utilities for MD5 hashing, JavaScript Object Notation (JSON) serialization, advanced string and date parsing, and more. Authors of this project are Christian Cantrell, Mike Chambers, Daniel Dura, and Darren Schall.
❑
FlexUnit — The FlexUnit library is a unit testing framework for Flex and ActionScript 3.0 applications. It copies the functionality of JUnit (a Java unit-testing framework), and includes a graphical test runner application built in Flex 2.0. Authors of the project are Matt Chotin, Daniel Dura, Alistair Mc Lead, Tom Ruggles, Steven Webster, and Jason Williams. All projects use the FlexUnit framework to test the libraries and ensure that they are working correctly.
❑
Flickr — The Flickr library is an ActionScript 3.0 API for use with the popular online photo-sharing Web application, Flickr. This library provides access to the entire Flickr API. The author of this project is Darren Schall.
❑
Mappr — The Mappr library is an ActionScript 3.0 API that provides access to Mappr’s geo-tagged image data. Mappr is a service that combines images from Flickr with geographically located information. The author of this project is Mike Chambers.
❑
RSS and Atom — The RSS and Atom libraries are used to parse Atom and all versions of RSS easily. You can parse any type of feed without knowing what kind of feed it is. The author of this project is Christian Cantrell.
❑
Odeo — The Odeo library is an ActionScript 3.0 API for searching and retrieving podcasts from Odeo. Odeo is a service that provides functionality to listen to, upload, and record your own podcasts. The author of this project is Mike Chambers.
❑
YouTube — The YouTube API provides an ActionScript 3.0 API to search for videos from YouTube. The author of this project is Daniel Dura.
How to Include the SWC in Your Application To include the SWC in your application, you must first download a library, such as the Corelib library that is used here for reference. Open the ZIP file and you will find three folders inside the corelib folder: bin, docs, and src. The bin folder contains the binary SWC file for use within your application. Be sure you know from where you extracted the files, and make a note as to where the binary SWC is. Open up Flex Builder 2 and select File ➪ Flex Project to see the screen shown in Figure 23-1. Follow the wizard and create a Flex project with a name and path, as shown in Figure 23-2. Then, click Next.
562
Chapter 23: Using the ActionScript 3.0 Libraries
Figure 23-1: New Flex Project opening screen
Figure 23-2: Assigning a name and path
As shown in Figure 23-3, you can either change the Main application file to whatever you like, or leave it as is. Select the Library Path tab and click the Add SWC button (Figure 23-4). Locate the binary SWC file in the bin directory of the unzipped Corelib library on your hard disk. You should see that it has been added to the build path libraries tree. Click the Finish button and you should be ready to use the Corelib library in your Flex application.
563
Part VI: Advanced Flex 2.0
Figure 23-3: Set build paths
Figure 23-4: Add SWC button
564
Chapter 23: Using the ActionScript 3.0 Libraries
Building a Simple Application Using One of the Libraries In Chapter 21 you learned how to build an application in the Cairngorm Framework. This example uses the Cairngorm Framework and the YouTube ActionScript 3 library. Figure 23-5 shows the completed application running in Flex.
Figure 23-5: Completed application
Listings 23-1 through 23-8 show the files that make up the application structured using the Cairngorm Framework. The only difference is that there is no Server Locator or any Business Delegates.
Listing 23-1: Main.mxml
Application { backgroundColor: #888888; } Label { fontFamily: Arial; fontSize: 11; } Button, ComboBox { highlightAlphas: 0.37, 0.73; fillAlphas: 0.6, 0.53, 0.88, 0.63; borderColor: #EEEEEE; themeColor: #0099cc; cornerRadius: 3; } @font-face { src: url(assets/fonts/arial_fonts.swf); fontFamily: Arial; } @font-face { src: url(assets/fonts/arial_fonts.swf); fontFamily: Arial; fontWeight: bold; }
ActionScript to CFC Wizard The ActionScript to CFC Wizard builds a CFC based on an ActionScript class. The main purpose of this is to create a DTO or VO for use in applications. This CFC would then be used to cast a complex object of a specific data type with its own properties, as well as getters and setters. Right-click an ActionScript from the list of available files in the Project Navigator to use the wizard. Choose ColdFusion Wizards ➪ Create CFC. Enter the location of where the file is to be saved in the first option of the dialog box that appears. You can either type the location or browse to it. Next, enter the name of the CFC that you’re creating. You may need to verify the overwriting of an existing file. If you are using this wizard to generate a DTO, you must choose the Generate Get/Set Methods option. Set the appropriate property scope (private/public). Click Finish and the generated CFC will display shortly.
CFC to ActionScript Wizard The CFC to ActionScript Wizard builds an ActionScript class based on a CFC VO. Select a ColdFusion CFC VO from the Project Navigator by right-clicking and choose ColdFusion Wizards ➪ Create AS Class. Nominate the project folder to save the file into by either typing the path or using the Browse button to locate it. Give the new class an appropriate packed name with the next option, then give the new class a name. Choose to overwrite any existing versions of the CFC. This will be selected for you by default. The last thing is to nominate the path to the CFC. This value will be used as part of the ActionScript class. This will create an alias for the location of the CFC that will be used as a binding in the ActionScript class, like the following example shows: [Bindable] [RemoteClass(alias=”sandboxes.flexApp.Employee”)]
Click Finish and the wizard will build the ActionScript class.
605
Part VI: Advanced Flex 2.0
Services Browser The Services Browser allows the developer to view CFCs and Web services hosted on the ColdFusion server. It displays a full listing of CFCs organized by path, showing the individual CFCs in a chosen location. Expanding a CFC in the view will reveal its methods with the data return type indicated. Methods can be expanded further to show their arguments. Setting a method of a function to remote, public, or private will affect its listing in the Services Browser. WSDL URLs can be added to the Services Browser so that it can be used to manage a list of Web services. The Services Browser can then be used to generate the necessary CFML to invoke a Web service in a ColdFusion page. You can also use it to generate CFML to create a Web service object, instead. The Services Browser can be used to generate the necessary ActionScript to consume a Web service.
Summar y Flex 2 and ColdFusion 7.0.2 are ready partners. Through Flash Remoting, they can seamlessly exchange complex data between each other. ColdFusion can also be used to communicate with Flex applications via Flex Data Services (FDS). Flex can also exchange data with ColdFusion by calling ColdFusion Components (CFCs) via the Flex Messaging Event Gateway. Publish-subscribe messaging applications can be built with a combination of FDS and ColdFusion. The Flex Web application can subscribe to data on the ColdFusion server via FDS and be aware of changes to information via the publish-subscribe managed by the Data Management Service provided by FDS. The ColdFusion Extensions for Flex Builder 2 offer a number of wizards that allow for the creation of ColdFusion Components and ActionScript classes used as part of the process of data connectivity and management. Other tools included in the ColdFusion Extensions give the developer access to information within the database. Chapter 25 discusses how to incorporate video and audio into your Flex application to create a richer experience for your user. The Flash run-time has become the most installed multimedia player with the highest penetration across all major operating systems, and Flex makes it easy to develop multimedia applications for that run-time.
606
Part VII: Integration Techniques Chapter 25: Rich Media Integration Chapter 26: Integration with External Applications
Rich Media Integration Video and audio are fast becoming an important part of business and consumer applications. If you take a look around the Web today, you will notice the influx of Web sites that contain video and audio. You probably find the wrong version of the media player is installed or there are limited options to interact with the video. All of this disrupts the user experience, and this is where Flex and Flash are far more superior. The Adobe Flash Player contains video and audio playback and streaming capabilities. As of this writing, Flash Player 8 is installed on 90 percent of users’ computers. This is the reason companies such as Brightcove, Google, and YouTube have adopted the Flash Player to play back video. With Flex, video is more than just a streaming experience. It can be a more tightly integrated part of the application. During playback of video, events can be triggered and behaviors of other components are driven by the events, all of which creates a much richer experience. The capabilities enable an extensive range of new, innovative, and highly interactive applications. Rich media comes from the term “multimedia,” and is actually audio, video, text, and graphics combined with animation and interactivity. All these kinds of media have been around for years on the desktop, but now the focus is using rich media on the Web. As always with new technology, it does pose a problem with accessibility. If done correctly, however, it can be an even better experience for the user. This chapter introduces you to the integration of rich media into your Flex applications, and shows how easy it is to implement and work with.
Part VII: Integration Techniques
Integration Before looking at an example application, you must understand how rich media is integrated into a Flex application. This section provides you with the basics of how easy it is to do this in Flex. To integrate rich media such as audio and video into your Flex application, you can use the flash.media .Sound class and flash.media.Video class, respectively. Working with those two lower-level classes might be a bit tedious for a beginner, so the Flex Framework provides easier ways to use audio and video in your application.
Audio To integrate sound (such as an .mp3 file), you can embed the sound file as you would an image, as the following example shows: [Embed(source=”sample.mp3”)] [Bindable] public var soundAsset:Class; public var s:Sound = new soundAsset() as Sound;
This example embeds the .mp3 file into your Flex application and casts the soundAsset instance to a Sound class instance. This allows you to access the sound file’s data and manipulate it as necessary. Doing it this way would increase the file size. For sound effects, it would probably be fine to embed the sound files, as long as they are not too big. For bigger sound files, it would not be recommended to do it this way. Instead, you could download the sound files progressively by using the flash.media.Sound class. The SoundEffect class lets you control the volume and panning of an .mp3 file. You can either specify the .mp3 file from a URL, or embed it and set the source property to the embedded class. This class can pan the .mp3 file from a range of –1.0 to 1.0, where –1.0 uses the left channel, and 1.0 uses the right channel. The following example embeds the .mp3 file and sets the panFrom and panTo properties of the SoundEffect instance:
Video To use video inside Flex, you must use a Flash Video (FLV) file, which is a proprietary file format developed by Macromedia (now Adobe) for use in Adobe Flash Player versions 6, 7, 8, and 9. Flash Player 6 and 7 used a variant of H.263 video standard by Sorenson Spark, and versions 8 and 9 use On2 TrueMotion VP6 codec, which is of a much higher quality. Flex provides a VideoDisplay component that lets you play an FLV file in your application. It contains no controls for the play, pause, or stop actions. So it is up to you to create the user interface for your video
610
Chapter 25: Rich Media Integration player. The VideoDisplay component supports progressive download over HTTP, streaming from Flash Media Server, and streaming from a Web cam using the Camera object. It is relatively simple to use VideoDisplay. Just set the source property to a relative or absolute path to the FLV file, as shown here:
As mentioned earlier, all you should see is a video playing and nothing else. The layout and interactivity of the VideoDisplay component is up to the developer. The following example defines a VideoDisplay component and two LinkButton components. The first LinkButton instance is used for two actions: play and pause the video. The second LinkButton instance is used to stop the video. The playPause() method checks to see if the label is set to “Play”. If so, it sets the label property of the LinkButton to “Pause” and plays the video. The same happens if the label property is set to “Pause”.
611
Part VII: Integration Techniques
Using the Camera The Camera class gives access to a Web camera on a client’s workstation. You mainly use the Camera class with Flash Media Server, but you can use it without the server. For example, you could capture a single frame from the camera stream, encode the data, and send it to the server to be stored. The camera can also be used to create cool effects, such as the ones in Apple’s PhotoBooth application. You could apply a blur filter, a sepia effect, or morphing to the streaming video. Some developers have even been able to create effects that interact with the user. The Microphone class again gives you access to a microphone on the client’s workstation. This can be used without the Flash Media Server, but again with limited functionality. The Camera class is used in conjunction with the VideoDisplay control. The following example shows this in action:
The next example uses the VideoDisplay, Image, and Button controls to capture an image from the camera stream and display it in the Image control instance. All the magic lies in this simple, but very powerful, getBitmapData(target:UIComponent) method. The implementation of this method allows you to capture BitmapData of any visual component at run-time.
By clicking the button, you capture the VideoDisplay control with an image from the camera stream. You could extend this application and encode the BitmapData using a compression algorithm such as JPEG or PNG, and send the data to the server to be stored for later retrieval.
Building an Application with Rich Media Integration So far, you have seen how easy it is to integrate rich media into your Flex applications. In this section, you build a simple application that integrates video and audio with some transitions and effects. Figure 25-1 shows the Flex application with video playing on the left-hand side. A reflection effect has been added to make it look more professional. This application did not take long to build, and all the code is housed in the root Main.mxml application file.
613
Part VII: Integration Techniques
Figure 25-1: Rich media application
Listing 25-1 shows the code for the entire application. Take a look through the code before moving on.
Listing 25-1: Main.mxml
Application { backgroundGradientColors: #000000, #000000; paddingBottom: 2; paddingLeft: 2; paddingRight: 2; paddingTop: 2; }
614
Chapter 25: Rich Media Integration List { fontSize: 40; color: #FFFFFF; backgroundAlpha: 0; borderStyle: none; fontFamily: myFontFamily; rollOverColor: #990000; selectionColor: #0099CC; } @font-face { src:local(“Arial Black”); fontFamily: myFontFamily; flashType: true; }
615
Part VII: Integration Techniques
616
Chapter 25: Rich Media Integration
The Inner Workings of the Application Now that you have looked over the code, take a look at the most important parts of the application. Without the VideoDisplay control, this application would be an application lacking rich media and, thus, this is the most important component. However, the application still needs logic to get the right video to display inside the VideDisplay control. To the right of the VideoDisplay control is a List control. This provides the list of trailers by using an inline data provider, for the sake of simplicity. The data provider is a list of objects with a label property and a data property. The label property is displayed in each row of the List control instance, and the data property contains the FLV filename.
617
Part VII: Integration Techniques
The List instance contains an inline item renderer so that the Label instance can be aligned vertically inside the VBox container. If you do not do this, you will find that the label aligns on the top. The List control instance contains a change event implementation that sets the videoDisplay.source property to the FLV file. So any time a row is selected, a new video starts playing in the VideoDisplay instance to the left. The doubleClick event of the List instance sets the videoPath property to the relative path of the relevant FLV file through the List instance selectedItem.data property. This means that any time a row is clicked in the List instance, the correct video is displayed in the VideoDisplay instance. The second piece of code that is executed in the doubleClick event handler sets the state of the Flex application to a new state. Following is the MXML code for the new state:
The new state removes the mainView instance, which is essentially the base state of the application, and adds a VBox container with the VideoDisplay control as its child. The tag ensures that when the application moves into the new state, the VideoDisplay instance source property in the base state is set to null. This ensures that only the right VideoDisplay instance is playing the FLV file. Figure 25-2 shows the new state of the application with the VideoDisplay control using the full width and height of the browser window. When the VideoDisplay control is double-clicked, the application will return to the base state using transitions and effects.
618
Chapter 25: Rich Media Integration
Figure 25-2: New state of the application
The following example shows the two transitions used in the application, one from the base state to the new state, and the other from the new state to the base state. Refer to Chapter 8 for more information on transitions.
619
Part VII: Integration Techniques
Using transitions in the application means that moving from one state to another looks more elegant and professional. The transition from the base state to the new state fades out the mainView instance, then removes it, adds the new state, and fades it in. The other transition does the exact opposite, and returns the user back to the base state. This application took but a few hours to build and shows just how easy it is to get rich media integration into your Flex application.
Summar y Over the next year or two, you will see more and more Web applications integrating rich media such as video and audio. Flex makes it easy to integrate all of this type of rich media into your application. This is the best time to get on the bandwagon and start developing killer Rich Internet Applications that use rich media. Chapter 26 discusses integrating external applications in Flex, such as using JavaScript to communicate between Flex and HTML applications, integrating with Microsoft Excel, and using the flash.net .LocalConnection class to communicate with a Microsoft Windows application.
620
Integration with External Applications ActionScript 3.0 supports the External API that defines a method for Adobe Flash Player SWFs to communicate with their container applications. The most common container applications that the Flash Player resides in are the browser or desktop applications with the Flash Player embedded. Along with learning about the newer External API, this chapter explores using LocalConnection as another method of communicating with outside applications. This chapter requires other non-Flex resources and development tools. For the ExternalInterface example, you will need Flash 8 Professional and the ability to create SWFs in the IDE. The LocalConnection example uses C# .NET technology, and was created using the freely available Microsoft Visual C# 2005 Express Edition of the Visual Studio product line. As of this writing, the link to Microsoft Visual C# 2005 Express Edition is located at http://msdn.microsoft.com/vstudio/express/visualcsharp/.
Using the External API The root of the External API stems around the ExternalInterface class. This class defines a standard method of communicating with container applications using the Flash Player. Just as the Remote Procedure Call service classes (HTTPService, WebService, and RemoteObject) provide methods to communicate with external back-end services, the ExternalInterface implements methods to communicate with Flash Player container applications. The External API is a replacement for the older fscommand() functionality. The ExternalInterface is, therefore, the framework and preferred method for talking with JavaScript. The Flex-Ajax Bridge (covered in Chapter 22) is an extension to ExternalInterface
Part VII: Integration Techniques that helps to solve some of the limitations of the ExternalInterface class. One way to look at it is that the Flex-Ajax Bridge helps you focus on writing JavaScript and not ActionScript, whereas ExternalInterface forces you to build all the communication structure on both sides.
AVM1 and AVM2 SWF Communication A good example to demonstrate how to use the ExternalInterface is to tackle the problem that became apparent with the rollout of a new ActionScript virtual machine (AVM) in Flash Player 9. An SWF created with Flex 2 and ActionScript 3 is AVM2 compatible, and any SWF created for the previous ActionScript virtual machine is called AVM1 compatible. The newer ActionScript virtual machine is quite different, which means AVM1 SWFs loaded into AVM2 cannot talk directly to each other. This is where ExternalInterface comes into to play. Follow these steps to create the AVM1 SWF used in this section:
1. 2. 3. 4. 5.
6. 7. 8.
Open Flash 8 Professional. Create a new Flash document called AVM1.fla. In the timeline, create two layers and call them ActionScript and Controls. Open up the Components window by pressing Ctrl+F7 or clicking Windows ➪ Components. Select the Controls layer and drag the following components onto the Flash Stage, as shown in Figure 26-1: a.
Button
b.
TextInput
c.
TextArea
Click the Button component and give it an instance name of btnSend. Click the TextInput component and give it an instance name of txtMessage. Click the TextArea component and give it an instance name of txtOutput.
Figure 26-1: Button, TextInput, and TextArea on the Flash Stage
622
Chapter 26: Integration with External Applications 9.
Select the ActionScript layer and copy the following ActionScript into the first frame:
import flash.external.ExternalInterface; import mx.utils.Delegate; // Register callback method for retrieving messages ExternalInterface.addCallback( “retrieveMessage”, this, retrieveMessage ); // Button Click Event btnSend.addEventListener(“click”, Delegate.create( this, sendMessage) ); function sendMessage():Void { ExternalInterface.call( “sendMessage”, “AVM1: “ + txtMessage.text ); } function retrieveMessage( msg ):Void { txtOutput.text += msg + “\n”; }
10.
Publish the AVM1.swf and make note of where it is located. You will need to copy the SWF into the Flex Builder project that you create in a moment.
That’s all for the AVM1 SWF part. The ActionScript code is very straightforward. The btnSend’s click event listener calls the sendMessage function. The sendMessage function executes an ExternalInterface call to the JavaScript sendMessage method, passing text from the txtMessage.text property as its parameter. The next steps revolve around Flex 2:
1. 2. 3. 4.
Open Adobe Flex Builder 2. Create a new Flex Basic Project. Open up the index.template.html page located in the html-template folder. Copy the following HTML code in between the and tags of the default template:
...
...
5.
Open up the project’s properties popup and set the Output folder and Output folder URL (located in the Flex Build Path section) to valid Web server values. This is required because of the security constraints of the Flash Player, which are enforced when using the ExternalInterface from local file system resources.
6. 7. 8.
Copy the AVM1.swf into the root folder of the Flex Builder 2 project. Rename the main.mxml to AVM2.mxml and copy the code from Listing 26-1 into the file. Run the file and see the results.
Listing 26-1: AVM2.mxml
9 ? num.toString() : “0” + num.toString(); } } }
The TracePanel.mxml now can include the new LocalConnectionTraceTarget.as class as a potential target for the loggers. The LocalConnectionTraceTarget class uses the LocalConnection to make a method call called “logMessage” on the “_flex2tracepanel” connection. The updates for the new LocalConnectionTraceTarget and checkbox for starting and stopping are found in Listing 26-3.
628
Chapter 26: Integration with External Applications Listing 26-3: TracePanel.mxml
Now the CustomLoggerMain.mxml application will execute both the TracePanelTarget and LocalConnectionTraceTarget, once the TracePanel title window has been called. The C# application will constantly look at the memory space for any LocalConnection messages made by calling logMessage on the connection named _flex2tracepanel. Follow these steps to create the C# application:
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16.
Open Microsoft Visual C# 2005 (Express Edition). Create a project, selecting the Windows Application project template. Name the project Flex2TracePanel and click the OK button. Change the name of Form1.cs to Flex2TracePanel.cs. Right-click the Flex2TracePanel.cs file and select View Code. Copy the code from Listing 26-4 into the file. Open up the Flex2TracePanel.Designer.cs file. Copy the code from Listing 26-5 into the file. Open up the Program.cs file. Copy the code from Listing 26-6 into the file. Select the Project ➪ Flex2TracePanel Properties menu item. With the project Properties page open, select the Build tab. Click the “Allow unsafe code” checkbox. Save the file by pressing Ctrl+S or selecting File ➪ Save Selected Items. You are now ready to build the project and run the application. Press F5 or select Debug ➪ Start Debugging to run the project application.
631
Part VII: Integration Techniques Listing 26-4 is rather long, but it helps demonstrate specific code functionality. Explanations appear after the listing. Listing 26-4 also contains in-code comments that help describe specific lines of code.
Listing 26-4: Flex2TracePanel.cs using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Runtime.Remoting; using System.Threading; // Used for DllImport using System.Runtime.InteropServices; namespace Flex2TracePanel { public partial class frmMain : Form { private string CONNECTION_NAME = “_flex2tracepanel”; private string METHOD_NAME = “logMessage”; private int DEBUG_LEVEL = (int)MessageLevel.Error; public frmMain() { InitializeComponent(); } private void Flex2TracePanel_Load(object sender, EventArgs e) { txtOutput.AutoScrollOffset = new Point(0, txtOutput.Height); } // Mutex for the Control of process private Mutex mut; // Pointer to the Memory of the Process private IntPtr hMapFile = IntPtr.Zero; private string lastArg1; private int lastArg2; private unsafe void pollMutex() { // false = don’t take ownership // “MacromediaMutexOmega” = name of mutex if( mut == null ) mut = new Mutex(false, “MacromediaMutexOmega”); try { // Wait 5 seconds if (mut.WaitOne(5000, false))
632
Chapter 26: Integration with External Applications { // Has control of mutex try { // OpenFileMapping method comes from the imported dll hMapFile = OpenFileMapping((int)MapAccess.FileMapAllAccess, false, “MacromediaFMOmega”); // MapViewOfFile method comes from the imported dll IntPtr baseMapAddress = MapViewOfFile(hMapFile, (int)MapAccess.FileMapAllAccess,0, 0, 0); if (baseMapAddress != null) { output(“Reading MapViewOfFile!”, (int)MessageLevel.Info); byte* buffer = (byte*)baseMapAddress.ToPointer(); //String hexStr = “”; // Make sure memory address is valid // Is byte 16 a AMF String (0x02) identifier if ( buffer != null && (int)buffer[16] == 2) { int currentPoint = 16 + 2; /** Find LocalConnection connection name **/ // 16 will always be a AMF String value 0x02 // next 2 bytes define length so we pick up the tail end one int len = (int)buffer[currentPoint]; // Move pointer to start reading string currentPoint++; // Convert bytes into String string connectionName = “”; for (int i = 0; i < len; i++) { // No char check, Assume values are valid connectionName += (char)ushort.Parse(buffer[currentPoint+i] .ToString(“X2”), System.Globalization.NumberStyles.HexNumber); } // Move pointer to next AMF data type currentPoint += len; if (CONNECTION_NAME == connectionName) { // AMF String (0x02) has two Length bytes that are Big Endian // Therefore you will see alot of + 2 pointers to get the Length // I am only reading the last Length byte and assuming the length will not be longer // Skip Protocol String by getting protocal string length and adding 2 bytes for the length output(“ Protocol len: “ + (int)buffer[currentPoint + 2]); currentPoint += (int)buffer[currentPoint + 2] + 3; // Move to Method Name strings length bytes currentPoint += 2;
633
Part VII: Integration Techniques // Get Method Name int lenMethod = (int)buffer[currentPoint]; // Move pointer to start reading string currentPoint++; string methodName = “”; for (int i = 0; i < lenMethod; i++) { // No char check, Assume values are valid methodName += (char)ushort.Parse(buffer[currentPoint + i].ToString(“X2”), System.Globalization.NumberStyles.HexNumber); } // Move pointer to next AMF data type currentPoint += lenMethod; output(“ConnectionName: “ + connectionName + “ MethodName: “ + methodName + “ len: “ + lenMethod); if (METHOD_NAME == methodName) { // Method arguments are in reverse order // You have to know how many parameters there are // Trace Logging Level int arg2 = 0; // Trace Message string arg1 = “”; // AMF Number (0x00) is Big Endian 64 bit so need to convert // Check to make sure Arg2 is a Number if (0 == (int)buffer[currentPoint]) { // Move to read Number currentPoint++; string strAMFNumber = “”; for (int i = 0; i < 8; i++) { // Reverse Binary String and then do Endian switch string hexValue = buffer[currentPoint + i].ToString(“X2”); string binaryStr = Convert.ToString(Convert.ToInt32 (hexValue, 16), 2).PadLeft(8, ‘0’); char[] chars = binaryStr.ToCharArray(); Array.Reverse(chars); string reversed = new string(chars); strAMFNumber += Convert.ToString(Convert.ToInt32(reversed, 2), 16).PadLeft(2,’0’); ; //output(“1: “ + reversed + “ - “ + binaryStr); } currentPoint += 8; //output(“strAMFNumber: “ + strAMFNumber); UInt64 realNumber = convertAMFNumber (UInt64.Parse(strAMFNumber, System.Globalization.NumberStyles.HexNumber)); arg2 = (int)realNumber;
634
Chapter 26: Integration with External Applications // Check to make sure Arg1 is a String if (2 == (int)buffer[currentPoint]) { currentPoint += 2; // Get String len int lenArg1 = (int)buffer[currentPoint]; // Move pointer to start reading string currentPoint++; for (int i = 0; i < lenArg1; i++) { // No char check, Assume values are valid arg1 += (char)ushort.Parse(buffer[currentPoint + i].ToString(“X2”), System.Globalization.NumberStyles.HexNumber); } } if (arg1 != lastArg1 || arg2 != lastArg2) { // Prep real message string msg = “”; string levelStr = “MSG”; if (arg2 == 2) levelStr = “DEBUG”; if (arg2 == 4) levelStr = “INFO”; if (arg2 == 6) levelStr = “WARN”; if (arg2 == 8) levelStr = “ERROR”; if (arg2 == 1000) levelStr = “FATAL”; msg = “[“ + levelStr + “]: “ + arg1; // Send message output(msg, (int)MessageLevel.ValidMessage); } lastArg1 = arg1; lastArg2 = arg2; } else { output(“Method level argument must be a Number!”, (int)MessageLevel.Error); } } } } } else { output(“MapViewOfFile failed!”); } }
635
Part VII: Integration Techniques finally { // Release ownership of the mutex object. mut.ReleaseMutex(); output(“Release Mutex!”); } } else { // Reached timeout try again output(“Mutex Timed out!”); Thread.Sleep(500); } } catch (AbandonedMutexException ame) { // Mutex was abandoned output(“Mutex was abandoned!”); Thread.Sleep(500); } Thread.Sleep(500); // Infinite Loop, handled by Thread Suspend/Resume pollMutex(); } private void output(string str) { output(str, (int)MessageLevel.Debug); } delegate void OutputCallback(string str, int level); private void output(string str, int level ) { // To Turn on internal code messages change to true if (DEBUG_LEVEL > 56) | ((AMFNumber > 24) & 0x0000000000FF0000) | ((AMFNumber >> 40) & 0x000000000000FF00) | (AMFNumber
Listing A-2: blueCSS.css /* CSS file */ Application { backgroundImage: “”; backgroundColor: #336699; } Panel { cornerRadius: 0; backgroundColor: #DDDDDD; borderStyle: none; } .sLogin { fillColors: #777777,#000000; color: #DDDDDD; }
Listing A-3: redCSS.css /* CSS file */ Application { backgroundImage: “”; backgroundColor: #993333; } Panel { cornerRadius: 6; backgroundAlpha: 0.2; backgroundColor: #DDDDDD; } Label { color: #FFFFFF; fontWeight: bold; fontStyle: italic; }
Create a Flex Builder project and put the Listing A-1, Listing A-2, and Listing A-3 files into the project root folder. Ensure that the CSS files have the Compile CSS to SWF context menu item selected and then run the application. Figure A-1 shows the initial state of the application and the three buttons on the bottom labeled one, two, and three. Button two (center) and button three (far right) are implemented to load the blueCSS.swf and redCSS.swf dynamically when each respective button is clicked. The button two style is shown in Figure A-2, and button three’s style is shown in Figure A-3.
645
Appendix A: Flex 2.0.1
Figure A-1: Default style
Figure A-2: Button two’s style
Figure A-3: Button three’s style
646
Appendix A: Flex 2.0.1 It is important to note that if the code did not unload the previous style each time the button were clicked, it would be possible to have leftover styles hanging around. For example, comment out the unloadCSS ( false ) and lastCSS = name; code lines in the RuntimeCSSMain.mxml, as shown here: ... private function changeCSS( name:String ):void { // If you do not unload the last style // previous style settings will be in effect // unloadCSS( false ); var styleEvent:IEventDispatcher = StyleManager.loadStyleDeclarations( name, true ); //lastCSS = name; } ...
Now, run the application and click button three (far right) first, then button two (center). The redCSS.swf sets the Label’s font color style to white and the font weight to bold. When clicking button two, the blueCSS.swf is loaded, but the Label’s style is not defined explicitly. Therefore, it is not reset, and stays bold and white. With the ability to load style resources at run-time, developers now have more options to approach lazyloading SWF applications. This will be a hot new feature.
ASDoc Tool The Adobe Flex 2 Language Reference documentation found on the Adobe Web site was created with a tool called ASDoc. Flex 2.0.1 provides developers the ASDoc command-line tool to create documentation for their own components and classes. The command-line executable is called asdoc and is located in the bin directory, along with the mxmlc and compc compilers. The tool generates HTML files that describe package, property, method, and other class information through syntax written as comments in the code. The syntax uses a number of specific ASDoc tags to tell asdoc how to generate the documentation.
ASDoc Tags and Syntax The following table lists the tags used in this appendix’s example code. The example logging code created in Chapter 19 will be modified to demonstrate ASDoc’s capabilities. ASDoc Tag Syntax
Description
/**
Comment the block starting with /** and ending with */. This syntax tells ASDoc to read text and tags inside the command block.
*/ /**
Text wrapped in a comment block not preceded by a tag will be read as the main description.
Continued
647
Appendix A: Flex 2.0.1 ASDoc Tag Syntax
Description