[an error occurred while processing this directive]

Page One
Page Two
The Databank
What Is Swing?
Special Report
IDE Roundup
Swing and the Web
Swing Text
Tech Topics
Friends
Tips and Tricks
The PLAF Papers
Call 911
The Archive
JFC Home
Download Swing
Swing API Docs
Download JDK
JDK Docs
Java Tutorial
 
The Swing Connection Tech Topics

Component Orientation in Swing
How JFC Components Support 'BIDI' Text

By Ralph Kar

Swing 1.1, which is now part of JDK 1.2, offers some support for the use of "BIDI" (bi-directional) text in buttons, labels and menu items. This new feature is a must for writing programs in languages that are not oriented from left to right and from top to bottom.

Some written languages, such as Chinese, are traditionally written from top to bottom and from right to left. Other languages, such as Hebrew and Arabic are written horizontally but from right to left. So one important goal of the creators of Swing was to provide an easy mechanism that allows some support for those languages.

The currently existing Swing components with BIDI support are JLabelapi, JButtonapi, JMenuItemapi, JCheckBoxMenuItemapi, JMenuapi, JRadioButtonMenuItemapi, JToggleButtonapi, JCheckBoxapi, and JRadioButtonapi. None of Swing's text components currently has BIDI support, but as Swing continues to evolve, plans are to add BIDI support to all approprate Swing components.

To support BIDI text, Swing uses the new java.awt.ComponentOrientation class in JDK 1.2. This new class allows components to encapsulate language-sensitive orientation information. With that capability, a component can be oriented vertically or horizontally and left-to-right or right-to-left. In JDK 1.2, the layout managers java.awt.FlowLayout and java.awt.BorderLayout have been updated to be able to handle these newly available orientation styles as well.

To provide backward compatibility, Swing's BIDI support can be used with JDK1.1.x as well. But when BIDI text is used with JDK 1.1.x, Swing always defaults to the left-to-right/top-to-bottom orientation.

To support BIDI text, Swing 1.1 recognizes two special constants: LEADING and TRAILING. Applications can use these constants to specify a horizontal text position in buttons, labels and menu items. The LEADING and TRAILING constants are designed to be used with two new methods: setHorizontalTextPosition() and setHorizontalAlignment().

Here's an example:

button.setHorizontalAlignment(JButton.LEADING);
button.setHorizontalTextPosition(JButton.TRAILING);

The LEADING and TRAILING constants

By using the LEADING and TRAILING constants, as shown in preceding examples, the calculations for laying out a Swing component can make use of a ComponentOrientation object. When a ComponentOrientation object is attached to a Swing component, LEADING is translated to mean LEFT in a left-to-right environment, but is translated to right RIGHT in a right-to-left environment. Conversely, the TRAILING constant is translated to mean RIGHT in a left-to-right environment and to mean LEFT in a right-to-left environment.

Here is how the text positioning looks like in a left-to-right environment:

 

And here is the same program running in a right-to-left environment:


BIDI coding: An example

In Example 1, we present the actual code that was used to create the pictures shown above. As you can see, this example demonstrates the use of Swing's BIDI text-orientation feature.

If you like, you can download a zip file containtaining the complete program and all its resources by clicking the Download button.


Example 1
How a Swing app can support bi-directional text

// Imports

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



/**
 * This class demonstrates the BIDI text feature in Swing 1.1 
 * under JDK 1.2.
 */
public class BidiDemo extends JApplet implements ActionListener
{
    ImageIcon       icon = new ImageIcon("duke.gif");

    JPanel          panel = new JPanel(new GridLayout(4, 2, 10, 5));

    JButton         but1 = new JButton("LEADING", icon);
    JButton         but2 = new JButton("TRAILING", icon);

    JCheckBox       box1 = new JCheckBox("LEADING");
    JCheckBox       box2 = new JCheckBox("TRAILING");

    JRadioButton    radio1 = new JRadioButton("LEADING");
    JRadioButton    radio2 = new JRadioButton("TRAILING");

    JLabel          label1 = new JLabel("LEADING", icon, JLabel.CENTER);
    JLabel          label2 = new JLabel("TRAILING", icon, JLabel.CENTER);

    JButton         switchOrientation = new JButton("Orientation: " +
                                                    "Left to Right");

    boolean         left2right = true;


