Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Java user interface design and development

Kelby Zorgdrager, Senior Software Engineer, STSHotelnet
Mr. Kelby Zorgdrager
Kelby Zorgdrager is a Senior Software Engineer with STSHotelnet. As a member of the Architectural committee, Kelby is responsible for designing the underlying Portal Framework using J2EE and other distributed Java technologies. Prior to working at STSHotelnet, Kelby was a Senior Software Engineer with Sun Microsystems where he worked on a distributed management infrastructure. Kelby was also a Java instructor for Sun Educational Services where he provided training and consulting services. Kelby has presented at major Java trade shows including JavaUniversity, JavaOne, Java Business Expo, and COMDEX. He has worked with the Java language since January, 1996.

Summary:  Many modern-day applications require customized user interfaces. Customized user interfaces can be used to incorporate a corporation's required layout, color schemas, and font styling, just to name a few. They may also require customized components, or components with differing looks (and possibly feels) from the ones provided in the standard Java2 Software Development Kit (SDK). Granted, there are plenty of third-party vendors that are more than willing to sell you one of "their" components. But, every once in a while, there comes along the requirement to have a component look a certain way that can't be obtained from components in standard and off-the-shelf libraries.

Date:  01 May 2001
Level:  Introductory

Activity:  1622 views
Comments:  

JDK 1.0: Abstract Windowing Toolkit (AWT)

Back in the "early" days of Java technology, designing and creating user interfaces was a relatively challenging task. As some of you may know, the Abstract Windowing Toolkit (AWT) in Java Development Kit (JDK) 1.0 definitely had its shortcomings. Taking the AWT for what it was worth (a base set of user interface components that theoretically could be used on any Java-enabled platform), and running with the AWT classes, it was possible to create customized user interfaces with customized components. Unfortunately for developers in the JDK 1.0 era, customized components really had to be specializations of existing components. So, if you wanted to create a button that displayed images, you had to extend java.awt.Button, override the paint(java.awt.Graphics g) method, and draw your image. The advantage of this model is that you could truly leverage the underlying button implementation code and only focus on what you were trying to change, the graphical representation. The following code example demonstrates how you could create your own interpretation of a java.awt.Label . The source code represents a specialization of java.awt.Label that draws its text vertically instead of horizontally.

import java.awt.*; 

    public class VerticalLabel extends Label 
    { 
      private int charBufferWidth = 2; 
      private int charBufferHeight = 2; 
       
      public VerticalLabel(String text) 
      { 
        setText(text); 
      } 
       
      public void paint(Graphics graphics) 
      { 
        graphics.setColor(Color.white); 
        graphics.fillRect(0,0,500,500); 
        graphics.setColor(getForeground()); 
       
        String labelText = getText(); 
        int stringLength = labelText.length(); 
         
        FontMetrics fontMetrics = graphics.getFontMetrics(); 
        int maxAscent = fontMetrics.getMaxAscent(); 
        int maxDescent = fontMetrics.getMaxDescent(); 
        int charHeight = maxAscent + maxDescent; 
             
        int xPosition = 1; 
        int yPosition = 1 + maxAscent; 
        String tmpString = null; 
         
        for(int i=0;i<stringLength;i++) 
        { 
          tmpString = labelText.substring(i,i+1); 
          graphics.drawString(tmpString,xPosition,yPosition); 
          yPosition = yPosition + charHeight + charBufferHeight; 
        } 
      } 
       
      public Dimension getPreferredSize() 
      { 
        int height = getVerticalStringLength(); 
        int width = getHorizontalStringLength(); 
        return new Dimension(height, width); 
      } 
       
      public Dimension getMinimumSize() 
      { 
        return getPreferredSize(); 
      } 
       
      public Dimension getMaximumSize() 
      { 
        return getPreferredSize(); 
      } 
       
      private int getVerticalStringLength() 
      { 
        FontMetrics fontMetrics = getGraphics().getFontMetrics(); 
        String text = getText(); 
        int stringLength = text.length(); 
        int verticalStringLength = fontMetrics.stringWidth(text) +  
                                (stringLength * charBufferHeight); 
        return verticalStringLength; 
      } 
       
      private int getHorizontalStringLength() 
      { 
        FontMetrics fontMetrics = getGraphics().getFontMetrics(); 
        String text = getText(); 
        int horizontalStringLength = fontMetrics.getMaxAscent() + 
                                                     charBufferWidth; 
        return horizontalStringLength; 
      } 
    } 


