toc

Team LiB
Next Section

Building Applications with IBM WebSphere Studio and JavaBeans: A Guided Tour
Building Applications with IBM WebSphere Studio and JavaBeans: A Guided Tour
by Colette Burrus and Stephanie Parkin ISBN:1931182140
MC Press © 2003 (444 pages)

This book is the definitive guided tour through learning how to develop applications using IBM WebSphere Studio and JavaBeans, with a clear and understandable explanation of XML and database programming.

CD Content CD Content
Table of Contents
 | Building Applications with WebSphere Studio and JavaBeans—A Guided Tour
 | Introduction
 | About This Book
 | Chapter 1 | - | Creating Your First Applet
 | Chapter 2 | - | Extending Your First Applet
 | Chapter 3 | - | Creating Your First Application
 | Chapter 4 | - | Creating a File-Manipulation Subcomponent
 | Chapter 5 | - | Using Layout Managers
 | Chapter 6 | - | Using Swing Components
 | Chapter 7 | - | When Something Goes Wrong—Debugging
 | Chapter 8 | - | Advanced Applet Development
 | Chapter 9 | - | Working With Databases
 | Chapter 10 | - | Working With XML Data
 | Chapter 11 | - | Using XML Schemas
 | Appendix A | - | Installing the Software
 | Appendix B | - | Java Basics
 | Index
 | List of Figures
 | List of Tables
 | List of Sidebars
 | CD Content CD Content

Team LiB
Next Section


backcover

Team LiB

Back Cover

Don’t be overwhelmed with programming gobbledygook. This book is the definitive guided tour through learning how to develop applications using IBM WebSphere Studio and JavaBeans, with a clear and understandable explanation of XML and database programming. In the simplest way possible, you’ll learn reusable concepts, not just product.

Along the way, you’ll learn the basics of how to develop Java applets and applications, as well as more advanced topics, such as using relational databases and eXtensible Markup Language (XML) documents to store your application data. By the end of the tour, you’ll be able to use IBM WebSphere Studio to build your own applications, and you’ll understand why JavaBeans are so useful for application programming.

This book assumes you have some basic knowledge of the Java programming language, but you certainly don’t need to be an expert to follow the tour. You do need to be running one of the Windows operating systems, and as long as you’re comfortable with Windows, the Internet, and Web browsers, you’re ready to learn Java. Experts will benefit from the tour, because it will teach you many of the IBM WebSphere Studio features that will let you build your Java applications easier and faster.

This book uses the “show and tell” approach. If you flip through the pages, you’ll notice that they are loaded with pictures showing you how your applications should look at each step along the way.

When you complete this book, you will know how to:

  • Use IBM WebSphere Studio and JavaBeans to easily create applications
  • Code in eXtensible Markup Language (XML)
  • Use databases with your applications
  • Build applications more efficiently and productively
  • Create applets
  • Use Swing components and layout managers

About the Authors

Colette Vurrus recently retired from IBM, after spending more than 20 years in a variety of programming and project management jobs. Her most recent assignment was project manager for the IBM alphaBeans project, working with the “Beans Around the World” team. She also coauthored a previous book, VisualAge for Java for Non-Programmers, and a corresponding Web-based tutorial series.

Stephanie Parkin is an information architect for the IBM WebSphere Developer Domain Web site. In her career at IBM she has been managing editor of the WebSphere and VisualAge Developer Domains, and has created and edited documents for various programming languages, including VisualAge for Basic. She also was the Editor-in-Chief of the WebSphere Developer Technical Journal. Stephanie also coauthored the previous book and tutorial series, and has published an article on Designing Beans in Java Developer’s Journal.

Team LiB


Building Applications with WebSphere Studio and JavaBeans - A Guided Tour

Team LiB

Building Applications with WebSphere Studio and JavaBeans—A Guided Tour

Stephanie Parkin
Colette Burrus

IBM Press™

Published by IBM Press™
IBM Associate Publisher: Tara B. Woodman, IBM Corporation
IBM Press Alliance Publisher: David M. Uptmor, MC Press

For information on translations and book distribution outside the United States or to arrange bulk-purchase discounts for sales promotions or premiums please contact:

MC Press
Corporate Offices:
125 N. Woodland Trail
Lewisville, TX 75077

Sales and Customer Service:
P.O. Box 4300
Big Sandy, TX 75755-4300

First edition
First printing: May 2003

1-931182-14-0

All rights reserved. No part of this publication may be reproduced in any form without prior permission in writing of the copyright owner.

Copyright © 2003 International Business Machines Corporation.

Portions © 2003 by MC Press

Every attempt has been made to provide correct information in this book. However, the publisher, the editors, and the authors do not guarantee the accuracy of the book and do not assume responsibility for information included in or omitted from it.

The following are trademarks of International Business Machines Corporation in the United States, other countries, or both: IBM, the IBM logo, IBM Press, the IBM Press logo. The e-business logo nad WebSphere logo are trademarks of IBM and used under license.

List of Trademarks:
Adobe, DB2, DB2 Universal Database, IBM, Java, JDBC, Microsoft, Netscape, Sun, VisualAge, WebSphere, Windows, Windows NT

Dedication

For Steve, forever.—Colette Burrus

For Sean, Calvin, and Sam.—Steph Parkin

Acknowledgments

As with our previous book, we first need to thank our colleagues at Software House Technology (now Exigen Latvia), in Riga, Latvia. Tatjana Lukovnikova, Pavels Nikolajevs, Juris Krikis, and Tatjana Apine wrote the initial VisualAge for Java tutorials upon which this book is based. Also, a huge thanks to Dave Pullin for the initial idea and the determination to get this knowledge in the hands of users. And thanks to the scores of developers who worked on the "JavaBeans Around the World" Project. Their beans provided the core technology that let us build the applications in this book.

Second, we'd like to thank our technical reviewers at IBM: Joe Winchester reviewed the entire book and gave excellent feedback, and Jim Mann also provided valuable comments. Thanks to Ernest Mah and Dr. Gili Mendel for answering product questions and to Lynn Jonas, Mark Edwards, John Botsford, Nak Paik, and Jeff Turnham for getting us early access to product drivers. Thanks to Merrikay Lee for her editing expertise. Finally, a warm thanks to Tara Woodman for a very smooth book-publishing process and equipment to help develop the book.


Introduction

This book takes you on a guided tour to building applications with the WebSphere Studio Visual Editor for Java and JavaBeans. Along the way, you'll learn the basics of how to develop Java applets and applications, as well as more advanced topics such as using relational databases and eXtensible Markup Language (XML) documents to store your application data. By the end of the tour you'll be able to use WebSphere Studio to build your own applications and you'll understand why JavaBeans are so useful for application programming.

If you're new to Java and Java development environments, that's OK. This book assumes you have some basic knowledge of the Java programming language, but you certainly don't need to be an expert to follow the tour. You do need to be running one of the Windows operating systems, and as long as you're comfortable with Windows, the Internet, and Web browsers, you're ready to learn Java.

If you are already familiar with Java and Java development environments, that's OK, too. You'll still benefit from going through the tour, because it will teach you many of the WebSphere Studio features that will let you build your Java applications easier and faster.

This book uses the "show and tell" approach. If you flip through the pages, you'll notice that they are loaded with pictures showing how your applications should look at each step along the way. In addition, we've included two CDs that contain all the tools you'll need to follow along with the lessons.

Why Java?

Java is considered the language of the Internet. It combines two important advances in computer science: object orientation and platform independence. Object orientation means that the programming language models real-world components and behavior. You organize your programs into objects with certain properties and define the activities that the objects can perform. Complex behavior is hidden in the implementation of the object, letting you just connect the object to other objects. Secondly, Java is platform-independent, which means that you can create programs on a Windows machine and be confident that the program will work in any environment that Java runs in.

In the past few years the use of Java has exploded. It has expanded well beyond its original main purpose of providing dynamic Web pages, to a full server-side programming language. It enables the development of complex Internet functionality, such as querying legacy databases, enabling business-to-business Web commerce, and providing interactive Web communications. Because it's based on open standards, all Java programs use a common API. This means that you can reuse other Java components and easily snap them into your programs.


Visual Editor for Java

WebSphere Studio Site Developer 5.0 is the development tool that you'll use during the guided tour. As you'll see, WebSphere Studio is a full-function integrated development environment that contains everything you need to create, test, and maintain your Java applications. The Visual Editor for Java, new with WebSphere Studio 5.0, makes development of Java applications even easier and faster—you just drag and drop the elements you want to use for your application and customize them to set the properties you want, and it generates the underlying code for you.


JavaBeans

JavaBeans are the Java components that you'll use to build applications during the guided tour. You'll use the standard user interface elements (visual beans such as buttons and text fields) that come with the Visual Editor, as well as non-visual beans to perform complex functions such as sorting data, working with databases, and working with XML documents. As you'll see, JavaBeans simplify the work of application programming because they provide prebuilt components with simple interfaces that you'll use to customize their functions and wire them into your applications.


Ready to learn how?

This book shows you how easy it is to create applications with the Visual Editor and JavaBeans. It provides all the tools and components you'll need, and explains how to use them together to create simple yet useful programs.

And, as an additional benefit for readers of this book, we've established an email contact where you can send your comments and questions about beans and programming with them. We will monitor this ID and answer any questions you send in. E-mail your questions and comments to beans@pobox.com.


About This Book

This "guided tour" is organized as a series of hands-on tutorials. These tutorials originally appeared online at the WebSphere Developer Domain Web site, at http://www.ibm.com/websphere/developer.

Each chapter of this book contains a tutorial that teaches a particular Java concept. In each chapter you'll create a new running program, test it, and optionally, export it to run independently from WebSphere Studio.

Chapter 1. Creating your first applet: Introduces you to the Visual Editor for Java and JavaBeans and teaches you how to build your first applet, a simple To Do list.

Chapter 2. Extending your first applet: Teaches how to expand your applet with more functionality and teaches how to publish your applet to run it in a Web browser.

Chapter 3. Creating your first application: Shows how to build the ToDoList program as a Java application with the capability to save the list in a file so that you don't lose your data each time you close the program.

Chapter 4. Creating a file-manipulation subcomponent: Teaches how to create a subcomponent (a.k.a. bean) that extends your ToDoList application by adding a reusable FileManipulationPanel component. You will add standard file dialog windows for loading and saving files and hide all the complex wiring inside your own visual bean.

Chapter 5. Using layout managers: Gives an overview of the layout managers that the Java platform provides, rules for using them, and some examples of usage. Layout managers let you align, space, and size the objects that make up your user interface.

Chapter 6. Using Swing components: Teaches how to use components of the Swing class library, which provides a customizable look and feel for your applications. These components also provide built-in functions such as icons, roll-over buttons, and help text.

Chapter 7. When something goes wrong: Debugging: Teaches how to debug problems in your applications using the WebSphere Studio debugger. We'll create a "buggy" application and then walk you through the steps of finding and correcting the problems.

Chapter 8. Advanced applet development: Discusses advanced topics, such as security issues, customizing your applets "on the fly", and using <param> tags, as well as controlling the browser that hosts your applet. Also discusses how to implement "drag and drop" functionality, as well as some security issues for browsers and when to save your applets as separate class files, versus saving them as JAR packages.

Chapter 9. Working with databases: Teaches the basics of storing your data in a relational database, including manipulating that data from your visual programs. You'll create a Friends database that lets you store information on your friends, including digital photos.

Chapter 10. Working with XML data: Looks at several features in WebSphere Studio that you can use to build Java applications that work with XML data. You'll use the XML perspective to create XML and DTD files and to generate JavaBeans that you'll use to build an XML application in the Visual Editor.

Chapter 11. Using XML Schemas: Shows how you can use XML Schemas to define vocabularies rather than DTDs. You'll use these schemas to generate JavaBeans that you'll use to build an XML application in the Visual Editor.

Appendix A. Installing the software: Provides the hardware and software requirements and installation instructions for installing the software packages included with this book.

Appendix B. Java basics: Provides a quick primer for the Java programming language. If you're new to Java, read this appendix before diving into the rest of the book.

Conventions

In each chapter of this book you'll create at least one complete applet or application. Each chapter provides certain key elements:

Time Required: This item tells you approximately how long each lesson should take to complete. Lessons generally take one to four hours.

Files Required: This list tells you which files you need from the CD to complete the lesson. We've provided components you'll need in each chapter, plus solution files that show the end result of each exercise. If you ever get lost, you can check the solution file to get you back on track. All of the required files are in the solutions subdirectory of the second CD.

Screen captures: Throughout the chapter, screen captures show you how to complete each step of the lesson.

Text conventions: Interface elements that you select, as well as text strings that you need to enter, appear in boldface. Icons are shown in the margins of the text. Code samples appear in monospace font.

Terminology definitions: Terms are defined at their first usage in the chapters. If you want to look up a particular term, check the index.

Sidebar text: Explanations of certain key concepts or terms that relate to the lesson on that page appear in sidebars when we don't want to interrupt the flow of detailed instructions.


About the CDs

The two CDs contain the IBM tools used in this book. WebSphere® Application Server—Express V5.0 Trial for Windows contains WebSphere Studio Site Developer, IBM's Web development environment. This trial version is "time-bombed", which means you can use it for up to 90 days. The trial version comes with 30 days of limited, online technical support at no charge. To activate your 30 days of support, visit this site and click Download Now to register for the product: http://www.ibm.com/websphere/developer/downloads/EXPRESSsupport.html.

IBM WebSphere Application Server—Express offers a quick and affordable onramp to e-business that is a ready-to-go, out-of-the-box solution. Based on the latest Java and Web services standards, WebSphere Application Server—Express lets you build dynamic Web sites; it allows you to view information and perform simple updates in back-end databases while providing the ability to integrate Web services and existing resources with packaged applications.

IBM WebSphere Studio Site Developer brings together everyone on your Web site team, including content authors, graphic artists, programmers, and Webmasters, into a common interface. This integrated tool makes it easy to collaboratively create, assemble, publish, deploy, and maintain dynamic, interactive Web applications designed to meet the requirements of today's open technology standards. It is the latest application development tool built on IBM's WebSphere Studio Workbench. WebSphere Studio Site Developer seamlessly interacts with most third party tools and the WebSphere Application Server to publish Web applications directly to a Server with new support for Web Application and J2EE packaging.

IBM DB2 UDB Personal Edition V8.1: This relational database engine also leads the industry, delivering Web-ready and multimedia data management. WebSphere Studio provides complete integration with DB2, via its DB beans for database access.

Solution Files: In the /solutions directory on CD2, you'll find subdirectories for each chapter. These subdirectories contain the following types of files:

  • JAR files: These files contain the reusable components you'll use to build your applications

  • XML files: These files contain templates that you'll import into WebSphere Studio to simplify the steps to build applications

  • Image files: These files contain graphics you'll use to build your applications

  • JAVA, DTD, XML Schema, and XML files: You can import these files into WebSphere Studio to look at our final version of each application you'll build. Use these when you get lost at any point in the exercises.


To learn more about IBM products

The following Web sites provide information on obtaining and using WebSphere and DB2 products:

  • http://www.ibm.com/university: If you're a faculty member of an accredited higher education institution, you can join the IBM Scholars Program. The IBM Scholars Program provides you with access to IBM software and hardware, tutorials and other training, course materials, certification, technical support, and more.

  • http://www.ibm.com/partnerworld: If you are an IBM Business Partner, you can download software or request software on CD for long term use.

  • http://www.ibm.com/developerworks: If you're interested in several IBM products, consider subscribing to the developerWorks Toolbox to receive expanded licensing, custom CDs, and technical support.

  • http://www.ibm.com/websphere/developer and http://www.ibm.com/software/data/developer: WebSphere Developer Domain and DB2 Developer Domain provide access to the latest product downloads, tutorials, technical articles, and product support. They also tell you how to purchase WebSphere and DB2 products.


Chapter 1: Creating Your First Applet

Download CD Content

Overview

We begin the tour with a simple example of how to build a Java™ applet. Applets are downloadable programs that run in a Web browser and that have restricted access to the client system for security reasons. The applet you'll build in this chapter is the ToDoList tracking applet shown in Figure 1.1.

Click To expand
Figure 1.1: The applet you'll create

Java and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc., in the United States and other countries.

The ToDoList applet includes visual controls to let you add entries to the list, clear all entries, and remove a selected entry. In the process of building this applet, you'll learn how to use the Visual Editor for Java and JavaBeans™ to add complex functions to your applet with just a few simple steps.


Before you begin

To follow along with the steps in this chapter, yu need the following:

  • IBM WebSphere Studio Site Developer 5.0: Install this program from the CD included with this book. See Appendix A for installation instructions.

  • Beans and solution files from the /solutions/chap01/ subdirectory on the CD included with this book. The [image] chap01.jar file in this subdirectory contains all the beans you'll need to build the ToDoList applet described in Chapters 1 and 2. Copy [image] chap01.jar to a folder on your machine, such as C:/beans, so that you can reference it easily from your Java projects in WebSphere Studio.

Start Sidebar
What's a JAR file?

JAR (Java archive) files are a convenient way to group other files together. They are typically stored in a compressed format for efficient storage and transfer across the Internet. In this book, JAR files contain all the files required for a particular set of JavaBeans (code, text, and image files).

End Sidebar


Setting up your project

Before you can build your first applet, you need to do some setup work in WebSphere Studio to specify where your applet will be saved, and to specify the JAR file for beans you'll use to build your applet.

WebSphere Studio is organized into a variety of perspectives, which are just different ways of looking at a development project based on your role on the development team. In this book, you'll mainly use the Java perspective, and within the Java perspective, your applications will be organized into projects and packages. You can switch perspectives whenever you need to. Within a particular perspective, you'll also see a variety of different editors and views that are applicable to the work done within that perspective. For example, within the Java perspective, you'll use the Visual Editor for Java, the Package Explorer, the Properties view, and the Java Beans view, but don't worry—we'll explain how each of these works as we go along.

Starting WebSphere Studio

  1. To start WebSphere Studio, click Start → Programs → IBM WebSphere Application Server - Express v5.0 → Studio Site Developer. When you start WebSphere Studio the first time, a window appears asking which directory you want to use for your workspace (the place where WebSphere Studio saves your work), as shown in Figure 1.2.

    Click To expand
    Figure 1.2: Workspace directory selection window

  2. Leave the directory name with the WebSphere Studio default, check the check box to not show the dialog box again, and click OK. After a few seconds, the WebSphere Studio Workbench appears, as shown in Figure 1.3.

    Click To expand
    Figure 1.3: The initial perspective in the WebSphere Studio Workbench

    Tip

    If you don't see the workspace directory selection window on startup and you want to change the default directory, start WebSphere Studio from a command prompt, by changing to the directory where you installed WebSphere Studio (such as C:/Program Files/IBM/WebSphere/Express/SiteDeveloper), and entering the following command: wasexpress -setworkspace

    The Workbench initially opens in the Web perspective, which is the perspective for working with Web projects (applications that run on Web servers). To close the Web perspective, right-click on the Web Perspective icon in the vertical toolbar along the left edge of the window and choose Close in the pop-up menu.

  3. To open another perspective, click on the Open a Perspective icon and choose Other… in the pop-up menu. The Select Perspective window appears with all the possible perspective types. Select Java and click OK. This brings up the default views and editors for the Java perspective, as shown in Figure 1.4.

    Click To expand
    Figure 1.4: The Java perspective in the WebSphere Studio Workbench

    Notice that a Java Perspective icon now appears in the vertical toolbar. You can have multiple perspectives open at any given time; the way to switch from one to another is just to select the icon for the perspective you want in the vertical toolbar.

Also notice that different options now appear in the horizontal toolbar along the top of the window. This toolbar contains icons for all the common actions you need when working within the Java perspective. It's a subset of the actions available from the pull-down menus, and you can customize it to add, reorder, or remove toolbar actions to suit your preferences.

Creating the project

The first thing you'll do in the Java perspective is to create a new Java project that will contain your ToDoList applet.

  1. To create the project, click on the Create a Java Project icon in the toolbar.

  2. Enter ToDoList as the project name, as shown in Figure 1.5.

    Click To expand
    Figure 1.5: Entering the Java project name

  3. Click Next.

  4. To complete this lesson, you'll need some programs included on our CD-ROM. To use these programs in your new project, you add them to the Java build settings for the project. Select the Libraries tab and click the Add External JARs… button. Browse to the location on your machine where you copied the [image] chap01.jar file (for example, C:/beans), select the file, and click Open, so that the Libraries tab looks like Figure 1.6.

    Click To expand
    Figure 1.6: Specifying bean JAR files for the Java project

    The Libraries tab now shows the standard Java classes (the default Java Runtime Environment (JRE) that's automatically supplied by WebSphere Studio) and the bean JAR file for this chapter.

    Start Sidebar
    Java Build Paths

    You can think of the Libraries in the Java build path as the entries in a traditional CLASSPATH setting. When a program is compiled or executed within a WebSphere Studio project, any classes it requires must be available within the project's build path. This situation is different from VisualAge for Java, where all classes were available at all times for compilation, and where each individual program specified its own classpath. In WebSphere Studio a project's build path defines the available classes for all programs within the project.

    End Sidebar

  5. Click Finish.

Your ToDoList project now appears as an entry in the Package Explorer. Click on the + sign to expand the project contents, and you'll see the list of Java classes that can be used by Java programs within this project: all the standard Java classes and the special bean JAR file for this chapter, which you just added to your project's build path.

Creating the package

Every Java program exists within a Java package. This can be the default package (what you get when you don't explicitly specify a package name for your program) or a specific package name, such as com.ibm.uicontrols. You use packages to organize Java programs into logical groupings. They define the scope for a particular program and provide unique names for programs. You'll use simple, descriptive package names for the programs in this book. Package names should be unique to avoid collision with other classes, so the convention is to take a company's Internet domain name, reverse it, and then add a suffix that is unique within the organization. For example, IBM's Internet domain is ibm.com, so the package name com.ibm.uicontrols can be used.

  1. To create the package, right-click on the ToDoList project in the Package Explorer and choose New → Package from the pop-up menu.

  2. In the New Java Package window that appears, enter toDoListPackage as the package name, as shown in Figure 1.7.

    Click To expand
    Figure 1.7: Creating a new Java package

  3. Click Finish.

The Package Explorer now appears with toDoListPackage as an entry under the ToDoList project. This is where you'll place the Java program for your applet.

Creating the applet

After you have created the project and package, the next step is to create the Java class for your applet.

Start Sidebar
What's a class?

A class is a set or group made up of members that share the same behavior and the same kinds of state information. Each Java program is a class, and each class has a superclass that defines where the class fits into the object hierarchy. Just as you may have inherited certain traits from your parents, a Java class can inherit state and behavior from its superclass. For more information on classes and objects, see Appendix B.

End Sidebar

  1. To create the class for your applet, right-click on toDoListPackage in the Package Explorer, and choose New → Visual Class from the pop-up menu.

    Tip

    If you don't see Visual Class listed in the menu, select New → Other…, then select Java, and then Visual Class.

  2. Enter ToDoList as the class name.

  3. Leave the default for Modifiers set to public (this makes your class accessible by other programs, such as a Web browser).

  4. Select Applet as the visual class to extend, and uncheck the Swing check box. By choosing these two options, you're telling WebSphere Studio that you want your new visual class to have java.applet.Applet as its superclass, which is the standard superclass for Java applets.

  5. Uncheck any check boxes to create method stubs (we'll explain these in later chapters), so that the Create a new Java Class using the Visual Editor window looks like Figure 1.8.

    Click To expand
    Figure 1.8: Creating an applet

  6. Click Finish.

Your new ToDoList class opens in the center of the Workbench using the Visual Editor for Java. Notice that views have also been added to the Workbench for Java Beans and Properties. You use these views to work with beans that you add to your visual classes. The Java Beans view shows a hierarchy of all beans in your visual composition, and the Properties view shows the property values for the currently selected bean. When you first open your applet, the only bean is the applet itself (called "this"). The Properties view is empty at this point, because no bean has been selected yet.


Your first applet

This section shows you how to start building your applet by adding beans to the design surface of the Visual Editor, customizing their properties in the Properties view, and writing the necessary code to connect the beans together.

Figure 1.9 shows your new applet in the Visual Editor.

Click To expand
Figure 1.9: ToDoList applet in the Visual Editor

The Visual Editor for Java

The Visual Editor works just like other visual design tools. The editor is composed of three parts: a palette of beans along the left edge of the window, a design surface where you visually work with beans, and, just below that, a source pane with the source code for your program. You can resize any of the panes by using the mouse or by clicking on the small arrows in the margins that separate the panes.

To create a program visually in the Visual Editor, you select the bean you want from the palette and drop it on the design surface. When you drop a bean on the design surface, its properties appear in the Properties view (along the right edge of the Workbench window), where you can customize the bean's properties to set the values you want to use. As you work with beans by resizing them on the design surface or modifying their properties in the Properties view, the Visual Editor automatically generates the underlying code and presents it in the source pane. You can also modify code directly in the source pane, and changes that you make there are automatically reflected in the design surface and Properties view.

The design surface can contain both visual and non-visual beans. For the ToDoList applet, you will add visual beans, such as buttons and text fields, to the visual surface of the applet. When you extend the applet in Chapter 2 to add logic to sort the list, you'll add a non-visual bean to the free-form portion of the design surface. Nonvisual beans are components that provide processing functions for your program but don't have any visual elements associated with them. A class is considered visual or non-visual based on whether the class inherits from java.awt.Component. All visual classes, such as buttons or text fields, inherit from java.awt.Component, and all other classes are non-visual. Visual classes are shown on the design surface as they appear at run time, while non-visual classes are shown with an icon and name.

Start Sidebar
VisualAge for Java users

If you ever used the Visual Composition Editor in VisualAge for Java, you'll notice many similarities between that editor and the Visual Editor for Java in WebSphere Studio. In both cases you select the beans you want from the palette, drop them on the design surface, and customize their properties. The main difference comes in how you connect beans together. With the Visual Composition Editor you wired beans together visually. With the Visual Editor for Java you'll have to write code to connect beans, but don't worry—you'll find it's not really that painful. If you're new to Java programming or just need a refresher on basics of the Java programming language, see Appendix B.

End Sidebar

Before you begin adding elements to the design surface, notice that the source pane already contains a stub for your program, as shown in Figure 1.10.

Start Figure
package toDoListPackage;
import java.applet.Applet;
public class ToDoList extends Applet {
}
End Figure

Figure 1.10: Initial source code for ToDoList applet

WebSphere Studio generated this stub using the information you supplied when you created the new visual class. Your package name is specified in the package statement, and your class name and its superclass are specified in the class statement. Now you can add beans to the design surface, customize their properties, and see how the source changes.

Laying out the interface and customizing properties

  1. Select the small rectangle in the Visual Editor's design surface. This is the visual surface for your applet, where you'll place elements such as buttons and text fields, so grab one corner of the rectangle and drag it to increase its size. When you select the rectangle, the applet's properties are presented in the Properties view. When you drag it to increase its size, the size property is updated to reflect the new size. Also notice that a default constructor and an init() method are added to your source code, along with code to initialize the applet's size. The init() method is a special method that gets called when an applet is first started, so this is where the Visual Editor places your initialization logic, such as the statement it just created to set your applet's initial size.

  2. In the Properties view, select the current value for the layout property and click the down arrow next to it to show the list of possible layout values. Select the null value, as shown in Figure 1.11 (we'll cover layouts in more detail in Chapter 5; null layout means that your visual elements will appear exactly where you place them on the applet's surface).

    Click To expand
    Figure 1.11: Modifying applet properties in the Properties view

    When you update the layout property in the Properties view, the corresponding code is automatically added to the init() method. Also, notice that ">" symbols have been placed next to any modified properties in the Properties view.

  3. Now you're ready to start adding beans to the applet's surface. The bean palette displays vertically on the left side of the Visual Editor window, separated into categories for all the standard Java visual elements. Standard Java currently provides two major sets of visual elements: Swing and the Abstract Window Toolkit (AWT). We'll go over the differences in detail later in this book. You'll see these basic categories in the bean palette: Swing Containers, Swing Components, Swing Menus, and AWT Controls, as shown in Figure 1.12.

    Click To expand
    Figure 1.12: The bean palette in the Visual Editor

    You'll use AWT Controls for the ToDoList applet, so scroll through that section of the bean palette until you see the Button control. To create a button, click the Button icon in the palette. Move the cursor to the visual surface, where the cursor changes to an arrow with a plus sign. Click the mouse again to place the button on the applet surface, as shown in Figure 1.13.

    Click To expand
    Figure 1.13: Placing a button on your applet

    When you drop the button on the visual surface, the button's properties display in the Properties view, and source code is automatically added to your applet for a new Button variable, as shown in Figure 1.14.

    Start Figure

    // a declaration is added for the button
   private java.awt.Button button = null;

// the instruction in bold is added to the init() method
   public void init() {
       this.setLayout(null);
       this.add(getButton(), null);
       this.setSize(311, 189);
   }
// a method is added to initialize and get the button
   private java.awt.Button getButton() {
         if(button == null) {
               button = new java.awt.Button();
               button.setBounds(32, 21, 14, 23);
         }
         return button;
   }
    End Figure

    Figure 1.14: Source code added for the button

  4. Now you can customize the button's properties. On the design surface, use the mouse to resize the button to make it larger, and in the Properties view, change the button's label property to Add. Notice that as you make changes in one pane, the corresponding updates are reflected in the other panes.

    Tip

    There are actually two ways in which you can drop a component onto the design surface. The first way is to press and release mouse button 1 as you just did, in which case the component is dropped with its top left corner at the mouse position. For null layout, the size is explicitly set to the preferred size of the component (what the component thinks is its best size—not something that you set). The other way is to press mouse button 1 and then drag out a rectangle for the initial size. When you release mouse button 1, the component is created with its size set to the drag rectangle. Setting the initial size on drop avoids having to drop and then select and resize the component, since these actions are done in a single gesture. Setting the initial size on drop is applicable only for the null layout manager. For other layout managers, the layout manager sets the component's size based on its preferred size and other parameters.

  5. Next, place a text field on the visual surface to the right of the button, by selecting the TextField icon from the palette of AWT Controls. Resize the text field so that your applet's surface looks like Figure 1.15.

    Click To expand
    Figure 1.15: Placing a text field on your applet

    Scroll through the source pane to see the code that was added for the new textField variable (a declaration for the variable, initialization in the init() method, and a new getTextField() method for initializing and accessing the text field).

  6. Finally, your applet needs to show the list of items to do. For this purpose, add a BoundList bean from the JAR file for this chapter to the applet surface. This bean isn't in the Visual Editor's standard bean palette, so the way you select it is by using the Choose Bean option. Click on Choose Bean at the top of the bean palette, and a window appears with a list of all possible classes that are available in your project's build settings. Enter BoundList in the class name field, as shown in Figure 1.16, and click OK.

    Click To expand
    Figure 1.16: The Choose a Bean window

  7. Move the cursor over the design surface in the Visual Editor and drop the BoundList bean on the applet's surface, as shown in Figure 1.17. Resize the BoundList bean so that it matches the width of the text field, and scroll through the source pane to see the code that was added for the new boundList variable (a declaration for the variable, initialization in the init() method, and a new getBoundList() method for initializing and accessing the list).

    Click To expand
    Figure 1.17: Adding a BoundList bean to your applet

Tip

For an easy way to align, resize, or reposition a group of visual elements, hold down the Shift key and use the mouse to select the elements you want to work with. The last one you select is the anchor control—that is, the one that the others will be made to match. Then click on the Alignment icon in the toolbar. The alignment window shown in Figure 1.18 appears with icons to align, match sizes, or distribute the selected elements on the visual surface.

Figure 1.18: Alignment icons for making your visual elements tidy

You've now created the initial visual elements for your applet. The next step is to add the code to connect these elements together to make them do what you want.

Start Sidebar
What's in a name?

Visual beans that you drop on the design surface are given variable names that begin with the name of the bean, followed by an optional sequence number. So, for example, Button beans that you drop on the design surface are given variable names of button, button1, button2, and so on. As you'll see in later chapters, you can rename variables for visual beans that you drop on the design surface, to make them more meaningful to your program.

Non-visual beans that you drop on the design surface are given similar variable names, except their names also have an "ivj" prefix, and you can't rename these variables.

End Sidebar

Making connections

You've already seen bean properties in action. You used properties to customize such things as the label that appears on the Add button and the sizes of visual elements. Now we'll describe the other two aspects of beans that make components so useful—events and methods.

Beans use events to notify other programs that a certain action has occurred (also called firing an event). Other programs listen for these events. When the event occurs, an associated method in the listener program is called, where it can take an appropriate action, such as calling methods in other beans to perform particular tasks. For example, Button beans fire action events when a user clicks on the button. This causes the associated method to be called in any program that's listening for the button's action events, so the listening program can take the appropriate steps whenever the button is clicked. To listen for an event, a program must implement the listener interface for that event, register itself as a listener for the event, and then take an appropriate action when the event occurs.

Start Sidebar
What's an interface?

An interface is a template that defines how a particular function should be implemented. Interfaces don't contain any executable code—they just define the pattern for other programs to follow, if those programs want to implement that function. Listener programs use interfaces to know which method is called when a particular event occurs.

End Sidebar

Beans use methods to let other programs tell them to take some action. Other programs call the method they want, passing the appropriate parameters as input and processing any return value passed back by the method. For example, the BoundList bean has an add(String) method to add an entry to the list, so another program that wants to add an entry to the list simply calls this method, passing the value that it wants added.

Events and methods are how you connect beans together. When an event is fired by one bean, it causes methods to be called in other beans to take the appropriate actions. Let's see how this is done with an example. You'll add code to your ToDoList applet to take the following actions whenever the user clicks on the Add button:

  1. Add the contents of the text field as a new entry in the list.

  2. Clear the text field.

  3. Set the focus to the text field (that is, make the text field the active element in the applet, so that the user can type in another entry).

Up to this point, WebSphere Studio has generated all the code for your ToDoList applet, so how do you figure out what code you need to write yourself to implement a particular listener interface or to call methods in beans to make them do what you want? You look at the bean's documentation.

For beans that are standard Java classes, such as buttons and text fields, you can access their documentation directly from WebSphere Studio. From the Help menu in the WebSphere Studio Workbench, select Help Contents and then click on J2SE SDK 1.3.1 APIs to access application programming interface (API) documentation for the standard Java classes. So, for example, if you look at the API for the Button bean (java.awt.Button), you'll see that it fires ActionEvents when the button is clicked, and any programs that want to listen for these events should implement the ActionListener interface in the java.awt.event package. If you then follow the link to the API for the ActionListener interface, you'll see that it contains just one method, actionPerformed(ActionEvent), which is the method that listening programs need to implement. If you have any problems following the instructions when we use standard Java classes in this book, check the documentation for the class or interface.

What if the bean you want to use isn't one of the standard classes? You still need to check the bean's documentation. For many of the beans supplied with this book, you'll see that their documentation is actually built into the bean as a special property: the aboutThisBean property. In other cases, such as the BoundList bean you're using in the ToDoList applet, the bean extends a standard Java class, java.awt.List, so most of its documentation is the same as that for its superclass, and we'll explain any differences as we use this type of bean in this book.

Tip

As you enter code in the Visul Editor source pane, you can also use its content assist feature to prompt you with the available choices. For example, if you're not sure of the syntax for a method name on a particular class, position the cursor at the point where the method name begins in your source code and press Ctrl+Space. The content assist window will appear, showing you the possible choices.

So let's get started. You want to listen for the Add button's action events and take the appropriate steps when these events are received. As with most things in programming, there are several ways to write the code for this task. You could have the ToDoList class itself listen for and process the events. To do this, you would add an "implements ActionListener" clause to your class statement, an actionPerformed(ActionEvent) method to process events, and code to register the applet as a listener for Add button action events. One of the difficulties with this technique is that once your applet listens for action events from more than one button, you have to include checks to see which button was clicked. That can make your actionPerformed(ActionEvent) method messy and slow down the performance of your applet. It's also a lot of code to keep track of, if your applet needs to listen to many different types of events fired by many different beans.

Luckily, the Visual Editor has an easier way—content assist templates, which you use to create inner classes for handling events. Templates are provided for individual event listeners and for groups of event listeners in a particular package, such as the java.awt.event package, which contains the ActionListener interface. You'll use content assist templates throughout this book to connect beans together. WebSphere Studio comes with the most commonly used templates already imported into the Workbench. As you'll see in later chapters, you can import any additional templates that you want to use.

Start Sidebar
What's an inner class?

Inner classes are a shortcut to creating Java classes. You place them directly in your program's source code, rather than as a separate .java file, and their functions are available only to your program. When you compile your program, the compiler creates multiple .class files—one for your program and one for each inner class contained in it.

End Sidebar

Let's use the templates to add an ActionListener to the Add button:

  1. Select the Add button on the design surface or in the Java Beans view. The source pane automatically scrolls to the getButton() method that initializes this bean.

  2. In the source pane, find the instruction button. setLabel ("Add"); in the getButton() method. Position the cursor after the semicolon, and press Enter to insert a new line in the source code. Enter the beginning of the new instruction by typing button.addA and press Ctrl+Space. The content assist window appears. Select addActionListener - addActionListener to a Component, as shown in Figure 1.19.

    Click To expand
    Figure 1.19: Content Assist Window for Add button

  3. Double-click addActionListener - addActionListener to a Component. The code shown in Figure 1.20 is added to your getButton() method.

    Start Figure

    // the lines in bold are added by content assist
private java.awt.Button getButton() {
 if(button == null) {
  button = new java.awt.Button();
  button.setBounds(30, 28, 65, 23);
  button.setLabel("Add");
  button.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent e) {
      }
  });
 }
 return button;
}
    End Figure

    Figure 1.20: Source code with inner class to process Add button action events

    As you can see, this single instruction does quite a lot. It creates a new ActionListener inner class with the necessary method for this listener interface (actionPerformed(ActionEvent)), and it registers the new class as a listener for Add button action events. Now all you need to do is add the code to take the appropriate steps whenever the Add button fires an action event.

    Tip

    Notice that the content assist window shown in Figure 1.19 lists two entries that begin with "addActionListener". The icons next to each entry identify whether it's just a method call or a complete template for handling the event. If you accidentally double-click on the wrong one, just delete the code you don't want or click the Undo icon in the Workbench toolbar. The Undo icon removes the latest change, so you can retry the operation.

  4. To process the Add button's action events, you need to add code to the newly created actionPerformed(ActionEvent) method to add the entry in the text field to the list, clear the text field, and set the focus to the text field. To do this, you use the BoundList bean's add(String) method and the TextField bean's getText(), setText(String), and requestFocus() methods, as shown in Figure 1.21.

    Start Figure

    // add the code in bold to the actionPerformed(ActionEvent) method
private java.awt.Button getButton() {
 if(button == null) {
  button = new java.awt.Button();
  button.setBounds(30, 28, 65, 23);
  button.setLabel("Add");
  button.addActionListener(new java.awt.event.ActionListener() {
    public void actionPerformed(java.awt.event.ActionEvent e) {
     getBoundList().add(getTextField().getText());
     getTextField().setText("");
     getTextField().requestFocus();
    }
  });
 }
 return button;
}
    End Figure

    Figure 1.21: Source code to take the appropriate actions when the user clicks on Add button

    Reminder

    If you're not sure which methods to call for a particular bean, check the API documentation for the bean. Or, if you think you know which methods to call, but you're just not sure of the syntax, use the Visual Editor's content assist.
Start Sidebar
Saving your work

To save your applet, right-click in the source pane and choose Save from the pop-up menu, or press the Ctrl+S key combination. You can now close the Visual Editor or exit WebSphere Studio if you wish. To reopen your applet in the Visual Editor, right-click on your applet in the Package Explorer and choose Open With → Visual Editor.

End Sidebar

Running the applet

To run your newly created applet, save your changes, click on the arrow next to the Run icon in the toolbar, and choose Run As → Java Bean / Applet. WebSphere Studio launches your ToDoList applet, and, as you can see, clicking on the Add button adds a new item to the list, as shown in Figure 1.22.

Click To expand
Figure 1.22: The ToDoList applet in action

We'll cover debugging techniques later in the book. If you find that nothing happens when you click on the Add button, check the code in your getButton() method to make sure it matches the preceding instructions.

Tip

If you receive the error message "Launch failed: no java bean found" when you try to run an applet in the Visual Editor, make sure the applet class is selected in the Workbench (and not something like a cell editor in the Properties view). The simplest way to make sure the applet class is selected is to click on it in the Package Explorer, and then try to run the applet again.


Adding functionality to your applet

Now that you've learned the basics of creating an applet with the Visual Editor for Java and JavaBeans, you can reinforce your understanding by adding more functionality to your ToDoList applet.

Removing all entries

Here's how to create a button that clears the entire ToDoList:

  1. Add another button from the palette of AWT Controls and set its label property to Clear, so that your applet's visual surface looks like Figure 1.23.

    Click To expand
    Figure 1.23: Adding a Clear button to the ToDoList applet

    Notice that the Visual Editor created your new Clear button as a variable named button1 and automatically added the code to initialize the button.

  2. Find the instruction button1.setLabel ("Clear"); in the getButton1() method in the source pane. Position the cursor after the semicolon, and press Enter to insert a new line in the source code. Enter the beginning of the new instruction by typing button1.addA and press Ctrl+Space to show the content assist window.

  3. Double-click addActionListener - addActionListener to a Component, so your getButton1() method looks like Figure 1.24.

    Start Figure

    // the lines in bold are added by content assist
private java.awt.Button getButton1() {
 if(button1 == null) {
  button1 = new java.awt.Button();
  button1.setBounds(30, 97, 65, 23);
  button1.setLabel("Clear");
  button1.addActionListener(new java.awt.event.ActionListener() {
    public void actionPerformed(java.awt.event.ActionEvent e) {

    }
  });
 }
 return button1;
}
    End Figure

    Figure 1.24: Source code with inner class to process Clear button action events

  4. Add code to the newly created actionPerformed(ActionEvent) method to remove all entries from the list whenever the Clear button is clicked, as shown in Figure 1.25.

    Start Figure

    // add the code in bold to the actionPerformed(ActionEvent) method
private java.awt.Button getButton1() {
 if(button1 == null) {
  button1 = new java.awt.Button();
  button1.setBounds(30, 97, 65, 23);
  button1.setLabel1("Clear");
  button1.addActionListener(new java.awt.event.ActionListener() {
    public void actionPerformed(java.awt.event.ActionEvent e) {
        getBoundList().removeAll();
    }
  });
 }
return button1;
    End Figure

    Figure 1.25: Removing all entries from the list when the user clicks on Clear button

Save your changes and run the ToDoList applet. Add some entries to your ToDoList and click on the Clear button to see that it does remove all entries from the list.

Removing the selected entry

Now let's create a button that removes the selected entry from the list:

  1. Add another button from the palette of AWT Controls, and set its label property to Remove, so that your applet's visual surface now looks like Figure 1.26.

    Click To expand
    Figure 1.26: Adding a Remove button to the ToDoList applet

    Notice that the Visual Editor created your new Remove button as a variable named button2 and automatically added the code to initialize the button.

  2. Use content assist to add an ActionListener inner class to the getButton2() method, so that your method looks like Figure 1.27.

    Start Figure

    // the lines in bold are added by content assist
private java.awt.Button getButton2() {
 if(button2 == null) {
  button2 = new java.awt.Button();
  button2.setBounds(30, 139, 65, 23);
  button2.setLabel("Remove");
  button2.addActionListener(new java.awt.event.ActionListener() {
    public void actionPerformed(java.awt.event.ActionEvent e) {

    }
  });
 }
 return button2;
}
    End Figure

    Figure 1.27: Source code with inner class to process Remove button action events

  3. Finally, add code to the actionPerformed(ActionEvent) method to remove the selected entry when the Remove button is clicked, as shown in Figure 1.28.

    Start Figure

    // add code in bold to actionPerformed(ActionEvent) method
private java.awt.Button getButton2() {
 if(button2 == null) {
  button2 = new java.awt.Button();
  button2.setBounds(30, 139, 65, 23);
  button2.setLabel("Remove");
  button2.addActionListener(new java.awt.event.ActionListener() {
   public void actionPerformed(java.awt.event.ActionEvent e) {
     getBoundList().remove(getBoundList().getSelectedItem());
   }
  });
 }
 return button2;
}
    End Figure

    Figure 1.28: Removing the selected entry from the list when the user clicks on Remove button

Save your changes and run the ToDoList applet. Add some entries to your ToDoList, select one of the entries, and click on the Remove button to see that the selected entry is removed from the list.

Importing the solution file

If you had any problems building the ToDoList applet, look at the [image] ToDoList.java solution file in the /solutions/chap01/toDoListPackage subdirectory on the CD included with this book.

To create a new package for the solution file and import the Java source into it:

  1. Right-click on the ToDoList project in the Package Explorer, and choose New → Package from the pop-up menu.

  2. Enter solutions.chap01.toDoListPackage for the package name, and click Finish.

  3. Right-click on solutions.chap01.toDoListPackage in the Package Explorer, and select Import… from the pop-up menu.

  4. Choose File system as the import source and click Next.

  5. Click the Browse… button next to the directory field to browse to the /solutions/chap01/toDoListPackage subdirectory on the CD, and click OK.

  6. Select [image] ToDoList.java as the file to import, and make sure that Create selected folders only is selected, as shown in Figure 1.29.

    Click To expand
    Figure 1.29: Importing the ToDoList.java solution file

  7. Click Finish

In the Package Explorer, select [image] ToDoList.java in the solutions.chap01.toDoListPackage package and open it with the Visual Editor to compare your program with the solution.


In review

In this chapter you learned how to build and run a simple applet in WebSphere Studio. You used the Visual Editor for Java to add visual beans to your applet and to customize the properties of the beans. You also learned how to implement event handling to connect beans together. In the next chapter you'll extend your applet using different types of events and non-visual beans, and you'll learn how to publish your applet to run in a Web browser.


Exercise

Add another text field to your applet and set its text property to show the current number of entries in the list whenever the user clicks the Add, Clear, or Remove button. Update the text field's properties so that it can't be edited directly by the user.

A solution file for this exercise is in the /solutions/chap01/toDoListPackage subdirectory on the CD included with this book. Import the Java source for [image] ToDoListExer1.java into the package named solutions.chap01.toDoListPackage and open it with the Visual Editor to compare your program with the solution.


Chapter 2: Extending Your First Applet

Download CD Content

In this chapter, you'll extend your ToDoList applet by adding functions to limit the number of entries in the list and to automatically present the entries in a sorted list, as shown in Figure 2.1.

Click To expand
Figure 2.1: The applet you'll create

You'll learn how to use PropertyChangeEvents to automatically detect when a property changes and how to use non-visual beans to add complex function to your applet with just a few simple steps. You'll also learn how to publish your applet to run in a Web browser.

Limiting the number of entries

You're now an expert at using action events in your applet, so in this chapter we'll look at another common event used by beans-the PropertyChangeEvent.

Bean properties that automatically notify other components when their value has changed are called bound properties. This lets other components take some action based on the new value. On the other hand, unbound properties don't notify other components when they change, so the other components have to write their own code to find out when the property changes. The standard Java classes, such as Text-Field and List, don't use bound properties, but the BoundTextField and BoundList beans used in this chapter do. That means a program can register as a listener for changes to bound properties in the BoundTextField or BoundList bean and be automatically notified when a change occurs.

In this section, you'll add a BoundTextField bean to your ToDoList applet to limit the number of entries that can be added to the list. Whenever the number of entries in the list reaches the limit specified in the BoundTextField, the Add button is automatically disabled. And, whenever the number of entries falls below the limit, such as when the user removes an entry, the Add button is enabled. The way you'll do this is by updating your applet to listen for PropertyChangeEvents fired by the BoundTextField and BoundList beans, and take the appropriate steps whenever either of the properties you're interested in (the BoundTextField bean's text property and the BoundList bean's itemCount property) changes.

As you learned in the previous chapter, listener interfaces define the method names that get called when a particular event is fired and what parameters are supplied as input to the methods. For the java.awt.event.ActionListener interface you used in Chapter 1, the method name was actionPerformed, and a java.awt.event.ActionEvent was passed as input to the method. In this chapter, you'll use the PropertyChangeListener interface in the java.beans package. This interface has one method, propertyChange, which is passed a java.beans.PropertyChangeEvent as input to the method.

As you'll see, PropertyChangeListeners are a more generic mechanism than ActionListeners. A bean fires PropertyChangeEvents when any bound property in it changes, and you have to examine the PropertyChangeEvent object to determine exactly which property changed. Most of the other events you'll use in this book are more explicit in describing exactly which event occurred, such as telling you when a specific button is clicked or when a file name is selected in a file dialog. Explicit events are easier for listeners to know exactly what happened, but they can also mean that you end up with many listeners in your applet or application. These are some of the trade-offs that bean developers need to consider when they're creating new beans, so that they will provide the type of events that listening programs need in a form that's easy to use.

So, let's add more beans to the ToDoList applet and connect them together using PropertyChangeEvents.

  1. If you don't already have [image] ToDoList.java open in the Visual Editor, open it.

  2. Use Choose Bean to select a BoundTextField bean from the com.ibm.uicontrols package, and drop it on your applet's visual surface.

  3. Change the BoundTextField bean's text property to 3.

  4. Select a Label bean from the palette of AWT Controls, and drop it on your applet's visual surface.

  5. Change the Label bean's text property to Max entries.

  6. Resize and reposition the beans so that they appear as shown in Figure 2.2.

    Click To expand
    Figure 2.2: Adding visual elements to limit the number of tasks

  7. Select the BoundTextField on the design surface to make the source pane scroll to the getBoundTextField() method. Start to add another instruction to the method, by typing boundTextField.addP, and press Ctrl+Space to show the content assist window.

  8. Double-click addPropertyChangeListener - addPropertyChangeListener to a bean so that your getBoundTextField() method looks like Figure 2.3.

    Start Figure

    // the lines in bold are added by content assist
private com.ibm.uicontrols.BoundTextField getBoundTextField() {
  if (boundTextField == null) {
   boundTextField = new com.ibm.uicontrols.BoundTextField();
   boundTextField.setBounds(30, 84, 35, 23);
   boundTextField.setText("3");
   boundTextField.addPropertyChangeListener
                 (new java.beans.PropertyChangeListener() {
             public void propertyChange(
                    java.beans.PropertyChangeEvent evt) {
                    ;
             }
   });
  }
  return boundTextField;
}
    End Figure

    Figure 2.3: PropertyChangeListener added by content assist

    Tip

    Make sure you select the addPropertyChangeListener template for handling events, not one of the addPropertyChangeListener methods.

  9. The name of the property that caused the event to be fired is available in the propertyName property of the PropertyChangeEvent object that's passed as input to this method. Add code to the newly created propertyChange (PropertyChangeEvent) method to check if it was the text property that changed, and if so, to set the Add button's enabled property based on whether the BoundTextField's value is greater than the number of items in the BoundList, as shown in Figure 2.4.

    Start Figure

    // add lines in bold to propertyChange(PropertyChangeEvent) method
private com.ibm.uicontrols. BoundTextField getBoundTextField() {
  if (boundTextField == null) {
   boundTextField = new com.ibm.uicontrols. BoundTextField();
   boundTextField.setBounds(30, 84, 35, 23);
   boundTextField.setText("3");
   boundTextField.addPropertyChangeListener
              (new java.beans.PropertyChangeListener() {
      public void propertyChange(
                java.beans.PropertyChangeEvent evt) {
        if ("text".equals(evt.getPropertyName()))
         getButton().setEnabled (getBoundList().getItemCount()<
           Integer.parseInt(getBoundTextField().getText().trim()));
      }
   });
  }
  return boundTextField;
}
    End Figure

    Figure 2.4: Processing PropertyChangeEvents for the BoundTextField bean

    Start Sidebar
    Working with different data types

    In the propertyChange(PropertyChangeEvent) method shown in Figure 2.4, special processing is required to convert the BoundTextField's text property (a String value) to a format that can be compared with the number of entries in the list (an int value). First, any leading and trailing blanks are removed by using the trim() method, and then the value (which we're assuming is a number) is converted to an int by using the static parselnt() method of the Integer class. The conversion is necessary because you can only compare like data types.

    End Sidebar

  10. Now you need to make a similar change to listen for property changes in the BoundList bean, because you might need to disable the button when the user adds an entry to the list or enable the button when the user removes an entry. Select the BoundList on the design surface to make the source pane scroll to the getBoundList() method, and use content assist to add a PropertyChangeListener, as shown in Figure 2.5.

    Start Figure

    // the lines in bold are added by content assist
private com.ibm.uicontrols.BoundList getBoundList() {
  if(boundList == null) {
   boundList = new com.ibm.uicontrols.BoundList();
   boundList.setBounds(142, 72, 146, 89);
   boundList.addPropertyChangeListener
      (new java.beans.PropertyChangeListener() {
         public void propertyChange(
                java.beans.PropertyChangeEvent evt) {
                ;
         }
   });
  }
  return boundList;
}
    End Figure

    Figure 2.5: PropertyChangeListener added by content assist

  11. Add code to the newly created propertyChange(PropertyChangeEvent) method to check if it was the itemCount property that changed, and if so, to set the Add button's enabled property based on whether the BoundTextField's value is greater than the number of items in the BoundList, as shown in Figure 2.6.

    Start Figure

    // add lines in bold to propertyChange(PropertyChangeEvent) method
private com.ibm.uicontrols.BoundList getBoundList() {
  if(boundList == null) {
   boundList = new com.ibm.uicontrols. BoundList();
   boundList.setBounds(142, 72, 146, 89);
   boundList.addPropertyChangeListener
      (new java.beans.PropertyChangeListener() {
         public void propertyChange(
                java.beans.PropertyChangeEvent evt) {
         if ("itemCount".equals(evt.getPropertyName()))
          getButton().setEnabled (getBoundList().getItemCount()<
           Integer.parseInt(getBoundTextField().getText().trim()));
          }
   });
  }
  return boundList;
}
    End Figure

    Figure 2.6: Processing PropertyChangeEvents for the BoundList bean

  12. Save your change and run the ToDoList applet. Add and remove entries in the ToDoList to verify that the BoundTextField value is, in fact, used to limit the number of entries in the list. But make sure you only enter valid numeric values in the BoundTextField—we're leaving error processing as an exercise for you at the end of this chapter!


Sorting the list

Now let's get really fancy and sort the list alphabetically. This example introduces a second list in which the items will be sorted. To do that, you'll use the Sort bean, which takes an array and sorts it.

  1. Resize your applet's visual surface to make room for new beans (see Figure 2.7 below). To resize the applet, select the large rectangle that surrounds your visual elements on the design surface and use the mouse to make it wider.

  2. Use Choose Bean to select another BoundList bean from the com.ibm.uicontrols package, and drop it on your applet's visual surface.

  3. Add another Label bean from the palette of AWT Controls, and change its text property to Sorted.

  4. Arrange these beans as shown in Figure 2.7.

    Click To expand
    Figure 2.7: Adding a second list

  5. Use Choose Bean to select a SortBean from the com.ibm.sort package, and place it on the design surface outside of the visual surface for your applet, as shown in Figure 2.8. (Although the bean currently appears on the design surface as SortBean_1, the actual variable name in the source code is ivjSortBean.)

    Click To expand
    Figure 2.8: Placing SortBean on the design surface

  6. In the Properties view, you can see that SortBean has two properties: aboutThisBean and ascending. You can probably guess the purpose of the ascending property: it specifies whether the list sorts in ascending or descending order. Click on the small box next to the aboutThisBean property, and a window opens with documentation on how to use SortBean, as shown in Figure 2.9. SortBean is an example of the beans supplied with this book that contain their own built-in help information.

    Click To expand
    Figure 2.9: SortBean's aboutThisBean property

  7. From SortBean's help information, you can see that it has a series of methods named sort(Type)Array(Type[]) that are each used to sort an array of the type specified in the method name, for example, sortStringArray(String[]) sorts an array of Strings. Click Cancel to close the help window.

    Tip

    If you accidentally click OK in the help window, the Visual Editor will try to add code to your applet to set the aboutThisBean property. If this happens, select the aboutThisBean property in the Properties view and click the Restore Default Value icon. This sets the property back to its normal, unmodified value. Any time you've made changes to a property and want to set it back to its original value, just select the property in the Properties view and click the Restore Default Value icon.

  8. Using the information you now know about how the SortBean works, find the getBoundList() method in the source pane, and add code to its PropertyChangeListener to sort the entries from the first list and place them in the second list whenever the items in the first list change, as shown in Figure 2.10. Notice that you need to remove all entries from the second list before you add the new entries; otherwise the newly sorted entries will just be tacked on to the end of the current list.

    Start Figure

    // add code in bold to propertyChange(PropertyChangeEvent) method
private com.ibm.uicontrols.BoundList getBoundList() {
  if(boundList == null) {
   boundList = new com.ibm.uicontrols.BoundList();
   boundList.setBounds(118, 72, 113, 89);
   boundList.addPropertyChangeListener
   (new java.beans.PropertyChangeListener() {
    public void propertyChange(
         java.beans.PropertyChangeEvent evt) {
     if ("itemCount".equals(evt.getPropertyName()))
       getButton().setEnabled (getBoundList().getItemCount()<
        Integer.parseInt(getBoundTextField().getText().trim()));
     if ("items".equals(evt.getPropertyName())) {
       getBoundList2().removeAll();
       String[] sortedArray = getIvjSortBean().sortStringArray
                    (getBoundList().getItems());
        int numItems = getBoundList().getItemCount();
        for (int i=0; i<numItems; i=i+1)
         getBoundList2().add(sortedArray[i]);
      }
     }
   });
  }
  return boundList;
}
    End Figure

    Figure 2.10: Placing sorted entries in the second list

Save your changes and run the ToDoList applet. Add and remove entries in the ToDoList to verify that as any changes are made to the first list, the entries are sorted and automatically placed in the second list, as shown in Figure 2.11.

Click To expand
Figure 2.11: Your final ToDoList applet

If you had any problems building the ToDoList applet, look at the [image] ToDoList.java solution file in the /solutions/chap02/toDoListPackage subdirectory on the CD included with this book. Create a package named solutions.chap02.toDoListPackage in your ToDoList project. Import /solutions/chap02/toDoListPackage/ToDoList.java into solutions.chap02.toDoListPackage, and open it with the Visual Editor to compare your program with the solution.


Publishing the applet

Now that you have a functioning applet, you're probably wondering how to incorporate your ToDoList applet into a Web page. You can do that with the help of WebSphere Studio. Before we leave the Visual Editor, check to see what value is specified for your ToDoList applet's size. You'll need this information to set up the Web page for your applet. To check the size, select the applet (the large rectangle that surrounds your visual elements) on the design surface, and look at the Properties view to see what value is specified for the size property (for example, 377,189). Save any changes and close the Visual Editor.

To run your applet in a Web browser, you first export it to its own JAR file.

Exporting to a JAR file

  1. Right-click on [image] ToDoList.java in the Package Explorer, and select Export… from the pop-up menu.

  2. Choose JAR file as the export destination and click Next.

  3. Click the Browse… button to browse to the folder where you want to place your exported JAR file, such as C:/export, and enter a file name for your applet's JAR file, such as [image] ToDoList.jar. Click Save.

  4. Choose the export options shown in Figure 2.12 (Export generated class files and resources and Compress the contents of the JAR file).

    Click To expand
    Figure 2.12: Exporting ToDoList applet to a JAR file

  5. Click Finish.

The WebSphere Studio Web perspective

To run your applet in a Web browser, you need a Web page that includes an appropriate <applet> tag and the resources required to run the applet (ToDoList.jar and [image] chap01.jar). You can create the Web page using any HTML or text editor and publish the page on a Web server, or you can perform all of these steps within WebSphere Studio.

Open a Web perspective, by clicking on the Open a Perspective icon in the vertical toolbar. Select Other…, then select Web and click OK. The Web Perspective icon appears in the vertical toolbar, and a new Web perspective is opened with its default editors and views. The first thing you need to do is create a Web project.

Creating a Web project

  1. Select File → New → Web Project to create a new Web project. Enter ToDoListWeb as the project name and leave all the defaults set to create a new Java 2 Enterprise Edition (J2EE) Web Project, as shown in Figure 2.13.

    Click To expand
    Figure 2.13: Creating a Web project

  2. Click Finish.

Importing resources

The next step in setting up your Web project in WebSphere Studio is to import the resources needed to run your applet in a Web page-namely, the [image] ToDoList.jar file that you just created and the [image] chap01.jar file with the beans used by your applet.

To import resources into a Web project, do the following:

  1. In the J2EE Navigator, click the + sign to expand the contents of the ToDoListWeb project. Right-click on the Web Content folder in the ToDoListWeb project, and select Import… from the pop-up menu.

  2. Select File system as the import source and click Next.

  3. Click the Browse… button next to the directory field to browse to the directory where you saved your ToDoList applet JAR file and click OK.

  4. Select the JAR file, and click Finish. The JAR file is added to the Web Content folder.

  5. Repeat steps 1 through 4 to import the [image] chap01.jar file into your Web project.

Creating a Web page

To create a Web page that will run your ToDoList applet in a Web browser, do the following:

  1. In the J2EE Navigator, right-click on the Web Content folder and select New → HTML/XHTML File from the pop-up menu.

  2. Enter [image] ToDoList.html for the HTML file name, as shown in Figure 2.14.

    Click To expand
    Figure 2.14: Creating an HTML page

  3. Click Finish.

  4. Your new [image] ToDoList.html file opens in the HTML editor in the Design view. Type in whatever text you want to appear on your Web page.

  5. Position the cursor to the point where you want your applet to be added to the Web page and select Insert → Others → Java Applet… Enter the Code name toDoListPackage.ToDoList.class (the name of the applet to run), Archive names [image] ToDoList.jar,chap01.jar (the JAR files where Web browsers look for your code), and width and height values to match the size specified for your ToDoList applet, as shown in Figure 2.15.

    Click To expand
    Figure 2.15: Adding the ToDoList applet to a Web page

  6. Click OK.

  7. Click on the Preview tab to see how your new Web page looks in a Web browser. Your ToDoList applet starts in the previewed Web page.

  8. Return to the Design tab and save your changes.

Running your applet in a Web browser

You now have a Web page for your applet and, as you just saw, you can preview the Web page in the WebSphere Studio HTML editor. Suppose you want to test your Web page in an actual Web server? No problem-you can do that in WebSphere Studio, too.

  1. Right-click on [image] ToDoList.html in the J2EE Navigator and select Run on Server… from the pop-up menu. The Server Selection window appears.

  2. Leave the server type set to WebSphere Express v5.0 Test Environment, and check the check box to set this server as the project default, as shown in Figure 2.16.

    Click To expand
    Figure 2.16: Server Selection window

  3. Click OK.

WebSphere Studio creates a default server configuration, starts the server, and launches your applet in a Web Browser within the Web perspective, as shown in Figure 2.17 (be patient—it may take a few minutes for the server to start).

Click To expand
Figure 2.17: Runing ToDoList in the WebSphere Studio Web browser

With the Web server running, you can also run your applet in a Web browser outside of WebSphere Studio. Just cut and paste the URL into a browser window, as shown in Figure 2.18.

Click To expand
Figure 2.18: Running ToDoList in an external Web browser

Stopping the WebSphere Studio server

To stop the WebSphere Studio server, go to the Servers view, right click on the server you want stopped, and select Stop from the pop-up menu, as shown in Figure 2.19.

Click To expand
Figure 2.19: Stopping the WebSphere Studio server
Tip

If you receive a message that the server is not responding, click OK to terminate the server.


In review

In this chapter you learned how to use PropertyChangeEvents to listen for changes to bound properties and how to add complex logic to your program with a non-visual bean. You also learned how to publish your applet to run in a Web browser. In the next chapter, you'll see how to use the Visual Editor to build stand-alone Java applications with beans that write to and read from files.


Exercises

  1. Add a label to your applet that contains a counter for the current number of entries in the ToDoList. Include code to update the counter automatically as entries are added or removed.

  2. Add error processing to your ToDoList applet to verify that the user enters a numeric value in the BoundTextField. If an invalid value is entered, set the BoundTexField back to the last valid value. (Hint: Check the WebSphere Studio help information for the java.lang.Integer class to see what exceptions the parseInt(String) method can throw, and include try-catch logic in your applet to handle the error condition.)

Solution files for both exercise are in the/solutions/chap02/toDoListPackage subdirectory on the CD included with this book. Import/solutions/chap02/toDoListPackage/ToDoListExer1.java and/solutions/chap02/toDoListPackage/ToDoListExer2.java into the package named solutions.chap02.toDoListPackage. Open the files with the Visual Editor to compare your programs with the solutions.


Chapter 3: Creating Your First Application

Download CD Content

Overview

In the previous chapters you built the ToDoList program as a Java applet. But suppose that you would like your program to work with files so that you don't lose your to-do list every time you restart your applet. One of the restrictions of applets is that, because they download information from a server to your machine, they always have to worry about security. So, applets have to get special permission to work with files (otherwise, a hostile applet might steal private information from your harddrive without your permission). Instead, we'll teach you how to develop Java applications, programs that don't get automatically loaded from Web pages, as applets are, but do have unrestricted access to the file system and other system resources. In this chapter, you'll build the ToDoList program as a Java application with the capability to save the list in a file, as shown in Figure 3.1.

Click To expand
Figure 3.1: The application you'll create

The ToDoList application includes the same basic functions as the ToDoList applet (add entries to the list, remove entries, and control the number of entries), plus new functions to save the list in a file and read the list from a file. The user enters the name of the file in a text field and clicks on the Save or Load buttons to cause the appropriate action to occur. You'll use the Visual Editor and JavaBeans to build the ToDoList application. You'll also learn how to publish your application to run it outside of WebSphere Studio.

Start Sidebar
What's an application?

An application is a stand-alone Java program, normally launched from the command line. Java applications start execution in their main(String []) method, which must be defined as public and static. Parameters, such as arguments entered on the command line, are passed to the method as a String array.

End Sidebar


Updating your project

The ToDoList application uses the same beans as the ToDoList applet, plus additional beans to work with files (ReadFile and WriteFile). So, the first thing you need to do is update your project to specify the JAR file for Chapter 3.

Updating the Java Build Path

  1. Copy [image] chap03.jar from the /solutions/chap03/ subdirectory on the CD included with this book to a folder on your machine, such as C:/beans, so that you can reference it easily from your Java projects in WebSphere Studio.

  2. From the Java perspective in WebSphere Studio, right-click on the ToDoList project in the Package Explorer and choose Properties from the pop-up menu.

  3. Select Java Build Path from the list of properties.

  4. Select the Libraries tab and click on the Add External JARs… button. Browse to the location on your machine where you copied the [image] chap03.jar file (for example, C:/beans), select the file, and click Open. The bean JAR file for Chapter 3 is added to the list of JARs and class folders on the Libraries tab, as shown in Figure 3.2.

    Click To expand
    Figure 3.2: Specifying bean JAR files for the Java project

  5. Click OK.

Creating the application

After updating the Java Build Path for your ToDoList project, the next step is to create a new class for your application.

  1. To create the class, right-click on toDoListPackage in the Package Explorer, and choose New → Visual Class from the pop-up menu.

  2. Enter ToDoListApplication as the class name.

  3. Leave Modifiers set to public.

  4. Select Frame as the visual class to extend, and uncheck the Swing check box. This sets java.awt.Frame as the superclass for your new visual class. Your ToDoList application will run as a stand-alone program using AWT controls, and Frame is the main container class for AWT-based applications.

  5. Since your program will run as an application, it will need a main method. Select the public static void main(String[] args) check box under "Which method stubs would you like to create?" to have WebSphere Studio create a stub for the main method, so that the window now looks like Figure 3.3.

    Click To expand
    Figure 3.3: Creating the application class

  6. Click Finish.

Your new ToDoListApplication class opens in the Visual Editor.


Your first application

This section shows you how to start building your application by setting up the frame class, adding beans to the design surface of the Visual Editor, customizing bean properties in the Properties view, and writing the necessary code to connect the beans together.

Setting up the frame class

  1. As you already know, the main method is what will be called when your application starts running, but right now your main method is just a stub. You need to add code to this method to create an instance of your application frame and to make the frame visible, as shown in Figure 3.4.

    Start Figure

    // add code in bold to create an instance of the frame and show it
    public static void main (String[] args) {
        ToDoListApplication frame = new ToDoListApplication();
        frame.show();
    }
    End Figure

    Figure 3.4: Creating an instance of the frame class

  2. Select the frame in the design surface. This is the visual surface for your application, where you'll place elements such as buttons and text fields, so grab one corner of the rectangle and drag it to increase its size. Notice that a default constructor and an initialize() method are added to your source code, along with code to initialize the size of the frame. The constructor is called whenever a new instance of the frame is created (as you just did in the main method), so this is where the Visual Editor places initialization logic (and where you will, too).

  3. Before you start adding beans to the frame's surface, there's one more bit of housekeeping to be done. You need to add logic to let users close the frame when they've finished using your application. If you run the application now, you'd find that nothing happens when you try to close the application window. That's because the window is firing an event, but no one's listening. The listener interface for window events is java.awt.event. WindowListener, and the method used to process window closing events is aptly called windowClosing(WindowEvent). WebSphere Studio includes a template for WindowListeners for processing all types of window events (opening, closing, activated, and so on), but it also includes a template for a WindowAdapter that exits the application when the window closing event is fired, which is exactly what we want. Find the ToDoListApplication constructor in your source code. Type in the beginning of a new instruction this.addW, press Ctrl+Space to view the content assist window, and double-click the template for addWindowClosing. The code shown in Figure 3.5 is added to the constructor.

    Start Figure

    // code in bold is added by content assist
public ToDoListApplication() {
  super();
  initialize();
  this.addWindowListener (new java.awt.event.WindowAdapter() {
   public void windowClosing(java.awt.event.WindowEvent e) {
   System.exit(1);
   }
  });
}
    End Figure

    Figure 3.5: Adding a WindowListener to exit when the user closes the frame


Laying out the interface and customizing properties

  1. Now you're ready to start adding beans to the frame's surface. Set the frame's title property to ToDoList and its layout property to null (a "null" layout means that your visual elements will appear exactly where you place them on the frame's surface).

  2. Select a Button bean from the palette of AWT Controls, and drop it on the frame.

  3. Set the Button's label property to Add.

  4. Select a TextField bean from the palette of AWT Controls, and drop it on the frame.

  5. Use Choose Bean to select a BoundList bean from the com.ibm.uicontrols package, and drop it on the frame.

  6. Arrange and resize the beans, so they appear as shown in Figure 3.6.

    Click To expand
    Figure 3.6: Initial visual elements for the ToDoList application

You've now created the initial visual elements for your application. The next step is to add the code to connect these elements together to make them do what you want.

Making connections

In this section, you'll add code to your ToDoList application to take the following actions whenever the user clicks on the Add button:

  • Add the contents of the text field as a new entry in the list

  • Clear the text field

  • Set the focus to the text field.

As you remember from Chapter 1, these actions should all be triggered when the Add button fires an action event. You'll use content assist to bring in the template for an ActionListener, and then add instructions to take the appropriate steps when the action event is fired by the Add button.

  1. Select the Add button on the design surface to cause the source pane to scroll to the getButton() method. Enter the beginning of the new instruction by typing button.addA and press Ctrl+Space to show the content assist window.

  2. Double-click addActionListener – addActionListener to a Component, so that your getButton() method looks like Figure 3.7.

    Start Figure

    // code in bold is added by content assist
private java.awt. Button getButton() {
  if (button == null) {
   button = new java.awt.Button();
   button.setBounds (24, 39, 79, 23);
   button.setLabel ("Add");
   button.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent e) {

            }
   });
  }
  return button;
}
    End Figure

    Figure 3.7: Adding an ActionListener for the Add button

  3. Add code to the actionPerformed(ActionEvent) method to add the entry in the text field to the list, clear the text field, and set the focus to the text field, as shown in Figure 3.8.

    Start Figure

    // add code in bold to process Add button action events
private java.awt.Button getButton() {
  if(button == null) {
   button = new java.awt.Button ();
   button.setBounds (24, 39, 79, 23);
   button.setLable l("Add");
   button.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent e) {
               getBoundList(). add(getTextField(). getText());
               getTextField(). setText("");
               getTextField(). requesFocus();
         }
   });
  }
  return button;
}
    End Figure

    Figure 3.8: Source code to take the appropriate actions when the user clicks on Add button

Save your changes.

Running the application

To run your newly created application, click on the arrow next to the Run icon in the toolbar, and choose Run As → Java Application. WebSphere Studio launches your ToDoList application in the main method. As you can see, clicking on the Add button adds a new item to the list, as shown in Figure 3.9.

Click To expand
Figure 3.9: The ToDoList application in action
Tip

If you receive the error message "Launch failed: no main type found" when you try to run an application in the Visual Editor, make sure the application class is selected in the Workbench (and not something like a cell editor in the Properties view). The simplest way to make sure the application class is selected is to click on it in the Package Explorer, and then try running the application again.


Adding functionality to your application

Now that you've learned the basics of creating an application with the Visual Editor and JavaBeans, let's practice a little more with action and property change events to add more functionality to your ToDoList application.

Removing all entries

Here's how to create a button that clears the entire ToDoList:

  1. Add another button from the palette of AWT Controls and label it Clear, so your frame's visual surface now looks like Figure 3.10.

    Click To expand
    Figure 3.10: Adding a Clear button to the ToDoList application

  2. Use content assist to add an ActionListener for the Clear button, as shown in Figure 3.11.

    Start Figure

    // code in bold added by content assist
private java.awt.Button getButton1() {
  if(button1 == null) {
   button1 = new java.awt.Button();
   button1.setBounds (24, 128, 79, 23);
   button1.setLabel ("Clear");
   button1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent e) {

            }
   });
  }
  return button1;
}
    End Figure

    Figure 3.11: Adding an ActionListener for the Clear button

  3. Add code to the actionPerformed(ActionEvent) method to remove all entries from the list when the user clicks on the Clear button, as shown in Figure 3.12.

    Start Figure

    // add code in bold to process Clear button clicks
private java.awt.Button getButton1 () {
  if (button1 == null) {
   button1 = new java.awt.Button();
   button1.setBounds (24, 128, 79, 23);
   button1.setLabel("Clear");
   button1.addActionListener(new java.awt.event.ActionListner() {
         public void actionPerformed(java.awt.event.ActionEvent e) {
                getBoundList().removeAll();
         }
   });
  }
  return button1;
}
    End Figure

    Figure 3.12: Logic to handle Clear button action events

Save your changes and run the ToDoList application. Add some entries to your ToDoList and click on the Clear button to see that it removes all entries from the list.

Removing the selected entry

Here's how to create a button that removes the selected entry from the list:

  1. Add another button from the palette of AWT Controls and label it Remove, so that your frame's visual surface now looks like Figure 3.13.

    Click To expand
    Figure 3.13: Adding a Remove button to the ToDoList application

    Reminder

    You can use the Visual Editor's alignment controls to easily line up visual elements and make them all the same width or height.

  2. Use content assist to add an ActionListener for the Remove button, as shown in Figure 3.14.

    Start Figure

    // code in bold added by content assist
private java.awt.Button getButton2() {
  if (button2 == null) {
   button2 = new java.awt.Button();
   button2.setBounds (24, 159, 79, 23);
   button2.setLabel ("Remove");
   button2.addActionListener(new java.awt.event.ActionListener() {
          public void actionPerformed(java.awt.event.ActionEvent e) {

          }
   });
  }
  return button2;
}
    End Figure

    Figure 3.14: Adding an ActionListener for the Remove button

  3. Add code to the actionPerformed(ActionEvent) method to remove the selected entry from the list when the user clicks on the Remove button, as shown in Figure 3.15.

    Start Figure

    // add code in bold to process Remove button clicks
private java.awt.Button getButton2() {
  if (button2 == null) {
   button2 = new java.awt.Button();
   button2.setBounds (24, 159, 79, 23);
   button2.setLabel ("Remove");
   button2.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent e) {
        getBoundList(). remove(getBoundList().getSelectedItem());
      }
   });
  }
  return button2;
}
    End Figure

    Figure 3.15: Logic to handle Remove button action events

Save your changes and run the ToDoList application. Add some entries to your ToDoList, select one of the entries, and click on the Remove button to check that the selected entry is removed from the list.

Limiting the number of entries

Next let's control the number of entries in the list:

  1. Use Choose Bean to select a BoundTextField bean from the com.ibm.uicontrols package, and drop it on the frame.

  2. Set the BoundTextField bean's text property to 3.

  3. Select a Label bean from the palette of AWT Controls, and drop it on the frame.

  4. Change the Label bean's text property to Max entries.

  5. Resize and reposition the beans, so they appear as shown in Figure 3.16.

    Click To expand
    Figure 3.16: Adding visual elements to limit the number of tasks

  6. Use content assist to add a PropertyChangeListener for the BoundTextField, as shown in Figure 3.17.

    Start Figure

    // code in bold added by content assist
private com.ibm.uicontrols.BoundTextField getBoundTextField() {
  if (boundTextField == null) {
   boundTextField = new com.ibm.uicontrols.BoundTextField();
   boundTextField.setBounds(24, 98, 24, 23);
   boundTextField.setText("3");
   boundTextField.addPropertyChangeListener
      (new java.beans.PropertyChangeListener() {
         public void propertyChange(
                java.beans.PropertyChangeEvent evt) {
                ;
          }
   });
  }
  return boundTextField;
}
    End Figure

    Figure 3.17: Adding a PropertyChangeListener for the BoundTextField

  7. Add code to the propertyChange(PropertyChangeEvent) method to check if it was the text property that changed, and, if so, to take the appropriate actions, as shown in Figure 3.18.

    Start Figure

    // add code in bold to process text property changes
private com.ibm.uicontrols.BoundTextField getBoundTextField() {
  if(boundTextField == null) {
   boundTextField = new com.ibm.uicontrols.BoundTextField();
   boundTextField.setBounds(24, 98, 24, 23);
   boundTextField.setText("3");
   boundTextField.addPropertyChangeListener
      (new java.beans.PropertyChangeListener() {
      public void propertyChange(
               java.beans.PropertyChangeEvent evt) {
        if ("text".equals(evt.getPropertyName()))
         getButton().setEnabled(getBoundList().getItemCount()<
          Integer.parseInt(getBoundTextField().getText().trim()));
       }
   });
  }
  return boundTextField;
}
    End Figure

    Figure 3.18: Processing BoundTextField PropertyChangeEvents

  8. Use content assist to add a PropertyChangeListener for the BoundList, as shown in Figure 3.19.

    Start Figure

    // code in bold added by content assist
private com.ibm.uicontrols.BoundList getBoundList() {
  if(boundList == null) {
   boundList = new com.ibm.uicontrols.BoundList();
   boundList.setBounds(150, 85, 126, 93);
   boundList.addPropertyChangeListener
      (new java.beans.PropertyChangeListener() {
         public void propertyChange(
                java.beans.PropertyChangeEvent evt) {
                ;
         }
   });
  }
  return boundList;
}
    End Figure

    Figure 3.19: Adding a PropertyChangeListener for the BoundList

  9. Add code to the propertyChange(PropertyChangeEvent) method to check if it was the itemCount property that changed, and, if so, to take the appropriate actions, as shown in Figure 3.20.

    Start Figure

    // add code in bold to process changes to itemCount property
private com.ibm.uicontrols.BoundList getBoundList() {
  if(boundList == null) {
   boundList = new com.ibm.uicontrols.BoundList();
   boundList.setBounds(150, 85, 126, 93);
   boundList.addPropertyChangeListener
      (new java.beans.PropertyChangeListener() {
         public void propertyChange(
                java.beans.PropertyChangeEvent evt) {
          if ("itemCount".equals(evt.getPropertyName()))
           getButton().setEnabled(getBoundList().getItemCount()<
            Integer.parseInt(getBoundTextField().getText().trim()));
          }
   });
  }
  return boundList;
}
    End Figure

    Figure 3.20: Processing BoundList PropertyChangeEvents

Save your changes and run the ToDoList application. Add and remove entries in the ToDoList to verify that the BoundTextField value is, in fact, used to limit the number of entries in the list.

As you can see, processing events in applications is just the same as in applets. We'll leave the function to add a sorted list as an exercise for you at the end of this chapter. Now, let's change gears and add functionality that applets don't normally support-working with files.


Working with files

In this section, you'll add functionality to your application to save and load your ToDoList. You only need to add a couple of beans and connect them into your existing components. The WriteFile and ReadFile beans (for writing a String array into a file and reading it from a file) are just what you're looking for.

Loading the ToDoList from a file

The way you make the ReadFile bean work is to set its input property (inputFileName) to the name of the file you want to read and call its triggerAction() method. For each line that the ReadFile bean reads from the file, it places the data in a bound output property, called currentStringResult. That means all you have to do to get the data from the file is listen for property change events that are fired when that property changes.

  1. Select a TextField bean from the palette of AWT Controls, and drop it on the frame.

  2. Select a Button bean from the palette of AWT Controls, and drop it on the frame.

  3. Set the Button bean's label property to Load.

  4. Use Choose Bean to select a ReadFile bean from the com.ibm.filemanagement package, and drop it on the design surface outside of the frame.

  5. Resize and reposition the beans so that they appear as shown in Figure 3.21.

    Click To expand
    Figure 3.21: Beans for loading from a file

    Note

    Althouggh the ReadFile bean may currently appear on the design surface as ReadFile_1, the actual variable name in the source code should be ivjReadFile.

  6. When the user clicks the Load button, you want to read the data from the file name specified in the text field and replace the current entries in the list with the data read from the file. That means you need to listen for action events fired by the Load button, and process the events by clearing the current list and invoking the ReadFile bean to get the new data. Use content assist to add an ActionListener for the Load button, as shown in Figure 3.22.

    Start Figure

    // code in bold added by content assist
private java.awt.Button getButton3() {
  if(button3 == null) {
   button3 = new java.awt.Button();
   button3.setBounds(203, 206, 40, 23);
   button3.setLabel("Load");
   button3.addActionListener(new java.awt.event.ActionListener() {
          public void actionPerformed(java.awt.event.ActionEvent e) {

          }
   });
  }
  return button3;
}
    End Figure

    Figure 3.22: Adding an ActionListener for the Load button

  7. Add code to the actionPerformed(ActionEvent) method to remove all entries from the list, set the inputFileName property for the ReadFile bean, and call the ReadFile bean's triggerAction() method, as shown in Figure 3.23.

    Start Figure

    // add code in bold to process Load button clicks
private java.awt.Button getButton3() {
  if(button3 == null) {
   button3 = new java.awt.Button();
   button3.setBounds(203, 206, 40, 23);
   button3.setLabel("Load");
   button3.addActionListener(new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent e) {
      getBoundList().removeAll();
       getIvjReadFile().setInputFileName(getTextField1().getText());
      getIvjReadFile().triggerAction();
     }
   });
  }
  return button3;
}
    End Figure

    Figure 3.23: Logic to handle Load button action events

  8. The preceding code triggers the ReadFile bean to do its work, so the second part of this logic is to process property change events that ReadFile fires as each line of data is read from the file. Use content assist to add a PropertyChangeListener to the ReadFile bean, as shown in Figure 3.24.

    Start Figure

    // code in bold added by content assist
private com.ibm.filemanagement.ReadFile getIvjReadFile() {
  if(ivjReadFile == null) {
   ivjReadFile = new com.ibm.filemanagement.ReadFile();
   ivjReadFile.addPropertyChangeListener
             (new java.beans.PropertyChangeListener() {
           public void propertyChange(
                  java.beans.PropertyChangeEvent evt) {
                  ;
           }
   });
  }
  return ivjReadFile;
}
    End Figure

    Figure 3.24: Adding a PropertyChangeListener for the ReadFile bean

  9. Finally, add code to the propertyChange(PropertyChangeEvent) method to check for changes to the currentStringResult property, and, when this property changes, to add the value to the list, as shown in Figure 3.25.

    Start Figure

    // add code in bold to process PropertyChangeEvents
private com.ibm.filemanagement.ReadFile getIvjReadFile() {
  if(ivjReadFile == null) {
   ivjReadFile = new com.ibm.filemanagement.ReadFile();
   ivjReadFile.addPropertyChangeListener
           (new java.beans.PropertyChangeListener() {
     public void propertyChange(
                 java.beans.PropertyChangeEvent evt) {
      if ("currentStringResult".equals(evt.getPropertyName()))
      getBoundList().add(getIvjReadFile().getCurrentStringResult());
     }
   });
  }
  return ivjReadFile;
}
    End Figure

    Figure 3.25: Logic to handle ReadFile bean PropertyChangeEvents

Saving the ToDoList in a file

The way you make the WriteFile bean work is even easier. You just set input properties with the name of the file you want to write to and an array of the data to be written, and call its triggerAction() method.

  1. Select a Button bean from the palette of AWT Controls, and drop it on the frame.

  2. Set the Button bean's label property to Save.

  3. Use Choose Bean to select a WriteFile bean from the com.ibm.filemanagement package, and drop it on the design surface outside of the frame.

  4. Resize and reposition the beans, so they appear as shown in Figure 3.26.

    Click To expand
    Figure 3.26: Beans for saving to a file

    Note

    Although the WriteFile bean may currently appear on the design surface as WriteFile_1, the actual variable name in the source code should be ivjWriteFile.

  5. When the user clicks the Save button, you want to write the current list entries to the file name specified in the text field. That means you need to listen for action events fired by the Save button, and process the events by setting the appropriate properties for the WriteFile bean and calling its triggerAction() method. Use content assist to add an ActionListener for the Save button, as shown in Figure 3.27.

    Start Figure

    // code in bold added by content assist
private java.awt.Button getButton4() {
  if(button4 == null) {
   button4 = new java.awt.Button();
   button4.setBounds(262, 206, 40, 23);
   button4.setLabel("Save");
   button4.addActionListener(new java.awt.event.ActionListener() {
          public void actionPerformed(java.awt.event.ActionEvent e) {
          }
   });
  }
  return button4;
}
    End Figure

    Figure 3.27: Adding an ActionListener for the Save button

  6. Add code to the actionPerformed(ActionEvent) method to set the WriteFile bean's input properties and call its triggerAction() method, as shown in Figure 3.28.

    Start Figure

    // add code in bold to process Save button clicks
private java.awt.Button getButton4() {
  if(button4 == null) {
   button4 = new java.awt.Button();
   button4.setBounds(262, 206, 40, 23);
   button4.setLabel("Save");
   button4.addActionListener(new java.awt.event.ActionListener() {
    public void actionPerformed(java.awt.event.ActionEvent e) {
     getIvjWriteFile().setInputFileName(getTextField1().getText());
     getIvjWriteFile().setInputArray(getBoundList().getItem());
     getIvjWriteFile().triggerAction();
    }
   });
  }
  return button4;
}
    End Figure

    Figure 3.28: Logic to handle Save button action events

Save your changes and run the ToDoList application. Use the Save and Load buttons to save your list in a file and read it back into the list, as shown in Figure 3.29.

Click To expand
Figure 3.29: The final running ToDoList application in action

If you had any problems building the ToDoList application, look at the solution file in the /solutions/chap03/toDoListPackage subdirectory on the CD included with this book. Create a package named solutions.chap03.toDoListPackage in your ToDoList project. Import /solutions/chap03/toDoListPackage/ToDoListApplication.java into solutions.chap03.toDoListPackage, and open it with the Visual Editor to compare your program with the solution.


Publishing your application

To publish your application and run it outside of WebSphere Studio, you need to have a Java Virtual Machine (JVM) installed. So before we dive into publishing, let's talk about the JVM for a moment. As you know, one of the main advantages of Java is its platform independence. You can create an application using a UNIX system and let Windows users run it on their computers (and vice versa). What allows Java to be so independent of the operating system? The answer is the JVM. The JVM acts as a translator between your compiled Java code (class file) and the underlying hardware platform and operating system where the class executes. Even though the Java code and the class files are the same, the JVMs differ for each particular operating system.

What is the Java Virtual Machine?

So, what is the JVM? It is a virtual computer that resides only in memory. It actually has a very small footprint when running in RAM. The JVM lets you execute Java programs and Web applets on your computer, outside of WebSphere Studio. Therefore, to run your applications outside of WebSphere Studio, you need to have the JVM installed on your computer. You might already have it.

The easiest way to check whether you already have the JVM is to go to the command prompt and try to execute the java command without any parameters. If you get the description of the command syntax for this command, you have the JVM. You also need to know the version of the JVM you have. Your version of the JVM should be compatible with the version you're using to develop your programs in WebSphere Studio. For WebSphere Studio 5.0, that means JDK 1.3. If you don't already have a compatible version on your system, follow the instructions in the "Where to get the JVM for your platform" section below.

So, how do you check the version? If the java command executes on your system successfully, you can figure out the version of the JVM by executing the following command in the command prompt.

java -version

If the version you have is JDK 1.2 or later, skip the next section and continue with the "Exporting to a directory" section.

Where to get the JVM for your platform

You can download the JVM from IBM's developerWorks Web site at http://www.ibm.com/java/jdk/download/. IBM's JVM comes as part of a Java Development Kit (JDK) package and is available for AIX, Linux, OS/2, Windows, and some other operating systems. For the Windows operating system, the IBM Web site also provides a separate Java Runtime Environment (JRE) package (select the link for IBM Developer Kit for Windows(R), Release 1.3.0). If you plan to do all your Java development work within WebSphere Studio and only execute Java programs outside of WebSphere Studio, then all you really need to run the programs is the JRE, rather than the complete JDK.

Another option for Solaris, Linux, and Windows users is the JRE package available on Sun Microsystems' site at http://java.sun.com/j2se/.

For instructions on installing the JVM on your system, see the installation materials included with the package you downloaded. After you install the JVM, you can execute Java class files. The next step is to export your class files from WebSphere Studio.


Exporting to a directory

  1. Right-click on [image] ToDoListApplication.java in the Package Explorer, and select Export… from the pop-up menu.

  2. Choose File system as the export destination and click Next.

  3. Click the Browse… button to browse to the folder where you want to place your exported class files, such as C:/export/. Click OK.

  4. Select ToDoListApplication.class and al the ToDoListApplication → n.class files (where n = 1–9—these are the inner classes for event handling) as the files to be exported and select Create directory structure for files, as shown in Figure 3.30.

    Click To expand
    Figure 3.30: Exporting the ToDoListApplication class files

  5. Click Finish.

WebSphere Studio creates the subdirectories for your project (ToDoList) and package (toDoListPackage), and places all the class files in the toDoListPackage subdirectory.

Referenced classes

Now you have exported the ToDoListApplication class files to a directory. However, as you know, you used several beans (such as the BoundList and ReadFile beans) to construct this class, and they weren't exported with the class files. These bean classes reside in the [image] chap01.jar and [image] chap03.jar files, so you'll need these JAR files to execute the application. To simplify the command syntax, we'll copy the JAR files to the same export directory where you'll run the ToDoList application.

Copy [image] chap01.jar and [image] chap03.jar to the ToDoList subdirectory that was created when you exported the class files, so your directory structure looks like this:

  • ToDoList folder contains [image] chap01.jar, [image] chap03.jar, and the toDoListPackage folder.

  • toDoListPackage folder contains the ToDoListApplication .class file and the nine ToDoListApplication → n.class files.

Now the application is ready to run outside WebSphere Studio.

Running the application from the command prompt

The general syntax of the java command is

java -classpath   list packagename.classname

where packagename is the name of the application's package, classname is the name of the application class, and list is a list of directories and files, separated by semicolons, in which to look for referenced classes. For classes packaged as JAR files, you need to specify the JAR files directly in the command.

To run your application, you'll need to go to your system's command prompt, change to the ToDoList folder in your export directory, and execute a java command that specifies the appropriate options and class file.

We'll use the Windows operating system; for other operating systems, the process is very similar. Windows users can run the application by opening the MS DOS command prompt (Start → Programs → Accessories → Command Prompt) and entering the following commands:

c:
cd export\ToDoList
java -classpath "chap01.jar;chap03.jar;.;%CLASSPATH%" toDoListPackage
.ToDoListApplication

The first two lines are DOS commands that move you to the correct subdirectory. The last line is the java command to execute your application.

Even though this isn't necessarily the easiest way to execute commands, for those of you familiar with DOS commands, it might be the fastest way. For applications that you use often, you might want to create a special executable file (such as a .bat file in Windows) that contains all the necessary commands.

To get more information on DOS commands, just enter help in the command line. Enter java to get an overview of the syntax of the command.

Note

If you receive error messages such as "Class not found", verify that your CLASSPATH setting includes all the required JAR files needed to run your application. It should include the standard Java classes, the current folder ("."), and any bean JAR files used by the application. Also verify that your package and class names are spelled correctly. Java is case sensitive, so make sure upper and lower case letters match exactly.


In review

In this chapter you learned how to build and run a simple application in WebSphere Studio. You used the Visual Editor to add visual and non-visual beans to your application and to customize the properties of the beans. You learned how to use the ReadFile and WriteFile beans to work with files and how to run your application outside of WebSphere Studio. In the next chapter, you'll learn more about how bean event handling works and will use the Visual Editor to create your own subcomponent to use in Java programs.


Exercise

Add functionality to your ToDoList application to show the entries in a sorted list.

A solution file for this exercise is in the [image] ToDoListApplicationExer1.java file in the /solutions/chap03/toDoListPackage subdirectory on the CD included with this book. Import /solutions/chap03/toDoListPackage/ToDoListApplicationExer1.java into the package named solutions.chap03.toDoListPackage, and open it with the Visual Editor to compare your program with the solution.


References

IBM developerWorks Web site: http://www.ibm.com/java/jdk/download/

Sun Microsystems' Java Web site: http://java.sun.com/j2se/x


Chapter 4: Creating a File-Manipulation Subcomponent

Download CD Content

The previous chapters introduced the Visual Editor and beans. If you followed all of the steps, you should have completed your first version of the ToDoList program, implemented first as an applet and then as an application. You should have a project called ToDoList and a package called toDoListPackage containing the ToDoList program in both applet and application forms. This chapter builds on the ToDoList application by changing how you specify the file name for reading from and writing to files. In the previous chapter you used a text field to enter the name. In this chapter you will use a file dialog to let you browse to specify the path and file names. In the process, you'll learn how to create a subcomponent and how to make the features of that subcomponent available to other programs.

Creating a subcomponent

In this chapter, you'll extend your ToDoList application by adding a reusable FileManipulationPanel subcomponent and by using a new bean called ExtendedFileDialog. You'll add standard file dialog windows for loading and saving files, and hide all the complexity of working with files in your subcomponent.

This chapter shows you how to

  • Build a component that can be reused across applications

  • Use the ExtendedFileDialog bean to simplify working with files

  • Promote bean features to make them accessible outside of your component

What are subcomponents?

Subcomponents are objects that encapsulate functions and that can be easily connected to other programs that want to use those functions. In Java, these objects are called beans. Bean developers write beans that hide the complexity of the functions for you (such as the ReadFile and WriteFile beans), but as your programs become more complicated, you might also need to hide that complexity by organizing your programs into subcomponents.

From the previous chapters, you already know how to connect beans together. Beans let you modularize your code, encapsulating complex functions so that your program can remain relatively simple. Each bean defines how other programs connect to it through the properties, methods, and events that is supports.

When you create a subcomponent, you need to think about how other programs might want to connect to your subcomponent. For example, how will you let other programs customize the functions that your subcomponent performs? How will other programs make your subcomponent do its work? And how will your subcomponent notify other programs that some action has taken place? These are the same features you used when you connected beans into your ToDoList application—properties, methods, and events. So, when you create a subcomponent, you need to think about what properties and methods you will make available for other programs to use and what events your subcomponent will fire to notify other programs that a particular action has taken place.

What you will create

In creating the ToDoList application, you learned how to save your to-do list into a file and how to read the file back in. However, in most applications today, you browse to specify file names rather than typing in the full path name. This chapter teaches you how to create a subcomponent that uses file dialogs and how to make this subcomponent into a bean that you can reuse in other applications that use files.

Creating beans is similar to creating applets or applications. You lay out the visual elements of the bean and then connect them to specify the behavior. When you place one of your visual beans on the design surface for another program, the visual components you designed appear on the surface, and your bean's properties, events, and methods are available for the other program to use.

The FileManipulationPanel bean you will create, shown in Figure 4.1, lets you call file dialog windows for loading and saving files, puts the name of the file the user chooses into a label, and includes functions for reading and writing the file.

Click To expand
Figure 4.1: The subcomponent you'll create

The way other programs use your subcomponent is very simple. For read operations, there are three steps:

  1. When the user selects a file name for reading, your subcomponent fires an event to tell the other program that a read operation should begin. This gives the program an opportunity to prepare, such as by clearing the area that will contain the new data.

  2. When the program is ready for the read operation to begin, it calls a method in your subcomponent to ask you to start reading the file.

  3. Finally, as each line is read from the file, your subcomponent fires an event to supply the line of data to the other program.

For write operations, the steps are even simpler:

  1. When the user selects a file name for writing, your subcomponent fires an event to tell the other program that a write operation should begin.

  2. When the program is ready for the write operation to begin, it calls a method in your subcomponent to ask you to start writing the file, passing you the data to be written.

Adding the JAR file for this chapter

Before you begin, you need to update your project's Java Build Path to add the JAR file for this chapter.

  1. Copy [image] chap04.jar from the/solutions/chap04/ subdirectory on the CD included with this book to a folder on your machine, such as C:/beans, so that you can reference it easily from your Java projects in WebSphere Studio.

  2. From the Java perspective in WebSphere Studio, right-click on the ToDoList project in the Package Explorer and choose Properties from the pop-up menu.

  3. Select Java Build Path from the list of properties.

  4. Select the Libraries tab and click on the Add External JARs… button. Browse to the location on your machine where you copied the [image] chap04.jar file (for example, C:/beans), select the file, and click Open.

  5. Click OK.

Importing the event handling template

The ExtendedFileDialog bean you use in this chapter fires an event to notify other programs when the user selects a file name in the file dialog. To simplify the coding for this event, the CD included with this book provides a content assist template for events fired by the ExtendedFileDialog bean. Follow these steps to import the template into the WebSphere Studio Workbench.

  1. From the Window menu in the WebSphere Studio Workbench, select Preferences.

  2. Click on the + sign next to Java to expand the possible preferences for Java projects, and then select Templates.

  3. Click on the Import… button on the right edge of the window and browse to the/solutions/chap04/subdirectory on the CD included with this book.

  4. Select the [image] addFileSelectionListener.xml file and click Open. The template for FileSelectionListeners is added to the list.

  5. Click OK.

Creating the FileManipulationPanel class

The next step is to create the new class for your subcomponent.

  1. Right-click on toDoListPackage in the Package Explorer, and choose New → Visual Class from the pop-up menu.

  2. Enter FileManipulationPanel as the class name.

  3. Leave Modifiers set to public (this lets other programs use your subcomponent).

  4. Select Panel as the visual class to extend, and uncheck the Swing check box. This makes java.awt.Panel the superclass for your new class. Panel is a container class for other visual elements, so it will hold the visual portion of your subcomponent.

  5. If any check boxes are selected to create method stubs for the new class, uncheck them so that the window now looks like Figure 4.2.

    Click To expand
    Figure 4.2: Creating the subcomponent class

  6. Click Finish.

Your new FileManipulationPanel class opens in the Visual Editor.

Adding a layout manager and visual beans

Layout managers are used to align, space, and size controls placed on an applet, frame, panel, or other container. In the previous chapters, you used a null layout, which meant that the visual components were placed in the container exactly where you dropped them (called absolute positioning). That's not particularly good design, because when you resize the window, objects don't change position as expected.

We'll cover layouts in more detail in Chapter 5, but for now we'll use GridBagLayout for the FileManipulationPanel to make it easy to resize the visual components.

  1. Select the small rectangle in the design surface. This is the visual surface for your subcomponent, where you'll place elements such as buttons, so grab one corner of the rectangle and drag it to increase its size. Notice that a default constructor and an initialize() method are added to your source code, along with code to initialize the size of the panel. The constructor is called whenever a new instance of the panel is created, so this is where the Visual Editor places initialization logic.

  2. Set the panel's layout property to GridBagLayout. When you add beans to the panel, GridBagLayout groups the beans in the center of the panel.

  3. Select a Button bean from the palette of AWT Controls, and drop it on the panel.

  4. Set the button's label property to Load. Notice that the button is automatically resized to match the length of the string used for the label.

  5. Click on the + sign next to the button's constraint property, and set the constraint-insets property to 3,3,3,3. The insets constraint is padding outside the bean, like margins, specified in pixels. There are separate insets for top, bottom, right, and left, which is why you specify four numbers for this property.

  6. Select another Button bean from the palette of AWT Controls, and drop it on the panel to the right of the Load button.

  7. Set the second button's label property to Save and its constraint-insets property to 3,3,3,3.

  8. Select a Label bean from the palette of AWT Controls, and drop it on the panel to the right of the Save button.

  9. Change the properties of the Label bean to the following:

    • text to " "(a blank space)

    • background to lightGray

      Tip

      To change the background property, click on the small button next to the current property value. In the Java Property Editor window that appears, select the Basic radio button to see a selection list for all the basic color values. Select the color you want, and click OK.

    • alignment to CENTER

    • constraint-fill to HORIZONTAL

    • contraint-weightx to 1

    • constraint-insets to 3,3,3,3.

      Note

      The fill constraint specifies which directions the bean can grow as the GridBag is resized. The weightx and weighty constraints specify how extra space is used. These properties are typically specified as values between 0 and 1, where components with higher weight values receive more space.

  10. Resize the panel, so that it appears as shown in Figure 4.3.

    Click To expand
    Figure 4.3: Initial visual elements for FileManipulationPanel subcomponent

Start Sidebar
GridBagLayout

GridBagLayout is a fairly complex layout manager, but the Visual Editor makes it easy for you to work with. GridBagConstraints position individual elements in the container, which, as you can see from the code that the Visual Editor generated for you, is not a trivial matter.

End Sidebar

You've now created the initial visual elements for your subcomponent. The next step is to add the remaining beans (ExtendedFileDialog. ReadFile, and WriteFile) and connect everything together.


Adding file dialogs

To add file dialogs to your FileManipulationPanel subcomponent, you'll use a bean from the [image] chap04.jar file called ExtendedFileDialog. ExtendedFileDialog has a method called show (), which displays a standard file dialog, and an event called file-Selected, which the dialog fires when the user selects a file name. Your FileManipulationPanel subcomponent will consist of

  • Load and Save buttons

  • ExtendedFileDialog beans that display when the buttons are clicked

  • A label to display the file name selected by the user

  • Beans to read and write the file specified

So far you have the buttons and label, so now you need to add the file dialogs and the logic to read and write files.

Adding beans to load a file

To load files, you need two components: the ExtendedFileDialog bean and the Read-File bean.

  1. Use Choose Bean to select an ExtendedFileDialog bean from the com.ibm.xml.wiringhelpers package by entering ExtendedFileDialog in the class name field and clicking OK. Drop the ExtendedFileDialog bean on the design surface outside of the panel.

  2. Use Choose Bean to select a ReadFile bean from the com.ibm.filemanagement package, and drop it on the design surface outside of the panel, so that your design surface looks like Figure 4.4.

    Click To expand
    Figure 4.4: Adding ExtendedFileDialog and ReadFile beans

    Note

    Even though the ReadFile bean currently appears on the design surface with the name ReadFile_1, the variable name in the source code is ivjReadFile.

  3. You want the ExtendedFileDialog to display when the user clicks the Load button, so use content assist to add an ActionListener for the Load button, and then add code to the actionPerformed(ActionEvent) method to call the ExtendedFileDialog bean's show() method, as shown in Figure 4.5.

    Start Figure

    // add code in bold to process Load button action events
private java.awt.Button getButton() {
  if(button == null) {
   button = new java.awt.Button();
   button.setLabel("Load");
   button.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent e) {
                   getExtendedFileDialog().show();
            }
   });
  }
  return button;
}
    End Figure

    Figure 4.5: ActionListener for Load button

    Reminder

    To scroll to the method for the Load button in the source pane, select the button on the design surface or in the Java Beans view. To use content assist to add an event handling template, type in the beginning of the instruction button.addA and then press Ctrl+Space.

  4. When the user selects a file name in the file dialog, the ExtendedFileDialog bean fires a fileSelected event. You want to listen for this event and take the appropriate actions when it's fired. Use content assist to add a FileSelectionListener to the ExtendedFileDialog bean, as shown in Figure 4.6.

    Start Figure

    // code in bold added by content assist
private com.ibm.xml.wiringhelpers.ExtendedFileDialog
        getExtendedFileDialog() {
  if(extendedFileDialog == null) {
   extendedFileDialog = new
    com.ibm.xml.wiringhelpers.ExtendedFileDialog(new
java.awt.Frame());
   extendedFileDialog.addFileSelectionListener(
     new com.ibm.xml.wiringhelpers.event.FileSelectionListener() {
     public void fileSelected(
         com.ibm.xml.wiringhelpers.event.FileSelectionEvent e) {
         ;
     }
     public void fileSelectionCancelled(
         com.ibm.xml.wiringhelpers.event.FileSelectionEvent e) {
         ;
     }
   });
  }
  return extendedFileDialog;
}
    End Figure

    Figure 4.6: Adding a FileSelectionListener to the ExtendedFileDialog bean

    Tip

    After content assist adds the new source code to your program, you may see the package name, com.ibm.xml.wiringhelpers.event, split across multiple input lines. The code works just fine this way; it's just that the code formatter in WebSphere Studio doesn't like the long package name.

  5. As you can see, the FileSelectionListener interface contains two methods. The fileSelected(FileSelectionEvent) method is called when the user selects a file name, so this is where you want to add your logic to process the event. You'll add more code to this method later, but for now just add code to copy the selected file name (in the ExtendedFileDialog bean's fullPath property) to the label's text property and to the ReadFile bean's inputFileName property, as shown in Figure 4.7.

    Start Figure

    // add code in bold to process fileSelected event
private com.ibm.xml.wiringhelpers.ExtendedFileDialog
        getExtendedFileDialog() {
  if(extendedFileDialog == null) {
   extendedFileDialog = new
    com.ibm.xml.wiringhelpers.ExtendedFileDialog(new java.awt.Frame());
   extendedFileDialog.addFileSelectionListener(
     new com.ibm.xml.wiringhelpers.event.FileSelectionListener() {
     public void fileSelected(
          com.ibm.xml.wiringhelpers.event.FileSelectionEvent e) {
       getLabel().setText(getExtendedFileDialog().getFullpath());
       getIvjReadFile().setInputFileName
             (getExtendedFileDialog().getFullpath());
     }
     public void fileSelectionCancelled(
          com.ibm.xml.wiringhelpers.event.FileSelectionEvent e) {
          ;
     }
   });
  }
  return extendedFileDialog;
}
    End Figure

    Figure 4.7: Initial code to handle fileSelected events for loading files

The next step could be to connect the fileSelected event to the triggerAction() method of the ReadFile bean. However, we said that your subcomponent should give other programs a chance to prepare for read operations; for instance, to clear the place for new contents, as in the ToDoList example. So, we'll leave this step until later when you make your subcomponent's features available to other programs.

Figure 4.8 shows a summary of the connections you just made in your subcomponent.

Click To expand
Figure 4.8: Initial connections for reading from a file

  • When the user clicks on the Load button, the ExtendedFileDialog bean's file dialog appears.

  • When the user selects a file name to load, the selected file name is copied to the label's text property and the ReadFile bean's inputFileName property.

Note that the functions you just added to your FileManipulationPanel bean are all encapsulated within the bean. Other programs using your bean don't need to be concerned with the mechanics of showing or processing the file dialog—it just happens.

Adding beans to save a file

To save files, you need two components: the ExtendedFileDialog bean and the WriteFile bean.

  1. Use Choose Bean to select another ExtendedFileDialog bean from the com.ibm.xml.wiringhelpers package, and drop it on the design surface outside of the panel.

  2. Use Choose Bean to select a WriteFile bean from the com.ibm.filemanagement package, and drop it on the design surface outside of the panel, so your design surface now looks like Figure 4.9.

    Click To expand
    Figure 4.9: Adding ExtendedFileDialog and WriteFile beans

    Note

    Even though the WriteFile bean currently appears on the design surface with the name WriteFile_1, the variable name in the source code is ivjWriteFile.

  3. You want the second ExtendedFileDialog to display when the user clicks the Save button, so use content assist to add an ActionListener for the Save button. Then, add code to the actionPerformed(ActionEvent) method to call the second ExtendedFileDialog bean's show() method, as shown in Figure 4.10.

    Start Figure

    // add code in bold to process Save button action events
private java.awt.Button getButton1() {
  if(button1 == null) {
   button1 = new java.awt.Button();
   button1.setLabel("Save");
   button1.addActionListener(new java.awt.event.ActionListener() {
          public void actionPerformed(java.awt.event.ActionEvent e) {
                 getExtendedFileDialog2().show();
          }
   });
  }
  return button1;
}
    End Figure

    Figure 4.10: ActionListener for Save button

  4. You also want to listen for fileSelected events fired by the second ExtendedFileDialog bean, so use content assist to add a FileSelectionListener to this bean, as shown in Figure 4.11.

    Start Figure

    // code in bold added by content assist
private com.ibm.xml.wiringhelpers.ExtendedFileDialog
       getExtendedFileDialog2() {
  if(extendedFileDialog2 == null) {
   extendedFileDialog2 = new
    com.ibm.xml.wiringhelpers.ExtendedFileDialog(new java.awt.Frame());
   extendedFileDialog2.addFileSelectionListener(
      new com.ibm.xml.wiringhelpers.event.FileSelectionListener() {
    public void fileSelected(
          com.ibm.xml.wiringhelpers.event.FileSelectionEvent e) {
          ;
    }
    public void fileSelectionCancelled(
          com.ibm.xml.wiringhelpers.event.FileSelectionEvent e) {
          ;
    }
   });
  }
  return extendedFileDialog2;
}
    End Figure

    Figure 4.11: Adding a FileSelectionListener for the second ExtendedFileDialog bean

  5. Just as with the first ExtendedFileDialog bean, you need to add logic to take the appropriate actions in the fileSelected(FileSelectionEvent) method. You'll add more code to this method later, but for now just add instructions similar to what you did before to copy the file name selected by the user to the label's text property and to the WriteFile bean's inputFileName property, as shown in Figure 4.12.

    Start Figure

    // add code in bold to process fileSelected event
private com.ibm.xml.wiringhelpers.ExtendedFileDialog
       getExtendedFileDialog2() {
  if(extendedFileDialog2 == null) {
   extendedFileDialog2 = new
    com.ibm.xml.wiringhelpers.ExtendedFileDialog(new java.awt.Frame());
   extendedFileDialog2.addFileSelectionListener(
      new com.ibm.xml.wiringhelpers.event.FileSelectionListener() {
    public void fileSelected(
          com.ibm.xml.wiringhelpers.event.FileSelectionEvent e) {
     getLabel().setText(getExtendedFileDialog2().getFullpath());
      getIvjWriteFile().setInputFileName
               (getExtendedFileDialog2().getFullpath());
    }
    public void fileSelectionCancelled(
          com.ibm.xml.wiringhelpers.event.FileSelectionEvent e) {
          ;
    }
    });
  }
  return extendedFileDialog2;
}
    End Figure

    Figure 4.12: Initial code to handle fileSelected events for saving files

  6. Save your changes.

Notice that you didn't connect the fileSelected event to the triggerAction() method of the WriteFile bean. We'll leave this step until later when you make your subcomponent's features available to other programs.

Figure 4.13 shows a summary of the connections you just made in your subcomponent.

Click To expand
Figure 4.13: Initial connections for writing to a file

  • When the user clicks on the Save button, the second ExtendedFileDialog bean's file dialog appears.

  • When the user selects a file name to save, the selected file name is copied to the label's text property and to the WriteFile bean's inputFileName property.

Just like the functions you added earlier to read from a file, these connections for writing to a file are all encapsulated within the FileManipulationPanel bean.

Testing the file dialogs

Now it's time to test your new panel. Click on the arrow next to the Run icon in the toolbar, and choose Run As → Java Bean / Applet. WebSphere Studio launches your FileManipulationPanel and writes an informational message to the console to tell you that your bean was started using its default (null) constructor. As you can see in Figure 4.14, clicking on the buttons causes the corresponding file dialog to appear. When you select a file, the file name is placed in the label. Notice also that, as you resize the window, the buttons and label are automatically resized, as you would expect.

Click To expand
Figure 4.14: FileManipulationPanel in action
Tip

If you receive the error message "Launch failed: no java bean found" when you try to run a subcomponent in the Visual Editor, make sure the subcomponent class is selected in the Workbench (and not something like a cell editor in the Properties view). The simplest way to make sure the subcomponent class is selected is to click on it in the Package Explorer, and then try to run it again.

Changing the title of the file dialog

As you may have noticed, both file dialogs are titled "Open" at execution time. The main functions of the two file dialogs are the same—letting the user choose the file. The ExtendedFileDialog bean controls this title and the button names via modes. In LOAD mode, the title is Open, and in SAVE mode, the title is Save. To make the second file dialog appear with the correct title and label, change its mode property to SAVE.


Promoting bean features

The basic features of your FileManipulationPanel are now in place. Next you'll promote the features of your bean that other programs need in order to use it. You make features accessible by providing methods that other programs can call, and by firing events that other programs can listen for. Making methods accessible to other programs is simple—you just add a new method with the functions to be performed and give the method a modifier of public. Making properties accessible to other programs is also simple—you just add public methods to get and set the property value. Firing events is a bit more complicated—you need to define a new event object and listener interface, and add code to your subcomponent to register listeners and to fire the new event at the appropriate times. Let's figure out which features of your bean to promote.

First, consider the data your bean will need to get from other programs and the data you will need to make accessible to other programs. The data that other programs need to supply is the text to be written into a file, which your bean then stores in the inputArray property of the WriteFile bean to make it available for the write operation. The data that your bean needs to make accessible to other programs is the text read from a file, which comes from the currentStringResult property of the ReadFile bean. You could make data items such as these accessible to other programs by making them properties of your bean, and we'll show you how to do that in Chapter 5. For this bean, however, you'll use a method to let other programs supply the text to be written to a file, and you'll use an event to make the text read from a file accessible to other programs.

Next, consider what events your bean needs to tell other programs about and what functions other programs need to ask your bean to do. Remember we said that your bean would fire events to let other programs know when a file has been selected for reading or writing? These events correspond to the fileSelected events fired by ExtendedFileDialog beans, so you need to promote these events to make them available to other programs. We also said that the programs using your bean would tell you when to actually begin a read or write operation, so these are the methods that you need to make available to other programs.

To summarize, the methods that you will make accessible to other programs are

  • triggerReadFile()—a method that other programs call to begin a read operation

  • triggerWriteFile(String[])—a method that other programs call to begin a write operation; the other programs pass the text to be written as a String array

The events that you will make accessible to other programs are:

  • loadFileSelected—fired when the user selects a file name using the Load button

  • saveFileSelected—fired when the user selects a file name using the Save button

  • currentStringResult—fired when a line of text is read from a file

We'll look at how to promote all these features in the following sections.

Adding methods

The FileManipulationPanel subcomponent needs to provide two methods for other programs to call—one to begin a read operation and another to begin a write operation. To make the new methods accessible to other programs you give them a modifier of public.

  1. In the source pane, enter a new triggerReadFile() method to make the ReadFile bean begin reading a file, as shown in Figure 4.15.

    Start Figure

    // add code in bold
public void triggerReadFile() {
    getIvjReadFile().triggerAction();
}
    End Figure

    Figure 4.15: Promoting the ReadFile bean's triggerAction() method

    Note

    You can add methods essentially anywhere within your source code, as long as they're inside the braces for the class and outside the code for any other methods. In the solution files, we put public methods at the start of the source code to make them easier to locate.

  2. In the source pane, enter a new triggerWriteFile(String[]) method to set the WriteFile bean's inputArray property to the passed value, and make the WriteFile bean write the data to a file, as shown in Figure 4.16.

    Start Figure

    // add code in bold
public void triggerWriteFile(String[] fileContents) {
    getIvjWriteFile().setInputArray(fileContents);
    getIvjWriteFile().triggerAction();
}
    End Figure

    Figure 4.16: Promoting the WriteFile bean's triggerAction() method

With these simple code changes, you just promoted the triggerAction() functions for both reading and writing files. Figure 4.17 shows the connecion you added for reading files. Now programs using your bean just need to call your triggerReadFile() method to read a file.

Click To expand
Figure 4.17: Connection added for reading files

Figure 4.18 shows the connection you added for writing files. Now programs using your bean just need to call your triggerWriteFile(String[]) method to write a string array to a file.

Click To expand
Figure 4.18: Connection added for writing files

Creating an event object

As you probably noticed, each of the events you have worked with so far has its own event object that describes the event, telling you things such as which object raised the event and any other details about the event such as mouse position, key pressed, and so on. For example, the ActionEvent object used by ActionListeners contains a command string associated with the action, and the PropertyChangeEvent object used by PropertyChangeListeners contains the name of the bound property that changed. Event objects typically have a superclass of java.util.EventObject, which provides the common base for event objects. Then they add properties to describe the specific event that occurred. To simplify the example in this chapter, you'll use one event object for all three events that are fired by your bean (loadFileSelected, saveFileSelected, and currentStringResult). You will create a new FileManipulationPanelEvent class to describe these events.

  1. To create the class for your event object, right-click on toDoListPackage in the Package Explorer, and choose New → Class from the pop-up menu.

    Note

    This is different from how you've been creating classes up to this point. Event objects don't have any visual aspects to them, so you use New → Class rather than New → Visual Class.

  2. Enter FileManipulationPanelEvent as the class name.

  3. Leave Modifiers set to public.

  4. Enter java.util.EventObject as the superclass. (You can either enter the superclass name directly in the input field or click the Browse… button next to the superclass field to get a Superclass Selection window, where you can select the class you want.)

  5. Check the check box to create method stubs for Constructors from superclass. This is necessary because event objects require an explicit constructor that passes the source object on which the event occurred—you'll see how this is used when you add code to fire your new events. The New Java Class window should look like Figure 4.19.

    Click To expand
    Figure 4.19: Creating the FileManipulationPanelEvent class

  6. Click Finish.

The new class opens in the standard Java Editor. Since this class doesn't have any visual elements, we'll stay in the standard editor to work with it.

You will use your new event object to pass the text read from a file (ReadFile bean's currentStringResult property) to listening programs, so you need to add a property to the event object for it. Your bean will set the new property when a line of data has been read from the file, and listening programs will get the property when your bean fires its currentStringResult event. That means you need methods to set and get the property.

  1. Add a declaration for a private currentStringResult property and public methods to get and set the property, as shown in Figure 4.20.

    Start Figure

    // add code in bold to your FileManipulationPanelEvent class
public class FileManipulationPanelEvent extends EventObject {
   private String currentStringResult;
   public FileManipulationPanelEvent(Object source) {
          super(source);
   }
   public void setCurrentStringResult(String s) {
             currentStringResult = s;
   }
   public String getCurrentStringResult(){
          return currentStringResult;
   }
}
    End Figure

    Figure 4.20: Adding a property to the event object

That's all there is to creating an event object. Save your changes and close the Java Editor.

Creating a listener interface

In order for other programs to listen for your bean's events, you need to create a listener interface to specify the methods that listener programs must implement. As you learned in Chapter 1, an interface is a template that defines how a particular function should be implemented. Interfaces don't contain any executable code—they just define the pattern for other programs to follow, if those programs want to implement that function.

  1. To create the listener interface, right-click on toDoListPackage in the Package Explorer, and choose New → Interface from the pop-up menu.

  2. Enter FileManipulationPanelListener as the interface name.

  3. Just as classes extend from a superclass, interfaces also extend from other interfaces. Click the Add… button, enter EventListener in the Choose interfaces field, and select java.util as the Qualifier, so that your interface extends java.util.EventListener, as shown in Figure 4.21.

    Click To expand
    Figure 4.21: The Extended Interfaces Selection window

  4. Click OK to return to the New Java Interface window, as shown in Figure 4.22.

    Click To expand
    Figure 4.22: The New Java Interface window

  5. Click Finish.

The new interface opens in the standard Java Editor, where you'll stay to work with it. Your bean will fire three different events (loadFileSelected, saveFileSelected, and currentStringResult), so your interface needs to include method declarations for each of these events. The method declarations define the method names, parameters, and any return value. In each case, the methods pass your FileManipulationPanelEvent object as a parameter to the listener program.

  1. Add method declarations for each of your bean's events, as shown in Figure 4.23.

    Start Figure

    // add code in bold to your FileManipulationPanelListener interface
public interface FileManipulationPanelListener extends EventListener {

   public void loadFileSelected(FileManipulationPanelEvent e);
   public void saveFileSelected(FileManipulationPanelEvent e);
   public void currentStringResult(FileManipulationPanelEvent e);
}
    End Figure

    Figure 4.23: Defining the interface

That's all there is to creating an event listener interface. Save your changes and close the Java Editor.

Registering listeners

Now that your event object and listener interface are defined, you can go back to your FileManipulationPanel and add the code to register listeners and fire events. First, you'll add the code to register listeners. The methods you need to add are

  • addFileManipulationPanelListener(FileManipulationPanelListener)

  • removeFileManipulationPanelListener(FileManipulationPanelListener).

Other programs call these methods to register and unregister as a listener for events fired by your bean. In the applications you've built so far in this book, you only registered to listen for bean events. In some cases a listener reaches a point where it doesn't need to listen for evens fired by a bean, so, to create a well-behaved bean, you must also provide the method for listeners to unregister.

  1. You keep track of registered listeners in a Vector, so add a declaration for this variable to your FileManipulationPanel bean, as shown in Figure 4.24.

    Start Figure

    // add a declaration for a Vector variable
private java.util.Vector listeners = new java.util.Vector();
    End Figure

    Figure 4.24: Adding a Vector to keep track of listeners

    Tip

    Since you need to access this variable from several methods within your program, place it at the start of the class where the other class variables are defined.
    Start Sidebar
    What's a Vector?

    A Vector is similar to an array, but it can contain any number of elements and it organizes the elements into an ordered list. A bean doesn't know in advance how many programs may want to listen for its events, so you need a Vector to keep track of listeners.

    End Sidebar

  2. Add an addFileManipulationPanelListener(FileManipulationPanelListener) method to your code to add a listener to the Vector, as shown in Figure 4.25. Notice that you specify the synchronized keyword on the method, which prevents multiple listeners from modifying the Vector at the same time.

    Start Figure

    // add method to register listeners
public synchronized void addFileManipulationPanelListener
                       (FileManipulationPanelListener listener) {
     listeners.addElement(listener);
}
    End Figure

    Figure 4.25: Method to register listeners

  3. Add a removeFileManipulationPanelListener(FileManipulationPanelListener) method to your code to remove a listener from the Vector, as shown in Figure 4.26.

    Start Figure

    // add method to unregister listeners
public synchronized void removeFileManipulationPanelListener
                       (FileManipulationPanelListener listener) {
     listeners.removeElement(listener);
}
    End Figure

    Figure 4.26: Method to unregister listeners

Save your changes. Your bean now includes the necessary methods to register and unregister listeners. The next step is to fire your events at the appropriate times.

Firing events

You have three events to be fired:

  • loadFileSelected fires when the user selects a file name using the Load button

  • saveFileSelected fires when the user selects a file name using the Save button

  • currentStringResult fires when a line of text is read from the file

To fire any of these events, you must create a new FileManipulationPanelEvent object that describes the event, and then call the appropriate method in all listener programs.

  1. To fire your loadFileSelected event, find the source code that listens for fileSelected events fired by the first ExtendedFileDialog bean. This is in the getExtendedFileDialog() method in your FileManipulationPanel bean where you already have code to copy the selected file name to the label's text property and the ReadFile bean's inputFileName property. Add the code shown in Figure 4.27 to create a new event object, and loop through your Vector to call the loadFileSelected(FileManipulationPanelEvent) method in all listener programs. Note that you need to clone (that is, make a copy) of the Vector so that it isn't modified while you're using it. Listeners may try to register or unregister as you're looping through the Vector, and that would cause an exception when you use the Iterator to process the Vector elements.

    Start Figure

    // add code in bold to fire loadFileSelected events
private com.ibm.xml.wiringhelpers.ExtendedFileDialog
        getExtendedFileDialog() {
  if(extendedFileDialog == null) {
   extendedFileDialog = new
    com.ibm.xml.wiringhelpers.ExtendedFileDialog(new java.awt.Frame());
   extendedFileDialog.addFileSelectionListener(
     new com.ibm.xml.wiringhelpers.event.FileSelectionListener() {
     public void fileSelected(
          com.ibm.xml.wiringhelpers.event.FileSelectionEvent e) {
       getLabel().setText(getExtendedFileDialog().getFullpath());
       getIvjReadFile().setInputFileName
             (getExtendedFileDialog().getFullpath());
   FileManipulationPanelEvent evt =
            new FileManipulationPanelEvent(this);
   java.util.Vector v;
   synchronized (this) {v = (java.util.Vector) listeners.clone();}
   java.util.Iterator iter = v.iterator();
   while (iter.hasNext())
         ((FileManipulationPanelListener)
               iter.next()).loadFileSelected(evt);
  }
     public void fileSelectionCancelled(
          com.ibm.xml.wiringhelpers.event.FileSelectionEvent e) {
          ;
     }
   });
  }
  return extendedFileDialog;
}
    End Figure

    Figure 4.27: Firing the loadFileSelected event

  2. To fire your bean's saveFileSelected event, find the source code that listens for file-Selected events fired by the second ExtendedFileDialog bean. This code is in the getExtendedFileDialog2() method in your FileManipulationPanel bean where you already have code to copy the selected file name to the label's text property and the WriteFile bean's inputFileName property. Add the code shown in Figure 4.28 to create a new event object and loop through the Vector to call the saveFileSelected(FileManipulationPanelEvent) method in all listener programs.

    Start Figure

    // add code in bold to fire saveFileSelected events
private com.ibm.xml.wiringhelpers.ExtendedFileDialog
       getExtendedFileDialog2() {
   if(extendedFileDialog2 == null) {
    extendedFileDialog2 = new
     com.ibm.xml.wiringhelpers.ExtendedFileDialog(new java.awt.Frame());
      extendedFileDialog2.addFileSelectionListener(
         new com.ibm.xml.wiringhelpers.event.FileSelectionListener() {
      public void fileSelected(
           com.ibm.xml.wiringhelpers.event.FileSelectionEvent e) {
      getLabel().setText(getExtendedFileDialog2().getFullpath());
      getIvjWriteFile().setInputFileName
               (getExtendedFileDialog2().getFullpath());
      FileManipulationPanelEvent evt =
            new FileManipulationPanelEvent (this);
      java.util.Vector v;
      synchronized (this) {v = (java.util.Vector) listeners.clone();}
      java.util.Iterator iter = v.iterator();
      while (iter.hasNext())
         ((FileManipulationPanelListener)
               iter.next()).saveFileSelected(evt);
      }
      public void fileSelectionCancelled(
         com.ibm.xml.wiringhelpers.event.FileSelectionEvent e) {
         ;
      }
   });
 }
 return extendedFileDialog2;
}
    End Figure

    Figure 4.28: Firing the saveFileSelected event

  3. For your bean's final event, you want to fire the currentStringResult event when the ReadFile bean's currentStringResult property changes. You don't currently have logic to listen for changes to this bound property, so find the getIvjReadFile() method in the source pane, and use content assist to add a PropertyChangeListener to the bean, as shown in Figure 4.29.

    Start Figure

    // code in bold added by content assist
private com.ibm.filemanagement.ReadFile getIvjReadFile() {
   if(ivjReadFile == null) {
      ivjReadFile = new com.ibm.filemanagement.ReadFile();
      ivjReadFile.addPropertyChangeListener
         (new java.beans.PropertyChangeListener() {
            public void propertyChange(
                  java.beans.PropertyChangeEvent evt) {
                  ;
            }
      });
   }
   return ivjReadFile;
}
    End Figure

    Figure 4.29: Adding a PropertyChangeListener

  4. Add code to the propertyChange(PropertyChangeEvent) method to check if it was the currentStringResult property that changed. If so, add code to fire your bean's currentStringResult event, as shown in Figure 4.30. Remember that you need to pass the string itself in your FileManipulationPanelEvent object. You get the new value of the property from the PropertyChangeEvent object.

    Start Figure

    // add code in bold to fire currentStringResult events
private com.ibm.filemanagement.ReadFile getIvjReadFile() {
   if(ivjReadFile == null) {
   ivjReadFile = new com.ibm.filemanagement.ReadFile();
   ivjReadFile.addPropertyChangeListener
      (new java.beans.PropertyChangeListener() {
         public void propertyChange(
                   java.beans.PropertyChangeEvent evt) {
            if ("currentStringResult".equals(evt.getPropertyName())) {
               FileManipulationPanelEvent e = new
                  FileManipulationPanelEvent(this);
               e.setCurrentStringResult((String)evt.getNewValue());
               java.util.Vector v;
               synchronized (this)
                  {v = (java.util.Vector) listeners.clone();}
               java.util.Iterator iter = v.iterator();
               while (iter.hasNext())
                  ((FileManipulationPanelListener)
                     iter.next()).currentStringResult(e);
               }
            }
      });
   }
   return ivjReadFile;
}
    End Figure

    Figure 4.30: Firing the currentStringResult event

Your bean is now ready to use. Save your changes. Figure 4.31 shows the final connections within your subcomponent for reading files. Programs using your bean now use your loadFileSelected event to make preparations for reading a new file, and they use your currentStringResult event to get the data read from the file.

Click To expand
Figure 4.31: Final connections for reading files

Figure 4.32 shows the final connections within your subcomponent for writing files. Programs using your bean use your saveFileSelected event to make preparations for writing to a file.

Click To expand
Figure 4.32: Final connections for writing files

For the convenience of programmers who will use your bean in WebSphere Studio, you may also want to provide an event handling template. We have one for you to use in this chapter on the CD-ROM included with this book. Follow these steps to import the template into the WebSphere Studio Workbench.

  1. From the Window menu in the WebSphere Studio Workbench, select Preferences.

  2. Click on the + sign next to Java to expand the possible preferences for Java projects, and then select Templates.

  3. Click on the Import… button on the right edge of the window and browse to the /solutions/chap04/subdirectory on the CD included with this book.

  4. Select the [image] addFileManipulationPanelListener.xml file and click Open. The template for FileManipulationPanelListeners is added to the list.

  5. Click OK.

Note

For information on how to create your own templates, see the WebSphere Studio help. From the Help menu in the Workbench, select Help Contents and then click on Web developer information. Instructions for writing your own templates are in the Java Development section.


Adding the bean to the ToDoList application

Now it is time to add your FileManipulationPanel bean to your ToDoListApplication and test how it works.

Initial preparation

Open [image] ToDoListApplication.java with the Visual Editor. In the design surface, remove the following old components: the Load and Save buttons, the ReadFile and WriteFile beans, and the text field for entering the file name (to remove a bean, select it on the design surface and press the Delete key). Notice that the corresponding code is automatically removed from the source pane. Your design surface should now look like Figure 4.33.

Click To expand
Figure 4.33: Removing beans from your old ToDoList application


Adding the FileManipulationPanel to the composition

  1. Use Choose Bean to select a FileManipulationPanel bean from the toDoListPackage package and drop it on the application's visual surface. Resize the bean so that it appears as shown in Figure 4.34.

Click To expand
Figure 4.34: Adding the FileManipulationPanel bean

Making connections

The connections you need to make to use the FileManipulationPanel bean in your ToDoListApplication are

  • When the user selects a file name to load, remove the current entries in the list and call the FileManipulationPanel bean's triggerReadFile() method to start reading the file.

  • When a line of data is read from the file, add it to the list.

  • When the user selects a file name to save, call the FileManipulationPanel bean's triggerWriteFile(String[]) method, passing the entries in the list as a parameter to the method.

The following steps show how to make these connections.

  1. Find the getFileManipulationPanel() method in the source pane, and use content assist to add a FileManipulationPanelListener to the bean, as shown in Figure 4.35.

    Start Figure

    // code in bold added by content assist
private toDoListPackage.FileManipulationPanel
             getFileManipulationPanel() {
   if(fileManipulationPanel == null) {
      fileManipulationPanel = new
            toDoListPackage.FileManipulationPanel();
      fileManipulationPanel.setBounds(11, 207, 306, 29);
      fileManipulationPanel.addFileManipulationPanelListener(
         new FileManipulationPanelListener() {
       public void loadFileSelected(FileManipulationPanelEvent e) {
           ;
       }
       public void saveFileSelected(FileManipulationPanelEvent e) {
           ;
       }
       public void currentStringResult(FileManipulationPanelEvent e) {
           ;
       }
      });
   }
   return fileManipulationPanel;
}
    End Figure

    Figure 4.35: Adding a FileManipulationPanelListener

  2. When the user selects a file name to load, the FileManipulationPanel bean fires a loadFileSelected event. Add code to the loadFileSelected(FileManipulationPanelEvent) method to clear the entries in the list, and call the FileManipulationPanel bean's triggerReadFile() method to read data from the file, as shown in Figure 4.36 (on the top of the following page). The triggerReadFile()method begins a read operation.

    Start Figure

    // add code in bold to process loadFileSelected events
private toDoListPackage.FileManipulationPanel
             getFileManipulationPanel() {
   if(fileManipulationPanel == null) {
      fileManipulationPanel = new
            toDoListPackage.FileManipulationPanel();
      fileManipulationPanel.setBounds(11, 207, 306, 29);
      fileManipulationPanel.addFileManipulationPanelListener(
         new FileManipulationPanelListener() {
       public void loadFileSelected(FileManipulationPanelEvent e) {
         getBoundList().removeAll();
         getFileManipulationPanel().triggerReadFile();
       }
       public void saveFileSelected(FileManipulationPanelEvent e) {
            ;
       }
       public void currentStringResult(FileManipulationPanelEvent e) {
            ;
       }
      });
   }
   return fileManipulationPanel;
}
    End Figure

    Figure 4.36: Processing loadFileSelected events

  3. As the ReadFile bean reads each line of data from the selected file, the FileManipulationPanel fires a currentStringResult event. To get the data, add code to the currentStringResult(FileManipulationPanelEvent) method to get the current string from the event object and add it to the list, as shown in Figure 4.37 (on the bottom of the following page).

    Start Figure

    // add code in bold to process currentStringResult events
private toDoListPackage.FileManipulationPanel
             getFileManipulationPanel() {
   if(fileManipulationPanel == null) {
      fileManipulationPanel = new
            toDoListPackage.FileManipulationPanel();
      fileManipulationPanel.setBounds(11, 207, 306, 29);
      fileManipulationPanel.addFileManipulationPanelListener(
         new FileManipulationPanelListener() {
       public void loadFileSelected(FileManipulationPanelEvent e) {
            getBoundList().removeAll();
            getFileManipulationPanel().triggerReadFile();
       }
       public void saveFileSelected(FileManipulationPanelEvent e) {
            ;
       }
       public void currentStringResult(FileManipulationPanelEvent e) {
            getBoundList().add(e.getCurrentStringResult());
       }
      });
   }
   return fileManipulationPanel;
}
    End Figure

    Figure 4.37: Processing currentStringResult events

  4. When the user selects a file name to save, the FileManipulationPanel bean fires a saveFileSelected event. To write the current list to the selected file, add code to the saveFileSelected(FileManipulationPanelEvent) method to call the FileManipulationPanel bean's triggerWriteFile(String[]) method, as shown in Figure 4.38. Pass the current items from the list as a parameter.

    Start Figure

    // add code in bold to process saveFileSelected events
private toDoListPackage.FileManipulationPanel
             getFileManipulationPanel() {
   if(fileManipulationPanel == null) {
      fileManipulationPanel = new
            toDoListPackage.FileManipulationPanel();
      fileManipulationPanel.setBounds(11, 207, 306, 29);
      fileManipulationPanel.addFileManipulationPanelListener(
         new FileManipulationPanelListener() {
       public void loadFileSelected(FileManipulationPanelEvent e) {
            getBoundList().removeAll();
            getFileManipulationPanel().triggerReadFile();
       }
       public void saveFileSelected(FileManipulationPanelEvent e) {
            getFileManipulationPanel().
                 triggerWriteFile(getBoundList().getItems());
       }
       public void currentStringResult(FileManipulationPanelEvent e) {
            getBoundList().add(e.getCurrentStringResult());
       }
      });
   }
   return fileManipulationPanel;
}
    End Figure

    Figure 4.38: Processing saveFileSelected events

Save your changes and run the ToDoList application. Use the Save and Load buttons to save your list in a file and read it back into the list, as shown in Figure 4.39.

Click To expand
Figure 4.39: The final running ToDoList application in action

If you had any problems building the FileManipulationPanel subcomponent, look at the solution files in the /solutions/chap04/toDoListPackage subdirectory on the CD included with this book. To add the solution files to your WebSphere Studio workspace, create a new package called solutions.chap04.toDoListPackage in the ToDoList project and import the following files into it:

  • /solutions/chap04/toDoListPackage/FileManipulationPanel.java

  • /solutions/chap04/toDoListPackage/FileManipulationPanelEvent.java

  • /solutions/chap04/toDoListPackage/FileManipulationPanelListener.java

  • /solutions/chap04/toDoListPackage/ToDoListApplication.java

Open visual classes (FileManipulationPanel.java and [image] ToDoListApplication.java) with the Visual Editor, and open non-visual classes (FileManipulationPanelEvent.java and [image] FileManipulationPanelListener.java) with the standard Java Editor.


In review

In this chapter you learned how to build a subcomponent that provides functions to select a file name with a file dialog and to read or write the file. You learned how to create your own event objects and listener interfaces, how to register listener programs, and how to fire events. You also learned how to connect your bean to use it in another application. In the next chapter, we'll cover more details about layout managers and building subcomponents.


Exercise

Add error processing to your FileManipulationPanel subcomponent to listen for error events fired by the ReadFile and WriteFile beans, and write an appropriate error mesage to the label whenever an error occurs.

Hint

Look at the aboutThisBean property for the ReadFile and WriteFile beans for a description of error events that these beans fire. Event handling templates for ReadFile and WriteFile bean error events are provided in the /solutions/chap04 subdirectory on the CD included with this book. To use the templates, import the [image] ReadWriteErrorTemplates.xml file into the WebSphere Studio Workbench.

Solution files for this exercise are in the /solutions/chap04/toDoListPackage subdirectory on the CD included with this book. To add the solution files to your WebSphere Studio workspace, import the following files into the solutions.chap04.toDoListPackage package:

  • /solutions/chap04/toDoListPackage/FileManipulationPanelExer1.java

  • /solutions/chap04/toDoListPackage/FileManipulationPanelExer1 Event.java

  • /solutions/chap04/toDoListPackage/FileManipulationPanelExer1Listener.java

  • /solutions/chap04/toDoListPackage/ToDoListApplicationExer1.java


Chapter 5: Using Layout Managers

Download CD Content

Overview

This chapter gives an overview of the layout managers that the Java platform provides. It includes rules for using the layout managers as well as some examples of their use. You use layout managers to align, space, and size controls placed on an applet, panel, frame, or other container. There are several types of layout managers; it just takes some practice to get used to each of them. The basic layout managers are:

  • BorderLayout

  • FlowLayout

  • CardLayout

  • GridLayout

  • BoxLayout

  • GridBagLayout

To give you practice with these layout managers, we'll create a Clock application that lets you change the settings of your clock display, including colors, format, and the appearance of digits.

You built the ToDoList program without a layout manager; it had the layout property set to null. Using a null layout is not good design because it uses pixel coordinates to position the controls. The null layout forces the positions of GUI beans to be fixed in the container, so when users resize windows, the beans won't change their relative positions to fill the larger space.

When you use a layout manager with a container, the layout manager calculates the coordinates for visual elements at run time, rather than using fixed positions. The layout manager uses variables, such as the overall window size, and the attributes of individual components, such as their preferred size, to position and size each component in the window. There are two types of layout managers: unconstrained and constrained. Unconstrained layout managers, such as FlowLayout, size each component on the basis of the component's preferred size. Constrained layout managers, such as GridBagLayout, use separate constraint objects, which specify additional information about how a particular component should be positioned and sized. In this chapter, we'll discuss how to use the various layout managers.

Start Sidebar
What size do you prefer?

When you drop a visual bean on the Visual Editor's design surface, the bean appears with its preferred size (what the bean determines to be its best size—not values that you typically set directly, although you could do so with Swing-based components). As you change the bean's properties in the Properties view, such as by changing a Button bean's label or font property, the bean's preferred size changes to accommodate the new values. Layout managers like FlowLayout automatically show the bean with the new preferred size.

End Sidebar


BorderLayout manager

BorderLayout has five areas for holding components: North, South, East, West, and Center. All extra space is allocated to the center area. The example applet shown in Figure 5.1 has a button in each area.

Click To expand
Figure 5.1: BorderLayout example

You will use BorderLayout as the main layout manager for your Clock application.

Before you begin

Before you create the Clock application, you need to set up a new project and package in WebSphere Studio.

  1. The bean you'll use in the Clock application, the IClock bean, is in the [image] chap05.jar file. Copy [image] chap05.jar from the /solutions/chap05/ subdirectory on the CD included with this book to a folder on your machine, such as C:/beans.

  2. To create the project, open a Java perspective in WebSphere Studio, and click on the Create a Java Project icon in the toolbar.

  3. Enter a project name of ClockProject, and click Next.

  4. Select the Libraries tab and click on the Add External JARs… button. Browse to the location on your machine where you copied the [image] chap05.jar file (for example, C:/beans), select the file, and click Open.

  5. Click Finish.

  6. To create the package, right-click on ClockProject in the Package Explorer, and choose New → Package from the pop-up menu.

  7. Enter clockPackage as the package name, and click Finish.

Creating the class

  1. To create the class for your application, right-click on clockPackage in the Package Explorer, and choose New → Visual Class from the pop-up menu.

  2. Enter Clock as the class name.

  3. Select Frame as the visual class to extend, and uncheck the Swing check box (this makes java.awt.Frame the superclass name). Your Clock application will run as a stand-alone program using AWT controls rather than Swing ones, and Frame is the main container class for AWT-based applications.

  4. Since your program will run as an application, it will need a main method. Select the public static void main (String[] args) check box to have WebSphere Studio create a stub for the main method, and uncheck any other check boxes for creating method stubs, so that the window now looks like Figure 5.2.

    Click To expand
    Figure 5.2: Creating a new class

  5. Click Finish.

Your new Clock class opens in the Visual Editor.

Setting up the frame class

Just as you did with the ToDoList application, you need to set up your new Clock application to show the frame when the application starts, initialize the frame's properties, and close the frame's window when the application ends.

  1. Add code to the main method to create an instance of your application frame and make the frame visible, as shown in Figure 5.3.

    Start Figure

    // add code in bold to create an instance of the frame and show it
    public static void main(String[] args) {
        Clock frame = new Clock();
        frame.show();
    }
    End Figure

    Figure 5.3: Creating an instance of the frame class

  2. Select the frame in the design surface, grab one corner of the rectangle, and drag it to increase its size.

  3. Set the title property of the frame to Clock and the layout property to null (we'll use a null layout first to illustrate the difference between it and BorderLayout).

  4. In the source pane, find the default constructor that the Visual Editor just created, and use content assist to add the WindowClosing template, which lets users close the window when they're finished using your application, as shown in Figure 5.4.

    Start Figure

    // add code in bold to create a WindowListener to close the window
public Clock() {
  super();
  initialize();
  this.addWindowListener(new java.awt.event.WindowAdapter() {
  public void windowClosing(java.awt.event.WindowEvent e) {
         System.exit(1);
  }
 });
}
    End Figure

    Figure 5.4: Adding a WindowListener

Reminder:

To use content assist, type in the beginning of a new instruction this.addW, press Ctrl+Space, and select addWindowClosing.

Adding the IClock bean

Now you're ready to start adding visual elements to your application.

  1. Use Choose Bean to select an IClock bean from the com.ibm.clock package, and drop it on the frame, as shown in Figure 5.5.

    Click To expand
    Figure 5.5: Clock application with IClock bean in analog mode

  2. Set the IClock bean's displayMode property to DIGITAL.

  3. Resize your clock, so it appears as shown in Figure 5.6.

    Click To expand
    Figure 5.6: Clock application with IClock bean in digital mode

  4. Save your changes and test the Clock application.

    Reminder:

    To run an application, click on the arrow next to the Run icon in the toolbar, and choose Run As → Java Application.

  5. Try to resize the window of the running application. The IClock bean does not change its size or position, because the Clock frame has the null layout manager. This behavior is not what you want for the application, so you need to change the layout.

Setting up the layout manager

Layout managers are properties of AWT containers (a frame is one kind of container), so you can set the layout manager in the property sheet of the container bean. You learned how to set the GridBagLayout manager when you created the FileManipulationPanel in Chapter 4. This time, you are going to set up the BorderLayout manager.

  1. Select the frame in the design surface so that its properties are shown in the Properties view. Change the frame's layout property to BorderLayout. The IClock is resized and placed in the closest area of the BorderLayout (north, west, and so on), depending on where the bean had been positioned in the frame with the null layout.

  2. If the IClock bean is not already in the center of the frame, select it in the design surface and move it to the center of the frame. As you move the bean, the various areas of the BorderLayout are highlighted (North, Center, and so on). These are the drop zones. They show the border area of the frame and are shown only at development time to help you add GUI beans to a container. When the center area is highlighted, as shown in Figure 5.7, release the mouse button to drop the IClock bean in the center of the frame.

    Click To expand
    Figure 5.7: Moving a bean in a frame with BorderLayout

  3. Save your changes and run the application again. It should look similar to Figure 5.8. Notice how it acts when you resize the window.

    Click To expand
    Figure 5.8: The running Clock application

Exploring the IClock bean properties

As you probably noticed, the IClock bean has a set of interesting properties. You can manipulate the colors of the digits and background for the analog and digital modes. By choosing different values for the digitalDisplayStyle, you can set up your clock to show the time in different ways, such as full, long, or short style.

What if you want to change settings during run time? You can add a button for each setting. You could add each button directly to the frame, but each button would need to be in a separate area (North, South, East, or West). Since the buttons should stay together in a group and not increase in size or move around the user interface, it is better to combine multiple buttons on a panel. An AWT panel is another type of container that can have its own layout manager. You can then add the panel to another container, such as your Clock frame, in one of the BorderLayout areas (North, South, East, or West).

Our goal for the next step is to create a panel that lets you easily manipulate the IClock properties at run time. As an easy solution, we'll create two panels with FlowLayout managers for the digit color and the background color. Then we'll try a more complex and interesting solution: We'll place three panels into one container with a CardLayout and select from them at run time. Let's start with the easy version, which is shown in Figure 5.9.

Click To expand
Figure 5.9: Clock application using BorderLayout and FlowLayout

FlowLayout manager

FlowLayout queues components in a row, sized at their preferred size. If the container is not wide enough to put all the components in one row, FlowLayout uses multiple rows. By default, the components are centered in the row, but you can also specify that they be left- or right-aligned. Figure 5.10 shows an applet that uses a FlowLayout.

Click To expand
Figure 5.10: Simple FlowLayout applet

Creating the digits color panel

  1. Select a Panel bean from the palette of AWT Controls, and place it on the design surface outside of the frame. Resize it as shown in Figure 5.11. Notice that the default layout for the panel is FlowLayout, which is exactly what you want.

    Click To expand
    Figure 5.11: Adding a panel to the design surface

  2. Select a Label bean from the palette of AWT Controls, and place it on the panel. Set the Label's text property to Digits color:. Notice that the label is automatically resized to fit the length of the new property value.

  3. Add three Button beans to the panel to the right of the label. When you select a bean and move the mouse over the panel, the Visual Editor shows a vertical bar to tell you where the new element will be added. When you set each Button's label, FlowLayout automatically resizes the Button for you. Set the label properties to Yellow, Green, and Red, so that your design surface now looks like Figure 5.12.

    Click To expand
    Figure 5.12: Digits color panel added to design surface

Making connections for the digits color panel

  1. Select the Yellow button on the design surface to scroll to its method in the source pane. Use content assist to add an ActionListener for the button, and add code to the actionPerformed(ActionEvent) method to set the IClock bean's digitalForeGroundColor property to yellow when the button is clicked, as shown in Figure 5.13. The Color class in the java.awt package includes fields for all the common color values (yellow, green, and so on), so you can use this class to set color values in your application.

    Start Figure

    // add code in bold to process action events for Yellow button
private java.awt.Button getButton() {
 if(button == null) {
   button = new java.awt.Button();
   button.setLabel("Yellow");
   button.addActionListener(new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent e) {
      getIClock().setDigitalForeGroundColor(java.awt.Color.yellow);
     }
   });
 }
 return button;
}
    End Figure

    Figure 5.13: ActionListener for the Yellow button

  2. Select the Green button on the design surface. Add an ActionListener for the button, and add code to the actionPerformed(ActionEvent) method to set the IClock bean's digitalForeGroundColor property to green when the button is clicked, as shown in Figure 5.14.

    Start Figure

    // add code in bold to process action events for Green button
private java.awt.Button getButton1() {
  if(button1 == null) {
   button1 = new java.awt.Button();
   button1.setLabel ("Green");
   button1.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent e) {
      getIClock().setDigitalForeGroundColor(java.awt.Color.green);
     }
   });
  }
  return button1;
}
    End Figure

    Figure 5.14: ActionListener for the Green button

  3. Select the Red button on the design surface. Add an ActionListener for the button, and add code to the actionPerformed(ActionEvent) method to set the IClock bean's digitalForeGroundColor property to red when the button is clicked, as shown in Figure 5.15.

    Start Figure

    // add code in bold to process action events for Red button
private java.awt.Button getButton2() {
  if(button2 == null) {
   button2 = new java.awt.Button();
   button2.setLabel("Red");
   button2.addActionListener(new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent e) {
      getIClock().setDigitalForeGroundColor(java.awt.Color.red);
     }
   });
  }
  return button2;
}
    End Figure

    Figure 5.15: ActionListener for the Red button

Creating the background color panel

  1. Select another Panel bean from the palette of AWT Controls, and place it on the design surface outside of the frame. Resize it to be the same size as in the first panel.

  2. Select a Label bean from the palette of AWT Controls, and place it on the second panel. Set the label's text property to Background color:.

  3. Add three Button beans to the second panel. Set their label properties to White, Blue, and Black, so your design surface now looks like Figure 5.16.

    Click To expand
    Figure 5.16: Background color panel added to design surface

Making connections for the background color panel

  1. Select the White button on the design surface. Add an ActionListener for the button, and add code to the actionPerformed(ActionEvent) method to set the IClock bean's digitalBackGroundColor property to white when the button is clicked, as shown in Figure 5.17.

    Start Figure

    // add code in bold to process action events for White button
private java.awt.Button getButton3() {
  if(button3 == null) {
   button3 = new java.awt.Button();
   button3.setLabel("White");
   button3.addActionListener(new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent e) {
      getIClock().setDigitalBackGroundColor(java.awt.Color.white);
     }
   });
  }
  return button3;
}
    End Figure

    Figure 5.17: ActionListener for the White button

  2. Select the Blue button on the design surface. Add an ActionListener for the button, and add code to the actionPerformed(ActionEvent) method to set the IClock bean's digitalBackGroundColor property to blue when the button is clicked, as shown in Figure 5.18.

    Start Figure

    // add code in bold to process action events for Blue button
private java.awt.Button getButton4() {
  if(button4 == null) {
   button4 = new java.awt.Button();
   button4.setLabel("Blue");
   button4.addActionListener(new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent e) {
      getIClock().setDigitalBackGroundColor(java.awt.Color.blue);
     }
   });
  }
  return button4;
}
    End Figure

    Figure 5.18: ActionListener for the Blue button

  3. Select the Black button on the design surface. Add an ActionListener for the button, and add code to the actionPerformed(ActionEvent) method to set the IClock bean's digitalBackGroundColor property to black when the button is clicked, as shown in Figure 5.19.

    Start Figure

    // add code in bold to process action events for Black button
private java.awt.Button getButton5() {
  if(button5 == null) {
   button5 = new java.awt.Button();
   button5.setLabel("Black");
   button5.addActionListener(new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent e) {
      getIClock().setDigitalBackGroundColor(java.awt.Color.black);
     }
   });
  }
  return button5;
}
    End Figure

    Figure 5.19: ActionListener for the Black button

Placing the panels in the frame

You now need to make these panels components of the Clock frame by placing them in their appropriate areas of the BorderLayout—in this case, North and South.

  1. Drag and drop the digits color panel on the top (North) section of the frame. When you drop the panel, make sure you're dropping it on the frame's surface and not on the IClock, which also has a BorderLayout. When you move the digits color panel over the drop zone for the frame, it should look like Figure 5.20. You can also check the source code or the Java Beans view after dropping the panel to verify that it was added to the correct container. In the source code, the panel should be added to the frame in the initialize() method; in the Java Beans view, the panel should be listed as a child component under the frame (this).

    Click To expand
    Figure 5.20: Drop zone for the frame's north section

  2. Drag and drop the background color panel on the bottom (South) section of the frame. Again, make sure you drop the panel on the frame and not on the IClock.

Tip

If you're having trouble dropping visual elements on the correct area of the design surface, you can try doing it in the Java Beans view instead, although you may still need to modify code. For example, select the panel bean you want to move in the Java Beans view and drop it on the frame (this). If the bean didn't land in the area of the frame's BorderLayout that you wanted, edit the code in the source pane to move it there.

Your Clock frame should now look like Figure 5.21.

Click To expand
Figure 5.21: Panels placed in Clock frame

Now you get to test your application. Save your changes and run your application. Try to change the digit and background colors of your clock. Also, try to resize your clock. Note that the panels at the top and bottom of the window always replace their components and arrange them, so FlowLayout is working as intended.

Adding vertical borders

Although your application already works properly, we want to demonstrate the full power of the BorderLayout for the Clock frame, so let's add some white borders to the right (East) and left (West) of the clock.

  1. Select a Label bean from the palette of AWT Controls and place it on the left side of the frame (West). Set the Label's text property to an empty string (select the current value and press the Delete key).

    Tip

    Again, if you're having trouble dropping the bean on the area of the frame you want on the design surface, try dropping it on the frame in the Java Beans view.

  2. Select another Label bean from the palette of AWT Controls and place it on the right side of the frame (East). Set the second Label's text property to an empty string. The design surface should now look like Figure 5.22, and the Java Beans view should look like Figure 5.23.

    Click To expand
    Figure 5.22: Adding white borders

    Click To expand
    Figure 5.23: Java Beans view for Clock application

Save your changes and run your application again. You should see something similar to Figure 5.24.

Click To expand
Figure 5.24: The final running Clock application

If you had any problems building this version of the Clock application, look at the solution file in the /solutions/chap05/clockPackage subdirectory on the CD included with this book. Create a package named solutions.chap05.clockPackage in your ClockProject project. Import/solutions/chap05/clockPackage/ClockBorderLayout.java into solutions.chap05.clockPackage, and open it with the Visual Editor to compare your program with the solution.

In the next section, you'll create a subcomponent for the setting panels, and use your subcomponent to build another version of the Clock application using CardLayout.


Creating a subcomponent with radio buttons

You're already familiar with subcomponents after creating the FileManipulationPanel in Chapter 4. Subcomponents encapsulate complex behaviour and present a simplified user interface exposing only the interface components that are necessary to make the bean perform its functionality. Subcomponents can be reused across applications. Let's take a break from layout managers and refresh your skills in constructing subcomponents. You'll create an additional panel that you'll reuse in your application to demonstrate the CardLayout manager. While creating this subcomponent, you'll learn about radio button groups, which you'll use to choose settings for IClock.

Your final subcomponent will look like Figure 5.25.

Click To expand
Figure 5.25: The final SettingPanel subcomponent

Creating the SettingPanel subcomponent

  1. Create a new visual class, SettingPanel, in your clockPackage, extending the java.awt.Panel class (select Panel as the visual class to extend and uncheck the Swing check box). Your subcomponent won't run as a stand-alone application, so uncheck the check box for creating a stub for the public static void main(String[] args) method.

  2. Your new class opens in the Visual Editor. Select the panel in the design surface, and set its background property to lightGray. The layout property is already set to FlowLayout, which is what you want.

  3. Resize your panel. Add one Label bean and three Checkbox beans from the palette of AWT Controls.

  4. Set the label's text property to Text Label Here: and its font property to dialog, bold, 12.

  5. Set the Checkbox beans' label properties to First, Second, and Third, so that your SettingPanel now looks like Figure 5.26.

    Click To expand
    Figure 5.26: Visual elements added to the SettingPanel

  6. The WebSphere Java Development Kit (JDK) does not provide radio buttons as a distinct class or bean. To get the radio button look and the behavior of mutually exclusive selection, you use multiple Checkbox beans and associate them in a group using a CheckboxGroup bean. Use Choose Bean to select a CheckboxGroup bean from the java.awt package, and drop it on the free-form surface outside of your panel.

  7. Update the initialization methods for each of the Checkbox beans to set the CheckboxGroup bean as their CheckboxGroup, as shown in Figure 5.27. When you add the code to set the checkboxGroup property, the CheckboxGroup bean may disappear from the design surface—don't worry, it's still in your program.

    Start Figure

    // add code in bold to put Checkbox beans in a CheckboxGroup
private java.awt.Checkbox getCheckbox() {
  if(checkbox == null) {
   checkbox = new java.awt.Checkbox();
   checkbox.setLabel("First");
   checkbox.setCheckboxGroup(getIvjCheckboxGroup());
  }
  return checkbox;
}
private java.awt.Checkbox getCheckbox1() {
  if(checkbox1 == null) {
   checkbox1 = new java.awt.Checkbox();
   checkbox1.setLabel("Second");
   checkbox1.setCheckboxGroup(getIvjCheckboxGroup());
  }
  return checkbox1;
}
private java.awt.Checkbox getCheckbox2() {
  if(checkbox2 == null) {
   checkbox2 = new java.awt.Checkbox();
   checkbox2.setLabel("Third");
   checkbox2.setCheckboxGroup(getIvjCheckboxGroup());
  }
  return checkbox2;
}
    End Figure

    Figure 5.27: Adding Checkbox beans to the CheckboxGroup

Start Sidebar
When to use radio buttons

Use radio buttons when you need to select one and only one option from a group of choices (such as one color for the IClock background). Radio buttons are always used as a group of two or more choices. Although each radio button is a separate control, a cluster of radio buttons behaves as a single control.

You should never use a single radio button to give the user a binary choice; instead, use a check box. You should also use check boxes if you can select more than one item in a group.

End Sidebar

Save your changes, and test your panel (Run As → Java Bean / Applet). Note that, even though your components look like check boxes in the design view, they look like and behave as a radio button group at run time. The CheckboxGroup bean changed their behavior.

The visual elements of your SettingPanel bean are now ready. You just need to promote the features that you might want to change when you reuse this bean. You want to be able to change the label's text and the radio button labels, so you have to make each of these features accessible to other programs. You also want to let other programs know which radio button the user has chosen. Radio buttons fire an itemStateChanged event when the button is selected, so you need to make this event accessible to other programs.

Promoting properties

As you learned in the previous chapter, you make properties accessible to other programs by adding public methods to your subcomponent to let other programs get and set the values.

  1. In the source pane, add getLabelText() and setLabelText(String) methods, as shown in Figure 5.28. Since these method names conform to the standard naming convention for beans, development tools such as the Visual Editor recognize labelText as a property of your bean, so they show the property in the bean's property sheet.

    Start Figure

    // add get and set methods for the labelText property
public String getLabelText() {
   return getLabel().getText();
}
public void setLabelText(String text) {
   getLabel().setText(text);
}
    End Figure

    Figure 5.28: Promoting the label's text property

  2. Add getFirstOption() and setFirstOption(String) methods, as shown in Figure 5.29.

    Start Figure

    // add get and set methods for the firstOption property
public String getFirstOption() {
   return getCheckbox().getLabel();
}
public void setFirstOption(String label) {
   getCheckbox().setLabel(label);
}
    End Figure

    Figure 5.29: Promoting the first radio button's label property

  3. Add the getSecondOption() and setSecondOption(String) methods, as shown in Figure 5.30.

    Start Figure

    // add get and set methods for the secondOption property
public String getSecondOption() {
   return getCheckbox1().getLabel();
}
public void setSecondOption(String label) {
   getCheckbox1().setLabel(label);
}
    End Figure

    Figure 5.30: Promoting the second radio button's label property

  4. Add the getThirdOption() and setThirdOption(String) methods, as shown in Figure 5.31.

    Start Figure

    // add get and set methods for the thirdOption property
public String getThirdOption() {
   return getCheckbox2().getLabel();
}
public void setThirdOption(String label) {
   getCheckbox2().setLabel(label);
}
    End Figure

    Figure 5.31: Promoting the third radio button's label property

Promoting events

You learned how to promote events when you created the FileManipulationPanel subcomponent in Chapter 4. You'll do the same thing here to promote SettingPanel events to notify other programs when the user selects a radio button. The events you want your subcomponent to fire are

  • firstOptionSelected—fired when the user selects the first radio button

  • secondOptionSelected—fired when the user selects the second radio button

  • thirdOptionSelected—fired when the user selects the third radio button

You know which radio button has been selected by listening for the radio button's itemStateChanged event. When a radio button fires this event, you will fire the appropriate event from your bean to notify your subcomponent's listeners.

You don't need to pass along any special information when you fire your subcomponent's events, so you don't need to create a special event object. You do need to create a listener interface, register listeners, and fire the events at the appropriate times.

  1. To create the listener interface, right-click on clockPackage in the Package Explorer, and choose New → Interface from the pop-up menu.

  2. Enter SettingPanelListener as the interface name.

  3. Click the Add… button, enter EventListener in the Choose interfaces field and select java.util as the Qualifier (this makes your new interface extend java.util.EventListener). Click OK to return to the New Java Interface window.

  4. Click Finish.

  5. Your new interface opens in the standard Java Editor. Add method declarations for each of your bean's events, as shown in Figure 5.32.

    Start Figure

    // add code in bold to the SettingPanelListener interface public interface SettingPanelListener extends EventListener {
   void firstOptionSelected(java.util.EventObject e);
    void secondOptionSelected(java.util.EventObject e);
    void thirdOptionSelected(java.util.EventObject e);
}
    End Figure

    Figure 5.32: Defining the interface

  6. Save your changes and close the Java Editor.

Now go back to your SettingPanel bean to add the code to register listeners and fire events. To register and unregister listeners, you need to add two methods to your SettingPanel bean: addSettingPanelListener(SettingPanelListener) and removeSettingPanelListener(SettingPanelListener).

Follow these steps to register and unregister listeners:

  1. Add a declaration for a Vector to keep track of registered listeners, as shown in Figure 5.33.

    Tip

    Since you need to access this variable from several methods within your program, place it at the start of the class where the other class variables are defined.

    Start Figure

    // add a declaration for a Vector variable
private java.util.Vector listeners = new java.util.Vector();
    End Figure

    Figure 5.33: Adding a Vector to keep track of listeners

  2. Add an addSettingPanelListener(SettingPanelListener) method to add a listener to your Vector, as shown in Figure 5.34.

    Start Figure

    // add method to register listeners
public synchronized void addSettingPanelListener
        (SettingPanelListener listener) {
     listeners.addElement(listener);
}
    End Figure

    Figure 5.34: Method to register listeners

  3. Add a removeSettingPanelListener(SettingPanelListener) method to remove the listener from your Vector, as shown in Figure 5.35. (You won't actually use this method in this chapter, but, as you learned in Chapter 4, well-behaved beans need to be able to remove their listeners.)

    Start Figure

    // add method to unregister listeners
public synchronized void removeSettingPanelListener
        (SettingPanelListener listener) {
     listeners.removeElement(listener);
}
    End Figure

    Figure 5.35: Method to unregister listeners

Your bean now includes the necessary methods to register and unregister listeners. The final step is to fire your events at the appropriate times.

You have three events to fire:

  • firstOptionSelected—fires when the user selects the first radio button

  • secondOptionSelected—fires when the user selects the second radio button

  • thirdOptionSelected—fires when the user selects the third radio button

You need to listen for itemStateChanged events fired by each of the radio buttons, and fire the appropriate event from your own bean to notify your listeners. To listen for itemStateChanged events, you need an ItemListener for each radio button. The template for adding an ItemListener inner class is provided with WebSphere Studio, but it isn't automatically imported into the Workbench, so you must first import it.

  1. From the Window menu in the WebSphere Studio Workbench, select Preferences.

  2. Click on the + sign next to Java to expand the possible preferences for Java projects, and then select Templates.

  3. Click on the Import… button on the right edge of the window and browse to the/wstools/eclipse/plugins/com.ibm.etools.jbcf.codegen_5.0.1/Examples/Templates/java/awt/event folder under the folder where you installed WebSphere Studio (for example, C:/Program Files/IBM/WebSphere/Express/SiteDeveloper).

  4. Select the addItemListener.xml file and click Open. The template for ItemListeners is added to the list.

  5. Click OK.

  6. To fire your firstOptionSelected event, select the first radio button on the design surface to scroll to its method in your source code, and use content assist to add an ItemListener, as shown in Figure 5.36.

    Start Figure

    // code in bold added by content assist
private java.awt.Checkbox getCheckbox() {
  if(checkbox == null) {
   checkbox = new java.awt.Checkbox();
   checkbox.setLabel("First");
   checkbox.setCheckboxGroup(getIvjCheckboxGroup());
   checkbox.addItemListener(new java.awt.event.ItemListener() {
         public void itemStateChanged(java.awt.event.ItemEvent e) {
                ;
         }
   });
  }
  return checkbox;
}
    End Figure

    Figure 5.36: Listener for radio button itemStateChanged events

  7. Add code to the itemStateChanged(ItemEvent) method to fire your firstOptionSelected event, as shown in Figure 5.37. Note that you use the ItemEvent to determine if the radio button was selected or deselected. You only want to pass along events when the radio button is selected.

    Start Figure

      // add code in bold to fire firstOptionSelected events
  private java.awt.Checkbox getCheckbox() {
    if(checkbox == null) {
     checkbox = new java.awt.Checkbox();
     checkbox.setLabel("First");
     checkbox.setCheckboxGroup(getIvjCheckboxGroup());
     checkbox.addItemListener(new java.awt.event.ItemListener() {
         public void itemStateChanged(java.awt.event.ItemEvent e) {
           if (e.getStateChange() == java.awt.event.ItemEvent.SELECTED) {
              java.util.EventObject evt = new java.util.EvenObject(this);
             java.util.Vector v;
             synchronized (this)
                    {v = (java.util.Vector) listeners.clone();}
             java.util.Iterator iter = v.iterator();
             while (iter.hasNext())
                ((SettingPanelListener)
                    iter.next()).firstOptionSelected(evt);
           }
         }
     });
  }
  return checkbox;
}
    End Figure

    Figure 5.37: Firing the firstOptionSelected event

  8. Add an ItemListener for the second radio button, and add code to the itemStateChanged(ItemEvent) method to fire your bean's secondOptionSelected event when the user selects the second radio button, as shown in Figure 5.38.

    Start Figure

    // add code to fire secondOptionSelected events
private java.awt.Checkbox getCheckbox1() {
  if(checkbox1 == null) {
   checkbox1 = new java.awt.Checkbox();
   checkbox1.setLabel("Second");
   checkbox1.setCheckboxGroup(getIvjCheckboxGroup());
   checkbox1.addItemListener(new java.awt.event.ItemListener() {
     public void itemStateChanged(java.awt.event.ItemEvent e) {
      if (e.getStateChange() == java.awt.event.ItemEvent.SELECTED) {
        java.util.EventObject evt = new java.util.EventObject(this);
         java.util.Vector v;
         synchronized (this)
                 {v = (java.util.Vector) listeners.clone();}
         java.util.Iterator iter = v.iterator();
         while (iter.hasNext())
           ((SettingPanelListener)
                iter.next()).secondOptionSelected(evt);
       }
     }
   });
  }
  return checkbox1;
}
    End Figure

    Figure 5.38: Firing the secondOptionSelected event

  9. Add an ItemListener for the third radio button, and add code to the itemStateChanged(ItemEvent) method to fire your bean's thirdOptionSelected event when the user selects the third radio button, as shown in Figure 5.39.

    Start Figure

    // add code in bold to fire thirdOptionSelected events
private java.awt.Checkbox getCheckbox2() {
  if(checkbox2 == null) {
   checkbox2 = new java.awt.Checkbox();
   checkbox2.setLabel("Third");
   checkbox2.setCheckboxGroup(getIvjCheckboxGroup());
   checkbox2.addItemListener(new java.awt.event.ItemListener() {
   public void itemStateChanged(java.awt.event.ItemEvent e) {
     if (e.getStateChange() == java.awt.event.ItemEvent.SELECTED) {
          java.util.EventObject evt = new java.util.EventObject(this);
          java.util.Vector v;
          synchronized (this)
                {v = (java.util.Vector) listeners.clone();}
          java.util.Iterator iter = v.iterator();
          while (iter.hasNext())
           ((SettingPanelListener)
                iter.next()).thirdOptionSelected(evt);
       }
     }
   });
  }
  return checkbox2;
}
    End Figure

    Figure 5.39: Firing the thirdOptionSelected event

Your bean is now ready to use. Save your changes.

For the convenience of programmers who will use your bean in WebSphere Studio, you may also want to provide an event-handling template. We have one for you on the CD included with this book. Follow these steps to import the template into the WebSphere Studio Workbench.

  1. From the Window menu in the WebSphere Studio Workbench, select Preferences.

  2. Click on the + sign next to Java, and then select Templates.

  3. Click on the Import… button on the right edge of the window and browse to the /solutions/chap05/ subdirectory on the CD included with this book.

  4. Select the [image] addSettingPanelListener.xml file and click Open. The template for SettingPanelListeners is added to the list.

  5. Click OK.

CardLayout manager

This section shows how to use your new SettingPanel bean to build a Clock application with the CardLayout manager.

The CardLayout allows two or more components to share the same display area. CardLayout arranges components in a linear depth sequence (like a deck of cards). Each component included in the deck is called a card. You add components to the CardLayout parent, which is the container that holds the cards. Conceptually, each component in a CardLayout manager is like a playing card; only the top card is visible at any time. You can choose the card that is showing in any of the following ways:

  • By flipping through the deck using previous or next

  • By specifying a card with a specific name

  • By asking for either the first or last card in the order it was added to the container

What you are going to create

We want to use the CardLayout for an additional panel that will include three SettingPanel beans for the different kinds of settings: digit colors, background colors, and format settings (short, long, or full format of time). The main purpose of the CardLayout manager in this example is to save application window space and put all the necessary settings in one place, which makes it easier to manipulate the Clock. Figures 5.40, 5.41 and 5.42 each show a different SettingPanel, but they all appear in the same place. The >> button lets you switch between the different SettingPanels.

Click To expand
Figure 5.40: Background color panel in use
Click To expand
Figure 5.41: Digits color panel in use
Click To expand
Figure 5.42: Date format panel in use

Initial preparation

Before you begin, you need to remove all the unnecessary components from your Clock composition:

  1. Remove the digits color panel (with buttons) from your composition (simply select the panel on the design surface and press the Delete key).

  2. Remove the background color panel (with buttons) from your composition.

  3. Remove the left and right empty labels from your composition.

  4. Change the digitalBackGroundColor of the IClock to white.

Your composition should look like Figure 5.43.

Click To expand
Figure 5.43: Initial panel for CardLayout Clock application

Adding the SettingPanel beans

Now, add the SettingPanel beans. You will need three instances of the bean for this application.

  1. Use Choose Bean to select a SettingPanel bean from the clockPackage package, and drop the bean on the freeform surface outside of your application's frame.

  2. Set the SettingPanel's labelText property to Format settings:, the firstOption property to Full, the secondOption property to Long, and the thirdOption property to Short, so your design surface looks like Figure 5.44.

    Click To expand
    Figure 5.44: Date format panel design

Repeat the previous steps and add two more SettingPanel beans to your free-form surface. Set their properties as shown in Table 5.1.

Table 5-1: Properties for additional SettingPanel beans
Property | Second SettingPanel bean | Third SettingPanel bean
LabelText | Digits: | Background:
firstOption | green | gray
secondOption | yellow | black
thirdOption | red | white

Making Connections

Make the following connections for the three SettingPanel beans.

  1. Use content assist to add a SettingPanelListener to the first SettingPanel bean, as shown in Figure 5.45.

    Start Figure

    // code in bold added by content assist
private clockPackage.SettingPanel getSettingPanel() {
  if(settingPanel == null) {
   settingPanel = new clockPackage.SettingPanel();
   settingPanel.setLabelText("Format settings:");
   settingPanel.setFirstOption("Full");
   settingPanel.setSecondOption("Long");
   settingPanel.setThirdOption("Short");
  settingPanel.addSettingPanelListener(new SettingPanelListener()
{
       public void firstOptionSelected(java.util.EventObject e) {
            ;
       }
       public void secondOptionSelected(java.util.EventObject e) {
            ;
       }
       public void thirdOptionSelected(java.util.EventObject e) {
            ;
       }
     });
    }
    return settingPanel;
}
    End Figure

    Figure 5.45: Adding a SettingPanelListener

  2. Add code to the SettingPanelListener to take the appropriate actions when the user selects a radio button in this SettingPanel, as shown in Figure 5.46. For this panel, you want to set the IClock bean's digitalDisplayStyle property to FULL (0), LONG (1), or SHORT (2) on the basis of the radio button selected.

    Start Figure

    // add code in bold to handle events fired by first SettingPanel
private clockPackage.SettingPanel getSettingPanel() {
  if(settingPanel == null) {
   settingPanel = new clockPackage.SettingPanel();
   settingPanel.setLabelText("Format settings:");
   settingPanel.setFirstOption("Full");
   settingPanel.setSecondOption("Long");
   settingPanel.setThirdOption("Short");
   settingPanel.addSettingPanelListener(new SettingPanelListener() {
     public void firstOptionSelected(java.util.EventObject e) {
          getIClock().setDigitalDisplayStyle(0);
     }
     public void secondOptionSelected(java.util.EventObject e) {
          getIClock().setDigitalDisplayStyle(1);
     }
     public void thirdOptionSelected(java.util.EventObject e) {
          getIClock().setDigitalDisplayStyle(2);
     }
   });
  }
  return settingPanel;
}
    End Figure

    Figure 5.46: Setting digitalDisplayStyle on the basis of the radio button selected

  3. Add a SettingPanelListener to the second SettingPanel bean, and take the appropriate actions to set the IClock bean's digitalForeGroundColor property on the basis of the radio button selected, as shown in Figure 5.47 (on top of following page).

    Start Figure

    // add code in bold to handle events fired by second SettingPanel
private clockPackage.SettingPanel getSettingPanel2() {
  if(settingPanel2 == null) {
   settingPanel2 = new clockPackage.SettingPanel();
   settingPanel2.setLabelText("Digits:");
   settingPanel2.setFirstOption("green");
   settingPanel2.setSecondOption("yellow");
   settingPanel2.setThirdOption("red");
   settingPanel2.addSettingPanelListener(new SettingPanelListener() {
    public void firstOptionSelected(java.util.EventObject e) {
    getIClock().setDigitalForeGroundColor(java.awt.Color.green);
    }
    public void secondOptionSelected(java.util.EventObject e) {
    getIClock().setDigitalForeGroundColor(java.awt.Color.yellow);
    }
    public void thirdOptionSelected(java.util.EventObject e) {
    getIClock().setDigitalForeGroundColor(java.awt.Color.red);
    }
   });
  }
  return settingPanel2;
}
    End Figure

    Figure 5.47: Handling events fired by the second SettingPanel bean

  4. Add a SettingPanelListener to the third SettingPanel bean, and take the appropriate actions to set the IClock bean's digitalBackGroundColor property on the basis of the radio button selected, as shown in Figure 5.48 (on bottom of following page).

    Start Figure

    // add code in bold to handle events fired by third SettingPanel
private clockPackage.SettingPanel getSettingPanel3() {
  if(settingPanel3 == null) {
   settingPanel3 = new clockPackage.SettingPanel();
   settingPanel3.setLabelText("Background:");
   settingPanel3.setFirstOption("gray");
   settingPanel3.setSecondOption("black");
   settingPanel3.setThirdOption("white");
   settingPanel3.addSettingPanelListener(new SettingPanelListener() {
    public void firstOptionSelected(java.util.EventObject e) {
    getIClock().setDigitalBackGroundColor(java.awt.Color.gray);
    }
    public void secondOptionSelected(java.util.EventObject e) {
    getIClock().setDigitalBackGroundColor(java.awt.Color.black);
    }
    public void thirdOptionSelected(java.util.EventObject e) {
    getIClock().setDigitalBackGroundColor(java.awt.Color.white);
    }
   });
  }
  return settingPanel3;
}
    End Figure

    Figure 5.48: Handling events fired by the third SettingPanel bean

Creating the card container panel

You have prepared three SettingPanel beans—three cards for your future card container panel. Now it's time to add the card container panel itself.

  1. Select a Panel bean from the palette of AWT Controls, and drop it on the South portion of the Clock application's frame (check the source code to make sure the panel was added to the frame's surface in the initialize() method, not the IClock's surface in the getIClock() method).

  2. Set the panel's layout property to CardLayout. Your design surface should now look like Figure 5.49. Notice that the card container panel currently uses just a small area at the bottom of the frame. That will change once you add the SettingPanel beans to it.

    Click To expand
    Figure 5.49: The initial CardLayout panel

You want to add each of the SettingPanel beans as cards in the card container panel. You can do this by moving elements on the design surface or by updating the source code directly, but the Visual Editor has an easier way. In the Java Beans view, select the first SettingPanel bean and drop it on the card container panel, so that it becomes a child component under the card container panel, as shown in Figure 5.50.

Click To expand
Figure 5.50: Using the Java Beans view to add a card to the card container panel

Notice that source code is added to the getPanel() method to add the first SettingPanel bean to the card container panel, and that on the design surface, the SettingPanel now appears on the same surface as the card container panel. Repeat these steps to drop the other two SettingPanel beans on the card container panel, so that the Java Beans view looks like Figure 5.51.

Click To expand
Figure 5.51: All SettingPanel beans added to the card container panel
Tip

To change which of the cards is visible on the design surface, select the card you want in the Java Beans view.

You still need one more component: the >> button, which switches the SettingPanels in the card container panel.

  1. Select a Button bean from the palette of AWT Controls, and drop it on the North portion of the frame (check the source code to make sure the button was added to the frame's surface in the initialize() method, not the IClock's surface in the getIClock() method).

  2. Set the button's label property to >>, so your design surface looks like Figure 5.52.

    Click To expand
    Figure 5.52: Adding the button to the frame

  3. Use content assist to add an ActionListener to the button, as shown in Figure 5.53.

    Start Figure

    // code in bold added by content assist
private java.awt.Button getButton() {
  if(button == null) {
   button = new java.awt.Button();
   button.setLabel(">>");
   button.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent e) {
      }
    });
  }
  return button;
}
    End Figure

    Figure 5.53: ActionListener added to button

  4. To switch to the next card whenever the button is clicked, you call the next(java.awt.Container) method of the CardLayout associated with the card container panel. You pass the card container panel as the parameter to this method, as shown in Figure 5.54.

    Start Figure

    // add code in bold to switch to the next card
private java.awt.Button getButton() {
  if(button == null) {
   button = new java.awt.Button();
   button.setLabel(">>");
   button.addActionListener(new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent e) {
         java.awt.CardLayout layout =
                   (java.awt.CardLayout) getPanel().getLayout();
          layout.next(getPanel());
     }
   });
  }
  return button;
}
    End Figure

    Figure 5.54: Code to switch to the next card

Now, save your changes and test the application.

If you had any problems building this version of the Clock application, look at the solution files in the /solutions/chap05/clockPackage subdirectory on the CD included with this book. Import the following files into the package named solutions.chap05.clockPackage in your ClockProject project:

  • /solutions/chap05/clockPackage/ClockCardLayout.java

  • /solutions/chap05/clockPackage/SettingPanel.java

  • /solutions/chap05/clockPackage/SettingPanelListener.java

Use the Visual Editor to open the visual classes (ClockCardLayout.java and [image] SettingPanel.java), and use the standard Java Editor to open the non-visual class (SettingPanelListener.java).


GridLayout manager

A GridLayout manager places components in a grid of cells; each component takes up all the available space within its cell, and each cell is exactly the same size as all the others. When you resize the GridLayout window, the GridLayout changes the cell size so that all the cells are as big as possible, given the space available to the enclosing container. GridLayout is often used for data entry forms because it can keep text fields and labels and labels aligned. When you change a container's layout to GridLayout, two additional properties appear in the Properties view: columns and rows. These properties let you specify the number of columns and rows for your grid, as shown in Figure 5.55.

Click To expand
Figure 5.55: GridLayout example

You'll use GridLayout for several of the applications you'll build later in this book.


BoxLayout manager

BoxLayout either places its components in a tight row from left to right or stacks them on top of each other (with the first component at the top). It is quite similar to FlowLayout, but the components don't wrap to the next line. BoxLayout is typically used for toolbars or menu bars, where you don't want to wrap components. Another difference between it and FlowLayout is that FlowLayout respects the preferred size of the components, while BoxLayout uses the minimum size of the components. As a result, components in a FlowLayout have margins, while components in a BoxLayout are narrower, giving it the appearance of a toolbar.

Figure 5.56 shows an example of BoxLayout properties.

Click To expand
Figure 5.56: BoxLayout example

You'll use BoxLayout(Y_AXIS) for one of the applications you build in Chapter 6.


GridBagLayout manager

GridBagLayout is the most flexible (and, therefore, the most complicated) layout manager that the Java 1.3 platform provides. A GridBagLayout places its components in a grid of rows and columns, allowing some components to span multiple rows or columns. In addition, all the rows do not necessarily have the same height and not all the columns necessarily have the same width. The GridBagLayout manager places components in the cells of the grid and then uses the preferred sizes of the components to calculate how big the cells should be. We used a GridBagLayout in Chapter 4 without really using many of its features. You'll use GridBagLayout for several of the applications you build later in this book.

Figure 5.57 shows an example of a GridBagLayout. As you can see, the grid has four rows and three columns. The label in the fourth row spans two columns, and the button in the first column spans two rows.

Click To expand
Figure 5.57: GridBagLayout example

The size and position characteristics of a component placed on a GridBagLayout container are specified by the constraint property, which is a GridBagConstraints object. The GridBagConstraints object has the following properties:

  • The anchor determines the location in the GridBag cell in which the GUI bean anchors itself. Directional values for this property are CENTER, NORTH, NORTHWEST, NORTHEAST, SOUTH, SOUTHWEST, SOUTHEAST, EAST, and WEST. The default value is CENTER.

  • The fill specifies which directions the GUI bean fills or grows as the GridBag is resized. Valid settings are NONE, BOTH, HORIZONTAL, and VERTICAL. The default value is NONE.

  • The gridheight and gridwidth are the number of cells that the GUI bean spans or occupies. By default, the GUI bean occupies one cell.

  • The gridx and gridy properties are the GridBag x and y coordinates for the bean.

  • The insets properties are the padding outside the GUI bean, specified in pixels. There are separate insets for top, bottom, right, and left.

  • The ipadx and ipady properties are the padding inside the GUI bean, specified in pixels. They are frequently used to increase the size of a GUI bean and give the effect of having a border around the bean.

  • The weightx and weighty properties specify how the GUI bean uses extra space. These properties are typically specified as values between 0 and 1, where components with higher weight values receive more space.

All these properties might seem too complex to code yourself, but, in fact, the Visual Editor does much of the work for you. As you saw in Chapter 4, when you build a GUI with GridBagLayout, the Visual Editor creates GridBagConstraints objects for you. All you need to do is drop your elements on the design surface and modify their properties in the Properties view. As another option, you can build your GUI interface with a null layout and then change the layout property to GridBagLayout. The Visual Editor automatically converts the elements to the appropriate GridBagLayout constraints.


In review

This chapter demonstrated how the Java platform's layouts provide a powerful GUI design facility. You learned how to use FlowLayout, BorderLayout, and CardLayout to develop applications in the Visual Editor. You also learned how to use radio button components and gained more practice building subcomponents.


Exercise

Add another card to your card container panel to let the user change the IClock's font to bold, italic, and plain values.

A solution file for this exercise is in the /solutions/chap05/clockPackage subdirectory on the CD included with this book. Import [image] ClockCardLayoutExer1.java into the package named solutions.chap05.clockPackage in your ClockProject project, and open it with the Visual Editor to compare your program with the solution file.

The solution file assumes that the [image] SettingPanel.java and [image] SettingPanelListener.java files in the /solutions/chap05/clockPackage subdirectory on the CD included with this book have also been imported into the package named solutions.chap05.clockPackage, so import these files, too, if you haven't already done so.


Chapter 6: Using Swing Components

Download CD Content

In the previous chapters you used many components from the Visual Editor's palette of Abstract Window Toolkit (AWT) controls. You may have already tried out the other palette categories and noticed the similarities between Swing components and AWT controls. The Swing palette categories contain components with similar names such as JButton, JLabel, and so on, which correspond to the AWT controls you've already used. So why do you need two types of button and label beans? What's the difference between the AWT and Swing components? Which components are better to use in a particular situation? This chapter answers these questions, as well as many others.

Java Foundation Classes and Swing

Swing is one of the technologies in the Java Foundation Class (JFC) libraries, the suite of libraries designed for building advanced Graphical User Interfaces (GUIs) with Java. The Swing palette categories in the Visual Editor (shown in Figure 6.1) contain three sets of visual JavaBeans: Swing Containers, Swing Components, and Swing Menus.

Click To expand
Figure 6.1: The Swing palette categories in the Visual Editor

The Swing Containers palette category includes counterparts to AWT containers you've already used, such as frames and panels. It also includes new containers, such as JTabbedPane and JSplitPane, which are not available as AWT controls. The Swing Components palette category has counterparts to the AWT conrols for such things as buttons, text fields, and labels. It also contains new components, such as JSlider and JProgressBar. The Swing Menus palette category includes controls for adding menus to your applications.

Look and feel

So, what makes Swing so exciting? Let's start with an example. Imagine you are creating an application for a large enterprise. Your application will be used by many people who are working on computers with different operating systems, such as Windows, Unix, and Macintosh. If you look at the visual components on the screens of the various machines, they do not all appear the same. The visual components on a screen look different because of a concept called look and feel. Macintosh users expect buttons to look a certain way, while Windows users expect buttons to look another way. As you know, Java programs are platform-independent, which means that they can work on any computer system. Java programs with AWT controls use the operating system's platform widgets, which means that an AWT button looks and behaves the same as buttons in any other program on the user's desktop. This gives AWT a high fit and finish with the user's other programs and is why AWT is sometimes called a heavyweight lookit, because it uses native underlying resources.

The disadvantage of AWT is that for each platform on which Java runs, a set of native widgets must be found for each GUI class. This leads to a lowest common denominator effect and is why AWT doesn't include rich user interface controls such as a tree, table, or notebook. Swing, by contrast, does not use native widgets for each of its GUI classes, but instead emulates the control's appearance using a low-level drawing API. This is why Swing is often referred to as a lightweight toolkit and is why it is able to provide such a rich set of GUI controls on all platforms.

One of the powerful design features of Swing is that it lets you create a more flexible application that can change its look and feel properties during run time, allowing the user to switch to different look and feels in order to select the most comfortable interface. Because Swing emulates the appearance of its controls, it does not necessarily need to make the appearance follow that of the operating system. The rendering of each Swing control is handled by the look and feel subsystem, so the look and feel of each component can be easily changed. Figure 6.2 shows examples of two common look and feels.

Click To expand
Figure 6.2: Look-and-feel examples

Swing or AWT?

Swing has many advantages over the older AWT components:

  • You can select from a wide variety of new rich user interface components such as tables, sliders, progress bars, internal frames, and text components.

  • You can show tool tips over components. A tool tip is a textual pop-up that momentarily appears when the mouse cursor points at the component.

  • You can arbitrarily bind keyboard events to components, defining how they will react to various keystrokes under given conditions.

  • You can use a lot of new visual features such as transparency, cursor type, built-in reaction on mouse movement events, and icons.

  • You can let users select the look and feel they prefer, rather than using the system's native look and feel.

So, is Swing replacing AWT? Not entirely—at least not for applet development. One of the main difficulties with Swing is that not all browsers support Swing, but there are ways you can get around this problem, as you'll see later in this chapter.

What you will create

In this chapter, you are going to create two applications that demonstrate Swing features. First is the SwingToDoList application, which is similar to the ToDoList application you built in Chapter 3. The SwingToDoList has basically the same functionality as the AWT-based ToDoList, but it highlights a variety of new opportunities provided by Swing. This example also demonstrates the differences in creating the same application with Swing components instead of AWT controls.

The second application that you will create shows you an example of using Swing's Model-View-Controller architecture. This scheme is native to Swing components; it lets you divide visual features and controlling features into different beans. The TimeModelDemo application combines three devices: a clock, a timer, and an alarm. It also illustrates Swing components such as JTabbedPane, JSlider, and JProgressBar.

The last sections of this chapter discuss the pros and cons of creating Swing applets and show how you can change the look and feel of your applications.


Creating a Swing application

In this section, you'll create the SwingToDoList application. You begin by setting up a new project, package, and visual class for the application.

  1. The beans you use in the SwingToDoList application (BoundJList and BoundJTextField) are in the [image] chap06.jar file. Copy [image] chap06.jar from the /solutions/chap06/ subdirectory on the CD included with this book to a folder on your machine, such as C:/beans.

  2. In the Java perspective in WebSphere Studio, create a new Java Project called SwingDemonstration. Specify [image] chap06.jar as an external JAR file on the Libraries tab.

  3. Create a new package called swingToDoListPackage in your SwingDemonstration project.

  4. To create the class for your application, right-click on swingToDoListPackage in the Package Explorer, and choose New → Visual Class from the pop-up menu.

  5. Enter SwingToDoList as the class name.

  6. Select Frame as the visual class to extend, and check the Swing check box (these should already be set as the defaults). This makes javax.swing.JFrame the superclass for your new visual class. JFrame is the Swing counterpart to the Frame class you used for AWT-based applications.

  7. Since your program will run as an application, it will need a main method. Check the check box to have WebSphere Studio create a stub for the main method, and uncheck any other check boxes to create method stubs.

  8. Click Finish.

Your new SwingToDoList class opens in the Visual Editor. Notice that in addition to creating the main method stub, the Visual Editor also creates a ContentPane component and places it in the JFrame. The ContentPane is a JPanel bean, the Swing counterpart to the Panel bean you've already used. As you add visual elements to your application, you add them to the ContentPane container, rather than the JFrame. ContentPane is used because, unlike AWT, you cannot add child components directly to the JFrame. Instead you must add them to its ContentPane, which is the area the JFrame sets aside for its child components. The Visual Editor creates the code for the ContentPane, so it can be selected on the design surface and in the Java Beans view.

Setting up the JFrame and ContentPane

Just as you did with the AWT-based ToDoList application, you need to set up your new SwingToDoList application to show the JFrame when the application starts, initialize the JFrame's properties, and close the JFrame's window when the application ends, but there ae some differences in how you implement some of these functions.

  1. Add code to the main method to create an instance of your application's JFrame and make it visible, as shown in Figure 6.3.

    Start Figure

    // add code in bold to create an instance of the JFrame and show it
   public static void main(String[] args) {
      SwingToDoList frame = new SwingToDoList();
      frame.show();
}
    End Figure

    Figure 6.3: Creating an instance of the application frame

  2. Select the JFrame in the design surface, grab one corner of the rectangle, and drag it to increase its size.

  3. Set the title property of the JFrame to SwingToDoList.

  4. Set the defaultCloseOperation property of the JFrame to EXIT. This is one example of how Swing makes things easier for you. With AWT, you had to add a WindowListener to the Frame to exit the program when the window was closed. With Swing, you just set the JFrame's defaultCloseOperation property to EXIT.

  5. Select the ContentPane in the design surface (the inner surface of the JFrame), and set the ContentPane's layout property to GridBagLayout.

Adding visual components

Now you're ready to start adding visual elements to your application.

  1. Add a JButton bean from the Swing Components palette category to the ContentPane, and set its properties as follows:

    • text to Add

    • constraint-gridx to 0

    • constraint-gridy to 0

    • constraint-fill to HORIZONTAL

    • constraint-anchor to NORTHEAST

    • constraint-insets to 1,1,1,1

  2. Use Choose Bean to select a BoundJTextField bean from the com.ibm.easyswing package, and drop it on the ContentPane (you can drop it anywhere on the ContentPane-you'll set properties to position it). Set the BoundJTextField bean's properties as follows:

    • text to 10

    • horizontalAlignment to LEFT

    • constraint-weightx to 0

    • constraint-gridx to 0

    • contraint-gridy to 1

    • constraint-fill to HORIZONTAL

    • constraint-anchor to NORTHEAST

    • constraint-insets to 1,1,1,1

  3. Add a second JButton bean to the ContentPane, and set its properties as follows:

    • text to Clear

    • constraint-gridx to 0

    • constraint-gridy to 2

    • constraint-fill to HORIZONTAL

    • constraint-anchor to NORTHEAST

    • constraint-insets to 1,1,1,1

  4. Add a third JButton bean to the ContentPane, and set its properties as follows, so that your design surface now looks like Figure 6.4.

    • text to Remove

    • constraint-gridx to 0

    • constraint-gridy to 3

    • constraint-fill to HORIZONTAL

    • constraint-anchor to NORTHEAST

    • constraint-insets to 1,1,1,1

    Click To expand
    Figure 6.4: Adding visual elements to the ContentPane

Renaming visual components

So far, you've used the default variable names supplied by the Visual Editor, so for example, the JButtons that you just added to your application are named jButton, jButton1, and jButton2. The Visual Editor lets you rename variables for visual components that you drop on the design surface. Let's see how this works.

  1. Save your changes.

    Tip

    All modified resources must be saved before you rename fields. If you have any unsaved changes, you'll be prompted to save them.

  2. Either on the design surface or in the Java Beans view, right-click on the first JButton bean, and select Rename Field from the pop-up menu.

  3. Enter addButton as the new name and check all of the check boxes, as shown in Figure 6.5.

    Click To expand
    Figure 6.5: The Rename Field window

  4. Click Finish. All references to the jButton variable are changed to references to addButton.

  5. Rename boundJTextField to maxEntries.

  6. Rename jButton1 to clearButton.

  7. Rename jButton2 to removeButton, so that the Java Beans view looks like Figure 6.6.

    Click To expand
    Figure 6.6: Java Beans view with renamed visual components

Setting the icon property

The first new Swing feature we are going to use is the icon feature. You can add an icon to almost all Swing components. Icons can be aligned horizontally and vertically. Let's add icons to the three buttons.

You specify the icons to use for Swing components as simple graphic files (.gif, .jpg, or .ico files). You can create images yourself using your favorite graphic editor or ask your designer to set them up for your project. To use images in your application, you need to do the following:

  • Create image files.

  • Import the image files into your WebSphere Studio project.

For this example, all the necessary images are provided on the CD included with this book. Follow these steps to import the image files into your SwingDemonstration project in WebSphere Studio:

  1. In the Package Explorer, right-click on swingToDoListPackage and select Import… from the pop-up menu.

  2. Select File system as the import source, and click Next.

  3. Click the Browse… button next to the Directory field, and browse to the /solutions/chap06/swingToDoListPackage folder on the CD included with this book. Click OK.

  4. Select all the image files in the folder, and click Finish.

The image files are added to the Package Explorer under swingToDoListPackage in the SwingDemonstration project. Now you can use the images in your application.

  1. Select the Add button on the design surface.

  2. Choose the icon property in the Properties view and click the small square button on the right of the icon property's value. The Select an Image File window appears.

  3. Click the + sign next to SwingDemonstration, select swingToDoListPackage, and select the [image] add.gif file, as shown in Figure 6.7.

    Click To expand
    Figure 6.7: Selecting an image file

  4. Click OK.

  5. Repeat the preceding steps to set the [image] clear.gif image as the icon for the Clear button.

  6. Set the [image] remove.gif image as the icon for the Remove button, so the design surface looks like Figure 6.8.

    Click To expand
    Figure 6.8: All three buttons with icons

Setting the alignment and text position

As you can see, the images on the buttons are not aligned the same way. To improve the design, you need to change the horizontalAlignment and horizontalTextPosition properties of the buttons. The horizontalAlignment allows you to align the icon and text relative to the button borders. The horizontalTextPosition defines the position of the text relative to the icon.

Arrange and align the icons and text on the buttons by doing the following:

  1. Set the horizontalAlignment property of all three buttons to LEFT.

  2. Set the horizontalTextPosition property of all three buttons to RIGHT, so that the design surface looks like Figure 6.9.

    Click To expand
    Figure 6.9: Buttons made tidy

Tip

For an easy way to modify common properties for a group of visual elements, hold down the Shift key and use the mouse to select the elements on the design surface that you want to work with. Now when you modify any property in the Properties view, the Visual Editor applies the change to all of the selected beans. You can also use the Marquee function to select a group of visual elements. Click on Marquee at the top of the Visual Editor's palette, and use the mouse to drag out an area on the design surface. If this selects more elements than you want, hold down the Ctrl key and click on the elements you want to remove from the selection group.

Setting the toolTipText property

Another new feature of Swing's visual components is the tool tip. You can add text to a component's toolTipText property to display brief help regarding the component. At run time, when the user moves the mouse pointer over the component's surface, its toolTipText appears next to the component.

  1. Set the toolTipText property of the Add button to Add Task.

  2. Set the toolTipText property of the Clear button to Clear Task List.

  3. Set the toolTipText property of the Remove button to Remove Task.

  4. Set the toolTipText property of the maxEntries field to Maximum Number of Tasks.

Save your changes and test the SwingToDoList application.

Reminder

To run an application, click on the arrow next to the Run icon in the toolbar, and choose Run As → Java Application. If you receive the error message "Launch failed: no main type found" when you try to run the application, make sure the application class is selected in the Workbench.

Your application should look like Figure 6.10.

Click To expand
Figure 6.10: Running application with tool tips

Adding Rollover buttons

You can see examples of rollover buttons when browsing Internet pages. These buttons change color each time you point your mouse at them. Usually, this effect is achieved by replacing one image with another during the MouseIn and MouseOut events. You can add this same effect to your Swing applications.

To add the rollover effect to your buttons, do the following:

  1. Set the [image] add_on.gif file as the rolloverIcon property of the Add button. Use the same steps you used to specify images for the icon property. Make sure the rolloverEnabled property of the Add button is true.

  2. Set the [image] clear_on.gif file as the rolloverIcon property of the Clear button. Make sure the rolloverEnabled property of the Clear button is true.

  3. Set the [image] remove_on.gif file as the rolloverIcon property of the Remove button. Make sure the rolloverEnabled property of the Remove button is true.

Save your changes and test the application. When you move the cursor over any of the buttons, the corresponding icon should change color from blue to red.

Changing the cursor

Another fun feature found on Internet pages is when the cursor changes its shape on links and appears as a hand. Sometimes it is useful to change the default cursor appearance for a particular component. To set the cursor shape for the buttons to a hand, do the following:

  1. Set the cursor property of the Add button to Hand.

  2. Set the cursor property of the Clear button to Hand.

  3. Set the cursor property of the Remove button to Hand.

Save your changes and test the application. Each time you point the mouse pointer at a button, the cursor shape changes to a hand.

Adding pressedIcon images

Another event for which you might want a visual signal is the button-pressed event. Use the pressedIcon property of the JButton bean to set the image for the JButton in a pressed state.

  1. Set the [image] add_pr.gif file as the pressedIcon property of the Add button. Use the same scenario as that for the icon property.

  2. Set the [image] clear_pr.gif file as the pressedIcon property of the Clear button.

  3. Set the [image] remove_pr.gif file as the pressedIcon property of the Remove button.

Save your changes and test the application. Now each time you click a button, its icon changes into the pressed icon image, as shown in Figure 6.11.

Click To expand
Figure 6.11: Running application with pressed icon images


Completing the SwingToDoList application

Now it's time to place the remaining visual components on the ContentPane and make the connections to complete your SwingToDoList application.

Adding the task field

  1. Add a JTextField bean from the Swing Components palette category to the ContentPane and set its properties as follows:

    • constraint-gridx to 1

    • constraint-gridy to 0

    • constraint-fill to HORIZONTAL

    • constraint-weightx to 1

    • constraint-insets to 1,1,1,1

    • toolTipText to Input Task Here

  2. Rename the JTextField to taskField (you will be prompted to save modified resources).

Your design surface should now look like Figure 6.12.

Click To expand
Figure 6.12: Adding a JTextField

Adding a JScrollPane and BoundJList

Unlike the AWT List component, the Swing JList and BoundJList beans do not contain any scrolling mechanism. So, if you want to be able to scroll the list of tasks, you have to put the JList or BoundJList into a JScrollPane container.

  1. Put a JScrollPane bean from the Swing Containers palette category on the ContentPane.

  2. Set the following properties for the JScrollPane:

    • constraint-gridx to 1

    • constraint-gridy to 1

    • constraint-gridheight to 4

    • constraint-fill to BOTH

    • constraint-insets to 1,1,1,1

  3. Use Choose Bean to select a BoundJList bean from the com.ibm.easyswing package and drop it on the JScrollPane, so that the design surface looks like Figure 6.13.

    Click To expand
    Figure 6.13: Final visual layout for SwingToDoList application

  4. Rename the BoundJList to taskList.

The visual stage of the application is complete. Now you just need to connect the beans together to add the functionality.

Making connections

First, add the connections to make button clicks work for the Add, Clear, and Remove buttons:

  1. Select the Add button on the design surface, to scroll to the code for it in the source pane. Use content assist to add an ActionListener to the button, and add code to the actionPerformed(ActionEvent) method to take the appropriate actions when the user clicks the Add button (add the entry to the task list, clear the task field, and set the focus to the task field), as shown in Figure 6.14.

    Start Figure

    // add code in bold to process Add button clicks
private javax.swing.JButton getAddButton() {
   if(addButton == null) {
    addButton = new javax.swing.JButton();
    addButton.setText("Add");
    addButton.setIcon(new javax.swing.ImageIcon(getClass().
       getResource("/swingToDoListPackage/add.gif")));
    addButton.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
    addButton.setHorizontalTextPosition
   (javax.swing.SwingConstants.RIGHT);
    addButton.setToolTipText("Add Task");
    addButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().
   getResource("/swingToDoListPackage/add_on.gif")));
    addButton.setCursor
   (new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
    addButton.setPressedIcon(new javax.swing.ImageIcon(getClass().
   getResource("/swingToDoListPackage/add_pr.gif")));
   addButton.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent e) {
         getTaskList().addItem(getTaskField().getText());
         getTaskField().setText("");
         getTaskField().requestFocus();
      }
   });
   }
   return addButton;
}
    End Figure

    Figure 6.14: Processing Add button clicks

  2. Use content assist to add an ActionListener for the Clear button, and add code to the actionPerformed(ActionEvent) method to remove all entries from the list when the user clicks the Clear button, as shown in Figure 6.15.

    Start Figure

    // add code in bold to process Clear button clicks
private javax.swing.JButton getClearButton() {
   if(clearButton == null) {
    clearButton = new javax.swing.JButton();
    clearButton.setText("Clear");
    clearButton.setIcon(new javax.swing.ImageIcon(getClass().
      getResource("/swingToDoListPackage/clear.gif")));
clearButton.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
    clearButton.setHorizontalTextPosition
   (javax.swing.SwingConstants.RIGHT);
    clearButton.setToolTipText("Clear Task List");
    clearButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().
      getResource("/swingToDoListPackage/clear_on.gif")));
    clearButton.setCursor(new java.awt.Cursor
      (java.awt.Cursor.HAND_CURSOR));
    clearButton.setPressedIcon(new javax.swing.ImageIcon(getClass().
      getResource("/swingToDoListPackage/clear_pr.gif")));
    clearButton.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent e) {
            getTaskList().removeAllItems();
      }
    });
   }
   return clearButton;
}
    End Figure

    Figure 6.15: Processing Clear button clicks

  3. Use content assist to add an ActionListener to the Remove button, and add code to the actionPerformed(ActionEvent) method to remove the selected item when the user clicks the Remove button, as shown in Figure 6.16.

    Start Figure

// add code in bold to process Remove button clicks
private javax.swing.JButton getRemoveButton() {
   if(removeButton == null) {
    removeButton = new javax.swing.JButton();
    removeButton.setText("Remove");
    removeButton.setIcon(new javax.swing.ImageIcon(getClass().
      getResource("/swingToDoListPackage/remove.gif")));
    removeButton.setHorizontalAlignment
      (javax.swing.SwingConstants.LEFT);
    removeButton.setHorizontalTextPosition
      (javax.swing.SwingConstants.RIGHT);
    removeButton.setToolTipText("Remove Task");
    removeButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().
      getResource("/swingToDoListPackage/remove_on.gif")));
    removeButton.setCursor(new java.awt.Cursor
      (java.awt.Cursor.HAND_CURSOR));
    removeButton.setPressedIcon(new javax.swing.ImageIcon(getClass().
      getResource"/swingToDoListPackage/remove_pr.gif")));
    removeButton.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent e) {
         getTaskList().removeItemAt(getTaskList().getSelectedIndex());
      }
    });
   }
   return removeButton;
}
    End Figure

    Figure 6.16: Processing Remove button clicks

Finally, to restrict the number of tasks, you need to add code to disable the Add button when the number of entries in the list reaches the maximum number specified by the user, and to enable the button when the number of entries in the list falls below that value. You do this by listening to changes in the maxEntries field's text property and the taskList's itemCount property, and taking the appropriate steps whenever either property changes.

  1. Use content assist to add a PropertyChangeListener to the maxEntries field, and add code to the propertyChange(PropertyChangeEvent) method to enable or disable the Add button when the text property changes, as shown in Figure 6.17.

    Start Figure

    // add code in bold to process PropertyChangeEvents
private com.ibm.easyswing.BoundJTextField getMaxEntries() {
   if(maxEntries == null) {
    maxEntries = new com.ibm.easyswing.BoundJTextField();
    maxEntries.setText("10");
    maxEntries.setHorizontalAlignment(javax.swing.JTextField.LEFT);
    maxEntries.setToolTipText("Maximum Number of Tasks");
    maxEntries.addPropertyChangeListener(new
       java.beans.PropertyChangeListener() {
    public void propertyChange(
       java.beans.PropertyChangeEvent evt) {
       if ("text".equals(evt.getPropertyName()))
          getAddButton().setEnabled(getTaskList().getItemCount()
            <Integer.parseInt(getMaxEntries().getText().trim()));
     }
    });
   }
   return maxEntries;
}
    End Figure

    Figure 6.17: PropertyChangeListener for maxEntries field

  2. Use content assist to add a PropertyChangeListener to the taskList, and add code to the propertyChange(PropertyChangeEvent) method to enable or disable the Add button when the itemCount property changes, as shown in Figure 6.18.

    Start Figure

    // add code in bold to process PropertyChangeEvents
private com.ibm.easyswing.BoundJList getTaskList() {
   if(taskList == null) {
    taskList = new com.ibm.easyswing.BoundJList();
    taskList.addPropertyChangeListener(new
      java.beans.PropertyChangeListener() {
    public void propertyChange(
      java.beans.PropertyChangeEvent evt) {
     if ("itemCount".equals(evt.getPropertyName()))
        getAddButton().setEnabled(getTaskList().getItemCount()
         <Integer.parseInt(getMaxEntries().getText().trim()));
     }
    });
   }
   return taskList;
}
    End Figure

    Figure 6.18: PropertyChangeListener for taskList

Save your changes and test your final SwingToDoList application. It should look similar to Figure 6.19.

Click To expand
Figure 6.19: Running SwingToDoList application

If you had any problems building the SwingToDoList application, look at the solution file in the /solutions/chap06/swingToDoListPackage subdirectory on the CD included with this book. Create a new package called solutions.chap06.swing ToDoListPackage in the SwingDemonstration project, and import the following files into it:

  • /solutions/chap06/swingToDoListPackage/SwingToDoList.java

  • all image files in the /solutions/chap06/swingToDoListPackage folder

Open SwingToDoList.java with the Visual Editor to compare your program with the solution.


Using Swing's Model-View-Controller design

Now that you're familiar with the new properties of Swing components, we're going to create another application that illustrates Swing's Model-View-Controller design. It also shows how to use some new components such as JTabbedPane, JSlider, and JProgressBar. The TimeModelDemo application lets you see the current time, alarm time, and time elapsed since the application started in different displays. You can also set an alarm interval to tell how often the alarm goes off.

The beans you use in the TimeModelDemo application (TimeModel and DigitalView) are in the [image] chap06.jar file. You already added this JAR file to the build path for the SwingDemonstration project, so the project is ready to use for this application. You just need to set up a new package and visual class.

  1. Create a new package called timeModelPackage in the SwingDemonstration project.

  2. Import the [image] clock.gif image file in the /solutions/chap06/timeModelPackage folder on the CD included with this book into your new timeModelPackage package.

  3. Create a new visual class called TimeModelDemo in the timeModelPackage. Make javax.swing.JFrame the superclass for your new class (select Frame as the visual class to extend and check the Swing check box), and check the check box to create a main method stub for your new class.

Setting up the JFrame

  1. Add code to the main method to create an instance of your application's JFrame and make it visible, as shown in Figure 6.20.

    Start Figure

    // add code in bold to create an instance of the JFrame and show it
    public static void main(String[] args) {
        TimeModelDemo frame = new TimeModelDemo();
        frame.show();
    }
    End Figure

    Figure 6.20: Creating an instance of the application frame

  2. Select the JFrame in the design surface, grab one corner of the rectangle, and drag it to increase its size.

  3. Set the title property of the JFrame to Time Model.

  4. Set the defaultCloseOperation property of the JFrame to EXIT.

Adding visual components

Now you're ready to start adding visual elements to your application.

Remember that the application consists of two objects: the JFrame itself and its content pane. The content pane is where you put your visual components. It already has its layout set to BorderLayout, which is the best choice for what you want—arranging a single component in the center of the content pane and setting its size to the maximum allowed by the container.

The TimeModelDemo application works in three modes simultaneously: clock, alarm, and timer. To separate these three devices, you will put them into three different tabs on one JTabbedPane. The JTabbedPane lets you hide and show various pages each time you click on a tab, similar to the CardLayout you used in Chapter 5.

  1. Select a JTabbedPane bean from the Swing Containers palette category, and drop it on the center of the ContentPane. By default, the JTabbedPane has no tabs-you add the tabs you want using the JPanel bean.

  2. Select a JPanel bean from the Swing Containers palette category, and drop it on the JTabbedPane.

  3. Rename the JPanel to clockTab. Set its tab title property to Clock and its tab tooltip text to Tells current time.

Your JTabbedPane now contains one tab—the Clock tab. To set the properties for JTabbedPane or one of its tabs, select the appropriate object, as shown in Figure 6.21.

Click To expand
Figure 6.21: Selecting the JTabbedPane or the JPanel

With only one tab on the JTabbedPane, you can select the object you want (JTabbedPane or JPanel) directly on the design surface. But, once you have added several tabs to the JTabbedPane, the easiest way to switch from one object to another is to select the object you want in the Java Beans view. Also note the drop areas on the design surface. To add another tab to the JTabbedPane, you drop the new JPanel over the top area of the JTabbedPane (above the area for the current tabs).

Adding more tabs

  1. Put another JPanel bean on the JTabbedPane (make sure you drop it on the JTabbedPane and not on the Clock tab).

  2. Rename the JPanel to alarmTab. Set its tab title property to Alarm and its tab tooltip text to Alarm Settings.

  3. Put a third JPanel bean on the JTabbedPane (make sure you drop it on the JTabbedPane and not on the Clock or Alarm tab).

  4. Rename the JPanel to timeTab. Set its tab title property to Timer and its tab tooltip text to Time elapsed since application started.

Your visual composition should look like Figure 6.22, and the Java Beans view should look like Figure 6.23.

Click To expand
Figure 6.22: JTabbedPane with three tabs
Click To expand
Figure 6.23: Java Beans view for JTabbedPane with three tabs

JTabbedPane has several interesting features. As you probably noticed, each tab has a tab icon property in its property sheet. You can put an icon on a tab's label like you did with buttons in the SwingToDoList application. Another feature of the tabs is that you can place them at each of four standard sides (top, botton, left, or right). To change the location of the tabs, change the tabPlacement property of the JTabbedPane. Figure 6.24 shows the JTabbedPane with the tabPlacement set to BOTTOM and icons on each tab.

Click To expand
Figure 6.24: JTabbedPane with different features enabled

The Model-View-Controller architecture

The Model-View-Controller (MVC) architecture is a well-known design for GUI objects. It divides each component into three parts:

  1. Model controls the state data of the component and manages data or values used by the component.

  2. View refers to how you see the component on the screen; it manages the way the component displays.

  3. Controller defines the component's reaction to events such as mouse clicks, gaining or losing focus, keyboard events, and so on. It also determines what happens when the user interacts with the component; for example, what occurs when the user clicks a button.

Classic MVC architecture, with some modifications, is also used in Swing's design. Swing combines the view and controller parts into a single user-interface object that draws the component on the screen and handles events. The model part, in turn, is responsible for maintaining information about the component's state and data. This kind of design is called a separable model architecture.

The TimeModelBean

It is generally considered good practice to center the architecture of an application around its data rather than its user interface. To support this paradigm, Swing defines a separate model interface for each kind of component that can store or manipulate values or data.

In this example, we are going to use beans from the Time bean suite included on the CD. This suite consists of four beans: AnalogView, DigitalView, LCDView, and TimeModel. The TimeModel bean can work in three different modes: clock, alarm, and timer. It also lets you manipulate the time data as well as alarm and timer settings. What are the other three beans for? Their purpose is visual representation of the information from the TimeModel bean. You can choose one of these three views to represent your clock, alarm, or timer visually, as shown in Figure 6.25.

Click To expand
Figure 6.25: Three views provided with the Time bean suite

In comparison with the IClock bean from Chapter 5, this scheme has the advantage of letting you tie multiple views to a single model. Imagine you had a huge amount of visual and non-visual properties for one bean; it would be a nightmare trying to separate the visual and non-visual functions and change them individually. For example, if you want an analog clock and digital clock showing the same time simultaneously, you would want to base the views of two components on a single data model. So, if the data needs to change (for example, to change the time zone), you need to change it only in the TimeModel. The views update themselves accordingly.

In the TimeModelDemo application, you are going to use only one of the three available views: the DigitalView.

  1. Switch to the Clock tab by selecting clockTab in the Java Beans view. The Clock tab moves to the foreground on the visual surface, and its properties appear in the Properties view.

  2. Set the Clock tab's layout property to BorderLayout. We choose this layout because you'll only have one component on this tab, and you're going to increase its size to the maximum.

  3. Use Choose Bean to select a DigitalView bean from the com.ibm.time package, and drop it on the center of the Clock tab. Rename the DigitalView bean to clock, and set its digitsFont property to Dialog, plain, 36, so that your design surface now looks like Figure 6.26.

    Click To expand
    Figure 6.26: Clock tab layout

  4. Select alarmTab in the Java Beans view. Set the Alarm tab's layout property to BoxLayout(Y_AXIS). BoxLayout is similar to GridLayout. BoxLayout aligns things either horizontally (X_AXIS) or vertically (Y_AXIS), but it does not support multiple columns and rows. BoxLayout also doesn't assume that all components in the major axis are the same size. (We are going to put several elements on the Alarm tab later in this lesson.)

  5. Use Choose Bean to select another DigitalView bean from the com.ibm.time package and drop it on the Alarm tab. Rename the DigitalView bean to alarm. Set its digitsFont property to Dialog, plain, 36 and its displayModelType property to ALARM_TIME, so that your design surface now looks like Figure 6.27.

    Click To expand
    Figure 6.27: Alarm tab layout

  6. Select timerTab in the Java Beans view. Set the Timer tab's layout property to BorderLayout.

  7. Use Choose Bean to select another DigitalView bean from the com.ibm.time package and drop it on the center of the Timer tab. Rename the DigitalView bean to timer. Set its digitsFont property to Dialog, plain, 36 and its displayModelType property to TIMER_TIME.

  8. Use Choose Bean to select the TimeModel bean from the com.ibm.time package, and place it on the design surface outside of the JFrame.

  9. Set the TimeModel bean's properties as follows:

    • alarmEnable to true

    • alarmAutoAdjust to true

    • alarmIntervalSeconds to 30.

Your design surface should now look like Figure 6.28.

Click To expand
Figure 6.28: Timer tab layout with TimeModel bean added
Note

Even though the TimeModel bean is currently named TimeModel_1 on the design surface, the actual variable name in the source code is ivjTimeModel.


Connecting beans in the TimeModelDemo application

This section shows you how to connect the three tabs of the JTabbedPane to the appropriate TimeModel properties.

Connecting the Clock tab

  1. Select the clock in the Java Beans view, and add code to set the TimeModel bean as its model property, as shown in Figure 6.29.

    Start Figure

    // add code in bold to connect clock to TimeModel bean
private com.ibm.time.DigitalView getClock() {
   if(clock == null) {
    clock = new com.ibm.time.DigitalView();
    clock.setDigitsFont(new java.awt.Font("sansserif", 0, 36));
    clock.setModel(getIvjTimeModel());
   }
   return clock;
}
    End Figure

    Figure 6.29: Connecting the clock to the TimeModel bean

    Note

    The TimeModel bean may disappear from the design surface and Java Beans view when you add this code. Don't worry—it's still in your program.

Connecting the Alarm tab

  1. Select the alarm in the Java Beans view, and add code to set the TimeModel bean as its model property, as shown in Figure 6.30.

    Start Figure

    // add code in bold to connect alarm to TimeModel bean
private com.ibm.time.DigitalView getAlarm() {
   if(alarm == null) {
    alarm = new com.ibm.time.DigitalView();
    alarm.setDigitsFont(new java.awt.Font("sansserif", 0, 36));
    alarm.setDisplayModelType(2);
    alarm.setModel(getIvjTimeModel());
   }
   return alarm;
}
    End Figure

    Figure 6.30: Connecting the alarm to the TimeModel bean

  2. You want the alarm time to be reset whenever your application starts, so you need to connect the windowOpened event of your application's JFrame to the setAlarmTimeToCurrent() method of the TimeModel bean. Find the source code for the TimeModelDemo constructor, use content assist to add a WindowListener, and add code to the windowOpened(WindowEvent) method to set the alarm time, as shown in Figure 6.31.

    Start Figure

    // add code in bold to set alarm time when application starts
public TimeModelDemo() {
   super();
   initialize();
   this.addWindowListener(new java.awt.event.WindowListener() {
    public void windowOpened(java.awt.event.WindowEvent e) {
    getIvjTimeModel().setAlarmTimeToCurrent();
   }
   public void windowClosing(java.awt.event.WindowEvent e) {
    ;
   }
   public void windowClosed(java.awt.event.WindowEvent e) {
    ;
   }
   public void windowIconified(java.awt.event.WindowEvent e) {
    ;
   }
   public void windowDeiconified(java.awt.event.WindowEvent e) {
    ;
   }
   public void windowActivated(java.awt.event.WindowEvent e) {
    ;
   }
   public void windowDeactivated(java.awt.event.WindowEvent e) {
    ;
   }
   });
}
    End Figure

    Figure 6.31: Setting the alarm time when the application starts

Connecting the Timer tab

  1. Select the timer in the Java Beans view, and add code to set the TimeModel bean as its model property, as shown in Figure 6.32.

    Start Figure

    // add code in bold to connect timer to TimModel bean
private com.ibm.time.DigitalView getTimer() {
   if(timer == null) {
    timer = new com.ibm.time.DigitalView();
    timer.setDigitsFont(new java.awt.Font("sansserif", 0, 36));
    timer.setDisplayModelType(1);
    timer.setModel(getIvjTimeModel());
   }
   return timer;
}
    End Figure

    Figure 6.32: Connecting the timer to the TimeModel bean

  2. You want the timer to begin whenever your application starts, so find the WindowListener that you just added to the JFrame, and add code to start the timer when the window opens, as shown in Figure 6.33.

    Start Figure

    // add code in bold to set timer time when application starts
public TimeModelDemo() {
   super();
   initialize();
   this.addWindowListener(new java.awt.event.WindowListener() {
    public void windowOpened(java.awt.event.WindowEvent e) {
    getIvjTimeModel().setAlarmTimeToCurrent();
     getIvjTimeModel().startTimer();
    }
    public void windowClosing(java.awt.event.WindowEvent e) {
    ;
    }
    public void windowClosed(java.awt.event.WindowEvent e) {
    ;
    }
    public void windowIconified(java.awt.event.WindowEvent e) {
    ;
    }
    public void windowDeiconified(java.awt.event.WindowEvent e) {
    ;
    }
    public void windowActivated(java.awt.event.WindowEvent e) {
    ;
    }
    public void windowDeactivated(java.awt.event.WindowEvent e) {
    ;
    }
   });
}
    End Figure

    Figure 6.33: Starting the timer when the application starts

Save your changes and test the application (Run As → Java Application). The Clock tab shows the current time, and the Timer tab shows the time elapsed since the application started. When you look at the Alarm tab, you'll see that the alarm time increases every 30 seconds but that the alarm doesn't actually do anything. To make your alarm work, you connect the alarmAction event of the TimeModel bean to do something useful. Let's display an additional Alarm warning window each time alarmAction occurs.

Adding a new dialog

  1. Select a JDialog bean from the Swing Containers palette category, and drop it on the design surface outside of the JFrame.

  2. Set the JDialog bean's title property to Alarm!, and resize the dialog window so that you can drop visual elements on it.

  3. As you probably guessed, the JDialog also consists of two objects: the JDialog itself and its content pane. Select the content pane on the design surface. The layout property of the content pane is already set to BorderLayout, which is what you want. Set the content pane's background property to white.

    Reminder

    Select the Basic radio button in the property editor to see a list of basic color values.

  4. Put a JLabel bean from the Swing Components palette category on the center of the content pane.

  5. Set the JLabel bean's text property to an empty string.

  6. Set the JLabel bean's icon property to the [image] clock.gif file, which you have already imported into your timeModelPackage package.

  7. Set the JLabel bean's horizontalAlignment and verticalAlignment properties to CENTER.

  8. Select the JDialog on the design surface, and resize the JDialog window so that your design surface looks like Figure 6.34.

Click To expand
Figure 6.34: Design surface with alarm dialog added

Setting the alarmAction

The TimeModel bean fires an Alarm event whenever the alarm goes off, so you need to add an AlarmListener to your TimeModel bean to listen for the event. An event handling template is provided for this event in the /solutions/chap06/ folder on the CD included with this book.

  1. Import the /solutions/chap06/addAlarmListener.xml template into your WebSphere Studio Workbench.

    Reminder

    Use Window → Preferences, Java, Templates to import the file.

  2. In the source pane, find the method that initializes your TimeModel bean and use content assist to add an AlarmListener. Add code to the alarmAction(AlarmEvent) method to set the JDialog's window relative to the JTabbedPane (this positions the JDialog to display over the JTabbedPane rather than in the center of the screen) and to make the JDialog visible, as shown in Figure 6.35.

    Start Figure

    // add code in bold to process Alarm events
private com.ibm.time.TimeModel getIvjTimeModel() {
   if(ivjTimeModel == null) {
    ivjTimeModel = new com.ibm.time.TimeModel();
    ivjTimeModel.setAlarmEnable(true);
    ivjTimeModel.setAlarmAutoAdjust(true);
    ivjTimeModel.setAlarmIntervalSeconds(30);
    ivjTimeModel.addAlarmListener
    (new com.ibm.time.events.AlarmListener() {
      public void alarmAction(com.ibm.time.events.AlarmEvent e) {
         getJDialog().setLocationRelativeTo(getJTabbedPane());
          getJDialog().show();
      }
    });
   }
   return ivjTimeModel;
}
    End Figure

    Figure 6.35: Handling Alarm events

Save your changes and test your application again. The first alarm dialog appears when the TimeModelDemo application starts. Close the alarm window to see the next window appear in 30 seconds.


Using JSlider and JProgressBar

The TimeModelDemo application is ready to use. However, we are going to add more components and some additional functionality to it to demonstrate two very useful Swing components: JSlider and JProgressBar.

Adding new components

  1. Switch to the Alarm tab of the JTabbedPane.

  2. Place two JLabel beans from the Swing Components palette category on the Alarm tab surface, one at the top and one at the bottom.

    Tip

    If the labels aren't dropping where you want them to on the design surface, try dropping them on the alarmTab in the Java Beans view instead.

  3. Set the text property of the top JLabel to Next Alarm Action At:

  4. Set the text property of the bottom JLabel to Alarm Interval (see):.

  5. Select a JSlider bean from the Swing Components palette category and place it at the bottom of the Alarm tab, as shown in Figure 6.36.

    Click To expand
    Figure 6.36: JSlider bean placement

Setting JSlider bean properties

Sliders are similar to scroll bars in that they let you drag a marker across the screen. However, sliders let you select a value across a scale, as opposed to moving a screen view. You're going to use the slider to change the alarm interval during run time. The slider's minimum and maximum values will be 0 and 60, respectively.

  1. Set the JSlider bean's minimum property to 0 and the maximum property to 60. These properties set the range for the JSlider.

  2. Set the majorTickSpacing property to 15 and the minorTickSpacing property to 1. These properties specify the increments for tick marks that display along the JSlider. Major tick marks appear larger than the minor tick marks.

  3. Set the value property to 30. This property sets the current value of the JSlider. The property changes as the user moves the slider.

  4. Set both the paintLabels and paintTicks properties to true. These properties specify whether labels and tick marks are displayed along the JSlider. To display tick marks, you set the spacing for major or minor tick marks to nonzero values and set paintTicks to true.

  5. Set the toolTipText property to Set the alarm interval in seconds.

Making connections

The JSlider bean fires a StateChanged event whenever its state changes, such as when the user moves the slider to set a new value. Your application will listen for this event and copy the JSlider's value property to the TimeModel bean's alarmIntervalSeconds property whenever the user is finished adjusting the value (the JSlider bean tells you whether the adjustment is complete through its valueIsAdjusting property).

  1. Import the event handling template for javax.swing.event.ChangeListener (this template is provided with WebSphere Studio but is not automatically imported into the Workbench). The template you want is the addChangeListener.xml file in the /wstools/eclipse/plugins/com.ibm.etools.jbcf. codegen_5.0.1/Examples/Templates/javax/swing/event folder under the folder where you installed WebSphere Studio (for example, C:/Program Files/IBM/WebSphere/Express/SiteDeveloper).

  2. In the source pane, find the method that initializes the JSlider bean. Use content assist to add a ChangeListener, and add code to the stateChanged(ChangeEvent) method to copy the JSlider bean's value property to the TimeModel bean's alarmIntervalSeconds property, as shown in Figure 6.37.

Save your changes and test your application.

Start Figure
// code in bold handles StateChanged events
private javax.swing.JSlider getJSlider() {
   if(jSlider == null) {
    jSlider = new javax.swing.JSlider();
    jSlider.setMaximum(60);
    jSlider.setMajorTickSpacing(15);
    jSlider.setMinorTickSpacing(1);
    jSlider.setValue(30);
    jSlider.setPaintLabels(true);
    jSlider.setPaintTicks(true);
    jSlider.setToolTipText("Set the alarm interval in seconds");
    jSlider.addChangeListener(new javax.swing.event.ChangeListener() {
      public void stateChanged(javax.swing.event.ChangeEvent e) {
      if (getJSlider().getValueIsAdjusting() == false)
         getIvjTimeModel().setAlarmIntervalSeconds
         (getJSlider().getValue());
      }
    });
   }
   return jSlider;
}
End Figure

Figure 6.37: Handling JSlider StateChanged events

Adding a JProgressBar

When an activity is going to take a long time to complete, many applications use progress bars to show the current status and help the user know that the process is continuing. However, that is not the only situation in which progress bars are used. We'll use a JProgressBar component on the Timer tab to show what percentage of a minute has passed by connecting the TimeModel bean's timerSeconds property to the progress bar's current value.

  1. Switch to the Timer tab.

  2. Select a JProgressBar bean from the Swing Components palette category, and place it on the north area of the Timer tab.

  3. Set the JProgressBar's maximum property to 60.

  4. In the source pane, find the method that initializes the TimeModel bean. Use content assist to add a PropertyChangeListener to the TimeModel bean, and add code to the propertyChange(PropertyChangeEvent) method to check if it was the timerSeconds property that changed, and if so, to copy timerSeconds to the value property of the JProgressBar bean, as shown in Figure 6.38.

    Start Figure

    // add code in bold to connect TimeModel bean to JProgressBar
private com.ibm.time.TimeModel getIvjTimeModel() {
   if(ivjTimeModel == null) {
    ivjTimeModel = new com.ibm.time.TimeModel();
    ivjTimeModel.setAlarmEnable(true);
    ivjTimeModel.setAlarmAutoAdjust(true);
    ivjTimeModel.setAlarmIntervalSeconds(30);
    ivjTimeModel.addAlarmListener
    (new com.ibm.time.events.AlarmListener() {
      public void alarmAction(com.ibm.time.events.AlarmEvent e) {
          getJDialog().setLocationRelativeTo(getIvjJTabbedPane());
          getJDialog().show();
      }
    });
    ivjTimeModel.addPropertyChangeListener
         (new java.beans.PropertyChangeListener() {
      public void propertyChange(
         java.beans.PropertyChangeEvent evt) {
        if ("timerSeconds".equals(evt.getPropertyName()))
            getJProgressBar().setValue
               (getIvjTimeModel().getTimerSeconds());
      }
    });
   }
   return ivjTimeModel;
}
    End Figure

    Figure 6.38: Connecting TimeModel timerSeconds to JProgressBar value

Save your changes, and test your application. It should now look similar to Figure 6.39.

Click To expand
Figure 6.39: TimeModelDemo with JProgressBar

If you had any problems building the TimeModelDemo application, look at the solution file in the /solutions/chap06/timeModelPackage subdirectory on the CD included with this book. Create a new package called solutions.chap06.timeModelPackage in the SwingDemonstration project, and import the following files into it:

  • /solutions/chap06/timeModelPackage/TimeModelDemo.java

  • /solutions/chap06/timeModelPackage/clock.gif

Open [image] TimeModelDemo.java with the Visual Editor to compare your program with the solution.


Swing applets

Now you probably would like to write some applets that use Swing. Before you do, consider one important technical issue: Swing is quite a large package. Can you afford to use it? If you are writing an applet to run on an intranet site, odds are this is not an issue. However, if you are writing an Internet applet, you need to tell your users how to put the Swing package into their browsers. If you forget this step, your users will get stuck downloading a huge file every time they run your applet.

Swing will work with Netscape Navigator and Internet Explorer, but it isn't included. Therefore, you may have to include the swing.jar file in the archive element of your applet tag (which is not viable unless you know that your clients will have fast connections) or have your clients install Swing in their CLASSPATH environment variable. Another option is to have your clients use the latest version of Sun's Java plugin, which includes Swing. Yet another alternative is to use the Java Web Start technology. In this case, the applet is still downloaded to the client machine, but it runs outside of the Web browser using the Java Runtime Environment installed on the client machine. For information on making browsers Swing-compatible and on using Java Web Start, see the references listed at the end of this chapter.

Creating a Swing applet is not really any different from creating a Swing application. You create the applet as a visual class, selecting Applet as the class to extend, and checking the Swing check box (this makes javax.swing.JApplet the superclass). Once the class has been created, you place visual elements on the content pane that the Visual Editor creates for the applet, and connect the elements together.


Changing the look and feel

Swing comes with a default look and feel called Metal. Metal combines some of the best graphical elements in today's look and feels, and it's the look and feel you used in both of the applications you built in this chapter. Suppose you want to change the look and feel, so that your application uses a different look and feel? No problem—a few lines of code in the application's main method is all it takes. Suppose you want to go a step further and let your users choose the look and feel they want at run time? Easy, again—just a few lines of code is all it takes to let your users switch from one look and feel to another.

You specify the look and feel you want by calling the setLookAndFeel(String) method in the javax.swing.UIManager class, passing the look and feel value as a parameter to the method. Some of the common look and feel values you can specify are:

  • com.sun.java.swing.plaf.windows.WindowsLookAndFeel

  • com.sun.java.swing.plaf.motif.MotifLookAndFeel

  • javax.swing.plaf.metal.MetalLookAndFeel.

When you specify any of these strings as the parameter to the setLookAndFeel(String) method, the corresponding look and feel is used (Windows, Motif, or Metal). You can also set the look and feel to your system's native look and feel by specifying javax.swing.UIManager.getSystemLookAndFeelClassName() as the parameter.

To set the look and feel for your application, call the setLookAndFeel(String) method at the start of your application's main method, before any visual components are created. For example, to set the look and feel for the SwingToDoList application to use the Motif look and feel, update the main method in SwingToDoList.java as shown in Figure 6.40. In this sample code, if any errors occur in the setLookAndFeel(String) method, the exception is ignored, and the default look and feel is used instead.

Start Figure
// add code in bold to set the look and feel to Motif
public static void main(String[] args) {
   try {
    javax.swing.UIManager.setLookAndFeel
      ("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
   }
   Catch (Exception ex) {}
   SwingToDoList frame = new SwingToDoList();
   frame.show();
}
End Figure

Figure 6.40: Setting the look and feel to Motif look and feel

You can also change the look and feel during run time, but in this case, you also need to call the updateComponentTreeUI(Component) method in the javax.swing.SwingUtilities class. You pass the top-level container, such as the frame for an application, as the parameter to this method, and the method updates the look and feel for all visual components in the container. For example, the code snippet shown in Figure 6.41 sets the look and feel to the system native look and feel and updates all visual elements in the SwingToDoList application to use the new look and feel.

Start Figure
try {
   javax.swing.UIManager.setLookAndFeel
      (javax.swing.UIManager.getSystemLookAndFeelClassName());
javax.swing.SwingUtilities.updateComponentTreeUI(SwingToDoList.this);
}
catch (Exception ex) {}
End Figure

Figure 6.41: Dynamically setting the look and feel to the system native look and feel
Tip

WebSphere Studio has several options to customize the look and feel for your applications within WebSphere Studio. To set the look and feel for visual elements presented on the Visual Editor's design surface, use Windows → Preferences, Java, Visual Editor, and select the look and feel you want to use (default, Metal, Windows, or Motif). This sets the look and feel for the visual elements when they're displayed on the design surface; it does not control how the elements look when you run the application. You can also set the look and feel value in WebSphere Studio launch configurations (predefined settings used to run a program), but these settings only apply when you run the program as a Java Bean in WebSphere Studio. To set the look and feel during run time for all cases (Java Bean or application, within or outside of WebSphere Studio), use the code described above.


In review

This chapter demonstrated how to use the Swing library to build advanced Graphical User Interfaces. You learned how to use many of the features of Swing components, such as tool tips, icons, sliders, and progress bars. You also learned about Swing's Model-View-Controller architecture, and how to build applications with beans that implement this architecture.


Exercise

Add another tab to the TimeModelDemo application to provide radio buttons to let the user change the application's look and feel to the following values during run time: Metal, Windows, or Motif.

Hint

You can create a group of Swing radio buttons using JRadioButton beans from the Swing Components palette category and the javax.swing.ButtonGroup class. JRadioButtons fire an action event when the radio button is selected.

A solution file for this exercise is in the /solutions/chap06/timeModelPackage subdirectory on the CD included with this book. Import the following files into solutions.chap06.timeModelPackage in the SwingDemonstration project:

  • /solutions/chap06/timeModelPackage/TimeModelDemoExer1.java

  • /solutions/chap06/timeModelPackage/clock.gif

Open [image] TimeModelDemoExer1.java with the Visual Editor to compare your program with the solution.


References

Java Foundation Classes http://java.sun.com/products/jfc/

Make Your Browser Swing! http://java.sun.com/products/jfc/tsc/articles/applets/index.html

Java Plug-in Home Page http://java.sun.com/products/plugin/

Java Web Start http://java.sun.com/products/javawebstart/


Chapter 7: When Something Goes Wrong - Debugging

Team LiB

Chapter 7: When Something Goes Wrong—Debugging

Download CD Content

Overview

Debugging is the process of detecting and correcting application errors, such as incorrect connections between beans or wrong settings in the property sheet. Sometimes it's very difficult to find the mistake, especially when it is a careless one and the application is large and complex.

When you build applications with the Visual Editor, you do much of the work visually, letting the Visual Editor generate the code for you. However, when you debug your applications, you need to understand the code that the Visual Editor generates for you, because the WebSphere Studio debugger works on the generated code rather than on the visual objects that you created.

In this chapter, you'll create a new "buggy" application (an application with some intentionally made mistakes, both careless and logical), and then detect and correct the errors using the WebSphere Studio Debug perspective. After finishing the debugging process, you'll have a working application that demonstrates some additional Swing components, such as menu bars and JFileChooser. You'll also be familiar with the Image Processing bean suite that lets you perform different operations on images. The application you'll build is shown in Figure 7.1.

Click To expand
Figure 7.1: The ImageProcessing application


ImageProcessing: Menu bar

In this section, you'll create an ImageProcessing application that lets you scale and rotate images. This application has two missions: First, it shows you how to use more Swing components and operate with images. Second, it provides an example of the debugging process using the WebSphere Studio Debug perspective. To show this process, we'll make some intentional mistakes when assembling the application and then correct them during the debugging process.

Before you begin

Before you create the ImageProcessing application, you need to set up a new project, package, and visual class in WebSphere Studio.

  1. The beans you use in the ImageProcessing application (ImageCanvas and RotationFilter) are in the [image] chap07.jar file. Copy [image] chap07.jar from the /solutions/chap07/ subdirectory on the CD included with this book to a folder on your machine, such as C:/beans.

  2. In the Java perspective in WebSphere Studio, create a new Java Project called ImageWork. Specify [image] chap07.jar as an external JAR file on the Libraries tab.

  3. Create a new package called imageProcessing in your ImageWork project.

  4. Create a new visual class called ImageProcessing in your imageProcessing package. Make javax.swing.JFrame the superclass for your new class, and check the public static void main(String[] args) check box to create a main method stub for your new class. Your new class opens in the Visual Editor.

Setting up the JFrame and ContentPane

  1. Add code to the main method to create an instance of your application's JFrame and make it visible, as shown in Figure 7.2.

    Start Figure

    // add code in bold to create an instance of the JFrame and show it
   public static void main(String[] args) {
      ImageProcessing frame = new ImageProcessing();
      frame.show();
   }
    End Figure

    Figure 7.2: Creating an instance of the application frame

  2. Select the JFrame on the design surface, grab one corner of the rectangle, and drag it to increase its size.

  3. Set the JFrame's title property to ImageProcessing and its defaultCloseOperation property to EXIT.

  4. The ContentPane's layout is already set to BorderLayout, which is what you want. Use Choose Bean to select an ImageCanvas bean from the com.ibm.uicontrolsswing package, and drop it on the center of the ContentPane, so that the design surface looks like Figure 7.3.

    Click To expand
    Figure 7.3: ImageProcessing class with ImageCanvas bean

The ImageCanvas bean is the container that holds images presented in the application. The images themselves are com.ibm.uicontrolsswing. ImageGlyph objects, and they're shown flush with the top and left margins of the container. Notice that the container actually occupies the entire ContentPane, since the ImageCanvas bean is in the center of the BorderLayout and no other sections of the BorderLayout are being used. Also notice that the ImageCanvas bean currently shows a "null" image (a square with an X through it), which is what the bean shows when a real image hasn't been selected.

Creating the menu bar

Select a JMenuBar bean from the Swing Menus palette category, and drop it on the top of the JFrame, so the design surface looks like Figure 7.4. (Make sure you drop the JMenuBar on the JFrame, and not on the north portion of the ContentPane.) Notice that the menu bar currently uses just a small area at the top of the frame. That will change in the next sections once you add menus to customize the menu bar.

Click To expand
Figure 7.4: Adding a menu bar

Creating the File menu

  1. Select a JMenu bean from the Swing Menus palette category, and drop it on the JMenuBar. Set the JMenu bean's text property to File, so that your design surface looks like Figure 7.5.

    Click To expand
    Figure 7.5: Adding the File menu to the menu bar

  2. To add menu items to the menu, you'll do something a little different. Select a JMenuItem bean from the Swing Menus palette category. But this time, drop it on the File menu bean in the Java Beans view, rather than on the design surface. The Java Beans view should now look like Figure 7.6.

    Click To expand
    Figure 7.6: Adding a menu item to the menu

    Tip

    Once you drop the JMenuItem on the JMenu, you'll find that the Delete option is not available for it (that is, the option is grayed out in the pop-up menu when you right-click on the JMenuItem bean in the Java Beans view). If you want to remove the JMenuItem, you can remove it by clicking the Undo icon, by manually deleting the code, or by deleting the entire JMenu.

  3. Set the JMenuItem bean's text property to Open… and its mnemonic property to O. The mnemonic property associates a keyboard button with the menu item to let you access the menu item without using the mouse.

  4. Select another JMenuItem bean from the Swing Menus palette category, and drop it on the File menu bean in the Java Beans view.

  5. Set the second JMenuItem bean's text property to Revert and its mnemonic property to R, so that the Java Beans view now looks like Figure 7.7.

    Click To expand
    Figure 7.7: Menu items added to the File menu

If you test your application now and choose the File menu, the window shown in Figure 7.8 should appear. The menu items don't do anything yet, but they are there. Notice that each menu item's mnemonic character is underlined.

Click To expand
Figure 7.8: Running application with File menu items

Creating the Image menu

  1. Select another JMenu bean from the Swing Menus palette category, and drop it on the JMenuBar just to the right of the File menu on the design surface.

  2. Set the second JMenu bean's text property to Image. This menu will contain commands for scaling and rotating images. Your design surface should now look like Figure 7.9.

    Click To expand
    Figure 7.9: Adding another menu to the menu bar

  3. Select a JCheckBoxMenuItem bean from the Swing Menus palette category, and drop it on the Image menu in the Java Beans view. The JCheckBox MenuItem works similarly to the CheckBox bean. You can either check or uncheck it and connect the state of the bean to other beans to do something useful.

  4. Set the JCheckBoxMenuItem bean's text property to Scalable and its mnemonic property to S.

  5. Select another JMenu bean from the Swing Menus palette category, and drop it on the Image menu in the Java beans view under the JCheckBoxMenuItem. This creates a submenu in the Image menu.

  6. Set the submenu's text property to Rotate…, so that the Java Beans view looks like Figure 7.10.

    Click To expand
    Figure 7.10: Adding a submenu to the Image menu

Creating the Rotate submenu

You will include four options on the Rotate submenu: 90, 180, 270, and 360, so that your rotate functions will use 90-degree angle increments.

  1. Select a JMenuItem bean from the Swing Menus palette category, and drop it on the Rotate submenu in the Java Beans view. Set the menu item's text property to 90 and mnemonic property to 1.

  2. Select another JMenuItem bean, and drop it on the Rotate submenu in the Java Beans view. Set the menu item's text property to 180 and mnemonic property to 2.

  3. Select a third JMenuItem bean, and drop it on the Rotate submenu in the Java Beans view. Set the menu item's text property to 270 and mnemonic property to 3.

  4. Select a fourth JMenuItem bean, and drop it on the Rotate submenu in the Java Beans view. Set the menu item's text property to 360 and mnemonic property to 4, so that the Java Beans view looks like Figure 7.11.

    Click To expand
    Figure 7.11: Rotate submenu items

Save your changes and test the application. When you run the application, the Image menu and Rotate submenu should look like Figure 7.12.

Click To expand
Figure 7.12: Running application with Image menu and Rotate submenu

The visual part of the application is ready, so the next step is to add the functionality.


ImageProcessing: Functionality

This section shows you how to add the functionality to the ImageProcessing application.

Open file option

When the user selects the Open menu item, you want to display a file dialog window to let the user select an image file name, which will be displayed in the ImageCanvas. In Chapter 4, you used the ExtendedFileDialog bean, which is an AWT-based file dialog. In this chapter, you'll use the Swing-based JFileChooser bean. Here's how you make the connections to do this:

  1. Use Choose Bean to select a JFileChooser bean from the javax.swing package, and drop it on the design surface outside of the JFrame, so that your design surface looks similar to Figure 7.13 (folder names in the file dialog will show the current folder on your machine).

    Click To expand
    Figure 7.13: Adding a JFileChooser bean

  2. The way you make the JFileChooser bean display an open file dialog is by calling its showOpenDialog(Component) method. You pass the parent container as a parameter to the method, and JFileChooser positions its dialog window relative to the parent container. Select the Open menu item in the Java Beans view to scroll to its code in the source pane. Use content assist to add an ActionListener, and then add code to the actionPerformed(ActionEvent) method to display the open file dialog when the user selects the Open menu item, as shown in Figure 7.14. Note that you pass the JFrame (ImageProcessing.this) as the parent container.

    Start Figure

    // add code in bold to process action events
private javax.swing.JMenuItem getJMenuItem() {
   if(jMenuItem == null) {
    jMenuItem = new javax.swing.JMenuItem();
    jMenuItem.setText("Open...");
    jMenuItem.setMnemonic('O');
    jMenuItem.addActionListener(new java.awt.event.ActionListener() {
       public void actionPerformed(java.awt.event.ActionEvent e) {
         getJFileChooser().showOpenDialog(ImageProcessing.this);
       }
     });
   }
   return jMenuItem;
}
    End Figure

    Figure 7.14: ActionListener for Open menu item

  3. You want to place the image from the file that the user selects into the ImageCanvas container. You get the selected file from the JFileChooser bean's selectedFile property, which is a property of type java.io.File. You use this property to set the image property of the ImageCanvas bean, as shown in Figure 7.15.

    Start Figure

    // add code in bold to process the selected file
private javax.swing.JMenuItem getJMenuItem() {
   if(jMenuItem == null) {
    jMenuItem = new javax.swing.JMenuItem();
    jMenuItem.setText("Open...");
    jMenuItem.setMnemonic('O');
    jMenuItem.addActionListener(new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent e) {
       getJFileChooser().showOpenDialog(ImageProcessing.this);
       getImageCanvas().setImage(new com.ibm.uicontrolsswing.ImageGlyph
         (getJFileChooser().getSelectedFile().getPath()));
     }
    });
   }
   return jMenuItem;
}
    End Figure

    Figure 7.15: The selected image file in the ImageCanvas

Save your changes and test the application. Now you can open image files (.jpg and .gif files) in your application window, as shown in Figure 7.16.

Click To expand
Figure 7.16: Running ImageProcessing application

Revert file option

The ImageProcessing application lets the user change the size and orientation of the image. When the image has changed several times, you might want to restore the initial image view without having the user select the file name again. This is what the Revert option on the File menu does.

  1. Select the Revert menu item in the Java Beans view. Use content assist to add an ActionListener, and then add code to the actionPerformed(ActionEvent) method to reset the image presented in the ImageCanvas bean, using the file name that the user previously selected with the Open menu item, as shown in Figure 7.17.

    Start Figure

    // add code in bold to process action events
private javax.swing.JMenuItem getJMenuItem1() {
   if(jMenuItem1 == null) {
    jMenuItem1 = new javax.swing.JMenuItem();
    jMenuItem1.setText("Revert");
    jMenuItem1.setMnemonic('R');
    jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent e) {
         getImageCanvas().setImage(new com.ibm.uicontrolsswing.ImageGlyph
            (getJFileChooser().getSelectedFile().getPath()));
      }
    });
   }
   return jMenuItem1;
}
    End Figure

    Figure 7.17: ActionListener for Revert menu item

Scalable option

The scalable menu option switches the modes of the ImageCanvas from scalable to non-scalable, and vice versa. If the ImageCanvas is in nonscalable mode, the image size doesn't change when you enlarge or shrink the application window. In scalable mode, the image size changes with the window size.

  1. Select the JCheckBoxMenuItem in the Java Beans view. When this bean's state property changes, you want to update the ImageCanvas bean's scalable property. Use content assist to add a PropertyChangeListener, and then add code to the propertyChange(PropertyChangeEvent) method to update the ImageCanvas bean's scalable property, as shown in Figure 7.18.

    Start Figure

    // add code in bold to process PropertyChangeEvents
private javax.swing.JCheckBoxMenuItem getJCheckBoxMenuItem() {
   if(jCheckBoxMenuItem == null) {
    jCheckBoxMenuItem = new javax.swing.JCheckBoxMenuItem();
    jCheckBoxMenuItem.setText("Scalable");
    jCheckBoxMenuItem.setMnemonic('S');
    jCheckBoxMenuItem.addPropertyChangeListener
         (new java.beans.PropertyChangeListener() {
     public void propertyChange(java.beans.PropertyChangeEvent evt) {
      if ("state".equals(evt.getPropertyName()))
      getImageCanvas().setScalable(getJCheckBoxMenuItem().getState());
     }
    });
   }
   return jCheckBoxMenuItem;
}
    End Figure

    Figure 7.18: PropertyChangeListener for Scalable checkbox menu item

RotationFilter bean

To rotate the image, you need the RotationFilter bean from the ImageProcessing bean suite. This bean suite contains a collection of beans that perform various operations on images, such as choosing between color and black-and-white, making a particular color transparent, flipping the image as in a mirror, and many other useful commands. You can create a multifunctional graphical application with these beans.

You'll connect the RotationFilter and ImageCanvas beans in such a way that the ImageCanvas bean's image property is used as input to the RotationFilter bean and the RotationFilter bean's result property is displayed in the ImageCanvas container. Both the image and result properties are bound, so you use PropertyChangeListeners to connect them.

  1. Use Choose Bean to select a RotationFilter bean from the com.ibm.imageprocessing package, and drop it on the design surface outside of the JFrame, as shown in Figure 7.19.

    Click To expand
    Figure 7.19: Adding the RotationFilter bean

    Tip

    Even though the RotationFilter bean is named RotationFilter_1 on the design surface, its variable name is ivjRotationFilter in the source code.

  2. Set the rotationAngle property of the RotationFilter bean to 0.

  3. Select the ImageCanvas bean on the design surface or in the Java Beans view. Use content assist to add a PropertyChangeListener, and add code to the propertyChange(PropertyChangeEvent) method to copy the ImageCanvas bean's image property to the RotationFilter bean's inputImage property, whenever the image changes, as shown in Figure 7.20. Note that you need to convert the ImageCanvas bean's image property from an ImageGlyph to a java.awt.Image, which is what the RotationFilter bean expects.

    Start Figure

    // add code in bold to process PropertyChangeEvents
private com.ibm.uicontrolsswing.ImageCanvas getImageCanvas() {
   if(imageCanvas == null) {
    imageCanvas = new com.ibm.uicontrolsswing.ImageCanvas();
    imageCanvas.addPropertyChangeListener
    (new java.beans.PropertyChangeListener() {
    public void propertyChange(java.beans.PropertyChangeEvent evt) {
         if ("image".equals(evt.getPropertyName()))
            getIvjRotationFilter().setInputImage
             (getImageCanvas().getImage().getImage());
     }
    });
   }
   return imageCanvas;
}
    End Figure

    Figure 7.20: PropertyChangeListener for ImageCanvas bean

  4. Select the RotationFilter bean on the design surface or in the Java Beans view. Use content assist to add a PropertyChangeListener, and add code to the propertyChange(PropertyChangeEvent) method to copy the RotationFilter bean's result property to the ImageCanvas bean's imagge property whenever the image changes, as shown in Figure 7.21.

    Start Figure

    // add code in bold to process PropertyChangeEvents
private com.ibm.imageprocessing.RotationFilter getIvjRotationFilter()
{
   if(ivjRotationFilter == null) {
    ivjRotationFilter = new com.ibm.imageprocessing.RotationFilter();
    ivjRotationFilter.setRotationAngle(0);
    ivjRotationFilter.addPropertyChangeListener
      (new java.beans.PropertyChangeListener() {
    public void propertyChange(java.beans.PropertyChangeEvent evt) {
      if ("result".equals(evt.getPropertyName()))
         getImageCanvas().setImage
       (new com.ibm.uicontrolsswing.ImageGlyph
          (getIvjRotationFilter().getResult()));
     }
    });
   }
   return ivjRotationFilter;
}
    End Figure

    Figure 7.21: PropertyChangeListener for RotationFilter bean

Rotation commands

For the rotation commands, you connect the actionPerformed events of the various options in the Rotate submenu to the RotationFilter bean to rotate the image by the amount specified.

  1. Select the 90 menu item in the Java Beans view. Use content assist to add an ActionListener, and then add code to the actionPerformed(ActionEvent) method to rotate the image by 90 degrees, as shown in Figure 7.22.

    Start Figure

    // add code in bold to process action events
private javax.swing.JMenuItem getJMenuItem2() {
   if(jMenuItem2 == null) {
    jMenuItem2 = new javax.swing.JMenuItem();
    jMenuItem2.setText("90");
    jMenuItem2.setMnemonic('1');
    jMenuItem2.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent e) {
         getIvjRotationFilter().setRotationAngle(90);
      }
    });
   }
   return jMenuItem2;
}
    End Figure

    Figure 7.22: ActionListener for the 90 menu item

  2. Select the 180 menu item in the Java Beans view. Use content assist to add an ActionListener, and then add code to the actionPerformed(ActionEvent) method to rotate the image by 180 degrees, as shown in Figure 7.23.

    Start Figure

    // add code in bold to process action events
private javax.swing.JMenuItem getJMenuItem3() {
   if(jMenuItem3 == null) {
    jMenuItem3 = new javax.swing.JMenuItem();
    jMenuItem3.setText("180");
    jMenuItem3.setMnemonic('2');
    jMenuItem3.addActionListener(new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent e) {
         getIvjRotationFilter().setRotationAngle(180);
     }
    });
   }
   return jMenuItem3;
}
    End Figure

    Figure 7.23: ActionListener for the 180 menu item

  3. Select the 270 menu item in the Java Beans view. Use content assist to add an ActionListener, and then add code to the actionPerformed(ActionEvent) method to rotate the image by 270 degrees, as shown in Figure 7.24.

    Start Figure

    // add code in bold to process action events
private javax.swing.JMenuItem getJMenuItem4() {
   if(jMenuItem4 == null) {
    jMenuItem4 = new javax.swing.JMenuItem();
    jMenuItem4.setText("270");
    jMenuItem4.setMnemonic('3');
    jMenuItem4.addActionListener(new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent e) {
            getIvjRotationFilter().setRotationAngle(270);
     }
    });
   }
   return jMenuItem4;
}
    End Figure

    Figure 7.24: ActionListener for the 270 menu item

  4. Select the 360 menu item in the Java Beans view. Use content assist to add an ActionListener, and then add code to the actionPerformed(ActionEvent) method to rotate the image by 360 degrees, as shown in Figure 7.25.

    Start Figure

    // add code in bold to process action events
private javax.swing.JMenuItem getJMenuItem5() {
   if(jMenuItem5 == null) {
    jMenuItem5 = new javax.swing.JMenuItem();
    jMenuItem5.setText("360");
    jMenuItem5.setMnemonic('4');
    jMenuItem5.addActionListener(new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent e) {
            getIvjRotationFilter().setRotationAngle(360);
     }
    });
   }
   return jMenuItem5;
}
    End Figure

    Figure 7.25: ActionListener for the 360 menu item

  5. Save your changes.

Did you catch the mistakes we made? Mistakes like these are sometimes difficult to detect. Let's leave them for the moment so we can explore how to detect and correct such mistakes.


Debugging events

First, you need to test your application. Then we'll show you how to detect and correct the errors, and how to make some additional improvements.

Testing the Scalable option

  1. Run the ImageProcessing application and open any image file (.jpg or .gif) using the Open… option from the File menu.

  2. Check the Scalable option in the Image menu. Resize the application window.

When the Scalable option is checked, the image size is supposed to change with the canvas size. But as you can see, that doesn't happen in this application. So, close the application window and return to the Visual Editor.

Setting breakpoints

The Scalable option is supposed to be set whenever the JCheckBoxMenuItem bean's state property changes. The code to do this is in the PropertyChangeListener that you added to listen for PropertyChange events fired by the JCheckBoxMenuItem bean. To debug events, you need to ask yourself several questions. First, is the event being fired? And second, if the event is being fired, is the listener taking the appropriate steps? To find out if the event is being fired by the bean, you'll set a breakpoint to stop execution when the PropertyChangeListener receives control.

  1. Select JCheckBoxMenuItem in the Java Beans view. In the source pane, find the statement that begins if ("state" .equals (evt.getPropertyName())) in the PropertyChangeListener's propertyChange(PropertyChangeEvent) method. This is where you want to set the breakpoint.

  2. Double-click in the source pane margin to the left of this line of code. A blue dot appears in the left margin, as shown in Figure 7.26.

    Click To expand
    Figure 7.26: Setting a breakpoint

You now have a breakpoint set at the first statement of the JCheckBoxMenuItem bean's PropertyChangeListener. The next step is to run the application in WebSphere Studio's debug mode, which will cause execution to stop at this breakpoint so that you can examine what's going on in your application.

The WebSphere Studio Debug perspective

To run your application in debug mode, click on the arrow next to the Debug icon in the toolbar, and choose Debug As → Java Application. Your application starts running in a separate application window, just as it does when you normally run it. What's different this time is that a Debug perspective opens in the WebSphere Studio Workbench. Notice that a Debug Perspective icon appears in the vertical toolbar, in addition to the icon for the Java perspective you were just working in. You can switch between the Java and Debug perspectives by clicking on their icons in the vertical toolbar.

The Debug perspective contains many new views, so let's take a moment to look at some of the ones you'll find useful in debugging your application.

Debug view

You use the Debug view to control the debugging process. This view shows information about all the threads in the currently running application. When a thread is suspended, this view shows details about the Java classes that make up the current thread. The Debug view shown in Figure 7.27 shows all the threads in your ImageProcessing application. As you can see, Java is doing quite a bit for you behind the scenes.

Click To expand
Figure 7.27: Debug view

Along the top of the Debug view are icons for commands you use to control the debugging process, such as resume, suspend, and terminate, as well as a set of commands for stepping through your code. We'll explain the commonly used commands as we debug your application in this chapter.

Start Sidebar
What's a thread?

A thread is a separate task or unit of work that is executed within your application. When an application runs, it has one main thread and multiple system threads, which the Java Virtual Machine (JVM) creates to manage events and perform other system activities. The main thread is the one that the JVM launches the startup class with, and where it calls the entry method to the program, such as the static void main(String[]) method for a Java application. In advanced applications, you can also create additional application threads for work that you want to take place in parallel with the main thread, such as performing a long-running task that might otherwise tie up the main thread.

End Sidebar

Breakpoints, Variables, Display, and Expressions views

Click on the Breakpoints tab in the window to the right of the Debug view, and you'll see a list of all the currently set breakpoints for your application, as shown in Figure 7.28. You can add or remove breakpoints in this window or directly in your source code.

Click To expand
Figure 7.28: Breakpoints view
Note

You may see slightly different line numbers for breakpoints in your application-it just means that your source lines are formatted a little differently than the program we used to generate these screenshots.

Other tabs in this window that you'll find useful for debugging are Variables, Display, and Expressions. The Variables view shows the content of variables in your program; in some cases you can modify variable content in this view during execution. The Display view lets you evaluate pieces of code—code snippets that you type in directly in the Display view—and the Expressions view displays the result of the code snippets that you evaluate. You'll see how to use these tabs as you debug your application in this chapter.

Visual Editor and Outline views

In the center of the Debug prespective is something you're very familiar with—the Visual Editor. You can't modify code during execution with the standard Java Runtime Environment supplied with WebSphere Studio, but you can use the Visual Editor to add or remove breakpoints, and examine or step through code as you debug your application.

The Outline view is in the window to the right of the Visual Editor. This view lists all the variables and methods in your class. When you select an item in the Outline view, the Visual Editor automatically scrolls to the corresponding variable declaration or method in the source pane, so this is an easy way to navigate through your source code.

Debugging the Scalable option

Let's run your application until it stops at the breakpoint you defined for it, and then see what the Debug perspective can tell us.

  1. Switch to the window that your application is running in, and use the Open… option in the File menu to select an image file (.jpg or .gif).

  2. Click on the Image menu.

  3. Notice that a lot of changes just happened in the Debug perspective. These changes mean that the JCheckBoxMenuItem bean fired a PropertyChangeEvent, and execution stopped at your breakpoint:

    • The statement where you set the breakpoint is highlighted in the Visual Editor, which shows that this statement is about to be executed.

    • The Debug view shows many more entries for the AWT-EventQueue thread, which is now in a suspended state. (These entries show all the behind-the-scenes work that Java is doing to fire the PropertyChangeEvent).

    • Click on the Variables tab, and you'll see that the Variables view now shows the variables in your PropertyChangeListener: this (the listener class itself) and evt (the PropertyChangeEvent that describes the current event—now that looks like something interesting!)

  4. In the Variables view, click on the + sign next to evt=java.beans.PropertyChangeEvent. The content of the PropertyChangeEvent is expanded, as shown in Figure 7.29.

    Click To expand
    Figure 7.29: PropertyChangeEvent variable in the Variables view

    Tip

    The id numbers you see in the Variables view are internal identifiers for the various objects in your program. You can use the numbers to follow the changes to a particular object.

    As you know from working with PropertyChangeEvents in your applications, the PropertyChangeEvent variable tells you the source of the event (the class that fired the PropertyChangeEvent) and the name of the property that changed. It also tells you the old value and new value of the property that changed. In this case, you can see that the source of the event is your JCheckBoxMenuItem bean, and the property that changed is called ancestor. We wanted to see what was going on with the state property, so this isn't the PropertyChangeEvent we were interested in.

    Tip

    For an easy way to see the state of a particular field, click on the Show Detail Pane icon. This shows a detail pane at the bottom of the Variables view. Then, when you select a field in the Variables view, the result of the field's toString() method appears in the detail pane.

  5. Click on the Resume icon in the Debug view to continue execution of your application.

  6. The debugger stops again at your breakpoint. Click on the + sign next to evt=java.beans.PropertyChangeEvent in the Variables view to see which property changed this time. It's the ancestor property again, so click on the Resume icon to continue execution.

  7. The Debug view shows that your application is running (that is, it's no longer suspended at any breakpoint), so switch to the window that your application is running in, and click on Scalable in the Image menu.

  8. The debugger stops again at your breakpoint. In the Variables view, click on the + sign next to evt=java.beans.PropertyChangeEvent to see which property changed. It's the ancestor property again, so click on the Resume icon to continue execution.

  9. The Debug view shows that your application is running, so switch back to the window that your application is running in. But what happened? The Scalable option must have been processed, because the Image menu is gone; but execution never stopped in the PropertyChangeListener when the state property changed. Let's try this once again. Click on the Image menu.

  10. The debugger stops at your breakpoint. In the Variables view, click on the + sign next to evt=java.beans.PropertyChangeEvent to see which property changed. It's the ancestor property again, so click on the Resume icon to continue execution.

  11. The Debug view shows that your application is running, so switch back to the window that your application is running in. The Scalable option is checked, so the state property must have changed when you clicked on the Scalable option; but we know from the debugger that the PropertyChangeListener never received control for this property.

  12. This is going to require more thought. We're finished with the debugger for the moment, so click on the Terminate icon in the Debug view to terminate execution of your application. Your application window closes, and the Debug view shows that all threads have been terminated. If you ever want to clean up the Debug view to remove the entries for terminated executions of your application, just click on the Remove All Terminated Launches icon.

So, what has the debugger told us? We know that the PropertyChangeListener for the JCheckBoxMenuItem bean is working properly, because it received control when the ancestor property changed. Why wouldn't it receive control when other properties, such as state, change? Let's go back to what you learned about PropertyChangeEvents in Chapter 2. Beans fire PropertyChangeEvents to notify listeners whenever changes are made to bound properties. Since the PropertyChangeListener never received control when the state property changed, that tells us that the state property is not bound—it doesn't automatically notify listeners when it changes. So, if PropertyChangeEvent isn't what's fired when the state changes, what is? We need to go back to the documentation for the JCheckBoxMenuItem bean to see what event we should have been listening for.

Fixing the Scalable option

The documentation for the JCheckBoxMenuItem bean is included in WebSphere Studio's help. Let's see what it has to say.

  1. Click on the Help menu in the WebSphere Studio Workbench and select Help Contents from the menu.

  2. In the Help window that appears, select J2SE SDK 1.3.1 APIs from the help contents.

  3. The bean you're interested in is JCheckBoxMenuItem in the javax.swing package, so click on the + sign next to javax.swing Package. Scroll down through the list of classes in that package and select JCheckBoxMenuItem. The bean's documentation appears in the right portion of the help window.

  4. If you've already explored the help documentation for standard Java classes, you know that in most cases the events fired by the bean are described right at the beginning of the documentation. In this case, the documentation points you to the "How to Use Menus" section of The Java Tutorial (a very useful resource on the JavaSoft website).

  5. Make sure you have an active Internet connection, and click on the How to Use Menus link.

  6. The Web page from the JavaSoft website appears in the help window. Scroll through the Web page until you get to the section titled "Handling Events from Menu Items". There we find the solution to our problem—we should have been listening for ItemEvents, not PropertyChangeEvents. Click on the How to Use Check Boxes link, which gives you more details, including sample code. To listen for changes to the JCheckBoxMenuItem's state property, we should have used a java.awt.event.ItemListener, and when the itemStateChanged(ItemEvent) method receives control, the stateChange property in the ItemEvent tells us whether the check box has been selected or deselected.

    Tip

    If images don't display when you browse the help information, check the browser settings on your machine. WebSphere Studio uses an embedded browser to display the help information, and it picks up browser settings from your machine, so to see images you must have your browser settings set to show graphics in Web pages.

  7. Switch back to the Java perspective in the WebSphere Studio Workbench, and, in the source pane, find the code that initializes the JCheckBoxMenuItem bean.

  8. Double-click on the blue dot in the source pane margin to remove the breakpoint, since we don't need it any more.

  9. Delete the lines of code for the PropertyChangeListener.

  10. The event handling template for java.awt.event.ItemListener is provided with WebSphere Studio but is not automatically imported into the Workbench. You should already have imported this template in Chapter 5, where you used it to listen for events fired by radio buttons. If not, import it now.

    Reminder

    Use Window → Preferences, Java, Templates to import the file. The template you want is /wstools/eclipse/plugins/com.ibm.etools.jbcf. codegen_5.0.1/Examples/Templates/java/awt/event/addItemListener.xml under the folder where you installed WebSphere Studio (for example, C:/Program Files/IBM/WebSphere/Express/SiteDeveloper)

  11. Use content assist to add an ItemListener to the JCheckBoxMenuItem bean, and add code to the itemStateChanged(ItemEvent) method to set the ImageCanvas bean's scalable property based on the stateChange property in the ItemEvent, as shown in Figure 7.30.

    Start Figure

    // add code in bold to process ItemEvents
private javax.swing.JCheckBoxMenuItem getJCheckBoxMenuItem() {
   if(jCheckBoxMenuItem == null) {
    jCheckBoxMenuItem = new javax.swing.JCheckBoxMenuItem();
    jCheckBoxMenuItem.setText("Scalable");
    jCheckBoxMenuItem.setMnemonic('S');
    jCheckBoxMenuItem.addItemListener
            (new java.awt.event.ItemListener() {
     public void itemStateChanged(java.awt.event.ItemEvent e) {
         getImageCanvas().setScalable
      (e.getStateChange() == java.awt.event.ItemEvent.SELECTED);
     }
    });
   }
   return jCheckBoxMenuItem;
}
    End Figure

    Figure 7.30: Adding an ItemListener to the JCheckBoxMenuItem bean

  12. Save your changes and run the application. The Scalable option now works, as you can see in Figure 7.31.

    Click To expand
    Figure 7.31: ImageProcessing application with improved Scalable option


Debugging logic errors

Generally, when you start creating a new application, you specify a set of requirements for the application to meet. For large corporate projects, you usually describe these requirements in a requirements specification, and then you perform testing to assure that your application meets its original requirements. The following are two requirements for our small ImageProcessing application:

  1. When you select the Open… operation from the File menu, or select the Revert option, the image should appear in the application window with its native orientation (rotationAngle=0).

  2. When you cancel the file-opening process (click the Cancel button in the Open file dialog window), the previous image should remain in the window and keep the rotation angle it had before the execution of the Open operation.

Let's test whether our application meets these requirements.

Testing the first requirement

Perform the following test for the Open operation:

  1. Run the ImageProcessing application.

  2. Open any image file in the application window (File → Open…).

  3. Rotate the image 90 degrees (Image → Rotate → 90).

  4. Try the Open operation from the File menu again to open another image file.

As you can see, the newly opened image is also rotated 90 degrees.

One more problem arises when you test the Revert operation:

  1. Run the ImageProcessing application.

  2. Open any image file in the application window (File → Open…).

  3. Rotate the image 90 degrees (Image → Rotate → 90).

  4. Try the Revert operation from the File menu.

  5. Rotate the image 90 degrees again.

The second rotation operation does not work as expected, which means that our application does not meet the first requirement and its behavior is rather confusing. Some minor improvements are needed to reset the rotationAngle when a new or reverted image is presented.

Improving the Revert operation

  1. Select the Revert menu item in the Java Beans view, and add code to its ActionListener to reset the RotationFilter bean's rotationAngle property to 0, as shown in Figure 7.32.

    Start Figure

    // add code in bold to reset rotationAngle
private javax.swing.JMenuItem getJMenuItem1() {
   if(jMenuItem1 == null) {
    jMenuItem1 = new javax.swing.JMenuItem();
    jMenuItem1.setText("Revert");
    jMenuItem1.setMnemonic('R');
    jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent e) {
         getImageCanvas().setImage(new com.ibm.uicontrolsswing.ImageGlyph
            (getJFileChooser().getSelectedFile().getPath()));
         getIvjRotationFilter().setRotationAngle(0);
     }
    });
   }
   return jMenuItem1;
}
    End Figure

    Figure 7.32: Resetting the rotationAngle when Revert operation is performed

This rotates the image to its native orientation each time the user chooses the Revert option.

Improving the Open file operation

  1. Select the Open menu item in the Java Beans view, and add code to its ActionListener to reset the RotationFilter bean's rotationAngle property to 0, as shown in Figure 7.33.

    Start Figure

    // add code in bold to reset rotationAngle
private javax.swing.JMenuItem getJMenuItem() {
   if(jMenuItem == null) {
    jMenuItem = new javax.swing.JMenuItem();
    jMenuItem.setText("Open...");
    jMenuItem.setMnemonic('O');
    jMenuItem.addActionListener(new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent e) {
      getJFileChooser().showOpenDialog(ImageProcessing.this);
       getImageCanvas().setImage(new com.ibm.uicontrolsswing.ImageGlyph
            (getJFileChooser().getSelectedFile().getPath()));
        getIvjRotationFilter().setRotationAngle(0);
     }
    });
   }
   return jMenuItem;
}
    End Figure

    Figure 7.33: Resetting the rotationAngle when Open operation is performed

This operation rotates the image to its native orientation each time the user chooses the Open… option. Save your changes.

Testing the second requirement

At the moment, our application meets the first requirement (that when Open… or Revert is selected from the File menu, the image appears in the application window with its native orientation). Try the following test:

  1. Run the ImageProcessing application.

  2. Open any image file in the application window.

  3. Rotate the image 90 degrees.

  4. Try to open another file using the Open… option from the File menu, and click the Cancel button in the Open file window.

Our application still does not meet the second requirement. After you click the Cancel button, the image in the application changes its orientation from 90 degrees to its native 0 degrees, which isn't what we specified.

Observing the RotationFilter bean

To detect the problem, we'll use the Debug perspective to observe what happens when the user selects the Open… option and then click Cancel.

  1. In the source pane, set a breakpoint in the Open menu item's ActionListener to stop after the open file dialog displays, as shown in Figure 7.34.

    Click To expand
    Figure 7.34: Setting a breakpoint in the Open menu item's ActionListener

  2. For this test, you want to stop at the breakpoint the second time the ActionListener is invoked, so right-click on the blue dot in the source pane margin and select Breakpoint Properties… from the pop-up menu. The Java Line Breakpoint Properties window appears. Select Enable Hit Count and enter 2 for the Hit Count value, as shown in Figure 7.35.

    Click To expand
    Figure 7.35: Java Line Breakpoint Properties window

  3. Click OK.

    Tip

    You can also use the Enable Condition option in the Breakpoint Properties window to enter a code snippet for a condition under which the breakpoint should stop. This limits the debugger to stopping at only the conditions you're interested in seeing.

  4. Start the application with the debugger (Debug As → Java Application).

  5. Open any image file in the application window. Notice that the debugger doesn't stop at your breakpoint, because the hit count has not been reached yet.

  6. Rotate the image 90 degrees.

  7. Try to open another file using the Open… option from the File menu, but click Cancel in the Open file window. This time the debugger stops at your breakpoint.

  8. The RotationFilter bean's rotationAngle property should be set to 90, so let's take a look at the current variables to verify that it is set correctly. In the Variables view, click on the + sign next to each variable to expand its contents, as shown in Figure 7.36.

    Click To expand
    Figure 7.36: Variables view

    As you can see, the Variables view only shows the variables for the currently executing class, which right now is the ActionListener for the Open menu item (not the main application class), so we need to find another way to view the contents of the RotationFilter bean. No problem-we can execute a code snippet in the debugger to look at it.

  9. In the source pane, select getIvjRotationFilter() in the statement following the one where the breakpoint is set, right-click, and select Inspect from the pop-up menu, as shown in Figure 7.37.

    Click To expand
    Figure 7.37: Using Inspect to execute a code snippet

    Tip

    Just select the first part of the statement in the source pane—we want to display the current content of the RotationFilter bean, not execute the entire statement to set the rotationAngle property.

  10. The debugger executes the selected code snippet, and presents the result in the Expressions view. Scroll down the window, and you can see that the current value of the rotationAngle property is 90, as shown in Figure 7.38.

    Click To expand
    Figure 7.38: Result of executing the getlvjRotationFilter() code snippet

  11. Let's step through the code until we find the problem. The current statement is about to set the image using the JFileChooser bean's selectedFile property, which looks like another problem, because we really shouldn't be setting the image when the user clicks the Cancel button on the open file dialog. To let the current statement execute, click on the Step Over icon in the Debug view until you reach the next statement.

    Tip

    If your source code for the current statement extends across more than one input line, you may need to click the Step Over icon several times to get to the next statement. Notice that the Debug view also includes Step Into and Step Return icons, which you can use to step through your code. Step Into steps into the current statement. Step Return completes execution of the current method and then stops.

  12. Here we already have the source of our rotation angle problem. We're about to set the rotation angle to 0, which, again, is something we shouldn't be doing when the user clicks the Cancel button on the open file dialog. Unlike the debugger in VisualAge for Java, you can't modify code on the fly in the WebSphere Studio debugger, so, for example, we can't just delete the current statement to prevent it from executing. Instead, we'll let the current statement execute as normal, and then set the rotationAngle property back to 90. Click on the Step Over icon. The current statement executes, and you can see in the Expressions view that the rotationAngle property changes to 0.

  13. What we want to do now is execute a code snippet to set the rotationAngle property back to 90. Click on the Display tab, and type in the following statement: getIvjRotationFilter().setRotationAngle(90);. Select this code snippet, right-click, and select Inspect from the pop-up menu, as shown in Figure 7.39.

    Click To expand
    Figure 7.39: Executing a code snippet in the Display view

  14. The Expressions view appears with the result of the code that was just executed, and shows that the rotationAngle has been reset to 90 (in effect, cancelling out what the incorrect instruction just did). Click the Resume icon in the Debug view to resume execution of the application. Switch to the window where your application is running; this time you see that the image remains in the correct orientation after you click the Cancel button.

  15. We're done testing with the debugger, so close the application window and the Debug perspective.

    Reminder

    To close a perspective, right-click on its icon and select Close from the pop-up menu.
    Warning

    It's also possible to change the value of some variables directly in the Variables and Expressions views; but doing it this way can give you unpredictable results, because the debugger modifies the variable directly without calling the associated setter method. That's why we used the Display view to call the rotationAngle property's setter method.

Final corrections

From our testing with the debugger, we saw that the logic in the Open menu item's ActionListener was not taking the proper steps when the user clicked the Cancel button in the open file dialog. The rotationAngle property should be reset to 0 only when the user actually selects an image file. Similarly, the image in the ImageCanvas should be updated only when the user selects a file. But how do we know if the user selects a file? Let's go look at the documentation for the JFileChooser bean.

  1. In the WebSphere Studio Help window, select JFileChooser in the javax.swing package. The sample code at the start of the documentation for JFileChooser shows what we should have been doing. The showOpenDialog(Component) method returns a value that tells us whether the user selected a file or not.

  2. Switch back to the Java perspective.

  3. Remove the breakpoint in the Open menu item's ActionListener by doubleclicking on the blue dot.

  4. Update the code in the ActionListener so that it sets the image and rotationAngle only when the user selects a file name in the open file dialog, as shown in Figure 7.40.

    Start Figure

    // updated code shown in bold
private javax.swing.JMenuItem getJMenuItem() {
   if(jMenuItem == null) {
    jMenuItem = new javax.swing.JMenuItem();
    jMenuItem.setText("Open...");
    jMenuItem.setMnemonic('O');
    jMenuItem.addActionListener(new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent e) {
     int returnVal =
            getJFileChooser().showOpenDialog(ImageProcessing.this);
     if (returnVal == javax.swing.JFileChooser.APPROVE_OPTION) {
      getImageCanvas().setImage(new com.ibm.uicontrolsswing.ImageGlyph
            (getJFileChooser().getSelectedFile().getPath()));
      getIvjRotationFilter().setRotationAngle(0);
      }
     }
    });
   }
   return jMenuItem;
}
    End Figure

    Figure 7.40: Updated ActionListener

Save your changes and test the application. Now it works as expected and meets both specifications.

You can find a final version of the corrected ImageProcessing application in the /solutions/chap07/imageProcessing subdirectory on the CD included with this book. Create a new package called solutions.chap07.imageProcessing in the ImageWork project, and import/solutions/chap07/imageProcessing/ImageProcessing.java into it. Open [image] ImageProcessing.java with the Visual Editor to compare your program with the solution.

Tip

In the examples shown in this chapter, we set breakpoints at specific statements in your source code. You can also set breakpoints to suspend execution when a particular Java exception is thrown, such as NullPointerException. In the Breakpoints view, click on the Add Java Exception Breakpoint icon. A window appears in which you select the exceptions you want to stop at. When you set a breakpoint for an exception, it is added to the list of breakpoints in the Breakpoints view. When that exception occurs, execution of your program stops so that you can analyze the cause of the exception.


In review

This chapter demonstrated how to use many of the features of the WebSphere Studio Debug perspective to debug and fix problems in your applications. You also learned how to use Swing menu components to add a menu bar and menu options to your applications, and how to use the JFileChooser bean to show an open file dialog.


References

The Java Tutorial: http://java.sun.com/docs/books/tutorial/index.html


Chapter 8: Advanced Applet Development

Download CD Content

Overview

So far, we have been creating two kinds of programs: applets and applications. Even though you go through very similar processes to create these programs in WebSphere Studio, there is an obvious difference between them. Applications are independent programs that execute from a specific location. Applets, on the other hand, are not independent and must be executed inside a browser. And if you write an Internet applet, you can't make any assumptions about the kind of system that might run your applet. This causes some differences in logic between applications and applets, and it puts some restrictions on what an applet can do.

This chapter discusses applet development in detail. It focuses on advanced topics such as using applet parameters, controlling the browser that hosts your applet, customizing your applets on the fly, and security issues. In addition, we'll discuss when to save your applets as separate class files versus saving them as JAR packages.

You will create two applets in this chapter. The first applet, shown in Figure 8.1, is a customizable NavigationPanel applet that can redirect the browser to other resources and change its status message.

Click To expand
Figure 8.1: NavigationPanel applet

The second applet, shown in Figure 8.2, is a customizable Running Text applet that demonstrates drag and drop functionality as well as some security issues for browsers.

Click To expand
Figure 8.2: RunningText applet


Using JAR files for applets

When you create a simple applet, usually you can just create a class to be exported into a single class file. In this case, the HTML descriptor, which calls this simple class, looks like the following:

<APPLET CODE="MyApplet.class" WIDTH="300" HEIGHT="200">
</APPLET>

When your browser comes across this sort of HTML descriptor in the context of a Web page, it downloads the specified MyApplet.class file from the server. What happens after that? The browser sends the class file to its built-in Java Virtual Machine (JVM). The JVM, in turn, performs all security procedures, and if it doesn't find any problems, it sends the class to the ClassLoader service for loading.

Now imagine that your applet uses several classes as well as some resource files such as images and audio. If you use the same scheme as the one for the simple class, the process is as follows. First, the class file gets downloaded to your computer from the server and sent to the JVM. Then, after security checking, the ClassLoader service detects that the class requires another class to be executed, which results in another connection to the server to download the missing class. The process is repeated for the next class, until all the necessary classes and resource files are downloaded. If your applet uses 10 classes, there will be 10 connections and disconnections to and from the server. Because of the way HTTP (the protocol that is used for transferring information through the Internet) works, this scenario is very ineffective.

Even though this scenario will work, it would be much more effective to use JAR archives instead of separate classes. As you know, you can export your classes and resource files to JAR archives using WebSphere Studio. To use the JAR archive in your HTML page, you can use the following descriptor:

<APPLET CODE="MyApplet.class" WIDTH="300" HEIGHT="200"
ARCHIVE="FirstArchive.jar, SecondArchive.jar">
</APPLET>

This code instructs the browser to download the JAR files until it finds the MyApplet class and any classes that it references. This is a much more efficient way of downloading applets. No matter how many files reside inside a JAR file, you need only one connect-disconnect session to the server to download a particular JAR file. You just need to be careful when you create the JAR files to include only the files that the applet really needs to run in the browser. For example, don't include design-time classes that are used only by the tools you use to develop your applet. Also, you can further optimize the download by placing classes that your applet uses only in special scenarios into a separate JAR file. That JAR file is downloaded to the browser only if the user runs that scenario.

Another advantage of using JAR archives is the ability to create trusted applets, which can access hard disks and other resources of the customer's computer. To create trusted applets, you need to generate a pair of private and public keys and obtain an object-signing certificate from one of these sources:

  • An independent certificate authority that authenticates your identity

  • Certificate authority server software running on your corporate internet or extranet

When you have the certificate, you can sign your JAR files. Users who trust your certificate can give your applets full access to their system, and the applets can perform almost everything an application does without any security restrictions. There are some tools for creating private and public keys and even for generating certificates for testing purposes. We'll take a closer look at one of these tools in the "Signing the RunningText applet" section later in this chapter.

Start Sidebar
Differences between browsers

In the past, only Netscape Navigator supported the ARCHIVE tag. Internet Explorer Version 4.0 and later, though, also supports the ARCHIVE tag. However, Internet Explorer does not recognize a signature in a JAR file. For more information on this topic, see the "HOWTO: Deploy Java in Internet Explorer 4.0 and Netscape 4.0" article at http://support.microsoft.com/support/kb/articles/Q179/6/52.asp.

Internet Explorer and Netscape Navigator also support different tags to run applets with the Java Plug-in. The APPLET tag works in both browsers, but it uses the Java Runtime Environment (JRE) that comes with the browser to run the applet. This could be an old version of the JRE, so it might not include all the functions you want to use, such as Swing. To run applets with the Java Plug-in, you use OBJECT and EMBED tags instead of the APPLET tag. For more information, see http://java.sun.com/j2se/1.4.1/docs/guide/plugin/developer_guide/using_tags.html.

End Sidebar


NavigationPanel applet

First, let's create an applet to demonstrate some of the advanced applet concepts. We'll create a NavigationPanel applet that can redirect the browser to other resources and change its status message.

Analyzing the functionality

Before we start building the NavigationPanel applet, let's talk about the functionality we are expecting from the applet. The task of the NavigationPanel applet is to direct the browser to any particular resource—local or remote. The applet consists of a set of controls, such as buttons and images, that can be clicked on to connect you to the appropriate URL. In the NavigationPanel applet, you are going to use two buttons and one image, so you can link to three URLs using these controls.

However, say you wanted to install your final NavigationPanel applet on a friend's Web page whose URL preferences differ from yours. What do you do? Change the applet code? No. The best solution is to allow the customer (in this case, your friend) to define some parameters for your applet without providing access to the source code. The <param> tags inside the <applet> descriptor in HTML files are used for this purpose. Take a look at the HTML code in Figure 8.3.

Start Figure
<html>
<head><title>NavigationPanel</title></head>
<body>
<h1>NavigationPanel</h1>
<p>
<applet CODE="navigationPanel.NavigationPanel.class"
ARCHIVE="NavigationPanel.jar,chap08a.jar" WIDTH="200" HEIGHT="200">
   <param name="name1" value="IBM">
   <param name="url1" value="http://www.ibm.com">
   <param name="name2" value="alphaWorks">
   <param name="ur12" value="http://www.alphaWorks.ibm.com">
   <param name="image" value="computer.jpg">
   <param name="url3" value="http://www.swh=t.com">
</applet>
</p>
</body>
</html>
End Figure

Figure 8.3: Using <param> tags in an <applet> descriptor

In the figure, there are six <param> tags inside the <applet> descriptor that set the parameters for this applet. Using parameters is a good way to make your applets customizable. As you can see, each <param> tag contains two parameters: name and value, letting the user set the appropriate parameters for the applet. In the following sections you'll learn how to use parameters in your applet and how to specify parameter values when you run your applet in WebSphere Studio.

Starting a new project

  1. The bean you use in the NavigationPanel applet (ImageCanvas) is in the [image] chap08a.jar file. Copy [image] chap08a.jar from the /solutions/chap08/ subdirectory on the CD included with this book to a folder on your machine, such as C:/beans.

  2. In the Java perspective in WebSphere Studio, create a new Java Project called AdvancedApplets. Specify [image] chap08a.jar as an external JAR file on the Libraries tab.

  3. Create a new package called navigationPanel in your AdvancedApplets project.

  4. Create a new visual class called NavigationPanel in your navigationPanel package. Make java.applet.Applet the superclass (select Applet as the visual class to extend and uncheck the Swing check box), and uncheck all check boxes to create method stubs. Your applet opens in the Visual Editor.

Composing visual components

  1. Select the applet on the design surface. In the Properties view, set the applet's layout property to GridBagLayout, background property to lightGray, and size property to 200,200. In the source pane, you can see that the code to set these properties is added to the init() method, rather than a separate initialize() method that's called by the constructor. Web browsers call the init() method that's called by the constructor. Web browsers call the init() method to initialize an applet when it starts running in the browser, so this is where the Visual Editor puts your initialization code.

  2. Select a Button bean from the palette of AWT Controls, and drop it on the applet's visual surface. Set the Button bean's properties as follows:

    • constraint-gridx to 0

    • constraint-gridy to 0

    • constraint-insets to 3,3,3,3

    • constraint-fill to BOTH

  3. Select another Button bean, and drop it on the applet's visual surface. Set the second Button bean's properties as follows:

    • constraint-gridx to 0

    • constraint-gridy to 1

    • constraint-insets to 3,3,3,3

    • constraint-fill to BOTH

  4. Use Choose Bean to select an ImageCanvas bean from the con.ibm.uicontrols package, and drop it on the applet's visual surface. (You used the Swing-based version of this bean in Chapter 7; this one is AWT-based.) Set the ImageCanvas bean's properties as follows:

    • constraint-gridx to 0

    • constraint-gridy to 2

    • constraint-insets to 3,3,3,3

Your composition should now look like Figure 8.4.

Click To expand
Figure 8.4: Initial layout of the NavigationPanel applet

Getting the parameters for the buttons

When the applet runs in a Web browser, it can use its getParameter(String) method to access the parameters that are specified in the HTML file. You pass the name of the parameter whose value you want to get as input to the getParameter(String) method, and it returns the parameter's value. For the Button beans, you'll use the name1 and name2 parameters to set the labels for the buttons, and the url1 and url2 parameters to set the action that occurs when the buttons, are clicked. The values returned by the getParameter(String) method are the parameter values specified in the APPLET tag in the HTML file, so, to change the values, you just change the HTML file.

  1. Select the first Button bean on the design surface to scroll to its method in the source pane, and add the code shown in Figure 8.5 to set its label and action-Command properties.

    Start Figure

    // add code in bold
private java.awt.Button getButton() {
  if(button == null) {
   button = new java.awt.Button();
button.setLabel(getParameter("name1"));
button.setActionCommand(getParameter("url1"));
   }
   return button;
}
    End Figure

    Figure 8.5: Setting the label and actionCommand for the first button

    Tip

    When you add this code, you'll see an error message that the code is too complicated to be evaluated. Ignore this design time message—you'll set the parameters in a launch configuration at run time. The Visual Editor is just letting you know that what you see on the design surface isn't what will appear when you run the applet.

  2. Select the second Button bean on the design surface, and add the code shown in Figure 8.6 to set its label and actionCommand properties.

    Start Figure

    // add code in bold
private java.awt.Button getButton1() {
  if(button1 == null) {
   button1 = new java.awt.Button();
button1.setLabel(getParameter("name2"));
button1.setActionCommand(getParameter("url2"));
   }
   return button1;
}
    End Figure

    Figure 8.6: Setting the label and actionCommand for the second button

  3. Save your changes.

Testing the button labels

If you try to run your applet now using Run As → Java Bean / Applet, you'll see the two buttons, but their labels will be blank. That's because no parameters have been supplied for your applet. The way you supply parameters is with a launch configuration.

  1. Click on the arrow next to the Run icon in the toolbar, and choose Run….

  2. The Launch Configurations window appears. Select Java Bean / Applet as the launch configuration to create, and click New. A new launch configuration appears in the window, with the JavaBean tab filled in with your project (AdvancedApplets) and applet (navigationPanel.NavigationPanel) names.

  3. Select the Applet Parameters tab, and click New to create a new applet parameter. The name-value pair of Name0 and Value0 appears in the table. Change Name0 to name1, and change Value0 to IBM. This defines your first applet parameter, which supplies the label for the first button.

  4. Click New again, and define the remaining applet parameters for the buttons, as shown in Figure 8.7.

    Click To expand
    Figure 8.7: Defining applet parameters in a launch configureation

  5. Click Run.

Your applet starts, and as you can see, the button labels appear with the parameter values you supplied in the launch configuration. To change the applet to use different button labels, you just change their values in the launch configuration.


Applet context and codeBase

The next task is to bring the buttons to life. Each time the user clicks a button, the Web browser should show the appropriate URL resource, which requires you to know the environment in which the applet is running (also called its applet context).

Getting the appletContext property

The applet context is a property of the applet, called appletContext, and of type java.applet.AppletContext. The AppletContext class provides methods to get an image or audio clip from a URL, to show a status message in the browser window, to find other applets within the HTML document, or to show a document at another URL.

You get the appletContext property by using the applet's getAppletContext() method. Code executing in your main applet class gets the property by specifying either this.getAppletContext() or simply getAppletContext(). Code executing in an inner class, such as an ActionListener for one of the buttons, needs to use a fully-qualified reference to the applet object, such as NavigationPanel.this.getAppletContext().

Showing the specified URL

Start Sidebar
HTML target parameter

Some HTML tags, such as <a> or <body>, let you specify the target parameter, which defines the destination where the particular resource will be displayed. For example, when you click on a hyperlink, the URL source might be displayed in the same browser window as the source document (by default), in a new window, or in a particular frame of a window. If you specify the target parameter's value as_blank, a new browser window gets created when you click on the link. For example, the following hyperlink opens the IBM Web page in a new browser window:

<a href="http://www.ibm.com" target="_blank">
Click here to open new window!</a>

For more information on the target parameter, consult an HTML reference.

End Sidebar

To direct the browser to the specified URL, you need one of the showDocument methods of the appletContext. The appletContext class gives you two showDocument methods: showDocument(java.net.URL) and showDocument(java.net.URL, java.lang.String). The first method lets you redirect your browser to the specified URL and show the URL's content in the current browser's window. But what if you need to show the URL's content in a new window or in a specific frame? In that case, you use the second method with two parameters. The showDocument(java.net.URL, java.lang.String) method takes a URL as its first parameter and the name of the target window or frame as its second parameter. As a result, the browser returns the URL's content in the specified frame or window.Let's try it out:

  1. Find the source code that initializes the first Button bean, and use content assist to add an ActionListener. Add code to the actionPerformed(ActionEvent) method to show the URL specified in the button's actionCommand property in a new browser window, as shown in Figure 8.8. Notice that you need to check for exceptions in case the URL specified in the applet parameter is invalid.

    Start Figure

    // add code in bold
private java.awt.Button getButton() {
  if(button == null) {
   button = new java.awt.Button();
   button.setLabel(getParameter("name1"));
   button.setActionCommand(getParameter("url1"));
button.addActionListener(new java.awt.event.ActionListener() {
 public void actionPerformed(java.awt.event.ActionEvent e) {
    try {
      NavigationPanel.this.getAppletContext().showDocument
        (new java.net.URL(getButton().getActionCommand()),"_blank");
    }
    catch (Exception ex) {}
}
});
 }
 return button;
}
    End Figure

    Figure 8.8: ActionListener for the first Button bean

  2. Find the source code that initializes the second Button bean, and use content assist to add an ActionListener. Add code to the actionPerformed(ActionEvent) method to show the URL specified in this button's actionCommand property in a new browser window, as shown in Figure 8.9.

    Start Figure

    // add code in bold
private java.awt.Button getButton1() {
  if(button1 == null) {
   button1 = new java.awt.Button();
   button1.setLabel(getParameter("name2"));
   button1.setActionCommand(getParameter("url2"));
button1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
  try {
   NavigationPanel.this.getAppletContext().showDocument
     (new java.net.URL(getButton1().getActionCommand()),"_blank");
  }
  catch (Exception ex) {}
}
});
}
return button1;
}
    End Figure

    Figure 8.9: ActionListener for the second Button bean

Controlling the status line

Another useful method of the appletContext class is the showStatus(String) method. This method sets text that displays in the status line of the browser window when a certain event occurs. We'll use the mouseEntered events of the Button beans to set the status line of the browser window to the target URL associated with each button.

  1. Find the source code that initializes the first Button bean, and use content assist to add a MouseListener. Add code to the mouseEntered(MouseEvent) method to set the status line, as shown in Figure 8.10.

    Start Figure

    // add code in bold
private java.awt.Button getButton() {
  if(button == null) {
   button = new java.awt.Button();
   button.setLabel(getParameter("name1"));
   button.setActionCommand(getParameter("url1"));
   button.addActionListener(new java.awt.event.ActionListener() {
   public void actionPerformed(java.awt.event.ActionEvent e) {
      try {
        NavigationPanel.this.getAppletContext().showDocument
          (new java.net.URL(getButton().getActionCommand()),"_blank");
      }
      catch (Exception ex) {}
   }
  });
button.addMouseListener(new java.awt.event.MouseListener() {
public void mouseClicked(java.awt.event.MouseEvent e) {
       ;
}
public void mousePressed(java.awt.event.MouseEvent e) {
       ;
}
public void mouseReleased(java.awt.event.MouseEvent e) {
       ;
}
public void mouseEntered(java.awt.event.MouseEvent e) {
       NavigationPanel.this.getAppletContext().showStatus
          (getButton().getActionCommand());
}
public void mouseExited(java.awt.event.MouseEvent e) {
       ;
}
});
   }
   return button;
}
    End Figure

    Figure 8.10: MouseListener for the first Button bean

  2. Find the source code that initializes the second Button bean, and use content assist to add a MouseListener. Add code to the mouseEntered(MouseEvent) method to set the status line, as shown in Figure 8.11.

    Start Figure

    // add code in bold
private java.awt.Button getButton1() {
  if(button1 == null) {
   button1 = new java.awt.Button();
   button1.setLabel(getParameter("name2"));
   button1.setActionCommand(getParameter("url2"));
   button1.addActionListener(new java.awt.event.ActionListener() {
   public void actionPerformed(java.awt.event.ActionEvent e) {
      try {
       NavigationPanel.this.getAppletContext().showDocument
        (new java.net.URL(getButton1().getActionCommand()),"_blank");
      }
      catch (Exception ex) {}
   }
   });
button1.addMouseListener(new java.awt.event.MouseListener() {
public void mouseClicked(java.awt.event.MouseEvent e) {
       ;
}
public void mousePressed(java.awt.event.MouseEvent e) {
       ;
}
public void mouseReleased(java.awt.event.MouseEvent e) {
       ;
}
public void mouseEntered(java.awt.event.MouseEvent e) {
       NavigationPanel.this.getAppletContext().showStatus
         (getButton1().getActionCommand());
}
public void mouseExited(java.awt.event.MouseEvent e) {
       ;
}
});
   }
   return button1;
}
    End Figure

    Figure 8.11: MouseListener for the second Button bean

As you can see from the code inserted by content assist, you can use several other mouse events. One of them is the mouseExited event, which is sometimes useful for restoring the initial value of the status line when the mouse pointer leaves the bean's visual area.

Save your changes and test the applet. Since you're not running in a true Web browser environment, clicking on either button has no effect, button has no effect, but when you move the mouse over a particular button, its URL appears in the applet status line.

URLs: Absolute and relative

You may have noticed that we used absolute URLs when describing the values for the url1, url2, and url3 parameters. An absolute URL is a URL that starts with a registered URL handler, such as http://, and specifies the full path to the resource. Sometimes, however, you need to use relative paths, such as when you need to download and display an image located in the same directory as the applet's class or JAR file on the server or in a subdirectory of that directory. In this case, it would be more effective to use short addresses such as [image] computer.jpg or images/computer.jpg. Such addresses are called relative because they specify the location of the resource relative to the current object.

When developing an applet, you might not know the name of the server where your final applet will reside. And if you're developing the applet for several customers, you need to make applets independent of their location. However, here we find a roadblock: The getImage(URL,String) method, which lets you use image files in applets, requires the absolute URL of the image file, not the relative URL. To solve this problem, we'll use the codeBase property of the applet, which contains the absolute URL of the running applet. (If, instead, you need the absolute URL of the HTML file in which the applet is running, use the documentBase property of the applet.)

Let's use this knowledge to place the image into the ImageCanvas with its relative path specified in the image parameter.

Displaying an image

To get the absolute URL of your running applet, you have to access its codeBase property. You can then use the codeBase to set the downloaded image for the ImageCanvas bean, as follows:

  1. Select the ImageCanvas bean on the design surface to scroll to its code in the source pane, and add code to set the image, as shown in Figure 8.12 (ignore the design-time error message that the code is too complicated to be evaluated).

    Start Figure

    // add code in bold
private com.ibm.uicontrols.ImageCanvas getImageCanvas() {
  if(imageCanvas == null) {
   imageCanvas = new com.ibm.uicontrols.ImageCanvas();
imageCanvas.setImage(new com.ibm.uicontrols.ImageGlyph
         (getImage(getCodeBase(),getParameter("image"))));
   }
   return imageCanvas;
}
    End Figure

    Figure 8.12: Setting the image property for the ImageCanvas bean

This code takes the applet's codeBase and appends the value of the image parameter (computer.jpg, in our case) to create an absolute URL for the getImage(URL, String) method. The code then converts the returned Image to an ImageGlyph to set the image for the ImageCanvas bean.

Final connections

Finally, let's make the image functional. Each time the user clicks on the image surface, we want to redirect the browser to the URL specified in the url3 parameter. We'll also set the status line of the browser to the url3 string whenever the mouse points at the image.

  1. Use content assist to add a MouseListener to the ImageCanvas bean. Add code to the mouseClicked(MouseEvent) method to show the URL specified in the url3 parameter in a new browser window. Add code to the mouseEntered (MouseEvent) method to show the url3 parameter in the browser status line, so your final MouseListener for the ImageCanvas bean looks like Figure 8.13.

    Start Figure

    // add code in bold
private com.ibm.uicontrols.ImageCanvas getImageCanvas() {
  if(imageCanvas == null) {
   imageCanvas = new com.ibm.uicontrols.ImageCanvas();
   imageCanvas.setImage(new com.ibm.uicontrols.ImageGlyph
        (getImage(getCodeBase(),getParameter("image"))));
imageCanvas.addMouseListener(new java.awt.event.MouseListener() {
public void mouseClicked(java.awt.event.MouseEvent e) {
  try {
    NavigationPanel.this.getAppletContext().showDocument
      (new java.net.URL(NavigationPanel.this.getParameter("url3")),
       "_blank");
  }
  catch (Exception ex) {}
}
public void mousePressed(java.awt.event.MouseEvent e) {
       ;
}
public void mouseReleased(java.awt.event.MouseEvent e) {
       ;
}
public void mouseEntered(java.awt.event.MouseEvent e) {
  NavigationPanel.this.getAppletContext().showStatus
            (NavigationPanel.this.getParameter("url3"));
}
public void mouseExited(java.awt.event.MouseEvent e) {
       ;
}
});
   }
   return imageCanvas;
}
    End Figure

    Figure 8.13: MouseListener for the ImageCanvas bean

  2. Save your changes.

Your applet is now complete. As you've already seen, testing your applet with the Applet launcher in the Java perspective is not a true Web browser environment, so for example, clicking on the image would not redirect to the specified URL. To test all your applet functions, you need to create a Web page to run in a Web browser. We're finished making changes to the NavigationPanel applet, so close the Visual Editor. We'll create a JAR file for your applet, and then switch to the Web perspective in WebSphere Studio to run your applet in a Web browser.


Running the NavigationPanel applet

To run your applet in a Web browser, you first export it to its own JAR file.

Exporting to a JAR file

  1. Right-click on [image] NavigationPanel.java in the Package Explorer, and select Export… from the pop-up menu.

  2. Choose JAR file as the export destination and click Next.

  3. Click the Browse… button to browse to the folder where you want to place your exported JAR file, such as C:/export, and enter a file name for your applet's JAR file, such as [image] NavigationPanel.jar. Click Save.

  4. Choose the export options Export generated class files and resources and Compress the contents of the JAR file.

  5. Click Finish.

Setting up the Web project

To run your applet in a Web browser, you need a Web page that includes an appropriate <applet> tag and the resources required to run the applet (NavigationPanel.jar, [image] chap08a.jar, and [image] computer.jpg). You can do this in a new Web project in WebSphere Studio. Follow these steps to create a new Web project, and import the resources into it.

  1. Open a Web perspective in WebSphere Studio.

    Reminder

    To open a Web perspective, click on the Open a Perspective icon, select other…, and then select Web from the list of choices and click OK.

  2. Create a new J2EE Web project named NavigationPanelWeb.

    Reminder

    To create a Web project, use File → New → Web Project. Enter NavigationPanelWeb as the project name, leave the defaults to create a new J2EE Web Project, and click Finish. If you are prompted to modify server configurations, click OK.

  3. In the J2EE Navigator, click on the + sign next to NavigationPanelWeb to expand the contents of the project. Right-click on the Web Content folder in the NavigationPanelWeb project, and select Import… from the pop-up menu.

  4. Select File system as the import source and click Next.

  5. Click the Browse… button next to the directory field to browse to the directory where you saved your [image] NavigationPanel.jar file and click OK.

  6. Select the JAR file, and click Finish.

  7. Repeat the preceding steps to import the [image] chap08a.jar and [image] computer.jpg files in the /solutions/chap08/subdirectory on the CD included with this book into your Web project.

Creating a Web page

To create a Web page that runs your applet in a Web browser, do the following:

  1. In the J2EE Navigator, right-click on the Web Content folder in the NavigationPanelWeb project and select New → HTML/XHTML File from the pop-up menu.

  2. Enter [image] NavigationPanel.html for the HTML file name, and click Finish.

  3. Your new [image] NavigationPanel.html file opens in the HTML editor. Click on the Design tab, and type in whatever text you want to appear on your Web page.

  4. Position the cursor to the point where you want your applet to be added to the Web page, and select Insert → Others → Java Applet…. Enter navigationPanel.NavigationPanel.class for the Code name (the name of the applet to run), [image] NavigationPanel.jar,chap08a.jar for Archives (the JAR files where Web browsers look for your code), 200 for Width, and 200 for Height, as shown in Figure 8.14.

    Click To expand
    Figure 8.14: Adding the NavigationPanel applet to a web page

  5. Click on the Parameters tab, and use the Add button to define the parameters for your applet shown in Table 8.1, so the parameters tab looks like Figure 8.15.

    Table 8-1: NavigationPanel applet parameters

    Name

    Value

    name1

    IBM

    url1

    http://www.ibm.com

    name2

    alphaWorks

    url2

    http://www.alphaWorks.ibm.com

    image

    computer.jpg

    url3

    http://www.swh-t.com

    Click To expand
    Figure 8.15: Specifying applet parameters

  6. Click OK.

  7. Click on the Preview tab to see how your new Web page looks in a Web browser. Your applet starts running, and should look similar to Figure 8.16.

    Click To expand
    Figure 8.16: Running the NavigationPanel applet in a Web page

    Make sure you have an active Internet connection. Now when you click on the buttons or the image, another browser window opens to show the appropriate Web page. Also, when you move the mouse pointer over the buttons or the image, the appropri-ate message appears in the browser's status line.

  8. Return to the Design tab and save your changes.

Configuring the applet

To change the links, labels, and image of the NavigationPanel, you just edit the applet parameters in the HTML file. Figure 8.17 shows an example of an edited HTML file.

Start Figure
<html>
<head><title>NavigationPanel</title></head>
<body>
<h1>NavigationPanel</h1>
<p>
<applet CODE="navigationPanel.NavigationPanel.class"
ARCHIVE="NavigationPanel.jar,chap08a.jar" WIDTH="125" HEIGHT="225">
   <param name="name1" value="Books">
   <param name="url1" value="http://www.redbooks.ibm.com/">
   <param name="name2" value="Java">
   <param name="url2" value="http://java.sun.com/">
   <param name="image" value="wsAbout.gif">
   <param name="url3" value="http://www7b.software.ibm.com/wsdd/">
</applet>
</p>
</body>
</html>
End Figure

Figure 8.17: Edited HTML for NavigationPanel applet

Figure 8.18 shows what the running applet would look like (don't forget to put the image file in the subdirectory where the applet is running from).

Click To expand
Figure 8.18: NavigationPanel with different parameters

If you had any problems building the NavigationPanel applet, look at the solution file in the /solutions/chap08/navigationPanel subdirectory on the CD included with this book. Create a new package called solutions.chap08.navigationPanel in the AdvancedApplets project, and import /solutions/chap08/navigationPanel/NavigationPanel.java into it. Open [image] NavigationPanel.java with the Visual Editor to compare your program with the solution.


Running Text applet

The next applet we are going to create displays customizable running text in the browser window. We'll provide two kinds of customizers. The first uses <param> tags in the <applet> descriptor for setting the text and the value of movement steps in two directions, horizontal and vertical. The second customizer is an additional frame that lets you customize the text color and the text itself during the applet's run time.

Using the Running Text applet, we'll also show you a technique for signing your applets.

Setting up the project

  1. The beans you use in the Running Text applet (Moving Text, DragBean, and DropBean) are in the [image] chap08b.jar file. Copy [image] chap08b.jar from the /solutions/chap08/ subdirectory on the CD included with this book to a folder on your machine, such as C:/beans.

  2. In the Java perspective in WebSphere Studio, update your AdvancedApplets project to add [image] chap08b.jar as an external JAR file on the Libraries tab.

    Reminder

    To update the project, right-click on it in the Package Explorer and select Properties from the pop-up menu. Select Java Build Path from the list of properties and use the Libraries tab to add external JAR files to the build path.

  3. Import the event handling templates in the [image] addDnDListeners.xml file in the /solutions/chap08/ subdirectory on the CD included with this book.

    Reminder

    To import the file, use Window → Preferences, Java, Templates.

  4. Create a new package called running Text in your AdvancedApplets project.

  5. Create a new visual class called Running Text in your running Text package. Make java.Applet the superclass (select Applet as the visual class to extend and uncheck the Swing check box), and uncheck all check boxes to create method stubs. Your new class opens in the Visual Editor.

Adding the MovingText bean

  1. Select the applet on the design surface. In the Properties view, set the applet's layout property to BorderLayout, and set its size property to 350,80.

  2. Use Choose Bean to select a MovingText bean from the com.ibm.textdesigner package, and drop it on the center of the applet.

  3. Set the MovingText bean's Dx property to 1 and Dy property to 0. This causes the text to move only horizontally.

  4. Set the borderSize property of the MovingText bean to 0.

  5. Set the foreground property of the MovingText bean to blue, its shadowColor property to gray, and its background property to lightGray. Your composition should now look similar to Figure 8.19 (you'll see the text property move about the bean's visual surface as you update the bean's properties, so your final composition may show the string in a different location, and that's OK; the MovingText bean is just doing what it does best—moving text).

    Click To expand
    Figure 8.19: MovingText component layout

Getting applet parameters

The RunningText applet uses parameters to let the user customize the MovingText bean's text, Dx, and Dy properties.

  1. Find the source code that initializes the MovingText bean, and add code to set its text, Dx, and Dy properties from the corresponding applet parameters, as shown in Figure 8.20.

    Start Figure

    // add code in bold
private com.ibm.textdesigner.MovingText getMovingText() {
  if(movingText == null) {
   movingText = new com.ibm.textdesigner.MovingText();
   movingText.setDx(1);
   movingText.setDy(0);
   movingText.setBorderSize(0);
   movingText.setForeground(java.awt.Color.blue);
   movingText.setShadowColor(java.awt.Color.gray);
   movingText.setBackground(java.awt.Color.lightGray);
movingText.setText(getParameter("text"));
movingText.setDx(Integer.parseInt(getParameter("dx")));
movingText.setDy(Integer.parseInt(getParameter("dy")));
  }
  return movingText;
}
    End Figure

    Figure 8.20: Getting applet parameters at run time

  2. Save your changes.

To test the applet, you need a launch configuration to specify applet parameters.

  1. Click on the arrow next to the Run icon in the toolbar, and choose Run….

  2. The Launch Configurations window appears. Select Java Bean/Applet as the launch configuration to create, and click New.

  3. Select the Applet Parameters tab, and define applet parameters, as shown in Figure 8.21.

  4. Click Run.

    Click To expand
    Figure 8.21: Defining applet parameters in a launch configuration

Your applet should look like Figure 8.22.

Click To expand
Figure 8.22: RunningText applet in action

Even though we could define more parameters for the applet and let the HTML designer customize the properties (such as color for the MovingText bean) using a <param> tag in the <applet> descriptor, we want to demonstrate another technique. We'll let the user of the applet customize its properties "in flight" (in other words, while the applet is running in the browser). For this purpose, we'll create a separate Customizer frame that appears on the screen each time the user clicks on the applet surface.

Creating the Customizer frame

  1. Select a Frame bean from the palette of AWT Controls, and drop it on the design surface outside of the visual surface of the applet.

  2. Resize the frame so you can add visual elements to it, and set its title property to Customizer.

  3. Set the layout of the Frame to GridLayout, the layout-rows property to 2, and the layout-columns property to 2.

  4. Add one Label bean and three TextField beans from the palette of AWT Controls to the Frame. Rename the TextField beans to messageField, greenField, and pinkField.

  5. Set the Label's text property to Input text:

  6. Set the messageField's text property to Drag & Drop.

  7. Set the background property of the greenField to green and the background property of the pinkField to pink. Set the editable property of both these fields to false. Arrange the beans so that your visual composition looks like Figure 8.23

    Click To expand
    Figure 8.23: Customizer frame layout

Connecting the applet and Customizer

To connect the applet and the Customizer frame, you add code to show the frame when the user clicks on the MovingText bean, and code to remove the frame when the user closes the frame's window or when the applet terminates.

  1. Select the MovingText bean on the design surface to scroll to its code in the source pane, and use content assist to add a MouseListener. Add code to the mouseClicked(MouseEvent) method to show the Customizer frame whenever the user clicks on the MovingText bean, as shown in Figure 8.24.

    Start Figure

    // add code in bold
private com.ibm.textdesigner.MovingText getMovingText() {
  if(movingText == null) {
   movingText = new com.ibm.textdesigner.MovingText();
   movingText.setDx(1);
   movingText.setDy(0);
   movingText.setBorderSize(0);
   movingText.setForeground(java.awt.Color.blue);
   movingText.setShadowColor(java.awt.Color.gray);
   movingText.setBackground(java.awt.Color.lightGray);
   movingText.setText(getParameter("text"));
   movingText.setDx(Integer.parseInt(getParameter("dx")));
   movingText.setDy(Integer.parseInt(getParameter("dy")));
movingText.addMouseListener(new java.awt.event.MouseListener() {
      public void mouseClicked(java.awt.event.MouseEvent e) {
             getFrame().show();
      }
      public void mousePressed(java.awt.event.MouseEvent e) {
             ;
      }
      public void mouseReleased(java.awt.event.MouseEvent e) {
             ;
      }
      public void mouseEntered(java.awt.event.MouseEvent e) {
             ;
      }
      public void mouseExited(java.awt.event.MouseEvent e) {
             ;
      }
});
  }
  return movingText;
}
    End Figure

    Figure 8.24: MouseListener for MovingText bean

  2. Select the Customizer frame on the design surface. Use content assist to add the WindowClosing template, and then modify the windowClosing (WindowEvent) method to just remove the frame (not exit the application) when the user closes the frame's window, as shown in Figure 8.25.

    Start Figure

    // add code in bold
private java.awt.Frame getFrame() {
  if(frame == null) {
   frame = new java.awt.Frame();
   java.awt.GridLayout layGridLayout2 = new java.awt.GridLayout();
   layGridLayout2.setRows(2);
   layGridLayout2.setColumns(2);
   frame.setLayout(layGridLayout2);
   frame.add(getLabel(), null);
   frame.add(getGreenField(), null);
   frame.add(getMessageField(), null);
   frame.add(getPinkField(), null);
   frame.setSize(300, 81);
   frame.setTitle("Customizer");
frame.addWindowListener(new java.awt.event.WindowAdapter() {
      public void windowClosing(java.awt.event.WindowEvent e) {
             getFrame().dispose();
      }
});
   }
   return frame;
}
    End Figure

    Figure 8.25: WindowListener for the Customizer frame

  3. The applet's destroy() method is called when the applet terminates. Add a destroy() method to your applet to call the superclass' destroy() method for it to perform its termination processing first, and then add code to remove the frame, as shown in Figure 8.26.

    Start Figure

    // add code in bold
public void destroy() {
      super.destroy();
      getFrame().dispose();
}
    End Figure

    Figure 8.26: Applet's destroy() method

Save your changes and test the applet. When you click on the MovingText bean, the Customizer frame appears.


Drag and drop functionality

To allow the user to change the properties of the applet "in flight", we are going to use two beans: DragBean, which you connect to the drag source, and DropBean, which you connect to the drop target. You need a separate DragBean and DropBean pair for each property you are going to drag and drop.

Dragging and dropping text

To let the user change the text of the moving message during run time, you use the Drag and Drop beans to drag the text in the messageField and drop it onto the MovingText bean.

  1. Use Choose Bean to select a DragBean from the com.ibm.dnd package, and drop it on the design surface outside of the visual elements.

  2. Find the init() method for your applet, and add code to set the DragBean's component property to the messageField, and to set the DragBean's input-Object property to the messageField's text property, as shown in Figure 8.27. This creates the DragBean instance, and then sets the messageField's text property as the drag source.

    Start Figure

    // add code in bold
public void init() {
      java.awt.BorderLayout layBorderLayout1 =
          new java.awt.BorderLayout();
      this.setLayout(layBorderLayout1);
      this.add(getMovingText(), java.awt.BorderLayout.CENTER);
      this.setSize(350, 80);
   getIvjDragBean().setComponent(getMessageField());
   getIvjDragBean().setInputObject(getMessageField().getText());
}
    End Figure

    Figure 8.27: Setting the drag source

  3. Since your applet lets the user change the value of the messageField's text property during run time, you also need to detect when the text string changes and supply the changed value to the DragBean. The messageField is a standard AWT TextField, so it fires a textValueChanged event when the text changes. Find the code that initializes the messageField, and use content assist to add a TextListener. Add code to the textValueChanged(TextEvent) method to update the DragBean's inputObject property with the new text value, as shown in Figure 8.28.

    Start Figure

    // add code in bold
private java.awt.TextField getMessageField() {
  if(messageField == null) {
   messageField = new java.awt.TextField();
   messageField.setText("Drag & Drop");
messageField.addTextListener(new java.awt.event.TextListener() {
public void textValueChanged(java.awt.event.TextEvent e) {
   getIvjDragBean().setInputObject(getMessageField().getText());
}
});
}
return messageField;
}
    End Figure

    Figure 8.28: TextListener for the messageField bean

  4. Use Choose Bean to select a DropBean from the com.ibm.dnd package, and drop it on the design surface outside of the visual elements.

  5. Find the init() method for your applet, and add code to set the DropBean's component property to the MovingText bean, as shown in Figure 8.29. This creates the DropBean instance, and then sets the MovingText bean as the destination object to deliver the property to.

    Start Figure

    // add code in bold
public void init() {
   java.awt.BorderLayout layBorderLayout1 =
       new java.awt.BorderLayout();
   this.setLayout(layBorderLayout1);
   this.add(getMovingText(), java.awt.BorderLayout.CENTER);
   this.setSize(350, 80);
   getIvjDragBean().setComponent(getMessageField());
   getIvjDragBean().setInputObject(getMessageField().getText());
getIvjDropBean().setComponent(getMovingText());
}
    End Figure

    Figure 8.29: Setting the drop destination object

  6. The DropBean fires a dropEnd event when the user releases the mouse button at the end of a drop operation. Find the code that initializes the DropBean and use content assist to add a DropListener (you should have imported the template for this listener earlier in this chapter). Add code to the dropEnd(DropEvent) method to set the MovingText bean's text property from the object being dropped, as shown in Figure 8.30.

    Start Figure

    // add code in bold
private com.ibm.dnd.DropBean getIvjDropBean() {
  if(ivjDropBean == null) {
   ivjDropBean = new com.ibm.dnd.DropBean();
ivjDropBean.addDropListener(new com.ibm.dnd.DropListener() {
public void dragEnter(com.ibm.dnd.DropEvent e) {
       ;
}
public void dragExit(com.ibm.dnd.DropEvent e) {
       ;
}
public void dragOver(com.ibm.dnd.DropEvent e) {
       ;
}
public void dropEnd(com.ibm.dnd.DropEvent e) {
   getMovingText().setText
     ((String) getIvjDropBean().getOutputDropObject());
}
});
  }
  return ivjDropBean;
}
    End Figure

    Figure 8.30: DropListener for the DropBean

Save your changes and test the applet. Click on the MovingText bean's surface to make the Customizer frame appear. Enter text in the messageField, and drag and drop it onto the MovingText. The running text message should change to what you entered.

Dragging and dropping colors

You have two sources from which to "grab" a new color for the running text message: greenField and pinkField. And you have only one destination component to receive these colors: the MovingText component. So this time, you need two more DragBeans, but only one DropBean.

  1. Use Choose Bean to select two more DragBeans from the com.ibm.dnd package, and drop them on the design surface outside of the visual elements.

  2. Find the init() method for your applet. Add code to set the greenField's background property as the drag source for one of the new DragBeans, and add code to set the pinkField's background property as the drag source for the other DragBean, as shown in Figure 8.31.

    Start Figure

    // add code in bold
public void init() {
 java.awt.BorderLayout layBorderLayout1 =
       new java.awt.BorderLayout();
 this.setLayout(layBorderLayout1);
 this.add(getMovingText(), java.awt.BorderLayout.CENTER);
 this.setSize(350, 80);
 getIvjDragBean().setComponent(getMessageField());
 getIvjDragBean().setInputObject(getMessageField().getText());
 getIvjDropBean().setComponent(getMovingText());
 getIvjDragBean2().setComponent(getGreenField());
 getIvjDragBean2().setInputObject(getGreenField().getBackground());
 getIvjDragBean3().setComponent(getPinkField());
 getIvjDragBean3().setInputObject(getPinkField().getBackground());
}
    End Figure

    Figure 8.31: Setting the drag source

  3. Use Choose Bean to select another DropBean from the com.ibm.dnd package, and drop it on the design surface outside of the visual elements.

  4. By default, the DropBean expects to receive a text string (in other words, an instance of the java.lang.String class) as the object being dragged. However, you can customize the DropBean's dataFlavor property and set it to any other legal Java type. We'll set the dataFlavor property to java.awt.Color, which is the class for the color type. In the Properties view, click on the small square to the right of the dataFlavor property. This brings up the DataFlavor window.

  5. Click Custom, and enter java.awt.Color in the input field, as shown in Figure 8.32.

    Click To expand
    Figure 8.32: The DataFlavor window

  6. Click Apply, and then OK. If the dataFlavor gets reset to java.lang.Object after you click the Apply button, go ahead and click OK, and then modify the source code to change java.lang.Object to java.awt.Color, so the second DropBean's method looks like Figure 8.33.

    Start Figure

    // add code in bold
private com.ibm.dnd.DropBean getIvjDropBean2() {
  if(ivjDropBean2 == null) {
   ivjDropBean2 = new com.ibm.dnd.DropBean();
ivjDropBean2.setDataFlavor
   (new com.ibm.dnd.DataFlavorDescriptor("java.awt.Color"));
   }
   return ivjDropBean2;
}
    End Figure

    Figure 8.33: Setting the dataFlavor property

  7. Find the init() method for your applet, and add code to set the second DropBean's component property to the MovingText bean, as shown in Figure 8.34. This sets the MovingText bean as the destination object to deliver the property to.

    Start Figure

    // add code in bold
public void init() {
 java.awt.BorderLayout layBorderLayout1 =
       new java.awt.BorderLayout();
 this.setLayout(layBorderLayout1);
 this.add(getMovingText(), java.awt.BorderLayout.CENTER);
 this.setSize(350, 80);
 getIvjDragBean().setComponent(getMessageField());
 getIvjDragBean().setInputObject(getMessageField().getText());
 getIvjDragBean().setComponent(getMovingText());
 getIvjDragBean2().setComponent(getGreenField());
 getIvjDragBean2().setInputObject(getGreenField().getBackground());
 getIvjDragBean3().setComponent(getPinkField());
 getIvjDragBean3().setInputObject(getPinkField().getBackground());
 getIvjDragBean2().setComponent(getMovingText());
}
    End Figure

    Figure 8.34: Setting the drop destination object

  8. Find the code that initializes the second DropBean and use content assist to add a DropListener. Add code to the dropEnd(DropEvent) method to set the MovingText bean's foreground property from the object being dropped, as shown in Figure 8.35.

    Start Figure

    // add code in bold
private com.ibm.dnd.DropBean getIvjDropBean2() {
  if(ivjDropBean2 == null) {
   ivjDropBean2 = new com.ibm.dnd.DropBean();
   ivjDropBean2.setDataFlavor
      (new com.ibm.dnd.DataFlavorDescriptor("java.awt.Color"));
   ivjDropBean2.addDropListener(new com.ibm.dnd.DropListener() {
     public void dragEnter(com.ibm.dnd.DropEvent e) {
          ;
     }
     public void dragExit(com.ibm.dnd.DropEvent e) {
          ;
     }
     public void dragOver(com.ibm.dnd.DropEvent e) {
          ;
     }
     public void dropEnd(com.ibm.dnd.DropEvent e) {
      getMovingText().setForeground
       ((java.awt.Color) getIvjDropBean2().getOutputDropObject());
     }
 });
   }
   return ivjDropBean2;
}
    End Figure

    Figure 8.35: DropListener for the second DropBean

Save your changes and test the applet again. It should look similar to Figure 8.36. Now you can change the color of the running text by dragging the colors from the Customizer color fields and dropping them onto the MovingText surface.

Click To expand
Figure 8.36: Running drag and drop functionality

If you had any problems building the RunningText applet, look at the solution file in the /solutions/chap08/runningText subdirectory on the CD included with this book. Create a new package called solutions.chap08.runningText in the AdvancedApplets project, and import /solutions/chap08/runningText/RunningText.java into it. Open [image] RunningText.java with the Visual Editor to compare your program with the solution.


Signing the RunningText applet

Your RunningText applet works fine when you run it with the Applet launcher in the WebSphere Studio Java perspective, but remember that this isn't true Web browser environment. Let's run it in a Web browser, and see what happens.

Exporting to a JAR file

  1. Right-click on [image] RunningText.java in the Package Explorer, and select Export… from the pop-up menu.

  2. Choose JAR file as the export destination and click Next.

  3. Click the Browse… button to browse to the folder where you want to place your exported jar file, such as C:/export, and enter a file name for your applet's JAR file, such as [image] RunningText.jar. Click Save.

  4. Choose the export options Export generated class files and resources and Compress the contents of the JAR file.

  5. Click Finish.

Setting up a Web project

  1. Switch to the Web perspective (click the Web Perspective icon in the vertical toolbar or open a new Web perspective if you don't still have one open).

  2. Create a new J2EE Web project named RunningTextWeb.

    Reminder

    Use File → New → Web Project to create a new Web project. If you are prompted to modify server configurations, click OK.

  3. In the J2EE Navigator, click on the + sign next to RunningTextWeb to expand the contents of the project. Right-click on the Web Content folder in the RunningTextWEb project, and select Import… from the pop-up menu.

  4. Select File systems as the import source and click Next.

  5. Click the Browse… button next to the directory field to browse to the directory where you saved your [image] RunningText.jar file and click OK.

  6. Select the JAR file, and click Finish.

  7. Repeat the preceding steps to import the [image] chap08b.jar file into your Web project.

Creating a Web page

To create a Web page that runs your applet in a Web browser, do the following:

  1. In the J2EE Navigator, right-click on the Web Content folder in the RunningTextWeb project and select New → HTML/XHTML File from the pop-up menu.

  2. Enter [image] RunningText.html for the HTML file name, and click Finish.

  3. Your new [image] RunningText.html file opens in the HTML editor. Click on the Design tab, and type in whatever text you want to appear on your Web page.

  4. Position the cursor to the point where you want your applet to be added to the Web page, and select Insert → Others → Java Applet… Enter runningText.RunningText.class for the Code name (the name of the applet to run), [image] RunningText.jar,chap08b.jar for Archives (the JAR files where Web browsers look for your code), 350 for Width, and 80 for Height.

  5. Click on the Parameters tab, and use the Add button to define parameters for your applet, as shown in Figure 8.37.

    Click To expand
    Figure 8.37: Specifying applet parameters

  6. Click OK.

  7. Click on the Source tab to see the HTML source for your new Web page. It should contain an APPLET tag that looks like Figure 8.38.

    Start Figure

    <APPLET code="runningText.RunningText.class"
    archive="RunningText.jar,chap08b.jar" width="350" height="80">
    <PARAM name="text" value="Running text">
    <PARAM name="dx" value="1">
    <PARAM name="dy" value="0">
</APPLET>
    End Figure

    Figure 8.38: APPLET tag for the RunningText applet

  8. Click on the Preview tab to see how your new Web page looks in a Web browser. Your applet starts running. Click on the applet's visual surface to make the Customizer frame appear. Notice that the message "Warning: Applet Window" is now at the bottom of the Customizer frame. Drag and drop text or one of the colors, and you see "Wa" letters instead of the drag and drop mouse images, as shown in Figure 8.39. This is because when you run the applet with the HTML Editor's Preview tab, WebSphere Studio enforces applet security restrictions, so it is warning you that unsigned windows are being used.

    Click To expand
    Figure 8.39: Running the RunningText applet in a Web page

  9. Return to the Design tab and save your changes.

Although applets using DragBeans and DropBeans might look fine when used in some Web browsers, they need to be signed to work properly in all browsers. We'll use the RunningText applet to demonstrate how to make applets signed or trusted. To do this, we'll export your applet resources from WebSphere Studio and show you how to use a signing tool.

When do you need to sign an applet?

Applets loaded over the network have the following restrictions imposed on them:

  • They cannot read or write files on the local file system.

  • They cannot manipulate files and directories (in other words, create, rename, copy, or delete them) on the local file system.

  • They cannot make arbitrary network connections, except to the host machine that they originally came from.

  • They cannot call external programs.

In addition to security restrictions, browsers may warn you when an applet performs any suspicious action (such as opening a new window).

However, you can overcome some limitations and get rid of warnings on applets in Web browsers by signing the files.

The problem we have with the RunningText applet is that, when you drag and drop properties from the Customizer window to the applet, the mouse icon image appears in a small additional window. This window is similar to the Customizer window itself, just much smaller. As you saw when you ran the applet in the Web perspective, the browser also put a warning message at the bottom of the Customizer window. This message is: "Warning: Applet Window". So, as you may guess, the "Wa" you saw for the drag and drop icons is just the beginning of the warning message. To make the browser "trust" your applet and not show the warning message, you have to sign the applet. We'll show you one way to do that.

Creating a signed applet

To create a signed applet, you need to generate a pair of private and public keys and then get a special certificate from a trusted authority. After you receive the certificate, you can use it to sign your applets. (For more information on signed applets, see the references listed at the end of this chapter.)

If you are new to this subject, or just want to test it out, you should start with the Netscape Signing Tool. This tool lets you create certificates for testing, create a signed JAR file for your applet, and run the signed applet in Netscape Communicator. The signed JAR file contains your applet's class files and the classes for beans that it references, such as DragBean and DropBean, so you need to place these classes in a directory for the Netscape Signing Tool to use. We'll use WebSphere Studio to gather all the necessary class files together in your AdvancedApplets project, and then export them to a directory that the Netscape Signing Tool can use.

  1. Switch back to the Java perspective in WebSphere Studio. Right-click on the AdvancedApplets project, and select Import… from the pop-up menu.

  2. Select Zip file as the import source and click Next. (You use Zip file to import resources from either a ZIP or JAR file.)

  3. Click the Browse… button next to the Zip file field to brose to the directory where you copied the [image] chap08b.jar file. Select [image] chap08b.jar and click Open.

  4. Click Finish. The contents of the JAR file are imported into WebSphere Studio in your AdvancedApplets project. Now you have all the necessary files that will go into the signed JAR file with your applet. We just need to select the ones we want, and export them to a directory for the Netscape Signing Tool to use.

  5. We'll start with the RunningText class files, and then add the files for the beans. Right-click on the runningText package, and select Export… from the pop-up menu.

  6. Select File system and click Next.

  7. All of the files in the runningText package are selected for export. Deselect the [image] RunningText.java file, since we only need the executable class files.

  8. Now we need to select the files for the beans that the RunningText applet uses. Click on the + signs to expand the contents of the com and ibm folders under the AdvancedApplets project. Select the dnd and textdesigner folders. This selects the necessary files for the Drag and Drop and MovingText beans (we omitted the aboutbeaneditor folder, since its classes are only used at design time).

  9. Click the Browse… button to browse to the folder where you want to place your exported files, such as C:/signdir, and click OK.

  10. Select Create directory structure for files, so the Export file system window looks like Figure 8.40.

    Click To expand
    Figure 8.40: Exporting files to create a signed applet

  11. Click Finish. The necessary files are exported to a folder where you can work with them using the Netscape Signing Tool.

The next step is to install the Netscape Signing Tool, and use it to create a certificate and a signed JAR file for your applet.

  1. Install the Netscape Signing Tool Version 1.3 (this product is available at http://developer.netscape.com/software/signeddobj/jarpack.html). After you have downloaded and unzipped the file, you should add the directory where the signtool.exe file is located to your PATH environment variable. This lets you execute the signtool utility from the command prompt in any folder. For the Windows operating system, use Start → Settings → Control Panel → System → Advanced to update environment variables.

    Start Sidebar
    Browser level

    The documentation for Netscape Signing Tool 1.3 says that it requires Netscape Communicator 4.06 or later. We recommend you use Netscape Communicator 4.51 or later. Our testing was done with Netscape Communicator 4.76.

    End Sidebar

  2. Start Netscape Communicator and click on the Security button in the toolbar to open the Security Info window. Select Passwords, and establish a password if you don't already have one (make sure you remember the password, because you'll need it later when you create the certificate and sign the JAR file). The password lets you execute applets that require more access to your computer resources than the JVM's security allows, because your applet is signed with the specified password. Click OK to close the window.

  3. Close Netscape Communicator.

  4. Open a command prompt window, and change to the directory where you exported the applet files (for example, C:\signdir). This directory should contain a folder named AdvancedApplets, which in turn contains folders named com and runningText, with the files for your applet and the beans it uses.

  5. Create a certificate by entering the following command:

    signtool-d"c:\Program Files\Netscape\Users\username" -G"certificate name"

    where username is your Netscape Communicator user name and certificate name is the name of your test certificate. The certificate name can be any name you want to use for testing purposes, so if your user name is Bob and your certificate name is beans, your command wood look like this:

    signtool-d"c:\Program Files\Netscape\Users\Bob" -G "beans"

    As a response, you'll see a warning message asking to make sure that your Netscape Communicator is closed. After you enter "y", you will be asked several questions about your organization, user name, and so on. The only important question is your password. Input the same password that you specified in Netscape Communicator.

  6. After you see the message that your certificate has been added to the database, enter the following command to create the signed JAR file:

    signtool-d "c:\Program Files\Netscape\Users\username" -k" certificate name" -Z"jar files" directoryname

    where username is your Netscape Communicator user name, certificate name is the name of your test certificate, jar file is the name of the signed JAR file you want to create, and directoryname is the directory where all the necessary files to go in the signed JAR file are located. For example, if your user name is Bob and the certificate you created in the preceding step is named beans, the command to create a signed JAR file named export.jar from the files in the AdvancedApplets directory would look like this:

signtool -d "c:\Program Files\Netscape\Users\Bob" -k "beans" -Z "export.jar" AdvancedApplets

    You will be asked to enter the password. Input the same password that you specified in Netscape Communicator.

  7. After the export.jar file is successfully created and signed, create an HTML file with the contents shown in Figure 8.41.

    Start Figure

    <html>
<head><title>RunningText</title></head>
<body>
<h1>RunningText</h1>
<p>
<applet CODE="runningText.RunningText.class"
ARCHIVE="export.jar" WIDTH="350" HEIGHT="80">
    <param name="text" value="Running text">
    <param name="dx" value="1">
    <param name="dy" value="0">
</applet>
<p>
</body>
</html>
    End Figure

    Figure 8.41: HTML for signed applet

  8. Place the HTML file in the same directory as the signed export.jar file, and test your HTML by opening it in Netscape Communicator. The Customizer frame should now show that the applet is signed, and the drag and drop images should appear properly.


In review

This chapter demonstrated several advanced applet features, such as how to use applet parameters, the applet context, and codeBase. You learned how to use the Drag and Drop beans to add drag and drop functionality to your programs. You also learned one technique for creating a signed applet.


Exercise

Modify the NavigationPanel applet to use your favorite links and graphics file.

Tip

You may need to also modify the applet's width and height values in the HTML file to accommodate your graphics file.


References

HOWTO: Deploy Java in Internet Explorer 4.0 and Netscape 4.0: http://support.microsoft.com/support/kb/articles/Q179/6/52.asp

Using OBJECT, EMBED, and APPLET tags in Java Plug-in: http://java.sun.com/j2se/1.4.1/docs/guide/plugin/developer_guide/using_tags.html

JDK 1.2 Signed Applet Example: http://java.sun.com/security/signExample12/

Java Plug-in documentation—How to sign applets using RSA certificates: http://java.sun.com/products/plugin/1.3/docs/rsa_signing.html

Netscape Signing Tool: http://developer.netscape.com/docs/manuals/cms/41/adm_gide/app_sign.htm http://developer.netscape.com/software/signedobj/jarpack.html


Chapter 9: Working With Databases

Download CD Content

Up to this point, we have focused on examples in which the amount of data you operated with was limited to what was entered during the program's run time. If you want to manipulate a large amount of data, you need a special persistent storage for it. At a minimum this storage should let you manipulate your data, like saving and retrieving it. For simple data manipulation, a text file suffices. However, when you want to search for and select particular data, the flat text file approach fails. You also might want to create reports with your data or work simultaneously with your coworkers on the same storage system, viewing and changing data. Most modern dtabases provide these and many other useful functions.

Introduction to databases

A database is a collection of data that is organized so that its contents can easily be accessed, managed, and updated. There are several kinds of databases, but the most prevalent type today is the relational database. A relational database is a collection of data items organized as a set of formally described tables, from which data can be accessed or reassembled in many different ways a without having to reorganize the database tables. The relational database was invented by E. F. Codd at IBM in 1970. Other types of databases include hierarchical, distributed, and object-oriented databases. However, this chapter will limit the discussion to relational databases, since they are currently the most popular.

This chapter gives you some basic knowledge about relational databases and explains some concepts and teminology. It also tells you where to get a database, how to set it up, and how to start using it. After you become acquainted with general concepts of databases, we'll show how you can use the Visual Editor to build an application that works with data in a relational database.

Where can you get database software?

Several products are available on the market, from programs for supporting small databases, such as MySQL, to large and powerful enterprise database servers such as IBM's DB2 Universal Database, Oracle's Oracle 8i, or Microsoft's SQL Server. Which of them should you choose? Actually, there is only one restriction: If you want to be able to connect to the database easily via Java applications, the database must support either Java Database Connectivity (JDBC) or Microsoft's Open Database Connectivity (ODBC) interface.

If you don't have a database program installed on your computer yet, we recommend you start with the DB2 Universal Database Personal Edition. A free copy is included with this book, and the latest information about the product is available on IBM's DB2 Web site at http://www.ibm.com/software/data/db2/. The examples you'll develop in this lesson were tested on the DB2 Universal Database Personal Edition for Windows Versions 7.1 and 8.1.

Installing database software

Each database program is different, so we can't provide generic instructions for installing the database you choose. You'll need to follow the installation instructions of your particular database program and read its documentation for more information. If you are just starting to work with databases, choose the Typical type of installation when asked. During the installation, you'll be asked to enter a user name and password for your database. Make sure you remember them, because they will be required to use you database in the future.

Please refer to Appendix A for detailed instructions on installing DB2.


Relational databases

Before we begin creating a real database, let's get acquainted with some basic terms and design concepts of relational databases.

Relational database structure

The relational scheme views data as rows of information; each row contains columns of data called fields. The main concept in the relational scheme is that the data is uniform. Each row contains the same number of columns. A collection of rows and columns is called a table. Many such tables combine to form a relational database.

You might wonder why this scheme is called relational. The relational part comes in when you need to access data from two different tables simultaneously. To do this, you need a mechanism to link the data from two tables or relate the tables.

Table, rows, columns

Figure 9.1 is an example of a simple table that could be found in a relational database. This table contains three columns (or fields) and three rows (or records). The columns are called Name, Phone, and Birthday. The rows contain the following data: Scott, 9576345, 3/12/60; Erik, 6789567, 7/7/70; and Tanya, 9657974, 3/9/74.

Click To expand
Figure 9.1: Friends table data

Primary Key

This table lets you store data about your friends. When you want to read any particular friend's data, you just need to find the correct record (or row) of data. This works fine as long as all your friends have different names. However, if there are two Scotts in your list, you can't uniquely identify the necessary record. Even if you include the last name in the Name field, you still could have friends with the same first and last names.

There are several ways to provide data uniqueness in a table. One way is to include an additional column, such as Friend_ID, that contains unique data for each row. For example, the column could contain a Social Security number, which uniquely identifies a U.S. citizen. But what if you have to deal with citizens of another country? For our example, we'll add a column containing simple numbers for identifying records, as shown in Figure 9.2.

Click To expand
Figure 9.2: Friends table with a primary key

The column, or set of columns, that provides enough information to distinguish each row in a table from every other row is called a primary key. In our example, the Friend_ID column is the primary key for the Friends table.

Adding more data

Let's assume that you want to save information about your friends' hobbies (such as reading, etc.). You can add hobby information to the database in several ways.

  1. We could add another column to the Friends table called Hobby, as in Figure 9.3.

    Click To expand
    Figure 9.3: Friends table with Hobby column

    You've probably spotted the problem with this approach: What if your friend has more than one hobby?

  2. You could put all the hobbies into one Hobby field and separate them by commas, as in Figure 9.4.

    Click To expand
    Figure 9.4: Friends table with multiple hobbies in a single column

    The drawback of this approach is that you can't select all your friends who enjoy travelling, for example.

  3. Another solution is to add several columns for hobbies, such as Hobby1, Hobby2, Hobby3, and so on, as in Figure 9.5.

    Click To expand
    Figure 9.5: Friends table with multiple hobby columns

    Hobbies are so unpredictable that it is possible that someone has more than three hobbies. So, if you restrict the table to N number of HobbyN columns, you could always have a friend who has N+1 hobbies. Therefore, this approach also fails.

  4. Finally, you could just distinguish all hobby data and put the hobbies into a separate table. For some exotic hobbies, you might like to add a description of what they are, as in Figure 9.6.

    Click To expand
    Figure 9.6: Separate Hobbies table

Now, the question is, how do you show the relationship between the Friends table and the Hobbies table?

Defining a relationship between tables

To define the relationship between two tables, the two tables need to have a common column, or you need to create a third table with two columns, one from the first table and one from the second table.

Two tables with a common column

In the example in Figure 9.7, we added the Friend_ID column to the Hobbies table.

Click To expand
Figure 9.7: Hobbies table with Friend_ID column

When one table contains values that are primary keys in another table, these values are called foreign keys. Most references between tables in a relational database are between foreign keys in one table and the corresponding primary keys in another table. In our example, the Friend_ID column in the Hobbies table is a foreign key. Technically speaking, for each row in the Friends table, there could be zero to many corresponding rows in the Hobbies table (zero if a friend doesn't have any hobbies).

Note that now the Hobbies table has both a primary key (Hobby_ID) and a foreign key (Friend_ID). The foreign key identifies which row in the Friends table is associated with a particular row in the Hobbies table.

As you can see in Figure 9.8, you now have to repeat rows of a particular hobby for each friend who has this hobby. For example, if you have two friends who enjoy travelling, you need two rows in the Hobbies table for that hobby (the rows shown in italics in the figure). Even though this approach can be effective, if there is a large amount of data, you will store a lot of redundant information in a table. Storing redundant data in a database is not good, because it wastes a lot of disk space and makes searches slower and less reliable (a search for a hobby of "travelling" will miss anyone for whom the same hobby was entered as "traveling" or "travel").

Click To expand
Figure 9.8: Two tables with a common column

A third table to relate the two tables

A better approach in this example is to create a third table, as shown in Figure 9.9.

Click To expand
Figure 9.9: A third table with two key columns

The new Friends Hobbies table has two columns, each of which is a key column. The Fr_ID and Hb_ID columns are foreign keys that relate this table with two other tables: the Friends table and the Hobbies table.

Now, if you want to find a list of your friends and the hobbies they have, go to the Friends Hobbies table, and read each row. Find the friend's name corresponding to the Fr_ID in the Friends table, find each row corresponding to the Hb_ID from the Hobbies table, and select the Name and Hobby columns.

Constraints

Usually in a database, you also store constraints for your tables and their values. For example, you can define that some fields (such as the primary key) will never be empty. This is a common requirement for primary keys, because otherwise anyone accessing the table using a foreign key couldn't uniquely identify rows. You can also define some numerical constraints—for example, the age of a friend can't be less than 0 or more than 120. Uniqueness is a common constraint as well, especially in primary keys, where it's often enforced by default.

The other important thing to think about when you're working with related tables is how to delete data from them. Suppose you want to delete your friend Erik from the Friends table. You should also delete all corresponding records from the Friends Hobbies table as well (in other words, all the records with Fr_ID=2). This table cleanup is typically done with database triggers that automatically delete any linked records.

These database concepts are the foundation of relational database design; they are not specific to any particular database product. The "Creating a database" section will show you how to implement these concepts in existing database products.

Primary data types

As you may have noticed from the examples, you can use different types of data in tables. For example, you can use text data for names, numerical data for telephone numbers, and date data for birthdays. Data types are different schemes for representing data in a computer. Different forms of representation are suitable for different kinds of information. When you create a table, you must tell the database the data type for each column in the table.

Data types are different for different databases, so you need to refer to your database's documentation. The following are some of the most common data types used in almost all popular databases today.

  • CHARACTER(integer), CHAR(integer), CHARACTER, or CHAR—fixed-length character string of length integer, which can be from 1 to 254.

  • VARCHAR(integer), CHARACTER VARYING(integer), or CHARVARYING(integer)—a varying-length character string of maximum length integer, which can be from 1 to 32,672.

  • SMALLINT—small integer data.

  • INTEGER or INT—large integer data.

  • FLOAT(integer)—single- or double-precision floating-point number, depending on the value of the integer. The value of the integer must be in the range 1 through 53. The values 1 through 24 indicate single precision, and the values 25 through 53 indicate double precision.

  • DECIMAL(precision-integer, scale-integer) or DEC(precision-integer, scale-integer)—decimal number. The first integer is the precision of the number (that is, the total number of digits, which can be from 1 to 31). The second integer is the scale of the number (that is, the number of digits to the right of the decimal point); this can be from 0 to the precision of the number. The words NUMBERIC and NUM can be used as synonyms for DECIMAL and DEC.

  • DATE—digits in date format.

Note that this isn't a complete list of all possible data types.

Example of using data types

For the Friends table in the "Relational database" section, the types of data for the columns can be defined as follows:

  • Friend_ID: CHARACTER(15)

  • Name: CHARACTER(25)

  • Phone: CHARACTER(30)

  • Birthday: DATE

The reason why we have chosen the CHARACTER data type for the Friend_ID field will become clear when you start to fill up the real database with real data. Often, it's difficult to remember which numbers are already in use for IDs, so it's a good idea to generate unique IDs automatically. (The "Providing unique IDs" section shows one technique for doing this.)


Creating a database

This section shows you how to create a new database and then create a table in that database. The tutorial uses IBM's DB2 Universal Database, which has an easy and intuitive interface for working with databases and tables.

To create a new database in DB2, use the Control Center tool. Other databases have different tools for new database creation; for example, in Oracle 8i, you'd use the Oracle Database Configuration Assistant. Usually, you need special authorization to create a new database. In our example, we'll assume that you have installed DB2 locally on your computer and that your user ID has administration rights. If you use another database or do not have administration rights, see your database administrator or documentation for more information.

If you have an existing database in which you have authority to create tables, you can use it to work with the rest of this chapter without creating a new instance. But make sure that you don't damage any other important data in the existing database.

Getting started with DB2

  1. To run the DB2 Control Center tool, select Start → Program → IBM DB2 → General Administration Tools → Control Center.

  2. If prompted to enter your user ID and password, do so. Click the + sign next to All Cataloged Systems. The window in Figure 9.10 appears.

    Click To expand
    Figure 9.10: DB2 Control Center

  3. You'll see the name of your computer instead of 600XIMGBK3-21-02. Click the + signs next to your computer's name, Instances, DB2, and Databases, as shown in Figure 9.11. If you have just installed DB2 and created the DB2 tools catalog during installation, you'll see the TOOLSDB database listed; otherwise, you won't have any database instances yet.

    Click To expand
    Figure 9.11: Navigating to the databases

Creating your first database

  1. Right-click on Databases and select Create → Database Using Wizard… from the pop-up menu. The Create Database Wizard window appears.

  2. Enter MyDB for the Database name and Alias, and enter My first database for the Comment, as shown in Figure 9.12.

    Click To expand
    Figure 9.12: The Create Database Wizard window

  3. Click Finish. You might need to wait a few minutes before you see your new database. If you see a question asking whether you want to launch the Configuration Advisor, click No.

  4. Click on the + sign next to MYDB, and select Tables. It should look similar to Figure 9.13.

    Click To expand
    Figure 9.13: Your first database

As you can see, a real database is rather complex, containing Table Spaces, Indexes, Views, Triggers, and other components. Read your database's documentation to learn more about these components. For now, the most important part of the database for us is Tables. Note that, even though you didn't tell DB2 to create any particular table, it automatically created the set of system tables that supports the database.

The next step is to create your own table.


Creating a simple table

To add more interesting data to your future application, let's add a new column to the Friends table called Photo. Even though you could store images as binary streams or as long character strings in a database, we aren't going to use those methods. Instead, we'll use a simpler method and save the full path to the image file as a character string in the Photo column, as shown in Figure 9.14. So, the field you are going to add will have the name Photo and a data type of VARCHAR(100).

Click To expand
Figure 9.14: Friends table with a Photo column

The structure of the table is as follows:

  • Friend_ID: CHARACTER(15)

  • Name: CHARACTER(25)

  • Phone: CHARACTER(30)

  • Birthday: DATE

  • Photo: VARCHAR(100)

Creating the Friends table in DB2

  1. To create the Friends table, right-click on Tables in the DB2 Control Center, and select Create… from the pop-up menu. The Create Table Wizard appears.

  2. The Table schema field is automatically set to your user ID, so you don't need to change it. Enter Friends in the Table name field and Friends Table in the Comment field, so that the windows looks like Figure 9.15.

    Click To expand
    Figure 9.15: The Create Table window

Defining columns

  1. Select Columns, and click Add… to add a new column.

  2. Enter Friend_ID for the Column name; select CHARACTER for the Datatype; enter 15 for the Length; and enter Unique identifier for the Comment field.

  3. Uncheck the Nullable check box, which means that this field cannot be empty, so the Add Column window looks like Figure 9.16.

  4. Click the Apply button. This action inserts the defined column into the list of columns.

    Click To expand
    Figure 9.16: Adding a column

  5. Enter data for the remaining columns, as described in Table 9.1, and close the Add Column window.

    Table 9-1: Column data

    Column name

    Datatype

    Length

    Nullable

    Comment

    Name

    CHARACTER

    25

    Unchecked

    Name of friend

    Phone

    CHARACTER

    30

    Checked

    Phone number

    Birthday

    DATE

    -

    Checked

    Birth date

    Photo

    VARCHAR

    100

    Checked

    Full path to file with photo

Your Create Table window should now look like Figure 9.17.

Click To expand
Figure 9.17: Create Table window with columns data

After you have defined all the columns, select Keys to define the primary key next.

Setting the Primary Key

  1. To define a primary key for the table, click Add Primary… The Define Primary Key window appears.

  2. Select Friend_ID from the Available columns list, and click the > button to move it to the Selected columns list.

  3. Click OK, so that the Create Table wizard looks like Figure 9.18.

    Click To expand
    Figure 9.18: Setting the primary key

Foreign Keys and Check Constraints

Note that this window also provides Foreign Keys and other constraint options. Even though you do not need to set up any foreign keys or constraints for the Friends table, you may want to look at these options and check out how they work.

Show SQL button

If you select Summary and click the Show SQL button, you'll see a description of the table to be created in structured query language (SQL). SQL is a database language that has constructs for data manipulation (such as creating, updating, and deleting), data definition (such as creating tables and columns), security for restricting access to data elements, data management, and transaction processing. Fortunately, you don't need to learn this language in detail when you use tools such as DB2 and WebSphere Studio. However, a basic understanding of this language can be helpful, so we'll talk about it next. Now, click the Finish button to create the Friends table. You should see a message that the commands completed successfully. Click Close to close the message window.

You can change the structure of the created table by right-clicking on the table name and selecting Alter… from the table's pop-up menu.

Creating the Friends table using an SQL command

If you're not using DB2 and your database doesn't provide a graphical interface for creating tables, you can use the database's SQL command processor (such as Oracle's SQL Plus) and use the SQL commands listed in Figure 9.19.

Start Figure
CREATE TABLE FRIENDS (
FRIEND_ID CHARACTER(15) NOT NULL,
NAME CHARACTER(25) NOT NULL,
PHONE CHARACTER(30),
BIRTHDAY DATE,
PHOTO VARCHAR(100),
PRIMARY KEY (FRIEND_ID))
COMMENT ON TABLE FRIENDS IS 'Friends Table'
COMMENT ON COLUMN FRIENDS.FRIEND_ID IS 'Unique identifier'
COMMENT ON COLUMN FRIENDS.NAME IS 'Name of friend'
COMMENT ON COLUMN FRIENDS.PHONE IS 'Phone number'
COMMENT ON COLUMN FRIENDS.BIRTHDAY IS 'Birth date'
COMMENT ON COLUMN FRIENDS.PHOTO IS 'Full path to file with photo'
End Figure

Figure 9.19: SQL commands for creating the Friends table

Note that each database vendor has its own implementation of SQL. So, the syntax of the commands can differ slightly for different databases. For example, in Oracle, you have to put a semicolon after each command.


Inserting and manipulating data

In this section, we'll show you some common SQL commands for working with data in a database. SQL is a standard language, and the basic syntax we'll use here is the same for any relational database, although there may be some slight differences, such as using semicolons to end commands. Even though we'll work with command prompts and input commands by hand, don't panic. As soon as you learn how to connect to the database through a Java applet or application in WebSphere Studio, you'll use a simpler interface for these operations. However, it is useful to understand how to enter these commands via the command prompt, so that you can understand the process inside the database.

Connecting to the database

Currently, the Friends table you created is empty; it provides a structure for data but not the data itself. Now we will show you how to input simple data into the table using SQL commands. First, you need to connect to the database.

  1. To start DB2's Command Line Processor, select Start → Programs → IBM DB2 → Command Line Tools → Command Line Processor. The DB2 command prompt window appears, as shown in Figure 9.20.

    Click To expand
    Figure 9.20: DB2 command prompt

  2. Enter the following command to connect to the MyDB database (be sure to press the Enter key after entering each command): connect to mydb

    Tip

    If you're using an Oracle database, you have to put a semicolon (;) at the end of each command.

  3. You should see Database Connection Information, as shown in Figure 9.21.

    Click To expand
    Figure 9.21: Database Connection Information

Entering data

Now you can input data into MyDB database tables. Let's try some examples.

Example 1

Enter the following command:

insert into friends (Friend_ID, Name, Phone, Birthday, Photo)
values ('1', 'Scott', '9576345', '03/12/1960',
'c:\Images\scott\.gif')

You should get a message that says the command was completed successfully. This command added the full record (all columns contain data) for the friend named Scott. As you can see, the syntax of the insert command is rather simple:

insert into <table name> (<names of fields, seperated by
commas>) values (<values, seperated by commas>)

Example 2

Enter the following command:

insert into friends (Friend_Id, Name, Birthday) values
('2', 'Erik', '07/07/1970')

As you can see, you don't have to enter values for all the columns. You can enter values for just those columns that cannot be null.

Example 3

Enter the following command:

insert into friends (Name) values ('Tanya')

This time, you get an error message, because you supplied a null value for the Friend_ID, and this column must be non-null.

Selecting data

  1. To select all data from the table, enter the following command:

    select * from friends

    Your result should look like Figure 9.22.

    Start Figure

    FRIEND_ID   NAME    PHONE       BIRTHDAY        PHOTO
---------   ------- ----------  -----------     -------------------
1           Scott   9576345     03/12/1960      c:\Images\scott.gif
2           Erik    -           07/07/1970      -

 2 record(s) selected.
    End Figure

    Figure 9.22: Selecting all the data from the table

  2. As you may have noticed, the table is too wide and each record splits in two rows, which makes the data representation difficult to read. You can create as more compact listing by excluding the Phone and Photo columns. Enter the following command:

    select Friend_ID, Name, Birthday from friends

    Your result should look like Figure 9.23.

    Start Figure

    FRIEND_ID   NAME    BIRTHDAY
----------- ------- ----------
1           Scott   03/12/1960
2           Erik    07/07/1970
2 record(s) selected.
    End Figure

    Figure 9.23: Selecting only certain columns

  3. When displaying data with the select command, you can sort the data by any particular column values. For example, you can sort in ascending order by birthday dates or alphabetically by names. Enter the following command:

    select Friend_ID, Name, Birthday from friends order by Name

    Figure 9.24 shows the result.

    Start Figure

    FRIEND_ID   NAME   BIRTHDAY
----------- ------ ----------
2           Erik   07/07/1970
1           Scott  03/12/1960

 2 record(s) selected.
    End Figure

    Figure 9.24: Sorting the data

  4. You can also select data by specifying a particular condition. Enter the following command:

    select Friend_ID, Name, Birthday from friends where Birthday> '01/01/1965'

Only the Erik record is displayed.

Modifying data

So far, we have two records in the Friends table, and one of these records (the record for Erik) does not contain complete data to describe the friend. How do you add data to an existing record? You use the update command. Let's set up values for Erik's Phone and Photo columns.

  1. Enter the following command:

    update friends set Phone='9657974', Photo='c:\Images\erik.gif' where Name='Erik'

  2. You can check the result using the select command. Enter the following command:

    select * from friends

    Figure 9.25 shows the result.

    Start Figure

    FRIEND_ID   NAME    PHONE       BIRTHDAY      PHOTO
----------  ------  ---------   -----------   -------------------
1           Scott   9576345     03/12/1960    c:\Images\scott.gif
2           Erik    9657974     07/07/1970    c:\Images\erik.gif

 2 record(s) selected.
    End Figure

    Figure 9.25: Checking updated records

Deleting data

You use the delete command when you need to remove data from the table. Let's delete the Erik record from the Friends table.

  1. Enter the following command:

    delete from friends where Friend_ID='2'

  2. Now enter this command:

    select Friend_ID, Name, Phone, Birthday from friends

The result should show only one record: the one for Scott.

Committing changes

So far, all the data you have inserted and updated in the Friends table is temporary. To make your changes to the database permanent, you must commit them. Before being committed, all data changes can be undone (this process is also called rollback).

For example, if you were to enter the rollback command right now (don't do that), the Friends table will be empty. The rollback command undoes all the changes made since the last commit, or since you started working with the database if you have never performed a commit operation.

The Friends table will also be empty if you disconnect from the database now. So, to save the data, perform the following steps.

  1. Enter this command to commit all previous changes: commit

  2. Enter this command to disconnect from the MyDB database: quit

  3. Enter this command to leave the Command Line Processor: exit


Creating the MyFriends database application

Now it's time to get back to WebSphere Studio. To access relational data (in other words, data from a relational database) from the Visual Editor, you need to add the following classes to the build path for your Java project:

  • The appropriate JDBC driver classes for the database you want to use— These driver classes let you connect to a particular database, such as a DB2 or Oracle database.

  • The jar file for the WebSphere Studio DB beans for database access—These beans give you an easy way to access and modify data in database tables.

The MyFriends application that you will build in this chapter is shown in Figure 9.26. This application uses the DBSelect bean from the WebSphere Studio DB beans for database access to connect to the MyDB database, browse through rows of the Friends table, update rows, insert new rows, and delete rows in the table.

Click To expand
Figure 9.26: MyFriends database application

Starting a new project

  1. In the Java perspective in WebSphere Studio, create a new Java Project called DatabaseAccess. Specify the following as extenernal JAR files on the Libraries tab:

    • The appropriate JDBC driver classes—If you are using DB2, these classes should be in x:/Program Files/IBM/SQLLIB/java/db2java.zip, where x is the drive on which you installed DB2. If you are using an Oracle database, the JDBC driver is usually placed in the x:/Ora8/jdbc/lib/classes111.zip file.

    • The dbbeans.jar file supplied with WebSphere Studio—This JAR file is in x:/WS_installdir/wstools/eclipse/plugins/com.ibm.etools.dbjars_5.0.1./jars/, where x:/WS_installdir is the folder where you installed WebSphere Studio, such as C:/Program Files/IBM/WebSphere/Express/SiteDeveloper.

  2. Create a new package called friends in your DatabaseAccess project.

  3. Import the image files in the /solutions/chap09/friends subdirectory on the CD included with this book into your friends package.

  4. Create a new visual class called MyFriends in your friends package. Make javax.swing.JFrame the superclass for your new class, and check the check box to create a method stub for the main method.

Setting up the frame and content pane

Just as you did with the other applications you built in this book, you need to set up your new MyFriends application to show the frame when the application starts, initialize the frame's properties, and close the frame's window when the application ends.

  1. Add code to the main method to create an instance of your application frame and make the frame visible, as shown in Figure 9.27.

    Start Figure

    // add code in bold to create an instance of the frame and show
it
public static void main(String[] args) {
   MyFriends frame = new MyFriends();
   frame.show();
}
    End Figure

    Figure 9.27: Creating an instance of the frame class

  2. Select the frame in the design surface, grab one corner of the rectangle, and drag it to increase its size.

  3. Set the frame's title property to My Friends Database and the defaultCloseOperation property to EXIT.

As you know from previous chapters, you place visual components for Swing-based applications on the content pane. To organize the components better, you will build visual elements for the MyFriends application as separate panels, and then place the panels on the content pane. You will also use the JToolBar bean to build the toolbar for your application, and then place the toolbar on the content pane. The content pane's layout is already set to BorderLayout, which is what you want.

TextPanel

  1. Select a JPanel bean from the Swing Containers palette category, and drop it on the design surface outside of the frame's visual surface. Rename the JPanel to textPanel, and resize it, so you can add visual elements to it.

  2. Set the TextPanel's layout property to GridLayout, the layout-rows property to 6, and the layout-columns property to 1.

  3. Add three JLabel beans and three JTextField beans from the Swing Components palette category to the TextPanel. Arrange the beans within the TextPanel and set their visual properties, as shown in Figure 9.28.

    Click To expand
    Figure 9.28: TextPanel layout

  4. Rename the JTextFields to IDField, nameField, and pathField, respectively.

    Tip

    when you rename the first JTextField to IDField, you'll see a message that, by convention, fields usually start with a lowercase letter; ignore the message.

  5. Move the TextPanel to the north area of the content pane, as shown in Figure 9.29. To move the entire TextPanel, you first need to select it in the Java Beans view. Move the mouse over an edge of the TextPanel in the design surface, until it changes to the move cursor with four directional arrows. Then drag and drop the TextPanel onto the north area of the content pane.

    Click To expand
    Figure 9.29: Adding the TextPanel to the content pane

Using the JToolBar bean

  1. Select a JToolBar bean from the Swing Containers palette category, and drop it on the design surface outside of the frame's visual surface. Resize the JToolBar so that you can add visual elements to it.

  2. Set the JToolBar's floatable property to false (this controls whether the user can move the toolbar to a separate window).

  3. Select a JButton bean from the Swing Components palette category, and drop it on the JToolBar. Set the JButton's icon property to the [image] execute.gif file, which you imported into the friends package. Rename the bean to executeButton.

  4. Add another JButton bean to the JToolBar to the right of the executeButton. Set its icon property to [image] first.gif and rename the bean to firstButton.

  5. Add a third JButton bean to the JToolBar. Set its icon property to [image] previous.gif, and rename the bean to previousButton.

  6. Add a fourth JButton bean to the JToolBar. Set its icon property to [image] next.gif, and rename the bean to nextButton.

  7. Add a fifth JButton bean to the JToolBar. Set its icon property to [image] last.gif, and rename the bean to lastButton.

  8. Add a sixth JButton bean to the JToolBar. Set its icon property to [image] insert.gif, and rename the bean to insertButton.

  9. Add a seventh JButton bean to the JToolBar. Set its icon property to [image] delete.gif, and rename the bean to deleteButton. The toolbar should now look like Figure 9.30.

    Click To expand
    Figure 9.30: JToolBar bean with JButtons

  10. Move the JToolBar to the south area of the content pane, as shown in Figure 9.31.

    Click To expand
    Figure 9.31: Adding the JToolBar to the content pane

PhotoPanel

  1. Select another JPanel bean from the Swing Containers palette category, and drop it on the design surface outside of the frame's visual surface. Rename the JPanel to photoPanel.

  2. Resize the PhotoPanel, so you can add visual elements to it, and set its layout property to BorderLayout.

  3. Select a JLabel bean from the Swing Components palette category, and drop it on the north area of the PhotoPanel. Set the JLabel bean's text property to Photo:

  4. Select a JButton bean from the Swing Components palette category, and drop it on the south area of the PhotoPanel. Set the JButton bean's text property to Change photo, and rename the JButton to changePhotoButton.

  5. Add another JLabel bean to the center of the PhotoPanel. Set its text property to an empty string, and rename the JLabel to photo (we'll use this bean's icon property to display photos). The PhotoPanel should now look like Figure 9.32.

    Click To expand
    Figure 9.32: PhotoPanel layout

  6. Move the PhotoPanel to the center of the content pane, as shown in Figure 9.33.

    Click To expand
    Figure 9.33: Adding the PhotoPanel to the content pane

    Reminder

    To move the entire PhotoPanel, select it first in the Java Beans view.

The visual part of the application is ready. Now it's time to apply the logic.


Using the DBSelect bean

In this section, you add the DBSelect bean to your application, set its properties, and connect it to the visual elements. The properties that you set for the DBSelect bean tell it the database to connect to and the SQL statement to execute. You then call methods in the bean to tell it what action you want it to do, such as execute the SQL statement, get the next row, or insert a new row. The DBSelect bean manages the connection to the database and the result set (the table rows and columns) returned by the SQL statement for you. It fires PropertyChangeEvents to let you know when a table row changes in the result set, and it has methods that you use to change the content of the current row. Let's see how it works.

Adding the DBSelect bean

  1. Use Choose Bean to select a DBSelect bean from the com.ibm.db.beans package, and drop it on the design surface outside of the frame's visual surface.

  2. Specify the URL to the database in the DBSelect bean's url property. In our example using a DB2 database, the url should be jdbc:db2:mydb. For other databases, the URL will be different. For example, if you use an Oracle database, the URL might be jdbc:oracle:thin:@userid:1521:mydb, where userid is the user ID you use to connect to the database.

  3. Specify the JDBC driver class for your database in the DBSelect bean's driverName property. The driver class is COM.ibm.db2.jdbc.app.DB2Driver for a DB2 database or oracle.jdbc.driver.OracleDriver for an Oracle database. Make sure you enter upper and lower case letters exactly as they are specified in the driver class name.

  4. Make sure the DBSelect bean's autoCommit property is set to true. This automatically commits all operations on database data after each SQL operation is performed, rather than let them wait to do an explicit commit after a batch of operations has been performed.

    Tip

    Setting the autoCommit property to true is fine for our simple application, but for complex database operations, such as operations that use triggers or referential constraints, you may need to wait for an entire set of updates to complete before committing the changes. In this case, you set the autoCommit property to false and call the DBSelect bean's commit() method to commit database changes explicitly.

  5. Enter the user ID and password for connecting to the database in the username and password properties, respectively.

    Tip

    If you leave these properties set to blanks, the user ID and password for the user who's running the application will be used to connect to the database. To have the user supply the user ID and password at run time, you could present a dialog window when the application starts for the user to enter the values.

  6. Enter the following SQL statement in the DBSelect bean's command property: SELECT FRIEND_ID, NAME, PHOTO FROM FRIENDS ORDER BY NAME. This is the SQL statement that the DBSelect bean will execute to select rows from your Friends table.

  7. Save your changes. As you can see in the source pane, the statements to set properties for the DBSelect bean are flagged as being in error. Move the mouse over the flagged statements, and you'll see that the problem is "Unhandled exception type java.sql.SQLException". These methods all throw exceptions, which you must handle in your application. In a production environment, such as where a user might specify values for these properties, you would want to check for exceptions and take some corrective action. For our testing purposes, we'll ignore the errors, so update the source code to add try-catch logic, as shown in Figure 9.34.

    Start Figure

    // add code in bold
private com.ibm.db.beans.DBSelect getIvjDBSelect() {
  if(ivjDBSelect == null) {
    ivjDBSelect = new com.ibm.db.beans.DBSelect();
 try {
      ivjDBSelect.setUrl("jdbc:db2:mydb");
      ivjDBSelect.setDriverName("COM.ibm.db2.jdbc.app.DB2Driver");
      ivjDBSelect.setCommand
         ("SELECT FRIEND_ID,NAME,PHOTO FROM FRIENDS ORDER BY NAME");
    }
    catch (java.sql.SQLException ex) {}
   }
   return ivjDBSelect;
}
    End Figure

    Figure 9.34: Handling exceptions thrown by the DBSelect bean

  8. Save your changes. The error messages disappear.

Connecting table columns and text fields

The DBSelect bean fires a PropertyChangeEvent whenever a column value in the result set changes, such as when the user goes to the next row. You use this event to set the corresponding values in the JTextFields.

  1. In the source pane, use content assist to add a PropertyChangeListener to the DBSelect bean. Add code to the propertyChange(PropertyChangeEvent) method to copy any changes to the DBSelect bean's FRIEND_ID, NAME or PHOTO properties to the corresponding JTextField, as shown in Figure 9.35.

    Start Figure

    // add code in bold
private com.ibm.db.beans.DBSelect getIvjDBSelect() {
  if(ivjDBSelect == null) {
    ivjDBSelect = new com.ibm.db.beans.DBSelect();
    try {
      ivjDBSelect.setUrl("jdbc:db2:mydb");
      ivjDBSelect.setDriverName("COM.ibm.db2.jdbc.app.DB2Driver");
      ivjDBSelect.setCommand
         ("SELECT FRIEND_ID,NAME,PHOTO FROM FRIENDS ORDER BY NAME");
    }
    catch (java.sql.SQLException ex) {}
    ivjDBSelect.addPropertyChangeListener
        (new java.beans.PropertyChangeListener() {
      public void propertyChange(
         java.beans.PropertyChangeEvent evt) {
        if ("FRIEND_ID".equals(evt.getPropertyName()))
              getIDField().setText((String) evt.getNewValue());
        if ("NAME".equals(evt.getPropertyName()))
              getNameField().setText((String) evt.getNewValue());
        if ("PHOTO".equals(evt.getPropertyName()))
              getPathField().setText((String) evt.getNewValue());
      }
     });
   }
   return ivjDBSelect;
}
    End Figure

    Figure 9.35: PropertyChangeListener for the DBSelect bean

Connecting buttons with the DBSelect bean

To bring the buttons in the JToolBar to life, you add ActionListeners to call the appropriate methods in the DBSelect bean.

  • When the user clicks the Execute button, you call the execute() method to execute the SQL statement specified in the command property. This puts the rows in a result set, which the DBSelect bean then manages for you.

  • When the user clicks the First, Previous, Next, and Last buttons, you call the corresponding method in the DBSelect bean to navigate the rows in the result set. The first(), previous(), next(), and last() methods apply any changes to the current row in the table, such as updates that the user enters in the application window, and then move to the specified row in the result set.

  • When the user clicks the Insert button, you call the newRow(boolean) method to add a new row to the table. This method also applies any changes to the current row in the table, and then adds a new empty row either before (true) or after (false) the current row.

  • When the user clicks the Delete button, you call the deleteRow() method to delete the current row from the table.

As you can see from this list, many of the methods update the current row before taking the specified action, so you need to make sure the DBSelect bean has the current values entered by the user before it performs its work. We'll use a useful feature called refactoring to create a common method in your application to perform these steps.

  1. Select the Execute button on the design surface, and use content assist to add an ActionListener. Add code to the actionPerformed(ActionEvent) method to execute the SQL statement, as shown in Figure 9.36.

    Start Figure

    // add code in bold
private javax.swing.JButton getExecuteButton() {
  if(executeButton == null) {
   executeButton = new javax.swing.JButton();
   executeButton.setIcon(new javax.swing.ImageIcon
     (getClass().getResource("/friends/execute.gif")));
   executeButton.addActionListener(new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent e) {
          try { getIvjDBSelect().execute(); }
          catch (java.sql.SQLException ex) {}
     }
     });
   }
   return executeButton;
}
    End Figure

    Figure 9.36: ActionListener for the Execute button

  2. Select the First button on the design surface, and use content assist to add an ActionListener. Add code to the actionPerformed(ActionEvent) method to update the column values in the result set with any data entered by the user, and navigate to the first record selected from the database, as shown in Figure 9.37.

    Start Figure

    // add code in bold
private javax.swing.JButton getFirstButton() {
  if(firstButton == null) {
   firstButton = new javax.swing.JButton();
   firstButton.setIcon(new javax.swing.ImageIcon
      (getClass().getResource("/friends/first.gif")));
   firstButton.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent e) {
            try {
               getIvjDBSelect().setColumnFromString
                     ("FRIEND_ID",getIDField().getText());
               getIvjDBSelect().setColumnFromString
                     ("NAME",getNameField().getText());
               getIvjDBSelect().setColumnFromString
                     ("PHOTO",getPathField().getText());
               getIvjDBSelect().first();
      }
            catch (java.sql.SQLException ex) {}
     }
   });
   }
   return firstButton;
}
    End Figure

    Figure 9.37: ActionListener for the First button

  3. The three statements that set column values from the JTextFields are the code you want to execute before many of the DBSelect bean actions, so you'll make these statements into their own method. Select all three statements with the mouse, right-click, and select Refactor → Extract Method… from the pop-up menu, as shown in Figure 9.38.

    Click To expand
    Figure 9.38: Extracting code to create a new method

  4. The Refactoring Extract Method window appears. Enter setColumns for the method name, and select private for the access modifier, as shown in Figure 9.39.

    Click To expand
    Figure 9.39: Extract Method window

  5. Click Finish.

  6. The new setColumns() method is added to your ActionListener for the First button. This works fine for the First button, but we want to use the setColumns() method for other ActionListeners in the MyFriends class, so select the code for the new method and move it outside of the ActionListener, as shown in Figure 9.40.

    Start Figure

    // move code in bold
private javax.swing.JButton getFirstButton() {
  if(firstButton == null) {
   firstButton = new javax.swing.JButton();
   firstButton.setIcon(new javax.swing.ImageIcon
                (getClass().getResource("/friends/first.gif")));
   firstButton.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent e) {
          try {
             setColumns();
             getIvjDBSelect().first();
          }
          catch (java.sql.SQLException ex) {}
      }
    });
   }
   return firstButton;
}
private void setColumns() throws DBException, SQLException {
    getIvjDBSelect().setColumnFromString
         ("FRIEND_ID",getIDField().getText());
    getIvjDBSelect().setColumnFromString
         ("NAME",getNameField().getText());
    getIvjDBSelect().setColumnFromString
         ("PHOTO",getPathField().getText());
}
    End Figure

    Figure 9.40: Making the setColumns() method accessible by all listeners

  7. Select the Previous button on the design surface, and use content assist to add an ActionListener. Add code to the actionPerformed(ActionEvent) method to call the setColumns() method, and navigate to the previous record selected from the database, as shown in Figure 9.41.

    Start Figure

    // add code in bold
private javax.swing.JButton getPreviousButton() {
if(previousButton == null) {
 previousButton = new javax.swing.JButton();
 previousButton.setIcon(new javax.swing.ImageIcon
    (getClass().getResource("/friends/previous.gif")));
 previousButton.addActionListener(new java.awt.event.ActionListener()
 {
   public void actionPerformed(java.awt.event.ActionEvent e) {
          try {
             setColumns();
             getIvjDBSelect().previous();
      }
           catch (java.sql.SQLException ex) {}
   }
  });
 }
 return previousButton;
}
    End Figure

    Figure 9.41: ActionListener for the Previous button

  8. Select the Next button on the design surface, and use content assist to add an ActionListener. Add code to the actionPerformed(ActionEvent) method to call the setColumns() method, and navigate to the next record selected from the database, as shown in Figure 9.42.

    Start Figure

    // add code in bold
private javax.swing.JButton getNextButton() {
 if(nextButton == null) {
   nextButton = new javax.swing.JButton();
   nextButton.setIcon(new javax.swing.ImageIcon
      (getClass().getResource("/friends/next.gif")));
   nextButton.addActionListener(new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent e) {
         try {
            setColumns();
            getIvjDBSelect().next();
      }
         catch (java.sql.SQLException ex) {}
    }
   });
   }
   return nextButton;
}
    End Figure

    Figure 9.42: ActionListener for the Next button

  9. Select the Last button on the design surface, and use content assist to add an ActionListener. Add code to the actionPerformed(ActionEvent) method to call the setColumns() method, and navigate to the last record selected from the database, as shown in Figure 9.43.

    Start Figure

    // add code in bold
private javax.swing.JButton getLastButton() {
  if(lastButton == null) {
   lastButton = new javax.swing.JButton();
   lastButton.setIcon(new javax.swing.ImageIcon
         (getClass().getResource("/friends/last.gif")));
   lastButton.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent e) {
            try {
               setColumns();
               getIvjDBSelect().last();
       }
             catch (java.sql.SQLException ex) {}
      }
   });
   }
   return lastButton;
}
    End Figure

    Figure 9.43: ActionListener for the Last button

  10. Select the Insert button on the design surface, and use content assist to add an ActionListener. Add code to the actionPerformed(ActionEvent) method to call the setColumns() method, and insert a new empty row after the currently selected row, as shown in Figure 9.44.

    Start Figure

    // add code in bold
private javax.swing.JButton getInsertButton() {
 if(insertButton == null) {
   insertButton = new javax.swing.JButton();
   insertButton.setIcon(new javax.swing.ImageIcon
     (getClass().getResource("/friends/insert.gif")));
   insertButton.addActionListener(new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent e) {
          try {
             setColumns();
             getIvjDBSelect().newRow(false);
       }
           catch (java.sql.SQLException ex) {}
      }
     });
   }
   return insertButton;
}
    End Figure

    Figure 9.44: ActionListener for the Insert button

  11. Select the Delete button on the design surface, and use content assist to add an ActionListener. Add code to the actionPerformed(ActionEvent) method to delete the currently selected row from the database, as shown in Figure 9.45.

    Start Figure

    // add code in bold
private javax.swing.JButton getDeleteButton() {
  if(deleteButton == null) {
   deleteButton = new javax.swing.JButton();
   deleteButton.setIcon(new javax.swing.ImageIcon
       (getClass().getResource("/friends/delete.gif")));
   deleteButton.addActionListener(new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent e) {
          try { getIvjDBSelect().deleteRow(); }
          catch (java.sql.SQLException ex) {}
     }
   });
   }
   return deleteButton;
}
    End Figure

    Figure 9.45: ActionListener for the Delete button

Running the application

Save your changes and test the application (Run As → Java Application). When the application starts, connect to the database by clicking the Execute button. Data from the first row in the table appears in the application window. Use the First, Last, Next, and Previous buttons to navigate through the records.

To modify the current record, do the following:

  1. Modify text information in the text fields.

  2. Move to another record using one of the navigation buttons (First, Last, Next, or Previous buttons).

To insert a new record, do the following:

  1. Click the Insert button to add a new empty row to the Friends table.

  2. Input data into the fields. Remember that the ID field must have a unique value for each record.

  3. Move to another record using one of the navigation buttons.

To delete the current record, just click the Delete button.

Note

One improvement you can make to the toolbar buttons is to add tool tips to give help information to describe what each button does. We're leaving that as an exercise for you at the end of the chapter.


Completing the application

Now, let's complete the application by making it display photos of your friends and generate unique IDs for new records inserted into the Friends table.

Displaying photos

To display the photo whose path is contained in the Photo column in the Friends table, add the following code:

  1. Select the DBSelect bean on the design surface, and update the bean's PropertyChangeListener to set the photo's icon property whenever the DBSelect bean's PHOTO property changes, as shown in Figure 9.46. Note that you need to check to make sure that the new PHOTO property's value is not null. If it is, you pass an empty string as the filename to have the Icon display as an empty image.

    Start Figure

    // add code in bold
private com.ibm.db.beans.DBSelect getIvjDBSelect() {
  if(ivjDBSelect == null) {
   ivjDBSelect = new com.ibm.db.beans.DBSelect();
   try {
      ivjDBSelect.setUrl("jdbc:db2:mydb");
      ivjDBSelect.setDriverName("COM.ibm.db2.jdbc.app.DB2Driver");
      ivjDBSelect.setCommand
         ("SELECT FRIEND_ID,NAME,PHOTO FROM FRIENDS ORDER BY NAME");
   }
   catch (java.sql.SQLException ex) {}
   ivjDBSelect.addPropertyChangeListener
          (new java.beans.PropertyChangeListener() {
    public void propertyChange(
        java.beans.PropertyChangeEvent evt) {
       if ("FRIEND_ID".equals(evt.getPropertyName()))
        getIDField().setText((String) evt.getNewValue());
       if ("NAME".equals(evt.getPropertyName()))
        getNameField().setText((String) evt.getNewValue());
       if ("PHOTO".equals(evt.getPropertyName())) {
         getPathField().setText((String) evt.getNewValue());
     if (evt.getNewValue() != null)
         getPhoto().setIcon(new javax.swing.ImageIcon
         ((String) evt.getNewValue()));
     else getPhoto().setIcon(new javax.swing.ImageIcon(""));
    }
   }
 });
  }
  return ivjDBSelect;
}
    End Figure

    Figure 9.46: Updated PropertyChangeListener for the DBSelect bean

Inserting and changing photos

Now, let's add the functionality for inserting and modifying photos of your friends.

  1. Use Choose Bean to select a JFileChooser bean from the javax.swing package, and drop it on the design surface outside of the frame's visual surface.

  2. Select the Change photo button on the design surface, and use content assist to add an ActionListener. Add code to the actionPerformed(ActionEvent) method to show the JFileChooser open dialog, and to set the path and image from the selected file name, as shown in Figure 9.47.

    Start Figure

    // add code in bold
private javax.swing.JButton getChangePhotoButton() {
  if(changePhotoButton == null) {
   changePhotoButton = new javax.swing.JButton();
   changePhotoButton.setText("Change photo");
   changePhotoButton.addActionListener
    (new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent e) {
       int returnVal = getJFileChooser().showOpenDialog(MyFriends.this);
      if (returnVal == javax.swing.JFileChooser.APPROVE_OPTION) {
        getPathField().setText
           (getJFileChooser().getSelectedFile().getPath());
        getPhoto().setIcon(new javax.swing.ImageIcon
           (getJFileChooser().getSelectedFile().getPath()));
      }
    }
   });
   }
   return changePhotoButton;
}
    End Figure

    Figure 9.47: ActionListener for the ChangePhoto button

Save your changes and test your application again. Now you can navigate through records; modify, insert, and delete them; and use the information from the database to find and display images.

Providing unique IDs

Your application is ready. However, as your database grows, it will become more and more difficult to provide unique IDs, so it's a good idea to make the process of entering IDs automatic. Your computer can generate unique numbers to use in the database. For example, you can use the system time in milliseconds for the unique number.

Start Sidebar
The java.util.Date class

The Date class represents a specific date and time. It is based on the epoch, which is midnight GMT (Greenwich Mean Time) on January 1, 1970. You can get the number of milliseconds since the epoch by using the time property of the Date class. If you're wondering why the epoch starts in 1970, this is simply taken from the convention used in Unix operating systems.

End Sidebar

We'll add a Dialog that appears each time you try to insert a new row. When you click the Set ID button in the Dialog window, it will generate a unique ID for the new row.

  1. Select a JDialog bean from the Swing Containers palette category, and drop it on the design surface outside of the frame's visual surface.

  2. Set the JDialog bean's title property to Set ID, and set its defaultCloseOperation property to DISPOSE_ON_CLOSE. Increase the size of the dialog surface so you can add visual elements to its content pane.

  3. The content pane already has its layout set to BorderLayout, which is what you want. Select a JButton bean from the Swing Components palette category, and drop it on the center of the content pane. Set the button's text property to Set ID.

  4. Select the Insert button on the design surface, and add code to its ActionListener to show the dialog after a new row is inserted into the table, as shown in Figure 9.48.

    Start Figure

    // add code in bold
private javax.swing.JButton getInsertButton() {
  if(insertButton == null) {
   insertButton = new javax.swing.JButton();
   insertButton.setIcon(new javax.swing.ImageIcon
       (getClass().getResource("/friends/insert.gif")));
   insertButton.addActionListener(new java.awt.event.ActionListener() {
   public void actionPerformed(java.awt.event.ActionEvent e) {
          try {
            setColumns();
            getIvjDBSelect().newRow(false);
            getJDialog().setLocationRelativeTo(MyFriends.this);
            getJDialog().show();
          }
          catch (java.sql.SQLException ex) {}
    }
    });
   }
   return insertButton;
}
    End Figure

    Figure 9.48: Updated ActionListener for Insert button

  5. When the user clicks the Set ID button, you want to get the current system time in milliseconds, and set this value in the IDField's text property. Select the Set ID button on the design surface, and use content assist to add an ActionListener. Add code to the actionPerformed(ActionEvent) method to set the IDField's text property to the current time, and dispose of the dialog window, as shown in Figure 9.49.

    Start Figure

    // add code in bold
private javax.swing.JButton getJButton() {
  if(jButton == null) {
   jButton = new javax.swing.JButton();
   jButton.setText("Set ID");
   jButton.addActionListener(new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent e) {
        getIDField().setText
             (String.valueOf((new java.util.Date()).getTime()));
        getJDialog().dispose();
    }
   });
   }
   return jButton;
}
    End Figure

    Figure 9.49: ActionListener for Set ID button

Save your changes and test the application. You should be able to add information about your friends to the database, as shown in Figure 9.50.

Click To expand
Figure 9.50: The MyFriends application in action

If you had any problems building the MyFriends application, look at the [image] MyFriends.java solution file in the /solutions/chap09/friends subdirectory on the CD included with this book. Create a new package called solutions.chap09.friends in the DatabaseAccess project, and import /solutions/chap09/friends/MyFriends.java and the image files in the /solutions/chap09/friends subdirectory into it. Open [image] MyFriends.java with the Visual Editor to compare your program with the solution. Before running the application, make sure you update the DBSelect bean's properties to specify the appropriate driverName, url, username, and password for your Friends database.

If you want to run this application outside of WebSphere Studio, remember that all classes used by the application must be specified in the CLASSPATH. That means you need to specify the classes for the JDBC driver you are using, as well as the jar file for the WebSphere Studio DB beans for database access. You also need to place the image files for the toolbar buttons in the same folder as your application classes.


In review

This chapter explored some concepts of relational database design and demonstrated how to use basic features of the IBM DB2 Universal Database. It also showed how to create an application that works with data in a relational database using the DBSelect bean, how to create a toolbar using the JToolBar bean, and how to use the WebSphere Studio refactoring function.


Exercise

Add improvements to the MyFriends application to prohibit users from entering data in the IDField, to enable the toolbar icons for working with table rows (such as the insert and first icons) only after the database connection has been established, and to add appropriate tool tips for the icons in the toolbar.

A solution file for this exercise is in the /solutions/chap09/friends subdirectory on the CD included with this book. Import /solutions/chap09/friends/MyFriendsExer1.java and the image files in the /solutions/chap09/friends subdirectory into the package named solutions.chap09.friends. Open [image] MyFriendsExer1.java with the Visual Editor to compare your program with the solution. Before running the application, make sure you update the DBSelect bean's properties to specify the appropriate driverName, url, username, and password for your Friends database.


References

IBM DB2 Web site: http://www.ibm.com/software/data/db2/


Chapter 10: Working With XML Data

Download CD Content

In this chapter we look at several features in WebSphere Studio that you can use to build Java applications that work with XML data. You'll use the XML perspective to create DTD and XML files and to generate JavaBeans from a DTD that you'll use to build an XML application in the Visual Editor. You'll also learn how to use the Swing JTable component.

Introduction to XML

XML stands for eXtensible Markup Language. You use XML to create your own markup language (or vocabulary) to describe data for a particular application. XML doesn't provide any functions to format or process the data—you do that with other tools or applications that you write. XML just gives you a mechanism to describe your data in a convenient and concise way that makes it very easy for other programs to understand the data and work with it. With XML, you break your data into elements, define the relationships between the elements, and give the elements names that make sense to you.

XML data is typically stored in ordinary text files with a .xml extension, although you can also store XML data in other formats, such as in a database. Each XML file has one root element, which is the parent for all other elements (called child elements) in that XML file. Child elements can, in turn, contain other child elements or they can contain text data—whatever makes sense to organize your data best.

Each XML element typically begins with a start tag and ends with an end tag. You use the start and end tags to surround the element contents, which can be actual text data (called parsed character data) or other child elements. When a program parses your XML data (that is, breaks it down into its individual elements), it looks for the start and end tags to recognize where a particular element begins and ends. You use angle brackets and slashes to identify start and end tags, so that for an element named myElement, you specify the start tag as <myElement> and the end tag as </myElement>. Elements can also have attributes, which are typically used to describe additional information about the element. In cases where an element has only attributes, without any data or child content, the end tag can be omitted. XML files also typically begin with an XML declaration that tells the parser how to parse the data, such as what character set is used for text data. You'll see that when you use the WebSphere Studio XML Editor, it takes care of all these syntax details for you.

Figure 10.1 shows an example of what an XML file might look like to describe the data from the ToDoList application you developed earlier in this book. This vocabulary for the ToDoList application has a root element called ToDoList, with child elements called ToDoListEntry that describe individual ToDoList items. The XML declaration at the beginning of the file tells the parser that text data is encoded with the Unicode character set (UTF-8). Note that it's not necessary to indent lines in an XML file—that's just to improve the readability for humans.

Start Figure
<?xml version="1.0" encoding="UTF-8"?>
<ToDoList>
  <ToDoListEntry>Learn how to work with XML data</ToDoListEntry>
  <ToDoListEntry>Create an XML application</ToDoListEntry>
  <ToDoListEntry>Have lunch</ToDoListEntry>
</ToDoList>
End Figure

Figure 10.1: An XML file for the ToDoList application

As you can see, the XML file itself just stores the data, although in a very structured and concise fashion. To use this data, you need to modify the ToDoList application to parse the contents of the XML file and to present the individual ToDoListEntry elements in the ToDoList.

Figure 10.2 shows an example of another XML file using the vocabulary for the MyBooks application you'll create in this chapter. This vocabulary has a root element called books that contains child elements called book. The book elements, in turn, contain child elements called title, author, and copyrightDate that describe a particular book. Notice that in the title for the second book element, the character "&" had to be replaced by "&amp;". Characters such as "&" and "<" have special meaning to the programs that parse XML data, so if you need to use these characters in the text for an element, you substitute the corresponding entity reference ("&amp;" and "&lt;").

Start Figure
<?xml version="1.0" encoding="UTF-8"?>
<books>
  <book>
    <title>VisualAge for Java for Non-Programmers</title>
    <author>Parkin, Burrus, Pullin</author>
    <copyrightDate>2002</copyrightDate>
  </book>
  <book>
    <title>Bird Life &amp; Behavior</title>
    <author>Sibley</author>
    <copyrightDate>2001</copyrightDate>
  </book>
</books>
End Figure

Figure 10.2: An XML file for the MyBooks application

The two examples we've looked at so far are both well-formed XML data, which means they have matching start and end tags for each element, elements are all nested properly, and so on. All XML data must be well-formed, or the programs that parse them can't process them properly. In addition, XML data is considered valid if the data conforms to the application's vocabulary. How do you define the vocabulary? There are actually several ways, and we'll look at two of them in this book: Document Type Definitions (DTDs) in this chapter and XML Schemas in the next chapter.

Document Type Definitions

You use DTDs to identify the rules for your vocabulary, such as what element names are allowed, how many times a particular element can be present, and how the elements are related to one another. DTDs use special notation to define element entities, but you'll see that when you use the WebSphere Studio DTD Editor, it takes care of all the syntax details for you. DTD files are usually stored in separate text files with a .dtd extension, although you can also have DTDs in-line in your XML file.

Figure 10.3 shows an example of what a DTD file looks like to define a vocabulary for the ToDoList application. This DTD defines the ToDoList and ToDoListEntry elements. It says that ToDoList elements contain ToDoListEntry child elements, and there can be zero or more child elements (that's what the "*" means). It also says that ToDoListEntry elements contain parsed character data (that's what "#PCDATA" means). As you can see, DTDs are clearly intended for programs to read, not humans.

Start Figure
<!ELEMENT ToDoList (ToDoListEntry*)>
<!ELEMENT ToDoListEntry (#PCDATA)>
End Figure

Figure 10.3: A DTD file for the ToDoList application

Once you create a DTD file, you add a document type declaration (DOCTYPE) to your XML file to tell validating parsers which file to use to verify that the XML file conforms to the rules for the vocabularly. Figure 10.4 shows an XML file for the ToDoList application with the document type declaration highlighted in bold. The DOCTYPE statement tells the parser that the root element is named ToDoList and that the parser should use the todolist.dtd file in the same folder as the XML file to validate this XML data.

Start Figure
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ToDoList SYSTEM "todolist.dtd">
<ToDoList>
  <ToDoListEntry>Learn how to work with XML data</ToDoListEntry>
  <ToDoListEntry>Create an XML application</ToDoListEntry>
  <ToDoListEntry>Have lunch</ToDoListEntry>
</ToDoList>
End Figure

Figure 10.4: Adding a document type declaration to an XML file

What's the advantage of specifying the DTD in an XML file? Very often they're left off because, if they are included, it means the DTD has to be shipped with the data. Programs that read the XML file can use the DTD to validate its content, but other than that the DTD doesn't provide any functionality. However, the DTD is very useful for programs that write XML files, such as the WebSphere Studio XML Editor, because these programs can use the DTD to do things like code assit or provide usability features that help write valid tag structures based on the DTD. So, the DTD can be more useful at design time for encoding the data, rather than at parse time for reading the data.

XML parsers

We've mentioned parsers several times now, without really explaining what they do. The purpose of a parser is to read your XML data and break it down into its individual elements. All parsers do this. In addition, some parsers validate your XML data using the vocabulary rules (such as a DTD) and tell you if there are any errors. There are a variety of parsers available for working with XML data, and they work in different ways. Some parsers build an in-storage copy of your data, called a Document Object Model (DOM), which you navigate to get the particular element you want. Other parsers just fire events when they reach certain points while processing an XML file, such as finding the start of an element, and then you have to keep track of where you are in the file.

The JavaBeans you'll use to work with XML data in this chapter use a DOM parser. The parser creates an in-storage tree structure with nodes to describe the XML data. The tree has a document node with information from the document type declaration, element nodes for each XML element, and other types of nodes depending on the content of the XML file. The tree can get fairly complicated, but the JavaBeans you'll use in this chapter shield you from much of the details, so you can just think in terms of the individual XML elements. For example, Figure 10.5 shows what an element tree might look like for the ToDoList application XML data shown earlier in this chapter.

Click To expand
Figure 10.5: An element tree for XML data for the ToDoList application

This tree structure for the ToDoList application's sample XML data consists of the ToDoList root element and three ToDoListEntry child elements: "Learn how to work with XML data", "Create an XML application", and "Have lunch". You navigate to a child element by starting at the root element and calling methods in the generated JavaBeans to get the particular child element you want to work with.


Creating the MyBooks application

Now that you've been introduced to the basic concepts of XML and DTDs, you can build an application that shows how to use them. The application you'll build in this chapter is shown in Figure 10.6.

Click To expand
Figure 10.6: The MyBooks application in action

The MyBooks application maintains a list of books, such as books in your personal library. Information about each book (title, author, and copyright date) is saved in an XML file. The application presents the information in a JTable component and lets you edit, add, or remove books in the list. When you click the Save button, the data is saved back to the XML file.

To build the MyBooks application, you use the XML perspective to

  • Create the DTD file that defines the vocabulary for the application

  • Create the initial XML file for the application

  • Generate JavaBeans from the DTD

You then use the Java perspective to build the application with the generated JavaBeans.

Before you begin

Since the MyBooks application is a Java application, you first need to set up a new Java project and package to contain the application files.

  1. In the Java perspective, create a new Java Project called XMLApplications. You don't need to specify any external JAR files; they'll automatically be added later.

  2. Create a new Java package, called books, in your XMLApplications project.

The XML perspective

To open an XML perspective, click on the Open a Perspective icon, select Other… from the pop-up menu, and then select XML and click OK. An XML perspective opens, and the XML Perspective icon appears in the vertical toolbar. To switch between the Java and XML perspectives, just click on the icons in the toolbar.

The XML perspective looks similar to the perspectives you've already worked with, although the default window arrangement is a little different. The Navigator window appears in the lower left portion of the Workbench. This is similar to the Package Explorer you use in the Java perspective. When you open a file in the XML perspective, its editor is displayed in the upper right portion of the Workbench and an outline of the file's content is shown in the Outline view. The Tasks view shows a list of any errors in your files, such as validation errors in an XML file. We'll explain how to use the various editors as we create files in the following sections.

Creating the DTD file

  1. In the Navigator, click the + sign next to XMLApplications to expand its contents.

  2. Right-click on the books folder and select New → DTD from the pop-up menu.

  3. Select Create DTD file from scratch and click Next.

  4. The XMLApplications/books folder is already selected as the folder where your new DTD file will be placed. Enter [image] books.dtd for the file name and click Finish.

  5. Your new DTD file opens in the DTD Editor. The editor has two tabs: Design and Source. Click on the Design tab.

    Tip

    If you ever want to see what the generated source looks like, switch to the Source tab. Also notice that the DTD contains what looks like an XML declaration—this is actually a text declaration, which can be used to specify special character encoding within the DTD.

  6. Start by defining the root element in the DTD. In the Outline view, right-click on [image] books.dtd and select Add Element from the pop-up menu. In the Design tab, enter books for the element name. This is the root element for your XML file. If you click on the + sign next to books, you'll see that its content is currently EMPTY. You can set its content after you define all the possible elements.

  7. Next you need to add an element for an individual book instance. In the Outline view, right-click on [image] books.dtd and select Add Element from the pop-up menu. In the Design tab, enter book for the element name (this is singular "book", unlike the "books" root element in the previous step).

  8. Repeat the previous step to add elements for title, author, and copyrightDate, so that the Outline view looks like Figure 10.7.

    Click To expand
    Figure 10.7: Elements added for the MyBooks application

  9. Now define the relationships between the elements. In the Outline view, click on the + sign next to books (the root element) and select EMPTY. Options appear in the Design tab for you to specify the content model for the books element (that is, to specify what type of content this element may contain). Select Children Content as the content model type. A group node is automatically created in the Outline view, and a newChild element is added as the first child.

  10. In the Design tab, select book as the name of the child element (the books root element will contain book child elements) and select Zero or more for occurrence (so there can be any number of book elements under the books root element). The Outline view should now look like Figure 10.8.

    Click To expand
    Figure 10.8: Adding the book element as a child element of books

  11. In the Outline view, click on the + sign next to book and select EMPTY. In the Design tab, select Children Content as the content model type. Another group node is created under the book element with a newChild element. Select title as the name of the child element and leave occurrence set to Just once.

  12. In the Outline view, right-click on the group node under book and select Add Element to Content Model from the pop-up menu. This adds another child under the book element. In the Design tab, select author as the name of the child element and leave occurrence set to Just once.

  13. Repeat the previous step to add copyrightDate as a child of the book element with occurrence of Just once, so that the Outline view looks like Figure 10.9.

    Click To expand
    Figure 10.9: Adding children to the book element

  14. The last step is to define the allowable content for the title, author, and copyrightDate elements. These will all contain normal text data, so you define them as parsed character data (PCDATA). In the Outline view, click on the + sign next to title and select EMPTY. In the Design tab, select (#PCDATA) as the content model type.

  15. Repeat the previous step to set the content model type to parsed character data for the author and copyrightDate elements, so that the Outline view looks like Figure 10.10.

    Click To expand
    Figure 10.10: The final DTD for the MyBooks application

Save your changes (Ctrl+S). To see the final DTD source, click on the Source tab. To verify whether your DTD is valid, click the Validate icon. Any errors are listed in the Tasks view.

Creating the XML file

Next you'll create an XML file from the DTD and enter some book elements. The DTD you just created defines the structure for your XML file, so in the same way that Java classes define the structure for object instances that are created from the class, you'll now create an XML instance file from the DTD.

  1. In the Navigator, right-click on [image] books.dtd and select Generate → XML File… from the pop-up menu.

  2. The folder name is already set to XMLApplications/books and the file name is set to [image] books.xml, so just click Next.

  3. The Select Root Element window appears, with the root element already set to books, which is what you want. Notice that the System ID is set to your [image] books.dtd file name. This is the reference to the DTD that goes in the XML file's document type declaration. Select Create required and optional content and click Finish.

  4. Your new XML file opens in the XML Editor. Click on the Design tab and click the + signs next to books and book to expand the content of these elements. As you can see, a book element was already added with default values for title, author, and copyrightDate. Type over the default values to enter a book description, as shown in Figure 10.11.

    Click To expand
    Figure 10.11: Defining a book

  5. To add another book, right-click on books in the Outline view or Design tab and select Add Child → book from the pop-up menu. Enter values for the new book's title, author, and copyrightDate.

    Reminder

    If a book's title contains special characters, such as "&", you need to enter the value in the XML Editor as the corresponding entity reference, such as "&amp;". For example, for the title "Bird Life & Behavior", enter the text as Bird Life &amp; Behavior. You'll see later that this isn't necessary when entering titles in the MyBooks application, but it is when you use the XML Editor.

Save your changes (Ctrl+S). To see the final XML source, click on the Source tab. To verify whether you XML file is valid, click the Validate icon. Any errors are listed in the Tasks view.

Generating JavaBeans from a DTD

You now have a DTD file that describes the vocabulary for your MyBooks application and an XML file that contains data for use in the application. The next step is to generate JavaBeans from the DTD, which you will use to build the application.

  1. In the Navigator, right-click on [image] books.dtd and select Generate → Java Beans… from the pop-up menu.

  2. The Generate Java Beans window appears with the container, package, and root element names already set to the values you want. Uncheck the check box to generate a sample test program, so that the window looks like Figure 10.12.

    Click To expand
    Figure 10.12: Generating JavaBeans from a DTD

  3. Click Finish.

Switch to the Java perspective so that you can see the changes that were just made to the XMLApplications project.

First, notice in the Package Explorer that three external JAR files were added to the XMLApplications project: XSDBEANS, XERCES, and XMLPARSERAPIS. Look at the properties for the XMLApplications project (Properties, Java Build Path, Libraries), and you see that these external JAR files are now listed on the Libraries tab. These JAR files are all used by the generated JavaBeans, so WebSphere Studio automatically updated the project to add them to the build path.

Next, notice that Java classes were added to the books package for each element in your DTD (books, book, title, author, and copyrightDate), along with a helper class (booksFactory). You use these classes to create an in-storage copy of the data in your XML file, manipulate the data, and save updates back to the XML file. The generated classes make it easy to work with XML data, because their methods are tailored to your XML vocabulary, so, for example, you call methods like getBook(int), getTitle(), and getAuthor() to get the data for a particular book element. We'll show you how to use the beans in the following sections.

Setting up the MyBooks visual class

  1. In the Java perspective, create a new visual class called MyBooks in your books package. Make javax.swing.JFrame the superclass for you new class and check the check box to create a method stub for the public static void main(String[] args) method.

  2. Just as you did for all the Java applications you built in this book, you need to add code to the main method to create an instance of the application frame and make the frame visible. But for the MyBooks application you also want to use the program arguments to get the XML file name. You'll supply the file name as the first argument to the application via a launch configuration, so in addition to the normal housekeeping you add at this point, add code to pass the file name to the frame's constructor and save it in a class variable, as shown in Figure 10.13.

    Start Figure

    // add a class variable to save the XML file name
private String XMLFileName = null;

// add code in bold to save the XML file name as a class variable
public MyBooks(String fileName) {
    super();
    XMLFileName = fileName;
    initialize();
}

// add code in bold to create an instance of the frame and show it,
// passing the XML file name as a parameter to the constructor
public static void main(String[] args) {
    MyBooks frame = new MyBooks(args[0]);
    frame.show();
}
    End Figure

    Figure 10.13: Creating an instance of the frame class and getting the argument

  3. Select the frame in the design surface, grab one corner of the rectangle, and drag it to increase its size.

  4. Set the frame's title property to My Books and the defaultCloseOperation property to EXIT.

Adding the visual elements

As you know from previous chapters, you place visual components for Swing-based applications on the content pane. To better organize the components, you'll build the buttons for the MyBooks application as a separate panel and then place it on the content pane. The content pane's layout is already set to BorderLayout, which is what you want.

  1. Select a JPanel bean from the Swing Containers palette category and drop it on the design surface outside of the frame's visual surface.

  2. Resize the JPanel so that you can add visual elements to it. The layout property for the JPanel is already set to FlowLayout, which is what you want.

  3. Select a JButton bean from the Swing Components palette category and drop it on the JPanel. Set the button's text property to Add book and rename the bean to addButton.

  4. Drop another JButton bean on the JPanel to the right of the addButton. Set the second button's text property to Remove book and rename it to removeButton.

  5. Drop a third JButton bean on the JPanel to the right of the removeButton. Set this button's text property to Save and rename it to saveButton.

  6. Select the JPanel on the design surface and move it to the south portion of the content pane.

  7. To present the book data, you'll use a JTable bean. JTable is just a view for table data; the table data itself is maintained by a separate table model (similar to the DigitalView and TimeModel beans you used in Chapter 6). JTable also doesn't contain any scrolling mechanism, so you need to place it in a JScrollPane container. Since JTables are commonly used with a JScrollPane, the Visual Editor has a component on its palette with this combination. Select a JTable on JScrollPane bean from the Swing Components palette category and drop it on the center portion of the content pane, so that your design surface looks like Figure 10.14.

    Click To expand
    Figure 10.14: Visual elements of the MyBooks application

  8. Select the JTable bean on the design surface (the inner grid that shows sample table entries) and set its selectionMode property to SINGLE_SELECTION. This property controls how many rows a user can select at a time.

Creating the table model

The table data currently shown in the design surface is just a preview of what a table with five rows and five columns might look like. For a real table to be presented at run time, you have to supply the actual data in a table model and then associate that table model with the JTable bean. There are several ways of creating table models. We'll show you how to create one that extends javax.swing.table.AbstractTableModel, using your book data as the model.

  1. In the Package Explorer, right-click on the books package and select New → Class from the pop-up menu. (The model doesn't have any visual elements to it, so you'll create it using the standard Java Editor.)

  2. Enter MyBooksTableModel for the class name and javax.swing.table.AbstractTableModel for the superclass name. (You can either enter the superclass name directly or click the Browse… button to select it from a list.)

  3. Uncheck the check box to create a method stub for the public static void main(String[] args) method. Check both the check boxes to create Constructors from superclass and to create Inherited abstract methods, so that the New Java Class window looks like Figure 10.15 (on the following page).

    Click To expand
    Figure 10.15: Creating the MyBooksTableModel class

  4. Click Finish.

Your new class opens in the standard Java Editor. As you can see, several methods have already been supplied because of the check boxes you checked on the New Java Class window. The JTable bean calls these methods in your table model class to get such things as the number of columns and rows in the table, or the data for a particular table cell. You need to implement the methods in your table model class, so that the JTable bean can access the data in the model and present it in its view of the table. The methods in the AbstractTableModel class that you need to implement are

  • getColumnCount()—returns an int value with the number of columns in the table

  • getColumnName(int)—returns a String value with the name of the column for the index specified

  • getRowCount()—returns an int value with the number of rows in the table

  • getValueAt(int,int)—returns an Object value with the table data at the row and column specified; the caller converts the Object to the appripriate format, such as a String, for rendering

  • isCellEditable(int,int)—returns a boolean flag to indicate whether the table data at the row and column specified is editable

  • setValueAt(Object,int,int)—sets the table data at the row and column specified to the value specified; the method accepts any Object as input for the table data

Here's how you implement these methods:

  1. To display column information, update the getColumnCount() method to return the number of columns and add a getColumnName(int) method to return the column names, as shown in Figure 10.16.

    Start Figure

    // add code in bold
public int getColumnCount() {
    return 3;
}

public String getColumnName(int column) {
    switch (column) {
            case 0: return "Title";
            case 1: return "Author";
            case 2: return "Copyright Date";
    }
    return "";
}
    End Figure

    Figure 10.16: Returning column count and name information

  2. To work with table rows, you first need to load the data from the XML file and create an in-storage copy of the data. The loadDocument(String) method in the booksFactory class does this for you, so you just call this method, passing it the XML file name. We'll use a parameter on the table model's constructor to get the file name, so update your code to add class variables for booksFactory and books and to load the document in the table model's constructor, as shown in Figure 10.17. You set the encoding properties to tell the parser what character set the XML file uses, and the packageName property to tell the booksFactory how to locate the generated JavaBean classes.

    Start Figure

    // add code in bold
private booksFactory iBooksFactory;
private books iBooks;

public MyBooksTableModel(String XMLFileName) {
   super();
   iBooksFactory = new booksFactory();
    iBooksFactory.setPackageName("books");
    iBooksFactory.setEncoding("UTF8");
    iBooksFactory.setEncodingTag("UTF-8");
    iBooks = (books) iBooksFactory.loadDocument(XMLFileName);
}
    End Figure

    Figure 10.17: Loading the XML file

  3. With the table data loaded into the iBooks class variable, your model now has access to everything it needs to work with the data. Update the getRowCount() method to return the number of book elements, as shown in Figure 10.18.

    Start Figure

    // add code in bold
public int getRowCount() {
   return iBooks.getbookCount();
}
    End Figure

    Figure 10.18: Returning the row count

  4. To get table data, update the getValueAt(int,int) method to return the table data at the row and column specified, as shown in Figure 10.19.

    Start Figure

    // add code in bold
public Object getValueAt(int rowIndex, int columnIndex) {
   switch (columnIndex) {
            case 0: return iBooks.getBook(rowIndex).getTitle();
            case 1: return iBooks.getBook(rowIndex).getAuthor();
            case 2: return iBooks.getBook(rowIndex).getCopyrightDate();
   }
   return null;
}
    End Figure

    Figure 10.19: Getting table data

  5. To set table data, add an isCellEditable(int,int) method to indicate that all cells are editable and add a setValueAt(Object,int,int) method to set the table data, as shown in Figure 10.20. The AbstractTableModel superclass takes care of firing events for your table model, so you just call its fireTableCellUpdated(int,int) method, and it notifies all listeners that the table model has changed.

    Start Figure

    // add code in bold
public boolean isCellEditable (int rowIndex, int columnIndex) {
   return true;
}

public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
   switch (columnIndex) {
     case 0:
            iBooks.getBook(rowIndex).setTitle((String) aValue);
            break;
     case 1:
            iBooks.getBook(rowIndex).setAuthor((String) aValue);
            break;
     case 2:
            iBooks.getBook(rowIndex).setCopyrightDate((String) aValue);
   }
   fireTableCellUpdated(rowIndex,columnIndex);
}
    End Figure

    Figure 10.20: Setting table data

  6. The final step is to associate your table model with the JTable bean. Save your changes to the MyBooksTableModel class and switch back to the MyBooks class in the Visual Editor. Update the source code to add a class variable for the table model, create an instance of the table model specifying the XML file name as the parameter on the table model's constructor, and pass the table model as a parameter on the JTable's constructor, as shown in Figure 10.21. Ignore the design time error message that the statement is too complicated to be evaluated.

    Start Figure

    // add a class variable for the table model
private MyBooksTableModel model = null;

// add code in bold
private javax.swing.JTable getJTable() {
   if(jTable == null) {
      model = new MyBooksTableModel (XMLFileName);
      jTable = new javax.swing.JTable(model);
      jTable.setSelectionMode
         (javax.swing.ListSelectionModel.SINGLE_SELECTION);
   }
   return jTable;
}
    End Figure

    Figure 10.21: Associating the table model with the JTable

Save your changes to the MyBooks class.

Testing the table

To test your application, you need to supply the XML file name as an argument in a launch configuration.

  1. Click on the arrow next to the Run icon in the toolbar and choose Run…

  2. The Launch Configurations window appears. Select Java Application as the launch configuration to create and click New. A new launch configuration appears in the window, with the Main tab filled in with the names of your project (XMLApplications) and application (books.MyBooks).

  3. Select the Arguments tab and enter the full path to your XML file name, as shown in Figure 10.22. The program arguments you enter here on the Arguments tab are passed to the main(String[] args) method when your application starts, so this is how your program gets the argument values.

    Tip

    The full path to your XML file name should be x:/workspace/XMLApplications/books/books.xml, where x:/workspace is your WebSphere Studio workspace directory, such as c:/Documents and Settings/Administrator/My Documents/IBM/wasexpress/workspace. Note that you need to surround the string in quotes if it contains any blanks.

    Click To expand
    Figure 10.22: Defining application arguments in a launch configuration

  4. Click Run.

Your application starts, and, as you can see, the table contains entries for the book data in your XML file. To change the application to use a different XML file name, you just change the argument in the launch configuration.

To select a table row, click it with the mouse. To edit a particular table cell, doubleclick it and type over the data you want, and then either press the Enter key or select another cell. To change the width of a column, move the mouse over the separator lines between column headings until it changes to a bidirectional arrow; then use the mouse to set the column width to whatever you want. These are just a few of the features that the JTable component provides.

Connecting the buttons

Finally, you need to bring the buttons to life by adding an ActionListener to each button and the logic to process the button clicks in the table model. First, you add the logic to process button clicks.

  1. Switch to the MyBooksTableModel class in the standard Java Editor.

  2. To add a book to the table, you need a method in the table model that creates a new book element, adds the element to the in-storage copy of the XML data, and then fires an event to tell listeners that a row has been added to the table. Add the code shown in Figure 10.23 to perform these steps. Note that the setBook(int,book) method is not actually setting a book element, but rather inserting a new element after the node index specified; to add the element to the end of the table, you need to set the index to the last node in the current structure. (This is one case where you currently need to access the details of the XML data's DOM when using the generated JavaBeans.)

    Start Figure

    // add code in bold
public void addRow () {
   book iBook = iBooksFactory.createbook("book");
   iBook.setTitle("title");
   iBook.setAuthor("author");
   iBook.setCopyrightDate("date");
   int index = iBooks.getXMLElement().getChildNodes().getLength() + 1;
   iBooks.setBook(index,iBook);
   fireTableRowsInserted(iBooks.getbookCount(),0);
}
    End Figure

    Figure 10.23: Method to add a book element

  3. To remove a book from the table, you need a method in the table model that removes the selected book element from the in-storage copy of the XML data and then fires an event to tell listeners that a row has been removed from the table. Add the code shown in Figure 10.24 to perform these steps.

    Start Figure

    // add code in bold
public void removeRow (int row) {
   iBooks.removeBook(row);
   fireTableRowsDeleted(row, row);
}
    End Figure

    Figure 10.24: Method to remove a book element

  4. To save the in-storage copy of the XML data back to the XML file, add a save() method in the table model that calls the booksFactory's save() method, as shown in Figure 10.25.

    Start Figure

    // add code in bold
public void save() {
   iBooksFactory.save();
}
    End Figure

    Figure 10.25: Method to save the XML data to the XML file

Save your changes to the MyBooksTableModel class and switch back to the MyBooks class in the Visual Editor to add the corresponding ActionListeners to call the new methods.

  1. Select the addButton on the design surface. Use content assist to add an ActionListener and add code to the actionPerformed(ActionEvent) method to call the table model's addRow() method, as shown in Figure 10.26.

    Start Figure

    // add code in bold
private javax.swing.JButton getAddButton() {
  if(addButton == null) {
   addButton = new javax.swing.JButton();
   addButton.setText("Add book");
   addButton.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent e) {
                model.addRow();
         }
   });
  }
  return addButton;
}
    End Figure

    Figure 10.26: ActionListener for the addButton

  2. Select the removeButton on the design surface. Use content assist to add an ActionListener and add code to the actionPerformed(ActionEvent) method to call the table model's removeRow(int) method to remove the selected row, as shown in Figure 10.27.

    Start Figure

    // add code in bold
private javax.swing.JButton getRemoveButton() {
 if(removeButton == null) {
   removeButton = new javax.swing.JButton();
   removeButton.setText("Remove book");
   removeButton.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent e) {
         model.removeRow(getJTable().getSelectedRow());
      }
   });
  }
  return removeButton;
}
    End Figure

    Figure 10.27: ActionListener for the removeButton

  3. Select the saveButton on the design surface. Use content assist to add an ActionListener and add code to the actionPerformed(ActionEvent) method to call the table model's save() method, as shown in Figure 10.28.

    Start Figure

    // add code in bold
private javax.swing.JButton getSaveButton() {
  if(saveButton == null) {
   saveButton = new javax.swing.JButton();
   saveButton.setText("Save");
   saveButton.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent e) {
                  model.save();
         }
   });
  }
  return saveButton;
}
    End Figure

    Figure 10.28: ActionListener for the saveButton

Save your changes and test the application. It should look similar to Figure 10.29.

Click To expand
Figure 10.29: Final MyBooks application

To add a row to the table, click Add book. The new row is added to the end of the table, where you can enter values for the new book's title, author, and copyright date. To remove a row, select it with the mouse and click Remove book. To save your changes back to the XML file, click Save.

If you had any problems building the MyBooks application, look at the solution files in the /solutions/chap10/books subdirectory on the CD included with this book. Create a new package called solutions.chap10.books in the XMLApplications project and import all of the files in the /solutions/chap10/books subdirectory into it. Open [image] MyBooks.java with the Visual Editor to compare your program with the solution. To run the solution, create a launch configuration to pass the appropriate XML file name as an argument to the program.


In review

This chapter introduced XML concepts and demonstrated how to use some of the features of WebSphere Studio to work with XML data. You learned how to build an application that uses JavaBeans generated from a DTD. You also learned how to use the Swing JTable component. In the next chapter, we'll show how you can use XML Schemas to define an XML vocabulary.


Chapter 11: Using XML Schemas

Download CD Content

In this chapter, we'll show you how to use XML Schemas as another way to define an XML vocabulary. You'll use the XML perspective to create XML Schemas and XML files, to generate JavaBeans from an XML Schema, and to use them to build an XML application in the Visual Editor. You'll also learn how to use more Swing features, such as the JComboBox component and DocumentListeners for JTextField components.

Introduction to XML Schemas

The MyBooks application that you created in the previous chapter used a DTD to define the XML vocabulary for the application. In this chapter, we'll show how you can use XML Schemas to define vocabularies. With DTDs, you defined structural rules for your vocabulary, such as element names and their relationships, and you defined some limited validation rules, such as how many times an element could occur. XML Schemas are another way to define structural rules, but they also let you define data types for each element (string, date, and so on) and allow much more extensive validation rules, such as validating whether or not an element is an integer within a particular range, say a number from 1 to 10. XML Schemas also let you easily combine elements from several different XML vocabularies.

XML Schemas are themselves XML files, so they must conform to the vocabulary for XML Schemas. As you might expect, this is a very complicated vocabulary, and we'll cover only a small portion of it in this chapter. XML Schemas are stored as ordinary text files with a .xsd extension. Since you now have XML files describing XML files, the actual files with your application's XML data are called XML instance documents to differentiate them from their associated XML Schema.

XML Schemas have a root element named schema, which contains child elements named element that you use to define the elements in your application's vocabulary. For each element in your application's vocabulary, you define the element's name, its data type, and any other attributes. Data types can be either complex or simple. You use complex types for your application elements that contain other child elements. You use simple types for application elements that consist entirely of text data without any other child elements. XML Schemas include all the basic data types you'd expect as built-in simple types, such as string, date, and integer. You can extend the built-in simple types to add more extensive validation, such as restricting a string to be a particular length. When you create a complex type or extend a build-in simple type, you can give your new type a name or leave it unnamed (called anonymous).

Figure 11.1 shows an example of what an XML Schema might look like for the ToDoList application's XML vocabulary.

Start Figure
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema">
  <element name="ToDoList">
    <complexType>
   <sequence>
      <element name="ToDoListEntry" type="string"
      minOccurs="0" maxOccurs="unbounded"></element>
   </sequence>
   </complexType>
  </element>
</schema>
End Figure

Figure 11.1: A sample XML Schema for the ToDoList application

This example defines an element named ToDoList, which has an anonymous complex type. The ToDoList element contains child elements named ToDoListEntry, which have the built-in simple type of string, and there can be zero or more ToDoListEntry elements (that's what the minOccurs and maxOccurs attributes mean). This XML Schema defines the same vocabulary for the ToDoList application as the DTD example shown in the previous chapter. It may be somewhat more readable than the DTD syntax, but, as with the other editors in WebSphere Studio, you'll see that the XML Schema Editor takes care of all the syntax details for you.

Notice the xmlns attribute on the schema element in Figure 11.1. This tells parsers to use the standard namespace for XML Schemas, http://www.w3.org/2001/XMLSchema, to interpret the XML Schema (more on namespaces in the next section).

Once you create an XML Schema, you add attributes to your XML instance document to tell parsers which file to use to verify that the XML instance document conforms to the rules for the vocabulary. Figure 11.2 shows an XML instance document for the ToDoList application updated to point to an XML Schema file named todolist.xsd.

Start Figure
<?xml version="1.0" encoding="UTF-8"?>
<ToDoList xmlns:xsi="http://www.w3.org/2001/XMLSchema-intance"
       xsi:noNamespaceSchemaLocation="todolist.xsd">
   <ToDoListEntry>Learn how to work with XML data</ToDoListEntry>
   <ToDoListEntry>Create an XML application</ToDoListEntry>
   <ToDoListEntry>Have lunch</ToDListEntry>
</ToDoList>
End Figure

Figure 11.2: Associating the ToDoList XML instance document with an XML Schema

The xmlns:xsi attribute on the ToDoList element tells parsers to use the standard namespace for XML Schema instance, http://www.w3.org/2001/XMLSchemainstance, to interpret any elements or attributes in the XML instance document that have a prefix set to "xsi". The noNamespaceSchemaLocation attribute has "xsi" as its prefix (the part of the attribute name located before the ":"). That puts the noNamespaceSchemaLocation attribute in the namespace for XML Schema instances, and parsers know to use the value specified for this attribute as the XML Schema file to validate anything in the XML instance document that isn't associated with a namespace—that is, any elements or attributes that don't have a prefix specified (again, more on namespaces in the next section).

But before you continue, notice that the XML file doesn't specify what its root element name is, as you had to do when you used a DTD to validate an XML file. With XML Schemas, any top-level element in the XML Schema (called global elements) can be the root element in an XML instance document. In this example, ToDoList is the only global element in the XML Schema, thus it must be the root element in the XML instance document.

Namespaces

Suppose you have two XML vocabularies that you want to use for an XML application, for example, a book vocabulary that defines books and a bookorder vocabulary that defines customer orders for purchasing books. If these vocabularies were developed by different organizations, they will probably contain elements that have the same name but mean entirely different things. For example, the book vocabulary may have a title element for a book's title (Murder on the Orient Express, and so on), while the bookorder vocabulary may have a title element for a person's title (Dr., Mr., and so on). How can you combine these two vocabularies to use them together in a single XML instance document? You assign each vocabulary to its own namespace and use qualified names in your XML instance document to specify which namespace a particular element belongs to.

You've already seen two examples of namespaces: one for XML Schemas and one for XML Schema instances. Each namespace has a unique identifier associated with it, called a universal resource identifier (URI). You'll commonly see URLs for an organization's Web site specified as a namespace identifier, but don't expect to find an actual XML file at the URL location. The URL is simply a unique identifier for an organization. Once you have a unique identifier for your namespace, you update your XML Schema to specify that identifier as the target namespace for the vocabulary, and you update your XML instance documents to use qualified names (names with a prefix) to associate elements and attributes with the namespace. Figure 11.3 shows an example of a book vocabulary that's associated with the http://www.mcpress.com namespace. This XML Schema defines a single book element that contains title, author, and copyrightDate child elements. The elementFormDefault attribute says that elements in the XML instance document must be qualified (that is, they must use a prefix to specify the namespace for this vocabulary).

Start Figure
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://www.mcpress.com"
    xmlns:book="http://www.mcpress.com" elementFormDefault="qualified">
   <element name="book">
   <complexType>
      <sequence>
         <element name="title" type="string"></element>
         <element name="author" type="string"></element>
         <element name="copyrightDate" type="string"></element>
      </sequence>
   </complexType>
   </element>

</schema>
End Figure

Figure 11.3: XML Schema associated with a namespace

Figure 11.4 shows an example of an XML instance document that uses this XML Schema.

Start Figure
<?xml version="1.0" encoding="UTF-8"?>
<book:book xmlns:book="http://www.mcpress.com"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.mcpress.com book.xsd">
   <book:title>Waiting for Godot</book:title>
   <book:author>Beckett</book:author>
   <book:copyrightDate>1954</book:copyrightDate>
</book:book>
End Figure

Figure 11.4: XML instance document using the book namespace

As you can see, all elements in this XML instance document use qualified names to specify the namespace that they belong to. The schemaLocation attribute associates the http://www.mcpress.com namespace with the XML Schema file, [image] book.xsd, which is in the same folder as the XML instance document.


Creating the BookOrder application

Now that you've been introduced to the basic concepts of XML Schemas, you can build an application that shows how to use them. The application you'll build in this chapter is shown in Figure 11.5.

Click To expand
Figure 11.5: The BookOrder application in action

The BookOrder application shows a portion of a customer order for a particular book. The application gets the information from an XML instance document and lets you edit the information and save it back to the file. The BookOrder application uses two XML Schemas and two namespaces to define the application's vocabulary: one for the book and another for the book order.

To build the BookOrder application, you use the XML perspective to

  • Create the XML Schema files that define the vocabulary for the application

  • Create the initial XML file for the application

  • Generate JavaBeans from the XML Schemas

You then use the Java perspective to build the application with the generated JavaBeans.

Before you begin

Since the BookOrder application is a Java application, you first need to set up a new Java package to contain the application files.

  1. In the Java perspective, create a new Java package called bookorder in your XMLApplications project.

  2. Switch to the XML perspective.

Creating the XML Schema for the book vocabulary

You can start by defining the XML Schema for the book vocabulary. This XML vocabulary defines an individual book element and uses a target namespace of http://www.mcpress.com.

  1. In the Navigator, right-click on the bookorder folder in the XMLApplications project and select New → XML Schema from the pop-up menu.

  2. The XMLApplication/bookorder folder is already selected as the folder where your new XML Schema file will be placed. Enter [image] book.xsd for the file name, and click Finish.

  3. Your new XML Schema file opens in the XML Schema Editor. Click on the Design tab.

    Tip

    If you ever want to see what the generated source looks like, switch to the Source tab. To see a graph view of the XML Schema, switch to the Graph tab.

  4. This schema is currently set up with a namespace prefix of book and a target namespace of http://www.ibm.com. We'll use http://www.ibm.com as the namespace for the bookorder vocabulary, so change the target namespace to http://www.mcpress.com and click Apply.

  5. Set the element form default to qualified. This says that elements in the XML instance document must use qualified names to identify which namespace they're in. The Design tab should now look like Figure 11.6.

    Click To expand
    Figure 11.6: Defining the book vocabulary's target namespace

  6. Next, define the book element and its content. In the Outline view, right-click on [image] book.xsd and select Add Global Element from the pop-up menu.

  7. In the Design tab, enter book as the element name and select User-defined complex type. The book element contains child elements, so it must use a complex type. You don't have to name the complex type explicitly, so it should remain "**anonymous**", as shown in Figure 11.7.

    Click To expand
    Figure 11.7: Defining the book element

  8. In the Outline view, right click on the complex type icon and select Add Content Model from the pop-up menu.

  9. A group node is added with the content model set to Sequence, which is what you want. (This says that child elements must be in the sequence defined in the XML Schema.) Right-click on the group node icon and select Add Element from the pop-up menu.

  10. In the Design tab, enter title as the element name and leave the type information set to the built-in simple type of string.

  11. In the Outline view, right-click on the group node and select Add Element from the pop-up menu. In the Design tab, enter author as the element name. This element will also use the built-in simple type of string.

  12. In the Outline view, right-click on the group node and select Add Element from the pop-up menu. In the Design tab, enter copyrightDate as the element name. For this element, you will extend the built-in simple type to add a restriction on the length of the string. Select user-defined simple type. A simple type node is added.

  13. Right-click on the simple type icon and select Add Restriction from the pop-up menu. A restriction node is added.

  14. In the Design tab, double-click the Value field next to the length restriction and enter a value of 4, as shown in Figure 11.8. This restricts copyrightDate values to be strings with a length of 4.

    Click To expand
    Figure 11.8: Defining a restriction for a simple type

Save your changes (Ctrl+S). The Outline view should now look like Figure 11.9.

Click To expand
Figure 11.9: XML Schema for the book vacabulary

The XML Schema for the book vocabulary is ready. To see the final XML source, click on the Source tab. To verify whether or not your XML Schema is valid, click the Validate icon. Any errors are listed in the Tasks view.

Creating the XML Schema for the bookorder vocabulary

Next you'll define the XML Schema for the bookorder vocabulary. This vocabulary defines the order information, such as the name of the person ordering the book, and references the book information in the book vocabulary.

  1. In the Navigator, right-click on the bookorder folder in the XMLApplications project and select New → XML Schema from the pop-up menu.

  2. Enter [image] bookorder.xsd for the file name, and click Finish.

  3. Your new XML Schema file opens in the XML Schema Editor. Click on the Design tab.

  4. This schema is already set up with a namespace prefix of bookorder and a target namespace of http://www.ibm.com, which is what you want. Set the element form default to qualified, so that the Design tab looks like Figure 11.10.

    Click To expand
    Figure 11.10: Defining the bookorder vocabulary's target namespace

  5. Next, define the bookorder element and its content. In the Outline view, rightclick on [image] bookorder.xsd and select Add Global Element from the pop-up menu.

  6. In the Design tab, enter bookorder as the element name and select userdefined complex type to create an anonymous complex type.

  7. In the Outline view, right click on the complex type icon and select Add Content Model from the pop-up menu.

  8. A group node is added with the content model set to Sequence, which is what you want. Right-click on the group node icon and select Add Element from the pop-up menu.

  9. In the Design tab, enter orderDate as the element name and select dateTime as the built-in simple type, as shown in Figure 11.11.

    Click To expand
    Figure 11.11: Defining the orderDate element

  10. In the Outline view, right-click on the group node and select Add Element from the pop-up menu. In the Design tab, enter person as the element name. The person element will contain child elements called title and name, so select user-defined complex type to create another anonymous complex type.

  11. In the Outline view, right click on the complex type icon under the person element and select Add Content Model from the pop-up menu.

  12. A group node is added with the content model set to Sequence. Right-click on the group node icon for this complex type and select Add Element from the pop-up menu. In the Design tab, enter title as the element name. (This element is for the person's title, such as Dr. or Mrs..)

  13. Right-click on the group node icon for this complex type again and select Add Element from the pop-up menu. In the Design tab, enter name as the element name. (This element is for the person's name.) The Outline view should now look like Figure 11.12.

    Click To expand
    Figure 11.12: orderDate and person elements added to the bookorder

  14. Next, import the book namespace so that you can use the book element in that namespace. In the Outline view, right-click on [image] bookorder.xsd and select Add Import from the pop-up menu. An import node icon appears in the Outline view. In the Design tab, click Select.

  15. The Select XML schema file window appears with the default set to select a schema from Workbench projects. Click Next.

  16. Select [image] book.xsd from the list of Workbench files, as shown in Figure 11.13.

    Click To expand
    Figure 11.13: Selecting a schema to import

  17. Click Finish. Now you can add a reference to the book element in the book namespace to your XML Schema for the book order.

  18. In the Outline view, click on the + signs to expand the content of the bookorder element, right-click on the group node for the bookorder element, and select Add Element Ref from the pop-up menu. In the Design tab, select book:book as the reference name, so that the Outline view looks like Figure 11.14.

    Click To expand
    Figure 11.14: Element reference added for book element

  19. Finally, add one more element to indicate whether or not the book is in stock. In the Outline view, right-click on the group node for the bookorder element and select Add Element from the pop-up menu. In the Design tab, enter inStock as the element name. For this element, you will extend the built-in simple type of string to add a restriction on the string values. Select userdefined simple type. A simple type node is added.

  20. In the Outline view, right-click on the simple type icon and select Add Restriction from the pop-up menu. A restriction node is added.

  21. Right-click on the restriction node icon and select Add Enumerations… (make sure you choose the plural, Enumerations) from the pop-up menu. The Add Enumerations window appears. Enter Yes,No, as shown in Figure 11.15.

    Click To expand
    Figure 11.15: Defining enumerations for a simple type

  22. Click OK. Two enumeration nodes are added.

Save your changes. The XML Schema for the bookorder vocabulary is ready. The Outline view should now look like Figure 11.16.

Click To expand
Figure 11.16: XML Schema for the bookorder vocabulary

Creating the XML file

Next, create an XML instance document from the XML Schemas you just created and enter information for a book order.

  1. In the Navigator, right-click on [image] bookorder.xsd and select Generate → XML File… from the pop-up menu.

  2. The folder name is already set to XMLApplications/bookorder and the file name is already set to [image] bookorder.xml, so just click Next.

  3. The Select Root Element window appears, with the root element already set to bookorder, which is what you want. Notice that the namespace information is also filled in. Select Create required and optional content and click Finish.

  4. Your new XML file opens in the XML Editor. Click on the Design tab and click the + signs next to bookorder:bookorder, bookorder:person, and book:book to expand the content of these elements. As you can see, the namespace information is supplied to identify the namespace associated with each prefix and the elements are already filled in with default values. Type over the default values to enter a book order, as shown in Figure 11.17.

    Click To expand
    Figure 11.17: Defining a bookorder

Save your changes. Notice that the restrictions you defined in the XML Schemas are enforced. For example, the inStock element allows values only of Yes and No.

Generating JavaBeans from XML Schemas

You now have XML Schema files that describe the vocabulary for your BookOrder application and an XML file that contains data for use in the application. The next step is to generate JavaBeans from the XML Schemas, which you will use to build the application.

  1. In the Navigator, right-click on [image] bookorder.xsd and select Generate → Java Beans… from the pop-up menu.

  2. The Generate Java Beans window appears with the container, package, and root element names already set to the values you want. Uncheck the check box to generate a sample test program, so that the window looks like Figure 11.18.

    Click To expand
    Figure 11.18: Generating Java Beans from an XML Schema

  3. Click Finish.

Switch to the Java perspective. As you can see, Java classes were added to the bookorder package for the book and bookorder elements, along with a helper class (bookorderFactory). You'll use these classes to create an in-storage copy of the data in your XML instance document, manipulate the data, and save updates back to the file.

Setting up the BookOrderApplication visual class

  1. Create a new visual class called BookOrderApplication in your bookorder package. Make javax.swing.JFrame the superclass for your new class. Check the check box to create a method stub for the public static void main(String[] args) method and uncheck any other check boxes to create method stubs.

  2. Just as you did for the MyBooks application in the previous chapter, you'll use the arguments passed to the application to get the file name for the XML instance document (the file with the book order data). Add the code shown in Figure 11.19 to create an instance of your application frame, make the frame visible, and get the XML file name.

    Start Figure

    // add a class variable to save the XML file name
private String XMLFileName = null;

// add code in bold to save the XML file name as a class variable
public BookOrderApplication(String fileName) {
    super();
   XMLFileName = fileName;
   initialize();
}

// add code in bold to create an instance of the frame and show it,
// passing the XML file name as a parameter to the constructor
public static void main(String[] args) {
   BookOrderApplication frame = new BookOrderApplication(args[0]);
   frame.show();
}
    End Figure

    Figure 11.19: Creating an instance of the frame class and getting the argument

  3. Select the frame in the design surface, grab one corner of the rectangle, and drag it to increase its size.

  4. Set the frame's title property to Book Order and the defaultCloseOperation property to EXIT.

Adding the visual elements

The content pane's layout is already set to BorderLayout, which is what you want. You can place the Save updates button at the bottom of the content pane and build the book order information in a separate JPanel with a GridLayout, which you can then add to the center of the content pane.

  1. Select a JButton bean from the Swing Components palette category and drop it on the south portion of the content pane. Set the button's text property to Save updates.

  2. Select a JPanel bean from the Swing Containers palette category and drop it on the design surface outside of the frame's visual surface.

  3. Resize the JPanel so that you can add visual elements to it. Set its layout property to GridLayout, its layout-columns property to 2, and its layout-rows property to 7.

  4. Select a JLabel bean from the Swing Components palette category and drop it on the JPanel. Set the label's text property to Order date.

  5. Drop another JLabel bean on the JPanel, after the first label. (It will actually be placed just under the first label. The components will move to the proper grid arrangement as you add more beans to the panel.) Set the second JLabel bean's text property to an empty string and rename the bean to orderDate. We're using a JLabel rather than a JTextField for the orderDate, because this application won't allow editing of the date.

    Tip

    If you have any problems dropping beans on the JPanel in the design surface, you can drop them on the JPanel in the Java Beans view instead. Solid lines in the Java Beans view show where a new bean will be dropped. You'll see the JPanel grow on the design surface as beans are added to it.

  6. Drop another JLabel bean on the JPanel. (As you add beans to the JPanel, drop the bean just after the preceding bean.) Set its text property to Title.

  7. Select a JTextField bean from the Swing Components palette category and drop it on the JPanel. Rename the bean to personTitle.

  8. Drop another JLabel bean on the JPanel. Set its text property to Name.

  9. Drop another JTextField on the JPanel. Rename the bean to personName.

  10. Drop another JLabel bean on the JPanel. Set its text property to Book title.

  11. Drop another JTextField on the JPanel. (Your JPanel should now have the proper grid arrangement shown in Figure 11.20.). Rename the bean to bookTitle.

    Click To expand
    Figure 11.20: JPanel with GridLayout

  12. Drop another JLabel bean on the JPanel. Set its text property to Author.

  13. Drop another JTextField on the JPanel. Rename the bean to author.

  14. Drop another JLabel bean on the JPanel. Set its text property to Copyright date.

  15. Drop another JTextField on the JPanel. Rename the bean to copyrightDate.

  16. Drop another JLabel bean on the JPanel. Set its text property to In Stock.

  17. Finally, select a JComboBox bean from the Swing Components palette category and drop it on the JPanel. The JPanel should look like Figure 11.21.

    Click To expand
    Figure 11.21: All visual elements added to the JPanel.

  18. Select the JPanel and move it to the center of the content pane, so that the design surface looks like Figure 11.22.

    Click To expand
    Figure 11.22: All visual elements added to the frame

    Reminder

    To move the panel, select it first in the Java Beans view.

Adding items to the JComboBox

To add items to the JComboBox, you use the bean's addItem(Object) method. You want the JComboBox to have values of "Yes" and "No" to match the possible values for the inStock XML element. Select the JComboBox bean on the design surface and add the code shown in Figure 11.23.

Start Figure
// add code in bold
private javax.swing.jComboBox get]ComboBox() {
   if(jComboBox == null) {
          jComboBox = new javax.swing.]ComboBox();
         jComboBox.addItem("Yes");
         jComboBox.addItem("No");
   }
   return jComboBox;
}
End Figure

Figure 11.23: Adding items to the JComboBox

Connecting the elements

Finally, you need to connect the visual elements with their corresponding XML elements so that the application starts with the values in your XML instance document and so that any changes made in the GUI are reflected in the XML elements. You'll load the XML instance document in your application's constructor, set the appropriate initialization value for each GUI component, and add a listener for the GUI component to update the in-storage copy of the XML instance document.

  1. In the source pane, add class variables for the bookorderFactory and bookorder, and then add code to the constructor to initialize the bookorderFactory and load the XML instance document, as shown in Figure 11.24. You set the packageName and encoding properties for the factory just as you did in the MyBooks application in the previous chapter; you also set properties to specify that qualified names are used and to specify the prefix for qualified names.

    Start Figure

    // add class variables for the bookorder factory and XML element
private bookorderFactory iBookorderFactory;
private bookorder iBookorder;

// add code in bold
public BookOrderApplication(String fileName) {
  super();
  XMLFileName = fileName;
  iBookorderFactory = new bookorderFactory();
  iBookorderFactory.setPackageName("bookorder");
  iBookorderFactory.setEncoding("UTF8");
  iBookorderFactory.setEncodingTag("UTF-8");
  iBookorderFactory.setPrefix("bookorder");
  iBookorderFactory.setElementQualified(true);
  iBookorder = (bookorder) iBookorderFactory. loadDocument(XMLFileName);
  initialize();
}
    End Figure

    Figure 11.24: Loading the XML instance document

  2. Select orderDate on the design surface and add code to set its value from the orderDate XML element, as shown in Figure 11.25. This value won't change, so no listeners are needed for it. Ignore the design time error message that the expression is too complicated to be evaluated.

    Start Figure

    // add code in bold
private javax.swing.jLabel getOrderDate() {
   if(orderDate == null) {
      orderDate = new javax.swing.]Label ();
      orderDate.setText(iBookorder.getOrderDate().toString());
   }
   return orderDate;
}
    End Figure

    Figure 11.25: Proceeding the orderDate

  3. Select personTitle on the design surface. For this, and the other JTextFields, you want to initialize the bean's text property to the value of the corresponding XML element and have any changes that the user makes reflected in the XML element. Unlike the BoundJTextField bean that you used in previous chapters, JTextField doesn't fire PropertyChangeEvents when its text property changes. Instead, you listen for events that are fired by the JTextField's model. Like all Swing components, JTextField is just a view, and the actual data that it contains is managed by a separate model. JTextField's model is called a Document, so you need a DocumentListener to listen for changes to the text data. Use Window → Preferences, Java, Templates to import the event handling template for javax.swing.event.DocumentListener. (This template is provided with WebSphere Studio, but is not automatically imported into the Workbench.) The template you want is the addDocumentListener.xml file in the /wstools/eclipse/plugins/com.ibm.etools.jbcf.codegen_5.0.1/Examples/Templates/javax/swing/event folder under the folder where you installed WebSphere Studio (for example, C:/Program Files/IBM/WebSphere/Express/SiteDeveloper).

  4. Use content assist to add a DocumentListener for the JTextField's document property and add the code shown in Figure 11.26 to initialize the text property and to update the XML element whenever the text changes.

    Start Figure

    // add code in bold
private javax.swing.jTextField getPersonTitle() {
  if(personTitle == null) {
   personTitle = new javax.swing.]TextField();
   personTitle.setText(iBookorder.getPerson().getTitle());
   personTitle.getDocument().addDocumentListener
        (new javax.swing.event.DocumentListener() {
   public void insertUpdate(javax.swing.event.DocumentEvent e) {
          iBookorder.getPerson().setTitle(personTitle.getText());
   }
   public void removeUpdate(javax.swing.event.DocumentEvent e) {
          iBookorder.getPerson().setTitle(personTitle.getText());
   }
   public void changedUpdate(javax.swing.event.DocumentEvent e) {
           ;
   }
  });
 }
 return personTitle;
}
    End Figure

    Figure 11.26: Processing the person Title

    Note

    The changedUpdate event is fired when text attributes (such as font) change, so you don't do anything when that event is fired. You're only concerned with text added or removed.

  5. Select personName on the design surface. Use content assist to add a DocumentListener and add the code shown in Figure 11.27 to initialize the text property and to update the XML element whenever the text changes.

    Start Figure

    // add code in bold
private javax.swing.jTextField getPersonName() {
  if(personName == null) {
   personName = new javax.swing.jTextField();
   personName.setText(iBookorder.getPerson().getName());
   personName.getDocument().addDocumentListener
       (new javax.swing.event.DocumentListener() {
    public void insertUpdate(javax.swing.event.DocumentEvent e) {
         iBookorder.getPerson().setName(personName.getText());
    }
   public void removeUpdate(javax.swing.event.DocumentEvent e) {
         iBookorder.getPerson().setName(personName.getText());
    }
   public void changedUpdate(javax.swing.event.DocumentEvent e) {
           ;
   }
  });
 }
 return personName;
}
    End Figure

    Figure 11.27: Processing the personName

  6. Select bookTitle on the design surface. Like the other JTextFields, you also want to initialize the bookTitle's text property from the XML element and make any updates back to the element, but remember that this element is in a different namespace. One limitation of the generated JavaBeans is that the factory class uses a single prefix to qualify all elements, so you need to reset the factory's prefix around calls to work with elements in the book namespace. Use content assist to add a DocumentListener and add the code shown in Figure 11.28 to initialize the text property and update the XML element.

    Start Figure

    // add code in bold
private javax.swing.jTextField getBookTitle() {
  if(bookTitle == null) {
   bookTitle = new javax.swing.jTextField();
   iBookorderFactory.setPrefix("book");
   bookTitle.setText(iBookorder.getBook().getTitle());
   iBookorderFactory.setPrefix("bookorder");
   bookTitle.getDocument().addDocumentListener
      (new javax.swing.event.DocumentListener() {
    public void inserUpdate(javax.swing.event.DocumentEvent e) {
         iBookorderFactory.setPrefix("book");
         iBookorder.getBook().setTitle(bookTitle.getText());
         iBookorderFactory.setPrefix("bookorder");
    }
    public void removeUpdate(javax.swing.event.DocumentEvent e) {
         iBookorderFactory.setPrefix("book");
         iBookorder.getBook().setTitle(bookTitle.getText());
         iBookorderFactory.setPrefix("bookorder");
    }
    public void changedUpdate(javax.swing.event.DocumentEvent e) {
            ;
    }
   });
  }
  return bookTitle;
}
    End Figure

    Figure 11.28: Processing the bookTitle

    Tip

    You can use the refactoring function you learned about in Chapter 9 to make the common code in the insertUpdate(DocumentEvent) and removeUpdate(DocumentEvent) methods into their own method.

  7. Select author on the design surface. This element is also in the book namespace, so use content assist to add a DocumentListener and add the code shown in Figure 11.29 to initialize the text property and update the XML element.

    Start Figure

    // add code in bold
private javax.swing.jTextField getAuthor() {
  if(author == null) {
   author = new javax.swing.jTextField();
   iBookorderFactory.setPrefix("book");
   author.setText(iBookorder.getBook().getAuthor());
   iBookorderFactory.setPrefix("bookorder");
   author.getDocument().addDocumentListener
         (new javax.swing.event.DocumentListener() {
    public void insertUpdate(javax.swing.event.DocumentEvent e) {
         iBookorderFactory.setPrefix("book");
         iBookorder.getBook().setAuthor(author.getText());
         iBookorderFactory.setPrefix("bookorder");
   }
   public void removeUpdate(javax.swing.event.DocumentEvent e) {
         iBookorderFactory.setPrefix("book");
         iBookorder.getBook().setAuthor(author.getText());
         iBookorderFactory.setPrefix("bookorder");
   }
   public void changedUpdate(javax.swing.event.DocumentEvent e) {
           ;
   }
  });
 }
 return author;
}
    End Figure

    Figure 11.29: Processing the author

  8. Select copyrightDate on the design surface. This element is also in the book namespace, so use content assist to add a DocumentListener and add the code shown in Figure 11.30 to initialize the text property and update the XML element.

    Start Figure

    // add code in bold
private javax.swing.jTextField getCopyrightDate() {
  if(copyrightDate == null) {
   copyrightDate = new javax.swing.jTextField();
   iBookorderFactory.setPrefix("book");
   copyrightDate.setText(iBookorder.getBook().getCopyrightDate());
   iBookorderFactory.setPrefix("bookorder");
   copyrightDate.getDocument().addDocumentListener
                     (new javax.swing.event.DocumentListener() {
    public void insertUpdate(javax.swing.event.DocumentEvent e) {
       iBookorderFactory.setPrefix("book");
       iBookorder.getBook().setCopyrightDate(copyrightDate.getText());
       iBookorderFactory.setPrefix("bookorder");
    }
    public void changeUpdate(javax.swing.event.DocumentEvent e) {
       iBookorderFactory.setPrefix("book");
       iBookorder.getBook().setCopyrightDate(copyrightDate.getText());
       iBookorderFactory.setPrefix("bookorder");
    }
    public void changedUpdate(javax.swing.event.DocumentEvent e) {
            ;
    }
  });
 }
 return copyrightDate;
}
    End Figure

    Figure 11.30: Processing the copyrightDate

  9. Select the JComboBox bean on the design surface. JComboBox beans fire itemStateChanged events when the user selects a new item in the combo box. You should have already imported the template for java.awt.event.ItemListener in Chapter 5, so use content assist to add an ItemListener and add the code shown in Figure 11.31 to initialize the JComboBox and update the XML element.

    Start Figure

    // add code in bold
private javax.swing.]ComboBox get]ComboBox() {
  if(jComboBox == null) {
   jComboBox = new javax.swing.]ComboBox();
   jComboBox.addItem("Yes");
   jComboBox.addItem("No");
   jComboBox.setSelectedItem(iBookorder.getInStock());
   jComboBox.addItemListener(new java.awt.event.ItemListener() {
    public void itemStateChanged(java.awt.event.ItemEvent e) {
     if (e.getStateChange() == java.awt.event.ItemEvent.SELECTED)
      iBookorder.setInStock((String)get]ComboBox().getSelectedItem());
    }
   });
  }
  return jComboBox;
}
    End Figure

    Figure 11.31: Processing the JComboBox

  10. Finally, you need an ActionListener for the Save updates button to save the changes back to the XML file. Select the JButton on the design surface, use content assist to add an ActionListener, and add code to the actionPerformed(ActionEvent) method to save the XML data back to the file, as shown in Figure 11.32.

    Start Figure

    // add code in bold
private javax.swing.]Button get]Button() {
  if(jButton == null) {
   jButton = new javax.swing.]Button();
   jButton.setText("Save updates");
   jButton.addActionListener(new java.awt.event.ActionListener() {
    public void actionPerformed(java.awt.event.ActionEvent e) {
         iBookorderFactory.save();
    }
  });
 }
 return jButton;
}
    End Figure

    Figure 11.32: Saving the XML data back to the file

Save your changes.

Testing the BookOrder application

To test the BookOrder application, you use a launch configuration that passes the file name for the XML instance document as an argument to the program.

  1. Click on the arrow next to the Run icon in the toolbar and choose Run…

  2. The Launch Configurations window appears. Select Java Application as the launch configuration to create and click New. A new launch configuration appears in the window, with the Main tab filled in with the names of your project (XMLApplications) and application (bookorder.BookOrder Application).

  3. Select the Arguments tab and enter the full path to your XML file name (bookorder.xml). Remember to surround the string in quotes if it contains any blanks.

  4. Click Run.

Your application starts, and, as you can see, the data appears with the values you entered for the book order in your XML instance document. Change the values and click Save updates to save the data back to the file. To change the application to use a different XML file name, you just change the argument in the launch configuration.

If you had any problems building the BookOrder application, look at the solution files in the /solutions/chap11/bookorder subdirectory on the CD included with this book. Create a new package called solutions.chap11.bookorder in the XMLApplications project and import all of the files in the /solutions/chap11/bookorder subdirectory into it. Open [image] BookOrderApplication.java with the Visual Editor to compare your program with the solution. To run the solution, create a launch configuration to pass the appropriate XML file name as an argument to the program.


In review

This chapter introduced XML Schemas and demonstrated how to use them to define an XML vocabulary. You learned how to build an application that uses JavaBeans generated from an XML Schema. You also learned how to use several more Swing components.


Exercise

Change the BookOrder application to use an enumeration for the valid values for the person's title. Use a JComboBox to present the current value and let the user select a new value.

Solution files for this exercise are in the /solutions/chap11/exer1 subdirectory on the CD included with this book. Create a new package called solutions.chap11/exer1 in the XMLApplications project and import all of the files in the /solutions/chap11/exer1 subdirectory into it. Open [image] BookOrderApplication.java with the Visual Editor to compare your program with the solution. To run the solution, create a launch configuration to pass the appropriate XML file name as an argument to the program.


Until we meet again...

Team LiB

Until we meet again…

You're done! You've completed the guided tour to building applications with the WebSphere Studio Visual Editor for Java and JavaBeans. You've learned how to create applets, applications, and subcomponents; how to debug your programs; and how to work with databases and XML data.

For more advice and tips on WebSphere Studio, visit the WebSphere Developer Domain's website at http://www.ibm.com/websphere/developer/.

Remember, as an additional benefit for readers of this book, we've established an email contact where you can send your comments and questions about beans and programming with them. We will monitor this ID and answer any questions you send in. Email your questions or comments to beans@pobox.com.


Appendix A: Installing the Software

This appendix provides installation instruction and hardware and software prerequisites for each of the software packages included with this book.

WebSphere Application Server Express Trial Edition, V5.0

WebSphere Application Server Express, Version 5.0 includes WebSphere Studio Site Developer, which is the development environment you use to develop the applications in this book. You can use this Trial Version for up to 90 days. If you are interested in purchasing the full WebSphere Application Server Express or WebSphere Studio, please visit http://www.ibm.com/websphere for purchase information.

This trial version comes with 30 days of limited, online technical support at no charge. To activate your 30 days of support, visit this site and click Download Now to register for the product: http://www.ibm.com/websphere/developer/downloads/EXPRESSsupport.html.

Prerequisites

Hardware

  • VGA (800 x 600) display minimum. (1024 x 768) recommended

  • Intel Pentium® II processor minimum. Pentium III 500 MHz or higher recommended

  • 512 MB RAM minimum. 768 MB RAM recommended

  • 760 MB minimum disk space for installing WebSphere Studio Site Developer and additional disk space for your development resources

Software

One of the following operating systems:

  • Windows® 2000 Server or Advanced Server with Service Pack 3 or higher

  • Windows® 2000 Professional with Service Pack 2 or higher

  • Windows XP Professional for the Studio Tools Component, including the Unit Test Environment only

  • Windows NT® Workstation or Server Version 4.0 with Service Pack 6a or higher

One of the following browsers:

  • Microsoft® Internet Explorer 5.5 with Service Pack 1 or higher

  • Netscape Navigator Version 4.76 or higher

Installation instructions

Before your install the product, check the following things:

  • In addition to the space required to install the product, you must have at least 50 MB free on your Windows system drive, and your environment variable TEMP or TMP must point to a valid temporary directory with at least 10 MB free.

  • You must not have the IBM HTTP server or WebSphere Application Server, Version 3.5 running.

  • If you have a previous copy of WebSphere Application Server—Express on your system, you should uninstall it before proceeding. As an additional safety measure, reboot after the uninstall completes.

  • If you have a previous copy of IBM Agent Controller on your system, you should uninstall it before proceeding.

  • If you have a previous copy of Studio Site Developer on your system, you should uninstall it before proceeding.


To install WebSphere Application Server - Express from the product CD:

Team LiB

To install WebSphere Application Server—Express from the product CD:

  1. Insert the WebSphere Application Server—Express CD-ROM into your CD drive.

  2. Log in as an administrator whose Windows user ID does not contain DBCS characters.

  3. If autorun is enabled on your system, the launchpad program will automatically come up. If autorun is disabled on your system, run launchpad.exe from the root of the CD drive.

  4. The WebSphere Application Server—Express installation launcher window contains several links that you can select to browse the readme file, the Installation Guide, the Getting Started Guide, the Migration Guide, or the Web development interactive tour. Select Install to begin installing the product. Select Exit to close the launchpad at any time. The launchpad does not have to remain running during the product installation.

  5. Follow the on-screen instructions for tasks such as specifying the target installation directory. Select typical install to install both Studio Site Developer and the Application Server.

    Tip

    Select custom install to install only Studio Site Developer. You can complete the lessons in this book with just Studio Site Developer, so you can save space by skipping the installation of the separate Application Server.

  6. Important: Do not install into a directory whose name contains DBCS characters. Doing so may cause undesirable results such as class path problems in the WebSphere test environment.

  7. Note that the full install takes between 10 and 30 minutes, depending on your hardware configuration.

  8. When WebSphere Application Server—Express is installed, click Finish to close the installation window.

  9. If any errors are reported refer to the indicated log file (expressIstallLog in the install destination directory) for more information.

  10. You will use Studio Site Developer to create and to deploy applications to Application Server. In addition you will use Studio Site Developer to administer (start, stop, change configurations) Application Server. You can start Studio Site Developer from the Start → Programs → IBM WebSphere Application Server - Express V5.0 pop-up menu.


DB2 Universal Database Personal Edition V8.1

The second CD that comes with this book contains the DB2 Universal Database, V8.1 Trial version. This trial version is also only available for 90 days. If you are interested in purchasing the full DB2 Universal Database, please visit: http://www.ibm.com/software/db2 for purchase information.

Prerequisites

Memory

  • 128 MB recommended if you plan to use the administration tools

Disk Space

  • Approximately 350 MB for a typical install

Operating system requirements

One of the following:

  • Windows ME

  • Windows NT Version 4 with Service Pack 6a or higher

  • Windows 2000 (32-bit)

  • Windows XP (32-bit or 64-bit)

  • Windows .NET (32-bit or 64-bit)

  • Windows XP (64-bit) and Windows .NET (64-bit) support:

    • local 32-bit applications

    • 32-bit UDFs and stored procedures

Hardware requirements

For DB2 products running on Intel and AMD systems, a Pentium or Athlon CPU is required.

Software requirements

MDAC 2.7 is required. The DB2 Setup wizard will install MDAC 2.7 if it is not already installed.

You will need a Java Runtime Environment (JRE) Version 1.3.1 to run DB2's Java-based tools, such as the Control Center, and to create and run Java applications, including stored procedures and user-defined functions. During the installation process, if the correct level of the JRE is not already installed, it will be installed.

A browser is required to view online help.

Installation instructions

To install DB2, you'll use the DB2 Universal Database CD included with this book. But before you insert the CD, you need to do some initial setup.

Since Windows NT is a very common operating system, we'll use it as the example for this tutorial. The installation steps are slightly different for other operating systems. If you use a different operating system, refer to the appropriate DB2 installation instructions before trying to install.

Step 1: Creating a user

Before you begin installation, you need to set up a user name that will be used to install DB2. The user name must belong to the Administrators group and be a valid DB2 username. For example, to create such a user name on Windows NT:

  1. Run the User Manager tool from the Start → Programs → Administrative Tools (Common) group.

  2. In the User Manager window, select the User → New User… option from the main menu. The New User window opens, as shown in Figure A.1.

    Click To expand
    Figure A.1: Creating a New User

  3. Complete all fields and click the Groups button, as shown in Figure A.2. Note that your Username and Password should not exceed 8 characters.

    Click To expand
    Figure A.2: Assigning Group Memberships

  4. Using the Add button, add the Administrators group to the list of groups of membership for the new user.

  5. Click OK in the Group Memberships window, then OK in the New User window. Now you've created the new user.

Step 2: Installing DB2

  1. Insert the DB2 Universal Database CD and run the Setup.exe file.

  2. Click the Install Products button. When you are asked to select the installation type, choose Typical.

  3. Input the User name and Password you just created for the Local DB2 user, as shown in Figure A.3.

    Click To expand
    Figure A.3: Entering User name and Password

  4. Accept all defaults. On the Specify a contact for health monitor notification, select Defer this task until after installation is complete.

  5. If prompted by the installation instructions, reboot the system after installation finishes. After the installation is complete and your computer system is rebooted, several DB2 connected system servers will be started automatically.

First, you will see the DB2 First Steps window offering to create the SAMPLE data base. You can return to this tool any time later and create this database.


Appendix B: Java Basics

If you're new to Java, or just looking for a refresher on basics of the Java programming language, we recommend that you read this appendix before starting the guided tour. Although the WebSphere Studio Visual Editor for Java provides many features to simplify building Java programs, you still need to write some code to develop programs, so you need a basic understanding of the Java programming language before you begin.

Java programs run on any Java-enabled platform, which include Web browsers, Web servers, you desktop machine, hand-held devices—any computer that contains a Java Runtime Environment (JRE). To create a Java program, you write source code, compile the source code to create an executable file, and then run the executable file with a special program called the Java interpreter. Because the process is broken into these separate steps, you can write your program and compile it on one machine, and then copy it to other machines to run. The only requirement for the other machines is that they have a JRE, and these days most devices do. You create your source code in ordinary text-based files that have a .java extension, such as MyProgram.java. When you compile your source code, the compiler creates one or more executable files with the .class extension, depending on the content of your source code.

Object-oriented terminology

Before going any further, we need to define terms such as object, class, type, instance, and so on. Obviously, their meanings depend on the situation they are used in, but here we use them in the context of object-oriented programming.

Let's start with the obvious interpretation. Objects are things that surround us in real life, such as cars, telephones, or computers. When dealing with an object, you don't distinguish it from its properties and behavior. A car can either move or stop; these are its behaviors. A car can be 2 meters high and painted red; these are its properties.

Many types of cars exist, with different colors and speed characteristics, but they are all "cars" because they have general attributes that unambiguously distinguish them from any other vehicles (such as bicycles, for example). All cars form a class of cars, as shown in Figure B.1.

Click To expand
Figure B.1: Cars are a class of objects.

Formally speaking, the definition of the class of cars should include the minimal set of properties and possible kinds of behavior peculiar to any car. For example, this definition might include the color property and the ability to move.

Now let's transform these ideas into Java terminology. Java is an object-oriented language; in other words, it operates with objects simillar to real-world objects. Just as real-world objects have properties and behavior, Java objects have properties to describe their data items and methods to define their behavior.

Java programs are called classes. Classes support an object's existence. You can think of classes as a kind of template for creating objects. The class defines the minimum necessary set of attributes (that is, the properties and methods) for each object. Classes also have types. For example, the class of cars has the Car type; the class of strings has the String type; and so on.

To use a class, you need to create an instance of the class. An instance is an object whose type is the class, and the process of creating class instance is called instantiation. So, for example, after an instantiation of the class of cars, you would have an object of type Car, or simply a Car. This Car object has properties specifying such things as its color and the numbe of doors, and methods to let other programs tell the car what to do next (move, stop, and so on).

Here's the tricky part. To create an instance of a class, we need to use a specific tool. Creating something is a process, so it's one of the behaviors of the class. That's why classes include special methods called constructors. A constructor is responsible for creating new instances of the class. The name of the constructor is the same as the name of the class, and you can have multiple constructors for a particular class to define different ways of initializing the new class instance. For example, you can have a default constructor for the class of cars to create a black car with four doors, and you can have another constructor that lets you specify the color and number of doors, as shown in Figure B.2.

Click To expand
Figure B.2: A single class can have multiple constructors.

Are you wondering why we need to arrange things into classes and objects? First, such an approach is the most natural and closest to real-world structure. Object-oriented design lets you hide complex functionality inside the object. For example, you don't have to know how a car works; you just need to know how to use it, and it's very simple. In object-oriented terminology, this is called encapsulation—an object encapsulates its properties and behavior and makes them available to other programs through very clearly defined programming interfaces. Together, the properties and behavior define what the object does and how other programs interact with it. Properties are the data items associated with the class, such as the color or number of doors for the Car class. Methods are the functions that the class performs (its behavior), such as move or stop for the Car class. Some Java classes also use events to notify other programs that some action has taken place. For example, the Car class could use an event to notify other programs when it runs out of fuel.

Another aspect of object-oriented languages that makes them so powerful is the concept of inheritance. When you create a new Java class, you specify the parent (or superclass) that your new class will be based on (or extend). This means that your program has all the state and behavior of its parent available to it. You can use the functions as is, or you can over-ride some of them to tailor them to the needs of your program. The Java language includes many classes that you can use as superclasses for your new programs, such as the Applet class for creating programs to run in a Web browser, and the Frame class for creating new stand-alone applications. All Java programs must have a superclass. If you don't explicitly specify one, your class will extend the generic Object class.

If you have ever looked at the Java application programming interface (API), you know that it is extensive and at times overwhelming. The API includes classes for all the common types of processing you need to do in a program, such as working with strings, building graphical user interfaces (GUIs), and processing files and databases. It also includs classes for more advanced functions, such as security and building programs that run in Web servers. As you build the applications in this book, you will come to appreciate the wealth of functions that the API provides.


What a Java program looks like

To cover the basic nuts and bolts of the Java programming language, we'll use a simple Java program and explain the various elements of its source code. Figure B.3 shows what the program looks like when you run it in WebSphere Studio.

Click To expand
Figure B.3: Running the program in WebSphere Studio

Figure B.4 shows the source code for the sample program.

Start Figure
  package sample;

  import java.applet.Applet;
  import java.awt.*;

  /**
   * Sample Java applet
   */
  public class SampleApplet extends Applet {

     private Button myButton = new Button();
     /**
      * The method that gets called when the applet starts
      */
     public void init() {
            this.setSize(200, 50);
            this.getMyButton().setLabel("Click me");
            this.add(getMyButton());
     }

     /**
      * A method to get the Button
      */
     public Button getMyButton() {
            return myButton;
     }

     /**
      * A method to set the Button
      */
     public void setMyButton(Button b) {
            myButton = b;
     }

     /**
      * Default constructor for SampleApplet class
      */
     public SampleApplet() {
            super();
     }
  }
End Figure

Figure B.4: Source code for a simple Java program

This program clearly doesn't provide much function at the moment. It shows a button, labeled Click me, but it doesn't define any action to occur when the button is clicked. When you follow the guided tour in this book, you'll learn all about how to take actions when buttons are clicked. For now, let's take a closer look at what the program does contain.

To start with, notice that the source code is full of semicolons, parentheses, braces, slashes, and asterisks. The Java compiler is very particular about its syntax, so it's important to get it exactly right.

Semicolons end each Java statement. Examples of statements in this sample program are the import and package statements at the beginning, the declaration for a Button variable, and instructions within the various functions that this program performs. Don't worry—we'll explain what all these are as we go through the source code.

Parentheses identify parameters (or the lack of parameters, where you just see opening and closing parentheses with nothing between them) that are passed to particular program functions, called constructors and methods. Whenever you create a new instance of an object, such as a new instance of a Button or the SampleApplet itself, a special constructor method is called to initialize the object. If the object supports it, you can pass parameters to the constructor to supply initialization values; otherwise, you call the default constructor without passing any parameters to create the object. Once an object has been created, you make it perform some task by calling methods in the object. Parentheses are also used on all method calls.

Braces delimit sections of your source code. You use an outer pair of braces for the class itself and inner pairs of braces to delimit methods within the class. Braces can also be used to delimit smaller portions of code within a particular method.

Slashes and asterisks identify comments in your program. The comments in this sample program are block comments at the start of the class and each method.

One other general word of warning—Java is case sensitive, so make sure that upperand lowercase letters in names of variables, methods, and so on always match exactly.

Now, let's look at each section of the code in this sample program in more detail.

The package statement

All Java programs exist within a Java package. This can be the default package (what you get when you don't explicitly specify a package name for your program) or a specific package name, such as sample, java.awt, or com.ibm.uicontrols. You use packages to organize Java programs into logical groupings. They define the scope for a particular program and provide unique names for programs. This sample program explicitly specifies a package name of sample, so the fully qualified name for this class is sample.SampleApplet. Your program must be saved on your machine's file system in folders that match the qualifiers in the package name, so for this example, the files SampleApplet.java and SampleApplet.class must be in a folder named sample.

Import statements

You use import statements to bring in classes for your program to use. They simplify your code, because they let you reference other classes by their unqualified class name (for example, Applet) rather than the fully qualified name (java.applet.Applet). The import statements in this sample program bring in the java.applet.Applet class and all of the classes in the java.awt package. (The asterisk in "java.awt.*" means all classes in that package.) For something like an applet, which uses many of the visual controls in the java.awt package (buttons, text fields, labels, and so on), it's much easier to include an import statement so that you don't have to key in fully qualified class names each time you reference a particular class.

Any classes that you want to use in your Java programs must be in the Java classpath. This is a set of folders and files where the Java compiler and runtime translator search for classes. In WebSphere Studio, you specify the classes to go in the classpath when you set up a project's build path.

The class statement

The class statement identifies the name of your class and its superclass. It also includes an access modifier to identify how your class can be accessed by other programs. In the case of this sample applet, the class name is SampleApplet; its superclass is Applet; and it has an access modifier of public, which means that other programs such as Web browsers can access it.

Declarations

Declarations identify the data variables for your class (its properties). You specify the name of the variable, its data type, an access modifier, and optionally, initialization values. By convention, variable names start with a lowercase letter, but you can generally name variables anything that's meaningful to you. The data type can be one of the primitive data types supported by Java, or it can be any Java class. Primitive data types include integer and floating-point numbers, character data, and boolean data (for true/false flags). Java also includes classes that correspond to the primitive data types, such as the Integer class, which you can use for things like converting a value of one data type to another data type. The declaration in the sample applet defines a variable named myButton with a data type of java.awt.Button.

Where you place the declarations in your source code determines the scope of the variable and how you can use it. When you place a declaration within a method, that variable is available only within that method—you do this for temporary work variables you need within a particular method. Since the declaration for the myButton variable in the sample applet is placed outside of any particular method, it can be accessed throughout the SampleApplet program, but because it has an access modifier of private, other programs cannot access it directly. Just as you saw on the class statement, variables also have access modifiers to identify how other programs can access the variables. It's good practice to declare all variables as private and then include public methods to get or set the variable's value for those variables that you want other programs to be able to access. If you ever need to access a variable directly, the syntax is objectname.variablename, as in myCar.color to access the color property in a Car object named myCar.

The declaration for the myButton variable in the sample applet does more than just declare the variable. It also initializes it by setting it to a new instance of a java.awt.Button object. Because no parameters are specified for the new instance, the default constructor for the Button class is used to create the new object.

You can also declare arrays of variables in your programs. An array is a set of elements in which each element is of the same data type (strings, integer numbers, floating-point numbers, and so on). An array always has a fixed size, which means that the number of items in an array is always limited. You declare an array by adding a pair of square brackets to the variable's declaration, as in the following example, which declares an array with two Strings initialized to the names of the days on weekends:

private String [] weekendDays = {"Saturday", "Sunday"};

Methods

Methods are how you define the functions that your program performs (its behavior). If you give a method the access modifier of private, the method can be called only from within your own program. You do this for internal routines that only your program needs. To make a method accessible to other programs, you give it an access modifier of public.

For each method, you define its input (the parameters passed to the method) and its output (a return value passed back from the method) in the method statement. If a method doesn't take any input parameters, you specify an empty string surrounded by opening and closing parentheses, such as move(). Otherwise, you specify the appropriate parameter values separated by commas and surrounded by opening and closing parentheses, such as refuel (Gasoline g, double amount). If a method doesn't pass back a return value, you specify void in the method statement; otherwise, you specify the date type of the return value in the method statement and include a return statement as the last line of your method. In the sample applet, the getMyButton() method doesn't take any parameters as input, and it returns a Button object as output. The setMayButton(Button) method takes one parameter as input (a Button object), and it does not pass back any return value. The init() method doesn't take any parameters as input, and it also doesn't pass back any return value.

The syntax for calling a method that takes input parameters is

objectname.methodname(parameter-1,…,parameter-n);

If the method doesn't take any input parameters, you specify

objectname.methodname();

The objectname is the name of the object instance whose method you want to call. If you want to refer to the current object, such as the instance of SampleApplet in the sample code, you use the keyword this.

When you call a method that passes back a return value, you need to do something with the return value, like copy it to another variable, use it in a computation, or use it in another method call. For example, the instruction this.add(getMyButton()); in the sample code takes the return value from the getMyButton() method and passes it as a parameter to the applet's add(Component) method.

When a method returns an object, you can also then call methods on the returned object. In the sample code, this.getMyButton() returns a Button object, so the second part of the instruction this.getMyButton().setLabel ("Click me"); can call the Button's setLabel(String) method to set its label to "Click me". You can have any number of these combinations of calling methods that return objects and calling other methods on the returned objects in a single instruction, so just be careful to try to keep your program understandable.

By virtue of inheritance, each class automatically has the methods of its superclass available to it. That's why the sample code can call the methods setSize(int,int) and add(Component) to set the size of the applet's visual surface and to add the Button variable to the visual surface, respectively. These methods exist in the Applet superclass, so the SampleApplet class can call them. Suppose you want to modify the functions performed by the superclass? No problem; override the methods that you want to change. In the sample code, the init() method of the Applet superclass is overridden to supply the appropriate initialization for SampleApplet. The init() method is called when an applet starts running, so this is where you can place initialization logic to build the applet's GUI.

You can also have multiple methods in a particular class with the same method name but each specifying a different set of input parameters. This is called overloading. You do this if you want ot provide a single function that takes inputs in different formats, such as a computation that could be done with either integer or floating-point numbers. Other programs call the appropriate method based on the format of data they're working with.

Finally, within your methods, you have all the basic programming constructs available to use, such as assignment, if-else, for, while, and switch statements. You use these statements to include conditional logic in your programs and for loop control, just like any programming language. The following sections describe some of the common statement you'll use in this book.

Assignment

You use assignment statements to copy the value of one variable to another variable, as in this example, which copies the length property of the weekendDays array to a variablecalled numItems:

numItems = weekendDays.]length;

When you perform assignments, the data types of the variables must match, so in this example, numItems must be numeric. The Java compiler tells you when you have a mismatch between data types. When this occurs, you need to include code to convert the source data type to a data type that is compatible with the receiver. (We include instructions in this book wherever you have to do conversions like this.)

If-else

The if-else statement adds conditional logic to your program. If a particular condition is true, your program performs one action; otherwise it performs a different action. The following example performs conditional logic based on whether a boolean variable called myFlag is true or false.

if (myFlag == true) {  code for true path goes here...   }
else {  code for false path goes here...  }

Your surround the condition with parentheses. Notice that in this case you use two equal signs (==) to do the comparison. Depending on the type of data you are comparing, you may need to use a method in the object instead, such as an equals(String) method. This example also shows how braces can be used within a particular method. If you have several statements to place in either the true or false paths, you surround them with braces.

For

You use the For statement to loop through a section of code multiple times, such as looping through elements in an array to perform some action on each element. You specify a starting value, a condition for ending the loop, and an increment to use each time through the loop. The following example loops through each element of an array named sortedArray.

for (i=0; i < sortedArray.length; i=i+1)
myList.add(sortedArray[i]);

This example adds each element of sortedArray to a list variable called myList. Braces aren't required in this example, because the loop consists only of the one statement, myList.add(sortedArray[i]);. Notice that array elements in Java are numbered beginning with element 0, so this example begins by adding sortedArray[0] to the list. The variable i is incremented by 1, and the next element, sortedArray[1], is added to the list. This continues until the last element of the array has been processed, sortedArray[sortedArray.length-1], when the loop stops and execution continues with the next statement in the program. The portion of code in this statement that increments the variable i by 1 can also be written with the increment operation, as in i++.

Constructors

Constructors are special methods you use to create new instances of a particular class. The method name must match the class name, and you use parameters to pass any initialization values. You also specify an access modifier for the constructor—topically public—to let other programs create new instances of your class. Constructors return a new instance of the class, using any initialization values passed by the caller. In the sample applet, only a default constructor is shown, and it contains only one statement, super();, which is a special statement that, in turn, invokes the default constructor in the superclass.

Just as with methods, you can have several constructors for your class, each specifying different input parameters. This lets other programs set a variety of different initialization values when they create new instances of your class.


In Review

And that's it for a very short crash course in Java. Let's go build some application!


References

New to Java Programming Center on the Sun Microsystems' Web site http://developer.java.sun.con/developer/onlineTraining/new2java/

Building a Java Applet http://www-105.ibm.com/developerworks/education.nsf/java-onlinecourse-bytitle/95CA3B95156F6FD852567570076D326?OpenDocument

Java Language Essentials http://www-105.ibm.com/developerworks/education.nsf/java-onlinecourse-bytitle/FCCCC34D4124A8C086256997006B7146?OpenDocument


Index

Note

Boldface numbers indicate illustrations.

A

aboutThisBean property, 22, 41
absolute positioning, 87
AbstractTableModel class, 371
Abstract Window Toolkit (AWT), 15, 171
ActionEvent object, 104
ActionListener, 23-25, 61, 63, 65, 70
actionPerformed(ActionEvent) method, 61, 63, 65, 91, 136, 187, 225, 231, 339
Add button, 23-26, 60-61, 187, 190
adding an ActionListener, 23, 61
maximum/minimum number of entries, 34
source code actions, 23, 61
addFileManipulationPanelListener (FileManipulationPanelListener) method, 111
addItem(Object) method, 405
add(String) method, 25
addRow() method, 379
addSettingPanelListener(Setting PanelListener) method, 148, 149
anchor, 166
anonymous data type, 384
AppletContext class, 264
appletContext property, 265
<applet> descriptor, 259, 260
applets, 1
applications vs., 53, 255-256
building, 12
changing properties "in flight", 284
class creation for, 10-12
configuration, 276
context, 264
creating, 10-12
Customizer frame, 281-284
customizing, 260
downloading, 258
drag and drop functionality, 284-291
dropping components onto the design surface, 17
error message, 27
getting parameters, 279-281
hostile, 53
init() method, 14
inner class, 23
installing on other Web pages, 259
Internet, 256
Java build paths, 8
listening for events, 22-25
loaded over the network, 295
opening, 11, 26
placing a button on, 16
publishing the, 43
resizing, 39
restrictions on, 295
running, 26-27
running in a Web browser, 49, 272
running with the HTML Editor Preview tab, 49, 294
running with the Java plug-in, 259
saving, 26
security, 53
signed, 295-300
specifying parameters, 275, 293
standard superclass for, 10
supplying parameters, 263-264
Swing, 211
termination, 284
testing, 272
ToDoList, 2
trusted, 258
using JAR files for, 257-258
using several classes, 257
using WebSphere Studio, 3 (See also WebSphere Studio)
viewing properties, 14
visual elements, 19
visual surface for, 14
APPLET tag, 259
<applet> tag, 45, 272
application programming interface (API), 426
applications, 53-54
applets vs., 255-256
correcting errors (See debugging)
creating a new class for, 56-57
defined, 54
exiting, 59
exporting to a directory, 77-78
loading from a file, 69-72
publishing, 75-79
running, 62, 78-79, 131
setting up the frame class, 58-59
Swing (See Swing applications)
thread, 236
using a UNIX system, 75
visual elements for, 59-60
architecture, 196
array, 430
ascending property, 22
asterisks, 428
<a>tag, 265
attributes, 356
autoCommit property, 336
AWT, 15, 171


Index_B

Team LiB

Index

B

background
creating color panel, 137
property, 89
bean palette, 15
beans. See also subcomponents
accessing documentation about, 21-22
adding and connecting using PropertyChangeEvents, 35-38
adding to frame's surface, 59-60
bound properties, 34
connecting, 21
creating, 83
customizing properties, 13
events, 20
ExtendedFiledFileDialog bean for, 90-92, 95
feature accessibility, 101
function of, 82
Java Beans view, 12
methods, 20-21
naming, 20
non-visual, 13, 20
promoting features, 101-117
Properties view, 12
PropertyChange, 35-38
ReadFile, 90, 94-95
selecting, 18
size preference, 127
unbound properties, 34
behaviors, 423
<body> tag, 265
BorderLayout manager, 127, 132-133, 193
borders, 132
vertical, 141
white, 142
BoundJList, 185
BoundList, 38, 68
BoundTextField, 36, 67
BoxLayout manager, 164-165
braces, 428
breakpoints
adding/removing, 236
conditions for stopping, 247
Enable Condition option, 247
exception, for an, 254
setting, 233-234
suspending execution, 254
viewing, 236
browsers
differences between, 259
directing to a URL, 265
HTML descriptor and, 257
level, 297
setting the status line of window, 267-269
trusting applets, 295
button-pressed event, 184
buttons
connecting in XML, 377-378
connecting with the DBSelect bean, 338-346
creating, 15-16
customizing properties of, 16-17
parameters for, 262
removing all entries, 62-64
removing selected entries, 64-65
rollover, 183
testing the labels, 263-264


Index_C

Team LiB

Index

C

card, 154, 161
card container panel
beans as child components under, 160
creating, 160-163
CardLayout manager, 153-163
choosing a card, 154
components in, 154
function of, 154
CardLayout panel, 160
certificate name, 299
changedUpdate event, 407
ChangePhoto button, 349
CHAR, 311
CHAR(integer), 311
CHARACTER(integer), 311
CHARACTER VARYING (integer), 311
CHARVARYING(integer), 311
check boxes, 145
CheckboxGroup bean, 145
child elements, 356
classes
creating applications, 56-57
creating for subcomponents, 86
defined, 10
event objects, for, 104-105
inner, 23
instance, 424
JDBC driver, 329
opening non-visual, 163
opening visual, 163
referenced, 78
superclass, 426
types, 424
visual vs. non-visual, 13
classpath, 429
CLASSPATH, 352
class statement, 429
Clear button, 27-28, 188
adding an ActionListener, 63
logic to handle action events, 64
codeBase property, 270
Color class, 136
colors
dragging and dropping, 287-291
running text, 291
columns, 164, 165
defining, 318-320
relational databases, 305
width of, 377
commit() method, 336
complex data type, 384
Constrained layout managers, 126
constraints, 310-311, 321
constructors, 58, 425, 428, 434
Content Assist Window, 24, 25
ContentPane
adding visual elements to, 176
set up, 174-175
currentStringResult events, 102, 112
currentStringResult property, 69
firing, 115
processing, 121
cursor, changing the, 183


Index_D

Team LiB

Index

D

Database Connection Information, 324
databases
committing changes, 328
connecting to, 323-324
constraints, 310-311, 321
creating, 313-316
data types, 311-312
defined, 304
generating unique numbers, 349-351
Java Database Connectivity (JDBC), 304
Open Database Connectivity (ODBC), 304
redundant data, 309
relational, 304 (See also relational databases)
software for, 304
software installation, 305
SQL, 321-322
triggers, 311
types of, 304
dataFlavor property, 288, 289
dataFlavor window, 289
data types, 37, 311-312, 384, 429-430
DATE, 312
Date class, 350
DB beans, 329
DBCS characters, 418
DBSelect bean, 335
adding, 335-337
autoCommit property, 336
connecting buttons with, 338-346
connecting table columns and text fields, 337-338
handling exceptions, 337
DB2 Universal Database, 304
command prompt, 323
creating databases, 315-316
creating tables, 316-322
navigating to the databases, 314
purchase information, 418
running the Control Center tool, 313-314
Show SQL button, 321-322
DB2 Universal Database Personal Edition, 304
installation instructions, 419-422
prerequisites, 418-419
debugging
events, 233-243
logic errors, 243-254
process of, 215
scalable option, 237-240
setting breakpoints, 233-234
Debug perspective, 234
Breakpoints tab, 236
cleaning up, 240
Display view, 237, 252
Expressions view, 237, 250, 252
terminating execution, 240
Variables view, 237, 238, 252
Debug view, 235
DEC(precision-integer, scaleinteger), 312
DECIMAL(precision-integer, scale-integer), 312
declarations, 429-430
Delete button, 346
deleteRow() method, 339
design surface, 14, 58
destroy() method, 284
digitalDisplayStyle, 133, 158
DigitalView bean, 197
Document, 407
DocumentListener, 407
Document Object Model (DOM), 359
Document Type Definitions (DTDs), 358-359
DOS commands, 79
DragBean, 284
DropBean, 284-285, 288
dropEnd event, 286
dropEnd(DropEvent) method, 286, 290
drop zones, 132, 140
DTD
creating a file, 362-365
creating XML file from, 365-367
generating JavaBeans from, 367-368
DTD Editor, 358


Index_E

Team LiB

Index

E

elementFormDefault attribute, 387
elements, 356
EMBED tag, 259
encapsulation, 426
end tag, 356
error message, 27
"Class not found", 79
complicated code, 262, 270
"Launch failed", 27, 62, 100, 182
event objects
adding properties to, 106-107
common base for, 104
creating, 104-107
function of, 104
events, 426
debugging, 233-243
firing, 20, 21, 101, 112-118, 233, 241
handling, 36
listening for, 20
programs accessing, 102
programs listening for, 107
promoting, 101
Execute button, 339
execute() method, 338
ExtendedFileDialog bean, 85, 100, 101
adding, 96
adding a FileSelectionListener, 93, 97
eXtensible Markup Language. See XML


Index_F

Team LiB

Index

F

file dialogs
adding, 90
changing the title of, 100
displaying open, 225
main function of, 100
processing, 95
showing, 95
testing, 99-100
FileManipulationPanel bean, 83
creating the class, 86
ExtendedFileDialog bean, 90-92, 95
initial visual elements for subcomponent, 89
ReadFile bean for, 90
subcomponent, 90
WriteFile bean, 95
File menu
adding items to, 219-220
creating, 219
Delete option, 220
Open, 245-246
Revert option, 226-227
files
connections added for reading, 103, 104
final connections for reading, 116
final connections for writing, 117
initial connections for writing to, 99
loading, 90-91, 94
saving, 95-98, 98
fileSelected(FileSelectionEvent) method, 93
fill, 166
fill constraint, 89
fireTableCellUpdate(int,int) method, 375
First button, Action Listener for, 340
first() method, 338
firstOptionSelected event, 147, 150, 151
FLOAT(integer), 312
FlowLayout manager
Box Layout vs., 164
Button and, 135
function of, 134
foreign keys, 309, 321
For statement, 433
frame
adding beans, 59-60
border areas, 132, 141-142
class set up, 58-59
closing, 58
layout property, 132
new instance of, 58
placing the panels in, 139-140
visible, 58
frame class, 128, 129-130


Index_G

Team LiB

Index

G

getAppletContext() method, 265
getColumnCount() method, 371, 373
getColumnName(int) method, 371, 373
getFirstOption() method, 146
getImage(URL,String) method, 270
getLabelText() method, 146
getParameter(String) method, 262
getRowCount() method, 372, 374
getSecondOption() method, 147
getThirdOption() method, 147
getValueAt(int,int) method, 372
global elements, 386
GridBagConstraints object, 166
GridBagLayout, 88-89, 90
gridheight, 166
GridLayout manager, 163-164, 165-167
grids, 163-164, 165, 166-167
gridwidth, 166
gridx, 166
gridy, 166


Index_H

Team LiB

Index

H

HTML page, 47
HTML tags, 265
HTTP, 257


Index_I

Team LiB

Index

I

IBM products, xxvii
icons, 178-181, 195
alignment of, 181
alignment of, 181
positioning of, 181
if-else statement, 433
ImageCanvas bean, 217, 218,, 228, 230, 270
Image menu
creating, 221
creating the rotate submenu, 222-223
rotation commands, 231
scalable option, 227
ImageProcessing bean suite, 227
images
displaying, 270
functional, 271
not displaying, 241
null, 218
performing operations on, 227
rotating, 227-232
when using help information, 241
import statements, 429
inheritance, 426
initialize() method, 58, 140, 261
init() method, 14, 17, 261
inner classes, 23
Insert button, 346, 351
insertUpdate(DocumentEvent) method, 409
insets, 166
instance, 424
instantiation, 425
INT, 312
INTEGER, 312
interfaces
ActionListener, 23
defined, 107
defining, 110
function of, 21
listener, 20, 35
PropertyChangeEvents, 35
Internet applet, 256
Internet Explorer, 259
Internet functionality, xx
ipadx, 166
ipady, 166
isCellEditable(int,int) method, 372, 375
ItemEvent, 151
ItemListener inner class, 150
itemStateChanged event, 146
itemStateChanged(ItemEvent) method, 242


Index_J-K

Team LiB

Index

J-K

JAR (Java archive) files, 2, 258
adding, 84-85
applets, for, 257-258
downloading, 258
exporting to, 43-44, 272, 291-292
Java, xix
application programming interface (API), 426
applications, xx
AWT controls and, 171
based on open standards, xx
building advanced Graphical
User Interfaces (GUIs), 170
classes, 424, 426
class statement, 429
command syntax, 78
creating a program, 423
creating a project, 5-8
creating the package, 8-9
declaration, 429-430
enabled platform, 423
features of, xx
import statement, 429
independence of, 75
interpreter, 423
methods, 430-432
objects, 424
package statement, 428-429
programming language, 426-428
running applications from the command prompt, 78
use of, xx
Visual Editor for (See Visual Editor)
java.awt.Color class, 288
java.awt.event package, 23
java.awt.event.WindowListener, 58
JavaBeans, xx-xxi
generating from a DTD, 367-368
generating from XML Schemas, 400-401
Java build path, 8, 55
Java Development Kit (JDK) package, 76
Java Editor, 163
Java Foundation Class (JFC) libraries, 170
Java interpreter, 423
Java program, 10
Java Runtime Environment (JRE) package, 76, 423
JavaSoft website, 241
java.util.Date class, 350
Java Virtual Machine, 75, 257
checking the version of, 76
downloading, 76
installation instructions, 76
JButton bean, 184
JCheckBoxMenuItem bean, 221-222
JComboBox bean, 405, 410
JDialog, 204
JFileChooser bean, 224
JFrame
adding child components to, 174
set up, 174-175, 192, 217
JMenuBar bean, 218
JMenu bean, 219, 221
JPanel bean, 174, 402
JProgressBar, 209-211
JScrollPane, 185
JSlider bean, 207-208
JTabbedPane, 193, 194-195
JTable bean, 370, 371
JTextField, 406, 407
JToolBar bean, 331, 332-333, 338
JVM. See Java Virtual Machine


Index_L

Team LiB

Index

L

Last button, 345
last() method, 338
layout
null, 87, 126
values for, 14
layout managers
basic, 126
constrained, 126
functions of, 87
GridBagLayout, 90
set up, 132-133
types of, 126
unconstrained, 126
uses of, 125
using with a container, 126
layout property, 14, 59
listener interface, 107-110
listeners
keeping track of, 111, 149
radio button itemStateChanged events, 151
registering, 110-112, 148-149
unregistering, 148-149
Vector, 111
Load button
ActionListener for, 92
adding an ActionListener, 70
logic to handle, 71
scrolling to a method in the source pane, 91
loadDocument(String) method, 373
loadFileSelected events, 102, 112
firing, 113
processing, 121
look and feel, 171, 172
changing, 212-213
values, 212


Index_M

Team LiB

Index

M

Marquee function, 181
menu bar, creating, 218
menus, 219-222
adding items to, 219-220
Metal, 212
method declarations, 109
methods, 21, 424, 426, 428, 430-432
AbstractTableModel class, 371
adding, 102-104
calling, 431-432
constructors, 434
creating stubs, 57
extracting code to create, 341
main, 58
multiple, 432
particular bean, for a, 25
programs accessing, 101-102
public, 101
refactoring, 339
and registering listeners, 110
syntax, 25
mnemonic property, 220
Model-View-Controller architecture (MVC), 196
mouseClicked(MouseEvent) method, 271
mouseEntered(MouseEvent) method, 267, 268, 271
mouseExited event, 268
MovingText bean, 279


Index_N

Team LiB

Index

N

namespaces, 386-387
target, 386
universal resource identifier (URI), 386
Netscape Communicator, 297
Netscape Navigator, 259
Netscape Signing Tool, 296, 297
newRow(boolean) method, 338
Next button, 344
next() method, 338
noNamespaceSchemaLocation attribute, 386
null layout, 87


Index_O

Team LiB

Index

O

object-oriented terminology, 423-426
objects
behaviors, 423
event (See event objects)
properties, 423, 424
OBJECT tag, 259
Open a Perspective icon, 4
Open file operation, 245-246
Oracle database, 323
overloading, 432


Index_P-Q

Team LiB

Index

P-Q

packageName property, 373
packages
creating, 8-9
function of, 8
naming, 8
package statement, 428-429
panels, moving, 404
parameters, 54, 260
target, 265
<param> tags, 259, 260, 278
parentheses, 428
parsed character data (PCDATA), 356, 365
parseInt() method, 37
parsers
purpose of, 359
XML, 359
XML Schema and, 385-386
perspectives, 3
closing, 252
Debug, 234
Java, 5
Web, 4, 45
XML, 361-362
PhotoPanel, 334
photos
displaying, 347-348
inserting and modifying, 348-349
platform independence, xx
pressedIcon property, 184
Previous button, 344
previous() method, 338
primary keys, 306, 311, 320-321
progress bars, 209-211
properties, 423, 424, 426
bound, 34
changing background, 89
layout managers, 132
mnemonic, 220
programs accessing, 101
unbound, 34
PropertyChangeEvent object, 104
PropertyChangeListener, adding a, 67, 68, 71
propertyChange(PropertyChangeEvent) method, 37, 190


Index_R

Team LiB

Index

R

radio buttons, 144
binary choices and, 145
firing events, 150-151
promoting events, 143-153
promoting properties, 146-147
use for, 145
ReadFile bean, 69, 71, 102
refactoring, 339, 409
relational databases
adding data, 306-307
columns, 305, 318-320
fields, 305
references between tables in, 309
rows, 305
structure, 305
table, 305 (See also tables)
removeButton, 380
Remove button, 29-30, 189
adding a, 64
adding an ActionListener, 65
logic to handle action events, 65
removeFileManipulationPanelListener(FileManipulationPaneListener) method, 111
removeSettingPanelListener(SettingPanelListener) method, 148, 149
removeUpdate(DocumentEvent) method, 409
renaming usual components, 177-178
requestFocus() method, 25
requirements specification, 243
Revert operation, 245
rollback, 328
Rollover buttons, 183
root elements, 356
rotation commands, 231-232
RotationFilter bean, 217, 227, 228, 229, 230
rows, 134, 164, 165
deleting, 339
relational databases, 305


Index_S

Team LiB

Index

S

saveButton, 380
Save button
ActionListener for, 96
adding an ActionListener for, 74
logic to handle action events, 74
saveFileSelected events, 102, 112
firing, 114
processing, 123
save() method, 378, 380
scalable option, 227
debugging, 237-240
fixing, 240-243
setting, 233
testing, 233
scrolling, 185
sliders vs., 207
secondOptionSelected event, 147, 150, 152
semicolons, 428
separable model architecture, 196
setBook(int,book) method, 378
setColumns() method, 342, 343
setFirstOption(String) method, 146
Set ID button, 351
setLabelText(String) method, 146
setLookAndFeel(String) method, 212
setSecondOption(String) method, 147
setThirdOption(String) method, 147
SettingPanel beans, 156-157, 161
setValueAt(Object,int,int) method, 373, 375
Show Detail Pane icon, 239
showDocument methods, 265
Show() method, 90, 91
Show SQL button, 321-322
showStatus(String) method, 267
signing applets, 295-300
simple data type, 384
slashes, 428
sliders, 207
SMALLINT, 311
solution file, 30-32
Sort bean, 39-43
aboutThisBean property, 40, 41
ascending property, 40
help window, 41
methods, 41
sortStringArray(String[]), 41
source code
asterisks, 428
braces, 428
extending across one input line, 251
Java program, 427
parentheses, 428
semicolons, 428
slashes, 428
SQL, 321-322
SQL commands, 322-328
connect to mydb, 323
delete, 327-328
insert, 324
rollback, 328
select, 325-326
update, 327
start tag, 356
StateChanged event, 208
statements
assignment, 432-433
classes, 429
For, 433
if-else, 433
import, 429
package, 428-429
Step Into icon, 251
Step Over icon, 251
Step Return icon, 251
subcomponent. See also beans
creating, 82-83
defined, 82
functions of, 143
radio buttons, 143-153
read operations, for, 83-84
write operations, for, 84
superclass, 426
Swing, 15, 170
advantages of, 172
applets, 211
browser support, 173
default look and feel, 212
design features, 171
GUI controls, 171
Internet Explorer and, 211
lightweight toolkit, 171
look and feel of components, 171
Metal, 212
Netscape Navigator and, 211
using Model-View-Controller design, 191-195
Swing applications
adding tabs, 194
adding visual components, 175-176, 193-194
changing the look and feel, 212-213
changing the cursor, 183
making connections, 186-189
rollover buttons, 183
set up, 173-174
using images in, 178-180
Swing components, 170-171, 406
AWT components vs., 170
controller, 196
icon feature, 178-181
model, 196
state and data of, 196
tool tip, 182
view, 196
Swing Containers, 170, 193
Swing Menus, 170, 171
Swing palette categories, 170


Index_T

Team LiB

Index

T

tables
adding a book to, 378
adding new rows, 338-339
columns, 318-320
column width, 377
connecting columns and text fields, 337-338
creating, 316-322
creating models, 370-371
data deletion, 327-328
data modification, 327, 347
data selection, 325-326
data uniqueness, 306
defining a relationship between, 308
deleting data from, 311
editing a cell, 377
entering data, 324-325
foreign keys, 309, 321
inputting data using SQL commands, 323-324
primary key, 306, 320-321
record deletion, 347
record insertion, 347
removing a book from, 378
selecting a row, 377
selecting specific columns, 325
setting data, 375
tabPlacement property, 195
tags, 356
target parameter, 265
templates
addChangeListener.xml file, 208
addDocumentListener.xml, 407
adding an event handling, 91
addPropertyChangeListener, 36
creating, 118
event handling, 117, 152-153, 407
importing, 85, 117
testing
applets, 272
Cancel button, 246
Open operation, 244-245
text, dragging and dropping, 285-287
text declaration, 362
textValueChanged(TextEvent) method, 285
thirdOptionSelected event, 147, 150, 153
thread, 236
Time bean suite, 197
TimeModel bean, 197
tool tip, 172
toolTipText property, 182
triggerAction() method, 69, 7, 98, 102, 103
triggerReadFile() method, 101, 119, 120
triggerWriterFile(String[]) method, 102-103, 118
trim() method, 37
types, 424


Index_U

Team LiB

Index

U

unconstrained layout managers, 126
universal resource identifier (URI), 386
URLs, 386
absolute, 269-270
directing the browser to, 265
relative, 269-270


Index_V

Team LiB

Index

V

VARCHAR(integer), 311
variables
accessing, 430
arrays of, 430
data, 429
Vector, 111, 149
VisualAge for Java, 8, 13
visual components
content pane, 193
look and feel of, 171
Visual Editor, xix, xx, 163
bean selection in, 13
content assist feature, 22
creating a program in, 13
customizing bean properties in, 13, 14-19
debugging and, 237
design surface, 13
grids, 166-167
initialization logic, 58
Outline view and, 237
renaming visual components, 177
Swing palette categories, 170
visual elements
adding, 66, 369-370, 402-404
modifying common properties for a group of, 181


Index_W

Team LiB

Index

W

Web page
creating, 47-49, 273-276, 292-295
previewing, 49
Web perspective, 45, 273
Web project
creating, 45-46, 46
importing resources, 45-46
set up, 272-273, 292
WebSphere Application Server Express Trial Edition, V5.0
installation instructions, 416-417
prerequisites, 415-416
purchasing the full version, 415
WebSphere Java Development Kit (JDK), 144
WebShphere Studio, xix
accessing relational data, 328-329
build path, 8
changing default directory, 4
classes required, 8
creating a Web page, 47-49
creating a Web project, 45-46
creating method stubs, 57
customizing the look and feel, 213
Debug perspective, 234
DTD Editor, 358
perspectives, 3, 4-5
purchase information, 415
running applications outside of, 76, 352
running your applet, 49
server, 49, 51
starting, 3-5
templates, 23
Web perspective, 45
XML Editor, 359
WebSphere Studio debugger, modifying code and, 251
WebSphere Studio Site Developer 5.0, xix. See also WebSphere Studio
weightx, 166
weighty, 166
WindowAdapter, 59
WindowClosing template, 130
windowClosing(WindowEvent) method, 58-59, 283
WindowListener, 59
WriteFile bean, 72-74, 96, 101, 103


Index_X-Z

Team LiB

Index

X-Z

XML
attributes, 356
child elements, 356
connecting buttons, 377-378
creating a file from the DTD, 365-367
declaration, 356
end tag, 356
function of, 355-356
namespaces, 386-387
parsers, 359
root element, 356
start tag, 356
XML data
document type declaration (DOCTYPE), 358
Document Type Definitions (DTDs), 358-359
entity reference, 357
organizing, 356
parsing, 356
storing, 356
valid, 357-358
validating parsers, 358
well-formed, 357
XML Editor, 359
XML instance documents, 384
connecting elements, 405-412
qualified names, 386
xmlns attribute, 385
xmlns:xsi attribute, 386
XML perspective, 388
opening, 361
opening a file in, 362
XML Schema Editor, 385
XML Schemas
adding enumeration nodes, 397
adding restriction nodes, 397
creating XML files from, 399-400
data types, 384
defining, 389-392
defining vocabulary, 393-398
element, 384
generating JavaBeans from, 400-401
global elements, 386
graph view of, 389
purpose of, 384
root element named, 384
schema, 384
storing, 384
target namespace, 386
top-level element in, 386
viewing the generated source, 389


List of Figures

Chapter 1: Creating Your First Applet

Figure 1.1: The applet you'll create
Figure 1.2: Workspace directory selection window
Figure 1.3: The initial perspective in the WebSphere Studio Workbench
Figure 1.4: The Java perspective in the WebSphere Studio Workbench
Figure 1.5: Entering the Java project name
Figure 1.6: Specifying bean JAR files for the Java project
Figure 1.7: Creating a new Java package
Figure 1.8: Creating an applet
Figure 1.9: ToDoList applet in the Visual Editor
Figure 1.10: Initial source code for ToDoList applet
Figure 1.11: Modifying applet properties in the Properties view
Figure 1.12: The bean palette in the Visual Editor
Figure 1.13: Placing a button on your applet
Figure 1.14: Source code added for the button
Figure 1.15: Placing a text field on your applet
Figure 1.16: The Choose a Bean window
Figure 1.17: Adding a BoundList bean to your applet
Figure 1.18: Alignment icons for making your visual elements tidy
Figure 1.19: Content Assist Window for Add button
Figure 1.20: Source code with inner class to process Add button action events
Figure 1.21: Source code to take the appropriate actions when the user clicks on Add button
Figure 1.22: The ToDoList applet in action
Figure 1.23: Adding a Clear button to the ToDoList applet
Figure 1.24: Source code with inner class to process Clear button action events
Figure 1.25: Removing all entries from the list when the user clicks on Clear button
Figure 1.26: Adding a Remove button to the ToDoList applet
Figure 1.27: Source code with inner class to process Remove button action events
Figure 1.28: Removing the selected entry from the list when the user clicks on Remove button
Figure 1.29: Importing the ToDoList.java solution file

Chapter 2: Extending Your First Applet

Figure 2.1: The applet you'll create
Figure 2.2: Adding visual elements to limit the number of tasks
Figure 2.3: PropertyChangeListener added by content assist
Figure 2.4: Processing PropertyChangeEvents for the BoundTextField bean
Figure 2.5: PropertyChangeListener added by content assist
Figure 2.6: Processing PropertyChangeEvents for the BoundList bean
Figure 2.7: Adding a second list
Figure 2.8: Placing SortBean on the design surface
Figure 2.9: SortBean's aboutThisBean property
Figure 2.10: Placing sorted entries in the second list
Figure 2.11: Your final ToDoList applet
Figure 2.12: Exporting ToDoList applet to a JAR file
Figure 2.13: Creating a Web project
Figure 2.14: Creating an HTML page
Figure 2.15: Adding the ToDoList applet to a Web page
Figure 2.16: Server Selection window
Figure 2.17: Runing ToDoList in the WebSphere Studio Web browser
Figure 2.18: Running ToDoList in an external Web browser
Figure 2.19: Stopping the WebSphere Studio server

Chapter 3: Creating Your First Application

Figure 3.1: The application you'll create
Figure 3.2: Specifying bean JAR files for the Java project
Figure 3.3: Creating the application class
Figure 3.4: Creating an instance of the frame class
Figure 3.5: Adding a WindowListener to exit when the user closes the frame
Figure 3.6: Initial visual elements for the ToDoList application
Figure 3.7: Adding an ActionListener for the Add button
Figure 3.8: Source code to take the appropriate actions when the user clicks on Add button
Figure 3.9: The ToDoList application in action
Figure 3.10: Adding a Clear button to the ToDoList application
Figure 3.11: Adding an ActionListener for the Clear button
Figure 3.12: Logic to handle Clear button action events
Figure 3.13: Adding a Remove button to the ToDoList application
Figure 3.14: Adding an ActionListener for the Remove button
Figure 3.15: Logic to handle Remove button action events
Figure 3.16: Adding visual elements to limit the number of tasks
Figure 3.17: Adding a PropertyChangeListener for the BoundTextField
Figure 3.18: Processing BoundTextField PropertyChangeEvents
Figure 3.19: Adding a PropertyChangeListener for the BoundList
Figure 3.20: Processing BoundList PropertyChangeEvents
Figure 3.21: Beans for loading from a file
Figure 3.22: Adding an ActionListener for the Load button
Figure 3.23: Logic to handle Load button action events
Figure 3.24: Adding a PropertyChangeListener for the ReadFile bean
Figure 3.25: Logic to handle ReadFile bean PropertyChangeEvents
Figure 3.26: Beans for saving to a file
Figure 3.27: Adding an ActionListener for the Save button
Figure 3.28: Logic to handle Save button action events
Figure 3.29: The final running ToDoList application in action
Figure 3.30: Exporting the ToDoListApplication class files

Chapter 4: Creating a File-Manipulation Subcomponent

Figure 4.1: The subcomponent you'll create
Figure 4.2: Creating the subcomponent class
Figure 4.3: Initial visual elements for FileManipulationPanel subcomponent
Figure 4.4: Adding ExtendedFileDialog and ReadFile beans
Figure 4.5: ActionListener for Load button
Figure 4.6: Adding a FileSelectionListener to the ExtendedFileDialog bean
Figure 4.7: Initial code to handle fileSelected events for loading files
Figure 4.8: Initial connections for reading from a file
Figure 4.9: Adding ExtendedFileDialog and WriteFile beans
Figure 4.10: ActionListener for Save button
Figure 4.11: Adding a FileSelectionListener for the second ExtendedFileDialog bean
Figure 4.12: Initial code to handle fileSelected events for saving files
Figure 4.13: Initial connections for writing to a file
Figure 4.14: FileManipulationPanel in action
Figure 4.15: Promoting the ReadFile bean's triggerAction() method
Figure 4.16: Promoting the WriteFile bean's triggerAction() method
Figure 4.17: Connection added for reading files
Figure 4.18: Connection added for writing files
Figure 4.19: Creating the FileManipulationPanelEvent class
Figure 4.20: Adding a property to the event object
Figure 4.21: The Extended Interfaces Selection window
Figure 4.22: The New Java Interface window
Figure 4.23: Defining the interface
Figure 4.24: Adding a Vector to keep track of listeners
Figure 4.25: Method to register listeners
Figure 4.26: Method to unregister listeners
Figure 4.27: Firing the loadFileSelected event
Figure 4.28: Firing the saveFileSelected event
Figure 4.29: Adding a PropertyChangeListener
Figure 4.30: Firing the currentStringResult event
Figure 4.31: Final connections for reading files
Figure 4.32: Final connections for writing files
Figure 4.33: Removing beans from your old ToDoList application
Figure 4.34: Adding the FileManipulationPanel bean
Figure 4.35: Adding a FileManipulationPanelListener
Figure 4.36: Processing loadFileSelected events
Figure 4.37: Processing currentStringResult events
Figure 4.38: Processing saveFileSelected events
Figure 4.39: The final running ToDoList application in action

Chapter 5: Using Layout Managers

Figure 5.1: BorderLayout example
Figure 5.2: Creating a new class
Figure 5.3: Creating an instance of the frame class
Figure 5.4: Adding a WindowListener
Figure 5.5: Clock application with IClock bean in analog mode
Figure 5.6: Clock application with IClock bean in digital mode
Figure 5.7: Moving a bean in a frame with BorderLayout
Figure 5.8: The running Clock application
Figure 5.9: Clock application using BorderLayout and FlowLayout
Figure 5.10: Simple FlowLayout applet
Figure 5.11: Adding a panel to the design surface
Figure 5.12: Digits color panel added to design surface
Figure 5.13: ActionListener for the Yellow button
Figure 5.14: ActionListener for the Green button
Figure 5.15: ActionListener for the Red button
Figure 5.16: Background color panel added to design surface
Figure 5.17: ActionListener for the White button
Figure 5.18: ActionListener for the Blue button
Figure 5.19: ActionListener for the Black button
Figure 5.20: Drop zone for the frame's north section
Figure 5.21: Panels placed in Clock frame
Figure 5.22: Adding white borders
Figure 5.23: Java Beans view for Clock application
Figure 5.24: The final running Clock application
Figure 5.25: The final SettingPanel subcomponent
Figure 5.26: Visual elements added to the SettingPanel
Figure 5.27: Adding Checkbox beans to the CheckboxGroup
Figure 5.28: Promoting the label's text property
Figure 5.29: Promoting the first radio button's label property
Figure 5.30: Promoting the second radio button's label property
Figure 5.31: Promoting the third radio button's label property
Figure 5.32: Defining the interface
Figure 5.33: Adding a Vector to keep track of listeners
Figure 5.34: Method to register listeners
Figure 5.35: Method to unregister listeners
Figure 5.36: Listener for radio button itemStateChanged events
Figure 5.37: Firing the firstOptionSelected event
Figure 5.38: Firing the secondOptionSelected event
Figure 5.39: Firing the thirdOptionSelected event
Figure 5.40: Background color panel in use
Figure 5.41: Digits color panel in use
Figure 5.42: Date format panel in use
Figure 5.43: Initial panel for CardLayout Clock application
Figure 5.44: Date format panel design
Figure 5.45: Adding a SettingPanelListener
Figure 5.46: Setting digitalDisplayStyle on the basis of the radio button selected
Figure 5.47: Handling events fired by the second SettingPanel bean
Figure 5.48: Handling events fired by the third SettingPanel bean
Figure 5.49: The initial CardLayout panel
Figure 5.50: Using the Java Beans view to add a card to the card container panel
Figure 5.51: All SettingPanel beans added to the card container panel
Figure 5.52: Adding the button to the frame
Figure 5.53: ActionListener added to button
Figure 5.54: Code to switch to the next card
Figure 5.55: GridLayout example
Figure 5.56: BoxLayout example
Figure 5.57: GridBagLayout example

Chapter 6: Using Swing Components

Figure 6.1: The Swing palette categories in the Visual Editor
Figure 6.2: Look-and-feel examples
Figure 6.3: Creating an instance of the application frame
Figure 6.4: Adding visual elements to the ContentPane
Figure 6.5: The Rename Field window
Figure 6.6: Java Beans view with renamed visual components
Figure 6.7: Selecting an image file
Figure 6.8: All three buttons with icons
Figure 6.9: Buttons made tidy
Figure 6.10: Running application with tool tips
Figure 6.11: Running application with pressed icon images
Figure 6.12: Adding a JTextField
Figure 6.13: Final visual layout for SwingToDoList application
Figure 6.14: Processing Add button clicks
Figure 6.15: Processing Clear button clicks
Figure 6.16: Processing Remove button clicks
Figure 6.17: PropertyChangeListener for maxEntries field
Figure 6.18: PropertyChangeListener for taskList
Figure 6.19: Running SwingToDoList application
Figure 6.20: Creating an instance of the application frame
Figure 6.21: Selecting the JTabbedPane or the JPanel
Figure 6.22: JTabbedPane with three tabs
Figure 6.23: Java Beans view for JTabbedPane with three tabs
Figure 6.24: JTabbedPane with different features enabled
Figure 6.25: Three views provided with the Time bean suite
Figure 6.26: Clock tab layout
Figure 6.27: Alarm tab layout
Figure 6.28: Timer tab layout with TimeModel bean added
Figure 6.29: Connecting the clock to the TimeModel bean
Figure 6.30: Connecting the alarm to the TimeModel bean
Figure 6.31: Setting the alarm time when the application starts
Figure 6.32: Connecting the timer to the TimeModel bean
Figure 6.33: Starting the timer when the application starts
Figure 6.34: Design surface with alarm dialog added
Figure 6.35: Handling Alarm events
Figure 6.36: JSlider bean placement
Figure 6.37: Handling JSlider StateChanged events
Figure 6.38: Connecting TimeModel timerSeconds to JProgressBar value
Figure 6.39: TimeModelDemo with JProgressBar
Figure 6.40: Setting the look and feel to Motif look and feel
Figure 6.41: Dynamically setting the look and feel to the system native look and feel

Chapter 7: When Something Goes Wrong—Debugging

Figure 7.1: The ImageProcessing application
Figure 7.2: Creating an instance of the application frame
Figure 7.3: ImageProcessing class with ImageCanvas bean
Figure 7.4: Adding a menu bar
Figure 7.5: Adding the File menu to the menu bar
Figure 7.6: Adding a menu item to the menu
Figure 7.7: Menu items added to the File menu
Figure 7.8: Running application with File menu items
Figure 7.9: Adding another menu to the menu bar
Figure 7.10: Adding a submenu to the Image menu
Figure 7.11: Rotate submenu items
Figure 7.12: Running application with Image menu and Rotate submenu
Figure 7.13: Adding a JFileChooser bean
Figure 7.14: ActionListener for Open menu item
Figure 7.15: The selected image file in the ImageCanvas
Figure 7.16: Running ImageProcessing application
Figure 7.17: ActionListener for Revert menu item
Figure 7.18: PropertyChangeListener for Scalable checkbox menu item
Figure 7.19: Adding the RotationFilter bean
Figure 7.20: PropertyChangeListener for ImageCanvas bean
Figure 7.21: PropertyChangeListener for RotationFilter bean
Figure 7.22: ActionListener for the 90 menu item
Figure 7.23: ActionListener for the 180 menu item
Figure 7.24: ActionListener for the 270 menu item
Figure 7.25: ActionListener for the 360 menu item
Figure 7.26: Setting a breakpoint
Figure 7.27: Debug view
Figure 7.28: Breakpoints view
Figure 7.29: PropertyChangeEvent variable in the Variables view
Figure 7.30: Adding an ItemListener to the JCheckBoxMenuItem bean
Figure 7.31: ImageProcessing application with improved Scalable option
Figure 7.32: Resetting the rotationAngle when Revert operation is performed
Figure 7.33: Resetting the rotationAngle when Open operation is performed
Figure 7.34: Setting a breakpoint in the Open menu item's ActionListener
Figure 7.35: Java Line Breakpoint Properties window
Figure 7.36: Variables view
Figure 7.37: Using Inspect to execute a code snippet
Figure 7.38: Result of executing the getlvjRotationFilter() code snippet
Figure 7.39: Executing a code snippet in the Display view
Figure 7.40: Updated ActionListener

Chapter 8: Advanced Applet Development

Figure 8.1: NavigationPanel applet
Figure 8.2: RunningText applet
Figure 8.3: Using <param> tags in an <applet> descriptor
Figure 8.4: Initial layout of the NavigationPanel applet
Figure 8.5: Setting the label and actionCommand for the first button
Figure 8.6: Setting the label and actionCommand for the second button
Figure 8.7: Defining applet parameters in a launch configureation
Figure 8.8: ActionListener for the first Button bean
Figure 8.9: ActionListener for the second Button bean
Figure 8.10: MouseListener for the first Button bean
Figure 8.11: MouseListener for the second Button bean
Figure 8.12: Setting the image property for the ImageCanvas bean
Figure 8.13: MouseListener for the ImageCanvas bean
Figure 8.14: Adding the NavigationPanel applet to a web page
Figure 8.15: Specifying applet parameters
Figure 8.16: Running the NavigationPanel applet in a Web page
Figure 8.17: Edited HTML for NavigationPanel applet
Figure 8.18: NavigationPanel with different parameters
Figure 8.19: MovingText component layout
Figure 8.20: Getting applet parameters at run time
Figure 8.21: Defining applet parameters in a launch configuration
Figure 8.22: RunningText applet in action
Figure 8.23: Customizer frame layout
Figure 8.24: MouseListener for MovingText bean
Figure 8.25: WindowListener for the Customizer frame
Figure 8.26: Applet's destroy() method
Figure 8.27: Setting the drag source
Figure 8.28: TextListener for the messageField bean
Figure 8.29: Setting the drop destination object
Figure 8.30: DropListener for the DropBean
Figure 8.31: Setting the drag source
Figure 8.32: The DataFlavor window
Figure 8.33: Setting the dataFlavor property
Figure 8.34: Setting the drop destination object
Figure 8.35: DropListener for the second DropBean
Figure 8.36: Running drag and drop functionality
Figure 8.37: Specifying applet parameters
Figure 8.38: APPLET tag for the RunningText applet
Figure 8.39: Running the RunningText applet in a Web page
Figure 8.40: Exporting files to create a signed applet
Figure 8.41: HTML for signed applet

Chapter 9: Working With Databases

Figure 9.1: Friends table data
Figure 9.2: Friends table with a primary key
Figure 9.3: Friends table with Hobby column
Figure 9.4: Friends table with multiple hobbies in a single column
Figure 9.5: Friends table with multiple hobby columns
Figure 9.6: Separate Hobbies table
Figure 9.7: Hobbies table with Friend_ID column
Figure 9.8: Two tables with a common column
Figure 9.9: A third table with two key columns
Figure 9.10: DB2 Control Center
Figure 9.11: Navigating to the databases
Figure 9.12: The Create Database Wizard window
Figure 9.13: Your first database
Figure 9.14: Friends table with a Photo column
Figure 9.15: The Create Table window
Figure 9.16: Adding a column
Figure 9.17: Create Table window with columns data
Figure 9.18: Setting the primary key
Figure 9.19: SQL commands for creating the Friends table
Figure 9.20: DB2 command prompt
Figure 9.21: Database Connection Information
Figure 9.22: Selecting all the data from the table
Figure 9.23: Selecting only certain columns
Figure 9.24: Sorting the data
Figure 9.25: Checking updated records
Figure 9.26: MyFriends database application
Figure 9.27: Creating an instance of the frame class
Figure 9.28: TextPanel layout
Figure 9.29: Adding the TextPanel to the content pane
Figure 9.30: JToolBar bean with JButtons
Figure 9.31: Adding the JToolBar to the content pane
Figure 9.32: PhotoPanel layout
Figure 9.33: Adding the PhotoPanel to the content pane
Figure 9.34: Handling exceptions thrown by the DBSelect bean
Figure 9.35: PropertyChangeListener for the DBSelect bean
Figure 9.36: ActionListener for the Execute button
Figure 9.37: ActionListener for the First button
Figure 9.38: Extracting code to create a new method
Figure 9.39: Extract Method window
Figure 9.40: Making the setColumns() method accessible by all listeners
Figure 9.41: ActionListener for the Previous button
Figure 9.42: ActionListener for the Next button
Figure 9.43: ActionListener for the Last button
Figure 9.44: ActionListener for the Insert button
Figure 9.45: ActionListener for the Delete button
Figure 9.46: Updated PropertyChangeListener for the DBSelect bean
Figure 9.47: ActionListener for the ChangePhoto button
Figure 9.48: Updated ActionListener for Insert button
Figure 9.49: ActionListener for Set ID button
Figure 9.50: The MyFriends application in action

Chapter 10: Working With XML Data

Figure 10.1: An XML file for the ToDoList application
Figure 10.2: An XML file for the MyBooks application
Figure 10.3: A DTD file for the ToDoList application
Figure 10.4: Adding a document type declaration to an XML file
Figure 10.5: An element tree for XML data for the ToDoList application
Figure 10.6: The MyBooks application in action
Figure 10.7: Elements added for the MyBooks application
Figure 10.8: Adding the book element as a child element of books
Figure 10.9: Adding children to the book element
Figure 10.10: The final DTD for the MyBooks application
Figure 10.11: Defining a book
Figure 10.12: Generating JavaBeans from a DTD
Figure 10.13: Creating an instance of the frame class and getting the argument
Figure 10.14: Visual elements of the MyBooks application
Figure 10.15: Creating the MyBooksTableModel class
Figure 10.16: Returning column count and name information
Figure 10.17: Loading the XML file
Figure 10.18: Returning the row count
Figure 10.19: Getting table data
Figure 10.20: Setting table data
Figure 10.21: Associating the table model with the JTable
Figure 10.22: Defining application arguments in a launch configuration
Figure 10.23: Method to add a book element
Figure 10.24: Method to remove a book element
Figure 10.25: Method to save the XML data to the XML file
Figure 10.26: ActionListener for the addButton
Figure 10.27: ActionListener for the removeButton
Figure 10.28: ActionListener for the saveButton
Figure 10.29: Final MyBooks application

Chapter 11: Using XML Schemas

Figure 11.1: A sample XML Schema for the ToDoList application
Figure 11.2: Associating the ToDoList XML instance document with an XML Schema
Figure 11.3: XML Schema associated with a namespace
Figure 11.4: XML instance document using the book namespace
Figure 11.5: The BookOrder application in action
Figure 11.6: Defining the book vocabulary's target namespace
Figure 11.7: Defining the book element
Figure 11.8: Defining a restriction for a simple type
Figure 11.9: XML Schema for the book vacabulary
Figure 11.10: Defining the bookorder vocabulary's target namespace
Figure 11.11: Defining the orderDate element
Figure 11.12: orderDate and person elements added to the bookorder
Figure 11.13: Selecting a schema to import
Figure 11.14: Element reference added for book element
Figure 11.15: Defining enumerations for a simple type
Figure 11.16: XML Schema for the bookorder vocabulary
Figure 11.17: Defining a bookorder
Figure 11.18: Generating Java Beans from an XML Schema
Figure 11.19: Creating an instance of the frame class and getting the argument
Figure 11.20: JPanel with GridLayout
Figure 11.21: All visual elements added to the JPanel.
Figure 11.22: All visual elements added to the frame
Figure 11.23: Adding items to the JComboBox
Figure 11.24: Loading the XML instance document
Figure 11.25: Proceeding the orderDate
Figure 11.26: Processing the person Title
Figure 11.27: Processing the personName
Figure 11.28: Processing the bookTitle
Figure 11.29: Processing the author
Figure 11.30: Processing the copyrightDate
Figure 11.31: Processing the JComboBox
Figure 11.32: Saving the XML data back to the file

Appendix A: Installing the Software

Figure A.1: Creating a New User
Figure A.2: Assigning Group Memberships
Figure A.3: Entering User name and Password

Appendix B: Java Basics

Figure B.1: Cars are a class of objects.
Figure B.2: A single class can have multiple constructors.
Figure B.3: Running the program in WebSphere Studio
Figure B.4: Source code for a simple Java program


List of Tables

Chapter 5: Using Layout Managers

Table 5-1: Properties for additional SettingPanel beans

Chapter 8: Advanced Applet Development

Table 8-1: NavigationPanel applet parameters

Chapter 9: Working With Databases

Table 9-1: Column data


List of Sidebars

Chapter 1: Creating Your First Applet

What's a JAR file?
Java Build Paths
What's a class?
VisualAge for Java users
What's in a name?
What's an interface?
What's an inner class?
Saving your work

Chapter 2: Extending Your First Applet

Working with different data types

Chapter 3: Creating Your First Application

What's an application?

Chapter 4: Creating a File-Manipulation Subcomponent

GridBagLayout
What's a Vector?

Chapter 5: Using Layout Managers

What size do you prefer?
When to use radio buttons

Chapter 7: When Something Goes Wrong—Debugging

What's a thread?

Chapter 8: Advanced Applet Development

Differences between browsers
HTML target parameter
Browser level

Chapter 9: Working With Databases

The java.util.Date class


CD Content

Team LiB
Previous Section

CD Content CD Content

Following are select files from this book's Companion CD-ROM. These files are copyright protected by the publisher, author, and/or other third parties. Unauthorized use, reproduction, or distribution is strictly prohibited.

Click on the link(s) below to download the files to your computer:

File | Description | Size
All CD Content | Building Applications with IBM WebSphere Studio and JavaBeans | 1,637,086
Chapter 1: | Creating Your First Applet | 330,931
Chapter 2: | Extending Your First Applet | 339,826
Chapter 3: | Creating Your First Application | 136,549
Chapter 4: | Creating a File-Manipulation Subcomponent | 22,203
Chapter 5: | Using Layout Managers | 31,366
Chapter 6: | Using Swing Components | 345,654
Chapter 7: | When Something Goes Wrong—Debugging | 109,093
Chapter 8: | Advanced Applet Development | 299,493
Chapter 9: | Working With Databases | 8,182
Chapter 10: | Working With XML Data | 5,947
Chapter 11: | Using XML Schemas | 11,129

Team LiB
Previous Section