    /**
     * Constructor for class BidiDemo.
     */
    public BidiDemo() {
        // Set the horizontal alignment and the horizontal 
        // text position for all the components.

        but1.setHorizontalAlignment(JButton.LEADING);
        but1.setHorizontalTextPosition(JButton.LEADING);

        but2.setHorizontalAlignment(JButton.TRAILING);
        but2.setHorizontalTextPosition(JButton.TRAILING);

        box1.setHorizontalAlignment(JCheckBox.LEADING);
        box1.setHorizontalTextPosition(JCheckBox.LEADING);

        box2.setHorizontalAlignment(JCheckBox.TRAILING);
        box2.setHorizontalTextPosition(JCheckBox.TRAILING);

        label1.setHorizontalAlignment(JLabel.LEADING);
        label1.setHorizontalTextPosition(JLabel.LEADING);

        label2.setHorizontalAlignment(JLabel.TRAILING);
        label2.setHorizontalTextPosition(JLabel.TRAILING);

        radio1.setHorizontalAlignment(JRadioButton.LEADING);
        radio1.setHorizontalTextPosition(JRadioButton.LEADING);

        radio2.setHorizontalAlignment(JRadioButton.TRAILING);
        radio2.setHorizontalTextPosition(JRadioButton.TRAILING);

        // Place the components in the panel.
        panel.add(but1);
        panel.add(but2);
        panel.add(box1);
        panel.add(box2);
        panel.add(label1);
        panel.add(label2);
        panel.add(radio1);
        panel.add(radio2);

        switchOrientation.addActionListener(this);

        this.getContentPane().setLayout(new BorderLayout());
        this.getContentPane().add(panel, BorderLayout.CENTER);
        this.getContentPane().add(switchOrientation, BorderLayout.SOUTH);
    }


    /**
     * Event handler for the button clicks.
     */
    public void actionPerformed(ActionEvent ev) {
        if (ev.getSource() == switchOrientation) {
            if (left2right) {
                // Set the orientation of each component
                // to RIGHT_TO_LEFT.
                but1.setComponentOrientation(
                                    ComponentOrientation.RIGHT_TO_LEFT);
                but2.setComponentOrientation(
                                    ComponentOrientation.RIGHT_TO_LEFT);
                box1.setComponentOrientation(
                                    ComponentOrientation.RIGHT_TO_LEFT);
                box2.setComponentOrientation(
                                    ComponentOrientation.RIGHT_TO_LEFT);
                radio1.setComponentOrientation(
                                    ComponentOrientation.RIGHT_TO_LEFT);
                radio2.setComponentOrientation(
                                    ComponentOrientation.RIGHT_TO_LEFT);
                label1.setComponentOrientation(
                                    ComponentOrientation.RIGHT_TO_LEFT);
                label2.setComponentOrientation(
                                    ComponentOrientation.RIGHT_TO_LEFT);

                switchOrientation.setText("Orientation: Right to Left");

                left2right = false;
            }
            else {
                // Set the orientation of each component
                // to LEFT_TO_RIGHT.
                but1.setComponentOrientation(
                                    ComponentOrientation.LEFT_TO_RIGHT);
                but2.setComponentOrientation(
                                    ComponentOrientation.LEFT_TO_RIGHT);
                box1.setComponentOrientation(
                                    ComponentOrientation.LEFT_TO_RIGHT);
                box2.setComponentOrientation(
                                    ComponentOrientation.LEFT_TO_RIGHT);
                radio1.setComponentOrientation(
                                    ComponentOrientation.LEFT_TO_RIGHT);
                radio2.setComponentOrientation(
                                    ComponentOrientation.LEFT_TO_RIGHT);
                label1.setComponentOrientation(
                                    ComponentOrientation.LEFT_TO_RIGHT);
                label2.setComponentOrientation(
                                    ComponentOrientation.LEFT_TO_RIGHT);

                switchOrientation.setText("Orientation: Left to Right");

                left2right = true;
            }
        }
        panel.revalidate();
        repaint();
    }


    /**
     * Main method
     */
    static public void main(String args[]) {
        JFrame frame = new JFrame("Bidi Text Demonstration");
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

        BidiDemo demo = new BidiDemo();

        frame.getContentPane().add(demo);

        frame.setSize(400, 400);
        frame.setVisible(true);
    }
}            
[an error occurred while processing this directive]