As you can see, creating a specialized Label using the AWT is relatively easy; you extend java.awt.Label and override paint(Graphics g) . Like all things in life, if something is too easy, there has to be a catch, right? Well, this is no different.

This becomes apparent when creating a more complex or advanced customization of a component. Take the image button mentioned above. Extending Button and overriding paint was great until you wanted to enhance the button by displaying different images for "in focus," "out of focus," "pressed," "un-pressed," and so on. Due to the platform-dependent, peer-based implementation nature of the AWT, this is when things got really difficult, as some platforms handled the rendering of components differently. For example, on one platform, your image button would look great, but on another it would look like a badly animated GIF. Therefore, it was quite common for the resulting customization to actually be a platform-specific implementation. More clever Java UI programmers reverted to extending java.awt.Canvas to create an image button. Extending Canvas was the closest thing to creating a platform-independent component while still being able to leverage some underlying code. Unfortunately, it too had its limitations.


Java 1.1: Enhancements

Then along came JDK 1.1. Had I been betting the farm on a more complete user interface component set, I would have been farmless. To its credit, JDK 1.1 did "open up" the development of customized components by allowing developers to extend java.awt.Component. This meant that a developer could truly control the graphical representation and the underlying event-handling mechanisms! I was and am still grateful for this enhancement. (Without it, we might not have Swing.) JDK 1.1 also introduced a standardized coding convention, as well as JavaBeans, utilities that made the creation and use of customized components easier. The ability to extend Component and the Bean model were major steps that had to be taken for developers to employ their creative talents in the user interface world. However, the underlying component set was still pretty limited (especially in comparison to the Microsoft Foundation Classes); thus, there was still a need for customized components.


Swing components

Soon after the release of JDK 1.1, an exciting extension to the Java language started to poke its head out from hiding. There was much stir and great excitement. The word was that the language was getting a new component set. This component set was "complete," extensible, and platform-independent. This component set made it unnecessary to purchase third-party tree-views and to license third-party multi-column lists. It was complete enough that a button supporting images was included (javax.swing.JButton). I had to wonder, "Was this the beginning of the end for those UI developers who had invested so much of their time in creating customized specialized buttons?"

Nope. After playing around with Swing for a while, you will probably come to the conclusion that there is still a need for customized components. Fortunately for those of you who are familiar with creating customized components in the AWT, you can leverage your existing understanding and apply it to Swing. Examining the Swing hierarchy, you will notice that every component in Swing extends from the lightweight platform-independent counterpart to java.awt.Component,javax.swing.JComponent. JComponent, in fact, is a subclass of java.awt.Component. Thus it leverages as much applicable code and as many constructs as possible. This means that when it comes to creating a customized JComponent, you can extend the class and override paint(Graphics g). For example, if you wanted to create a JLabel that displayed its text vertically, you could extend JLabel and override paint(Graphics g). The following code example demonstrates just that:

import java.awt.*; 
import javax.swing.*; 

    public class VerticalJLabel extends JLabel 
    { 
      private int charBufferWidth = 2; 
      private int charBufferHeight = 2; 
       
      public VerticalJLabel(String text) 
      { 
        super(text); 
      } 

      public void paint(Graphics graphics) 
      { 
        System.out.println("paint(Graphics) called"); 
        //super.paint(graphics); 
        String labelText = getText(); 
        int stringLength = labelText.length(); 
         
        FontMetrics fontMetrics = graphics.getFontMetrics(); 
        int maxAscent = fontMetrics.getMaxAscent(); 
        int maxDescent = fontMetrics.getMaxDescent(); 
        int charHeight = maxAscent + maxDescent; 
             
        int xPosition = 1; 
        int yPosition = 1 + maxAscent; 
        String tmpString = null; 
        System.out.println("passed super.paint(graphics)"); 
        for(int i=0;i<stringLength;i++) 
        { 
          tmpString = labelText.substring(i,i+1); 
          graphics.drawString(tmpString,xPosition,yPosition); 
          yPosition = yPosition + charHeight + charBufferHeight; 
        }  
      } 
               
       private int getVerticalStringLength() 
      { 
        FontMetrics fontMetrics = getGraphics().getFontMetrics(); 
        String text = getText(); 
        int stringLength = text.length(); 
        int verticalStringLength = fontMetrics.stringWidth(text) +  
                                (stringLength * charBufferHeight); 
        return verticalStringLength; 
      } 
       
      private int getHorizontalStringLength() 
      { 
        FontMetrics fontMetrics = getGraphics().getFontMetrics(); 
        String text = getText(); 
        int horizontalStringLength = fontMetrics.getMaxAscent() + 
                                                     charBufferWidth; 
        return horizontalStringLength; 
      }  
              
      public Dimension getPreferredSize() 
      { 
        int height = getVerticalStringLength(); 
        int width = getHorizontalStringLength(); 
        return new Dimension(height, width); 
      } 
    } 

As you can see, the implementation of the VerticalJLabel is really not that different from the implementation of VerticalLabel . There is one major side effect of a design that follows VerticalJLabel . By overriding paint(Graphics g) , you are changing the way the component is rendered. The implementation of paint(Graphics g) is solely responsible for how the component is drawn. So, if the user of your VerticalJLabel sets a javax.swing.border.Border with the expectation that it will be drawn and the paint(Graphics g) does not support that behavior, the Border will not appear. Likewise, if a user wants to set a javax.swing.Icon on your VerticalJLabel and the paint(Graphics g) does not support that option, the Icon will not be displayed. From an API perspective, your VerticalJLabel denotes that it supports both Border s and Icon s, but the implementation does not. This could be quite confusing to the user of your VerticalJLabel .

An easy way to take advantage of the default rendering while still customizing the look of a component is to override paintComponent(Graphics g) instead of paint(Graphics g) . The default implementation of paint(Graphics g) , inherited from JComponent , uses "delegation" to create the graphical representation of the component. The default behavior relies on three additional methods to render the component: paintComponent(Graphics g), paintBorder(Graphics g) , and paintChildren(Graphics g) . As their names imply, each method is used to draw a specific part of the graphical representation. By extending the specific component and overriding the appropriate method, you can change the way the component is drawn in terms of its borders, its children, and the graphical representation of its state. Therefore, an alternative implementation for our VerticalJLabel would extend JLabel and override paintComponent(Graphics g) , thus supplementing the default rendering. This type of implementation can be seen in the following code listing:

import java.awt.*; 
   import javax.swing.*; 

    public class VerticalJLabel extends JLabel 
    { 
      private int charBufferWidth = 2; 
      private int charBufferHeight = 2; 
       
      public VerticalJLabel(String text) 
      { 
        super(text); 
      } 
       
      protected void paintComponent(Graphics graphics) 
      { 
        String labelText = getText(); 
        int stringLength = labelText.length(); 
         
        FontMetrics fontMetrics = graphics.getFontMetrics(); 
        int maxAscent = fontMetrics.getMaxAscent(); 
        int maxDescent = fontMetrics.getMaxDescent(); 
        int charHeight = maxAscent + maxDescent; 
             
        int xPosition = 1; 
        int yPosition = 1 + maxAscent; 
        String tmpString = null; 
         
        for(int i=0;i<stringLength;i++) 
        { 
          tmpString = labelText.substring(i,i+1); 
          graphics.drawString(tmpString,xPosition,yPosition); 
          yPosition = yPosition + charHeight + charBufferHeight; 
        }  
      } 
       
      public Dimension getPreferredSize() 
      { 
        int height = getVerticalStringLength(); 
        int width = getHorizontalStringLength(); 
        return new Dimension(height, width); 
      } 

      private int getVerticalStringLength() 
      { 
        FontMetrics fontMetrics = getGraphics().getFontMetrics(); 
        String text = getText(); 
        int stringLength = text.length(); 
        int verticalStringLength = fontMetrics.stringWidth(text) +  
                                (stringLength * charBufferHeight); 
        return verticalStringLength; 
      } 
       
      private int getHorizontalStringLength() 
      { 
        FontMetrics fontMetrics = getGraphics().getFontMetrics(); 
        String text = getText(); 
        int horizontalStringLength = fontMetrics.getMaxAscent() + 
                                                     charBufferWidth; 
        return horizontalStringLength; 
      } 
    } 

As with any overridden method, if you wish to perform the inherited behavior and your specific behavior, you can use the super keyword to access the inherited behavior. In our example, if you wanted to perform the inherited paintComponent(Graphics g) behavior along with your implementation, the implementation of paintComponent(Graphics g) could include a super.paintComponent(Graphics g) call. This is particularly useful when overriding paint(Graphics g) .


Model-View-Controller and Swing

There is one major difference between a component that extends java.awt.Component and one that extends javax.swing.JComponent . Components that extend JComponent are built using a common user interface design pattern called Model-View-Controller (MVC). The MVC design pattern employs three different components to "make up" a user interface component. The graphical representation (the view) is separated from the state data (the model), which are both separated from the event handler (the controller). The idea is that the controller provides the communication between the model and the view. The controller tells the view when the model changes, thus the view uses the new state data to update itself. The controller can also inform the model to change its state based on some user input. The use of three different pieces to create a single UI component provides for an extensible and highly customizable component.

Swing uses the idea of MVC, but changes it just a little bit. There are still three components; logically, the model and the view are tied to the controller through the use of a JComponent . Therefore, the JComponent implementation provides the necessary means for the model, the view, and the controller to interact with one another. The Model-View-Controller pattern makes customizing a component a relatively straightforward process. You either change the view, the controller, the model, or a combination of the three. Some Swing components, like JLabel , are not fully implemented using MVC, whereas other components like JTree are. In almost every case, however, the view is separate. This decoupling provides the basis for the "pluggable-look-and-feel" behaviors found in Swing. JLabel does separate the model from the view, but the model and the controller are embodied in the JLabel class itself. JTree , on the other hand, does separate the model from the view and from the controller. The view of a component is changed by calling the setUI(ComponentUI) method on the component. In most cases, the model is changed by calling a variation of setModel(_).

Let's revisit the concept of creating a JLabel that draws the text vertically instead of horizontally. We have already seen two different ways to achieve this, overriding either paint(Graphics g) or paintComponent(Graphics g) . Applying what we know about Swing and the MVC pattern, the third way to create a customized version of the JLabel is to change the piece that graphically renders the label. To do that, we need to create an implementation of a javax.swing.plaf.LabelUI that renders the text vertically. Every JComponent has an associated UI found in the javax.swing.plaf package. JComponent has ComponentUI, JLabel has LabelUI, JButton has ButtonUI , and so on. In fact, some default UI implementations exist in the javax.swing.plaf.basic and javax.swing.plaf.metal packages. When creating an implementation of a UI, you can either extend the default UI class found in the javax.swing.plaf package, or you can extend one of the implementations found in the other two packages. The class you choose to extend should be determined by the amount of inherited behaviors you wish to leverage. In the case of a vertical label, the default behaviors provided by ComponentUI and LabelUI are sufficient ( LabelUI extends ComponentUI ).

When creating an implementation of a UI, there are two main methods that you will override: createUI(JComponent) and paint(Graphics g, JComponent c) . The createUI(JComponent) method is used to create a UI object for the given JComponent . The result is then associated with the JComponent in the javax.swing.UIManager . In many cases, implementing createUI(JComponent) to return a singleton will suffice. The implementation of the paint(Graphics g, JComponent c) method is responsible for drawing the visual representation of the component. Since the visual representation is dependent on the model, the paint(Graphics g, JComponent c) method should retrieve the state data from the JComponent and then render the data appropriately. You may also consider overriding getPreferredSize(JComponent) so that the returned Dimension is specific to the amount of space required to properly render the data in the model. Since the paint(Graphics g, JComponent c) method does not exist in the JComponent itself, the paint(Graphics g, JComponent c) method must rely on the data passed in to retrieve component specific information. In the case of a vertical label, the implementation of the paint(Graphics g, JComponent c) method retrieves the label's text from the passed JComponent. Beyond that, the implementation is almost exactly the same as the others.

import javax.swing.*; 
   import java.awt.*; 
   import javax.swing.plaf.*; 

    class VerticalLabelUI extends LabelUI 
    { 
      private static final VerticalLabelUI labelUI = 
                              new VerticalLabelUI(); 
      private int charBufferWidth; 
      private int charBufferHeight; 
       
      public VerticalLabelUI() 
      { 
        charBufferWidth = 2; 
        charBufferHeight = 2; 
      } 
       

      //override ComponentUI's implementation for the following ...  
      public void installUI(JComponent c) { 
        /**  
        * LookAndFeel is a class that characterizes the LookAndFeel. 
        * The installColorsAndFont(...) method can be used 
              as a convenience  
        * method to associate a component's foreground color, 
              background color 
        * and font properties with values from the current 
              defaults table found. 
        * In our case, it allows the VerticalLabelUI to use the 
              default properties 
        * for a Label. This keeps the look of the JLabel consistent 
              with other JLabels 
        * using UIs other than VerticalLabelUI. 
        */        
        LookAndFeel.installColorsAndFont(c, "Label.background", 
            "Label.foreground", "Label.font"); 
      } 
       
      public void paint(Graphics graphics, JComponent c) { 
        if(!(c instanceof JLabel)) 
          return; 
           
        JLabel label = (JLabel) c; 
        String labelText = label.getText(); 
        int stringLength = labelText.length(); 
         
        FontMetrics fontMetrics = graphics.getFontMetrics(); 
        int maxAscent = fontMetrics.getMaxAscent(); 
        int maxDescent = fontMetrics.getMaxDescent(); 
        int charHeight = maxAscent + maxDescent; 
             
        int xPosition = 1; 
        int yPosition = 1 + maxAscent; 
        String tmpString = null; 
         
        for(int i=0;i<stringLength;i++) 
        { 
          tmpString = labelText.substring(i,i+1); 
          graphics.drawString(tmpString,xPosition,yPosition); 
          yPosition = yPosition + charHeight + charBufferHeight; 
        } 
      } 
       
      public Dimension getPreferredSize(JComponent c) { 
        int height = getVerticalStringLength(c); 
        int width = getHorizontalStringLength(c); 
        return new Dimension(height, width); 
      } 
       
      public static ComponentUI createUI(JComponent c) { 
        return labelUI; 
      } 
       
      private int getVerticalStringLength(JComponent component) { 
        FontMetrics fontMetrics = component.getGraphics().
                                             getFontMetrics(); 
        String text = ((JLabel) component).getText(); 
        int stringLength = text.length(); 
        int verticalStringLength = fontMetrics.stringWidth(text) +  
                        (stringLength * labelUI.charBufferHeight); 
        return verticalStringLength; 
      } 
       
      private int getHorizontalStringLength(JComponent component) { 
        FontMetrics fontMetrics = component.getGraphics().
                                             getFontMetrics(); 
        String text = ((JLabel) component).getText(); 
        int horizontalStringLength = fontMetrics.getMaxAscent() +       
                                         labelUI.charBufferWidth; 
        return horizontalStringLength; 
      } 
    } 

Now that we have created our customized UI, we need to associate it with the JLabel itself. To do this, we need to first create an instance of the VerticalLabelUI and then pass this instance to the JLabel. We can use the createUI(JComponent) method found in the VerticalLabelUI class to create the UI. Once we have a UI object, we can then associate the UI with the JLabel by calling setUI(ComponentUI). That's it!

   import javax.swing.*; 
   import javax.swing.plaf.*; 
   import javax.swing.border.*; 
   import java.awt.*; 
   import java.awt.event.*; 
      
    public class BasicApp 
    { 
      public static void main(String [] args) 
      { 
        if(args.length > 0) 
        { 
          BasicApp app = new BasicApp(args[0]); 
          app.start(); 
        } 
        else 
        { 
          System.out.println("usage: java BasicApp label_value"); 
          System.exit(-1); 
        } 
      } 
       
      private JFrame frame; 
      private JLabel labelOne, labelTwo; 
       
      private BasicApp(String labelText) 
      { 
        frame = new JFrame("Basic App"); 

        labelOne = new VerticalJLabel(labelText); 
        labelOne.setBorder(BorderFactory.createBevelBorder
                                       (BevelBorder.LOWERED)); 
        labelTwo = new JLabel(labelText); 
        labelTwo.setBorder(BorderFactory.createBevelBorder
                                       (BevelBorder.LOWERED)); 
        labelUI = (LabelUI) VerticalLabelUI.createUI(labelTwo); 
        labelTwo.setUI(labelUI); 
         
        Container container = frame.getContentPane(); 
        container.add(labelOne, BorderLayout.WEST); 
        container.add(labelTwo, BorderLayout.EAST); 
      } 
       
      private void start() 
      { 
        frame.addWindowListener(new WindowAdapter() { 
          public void windowClosing(WindowEvent we) 
          { 
            Component source = we.getComponent(); 
            if(source instanceof Frame) 
            { 
              ((Frame)source).setVisible(false); 
              ((Frame)source).dispose(); 
              System.exit(0); 
            } 
          } 
        }); 
      
        frame.setSize(100,150); 
        frame.setVisible(true); 
       } 
    } 

If you think back to our discussion of the paintComponent(_) method, we discussed how Swing uses delegation to render a component. The default behavior of paintComponent(_) is to call paint(Graphics g, JComponent c) on the associated UI object. Therefore, overriding paintComponent(_) as we did in our last example will disregard the rendering instructions in the associated UI. Thus, associating a UI with a component using setUI(ComponentUI) does not guarantee the UI will be used to render the component. However, by overriding the paintComponent(_) method, you lose the flexibility found in MVC, not to mention the "Pluggable-Look-And-Feel" behaviors. Therefore, when creating a customized component in Swing, create a customized view (UI) and associate that with the component. Then, if for some reason in the future you want to display the label text on a 45-degree angle, all you have to do is swap out the view!


About the author

Mr. Kelby Zorgdrager

Kelby Zorgdrager is a Senior Software Engineer with STSHotelnet. As a member of the Architectural committee, Kelby is responsible for designing the underlying Portal Framework using J2EE and other distributed Java technologies. Prior to working at STSHotelnet, Kelby was a Senior Software Engineer with Sun Microsystems where he worked on a distributed management infrastructure. Kelby was also a Java instructor for Sun Educational Services where he provided training and consulting services. Kelby has presented at major Java trade shows including JavaUniversity, JavaOne, Java Business Expo, and COMDEX. He has worked with the Java language since January, 1996.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Sample IT projects
ArticleID=10133
ArticleTitle=Java user interface design and development
publish-date=05012001
author1-email=
author1-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).