Member Avatar for r.stiltskin

I have two problems with the focus on buttons in this project.

I've pared the code down to barebones to show the problems; there are only 2 simple classes remaining & still the problems persist. It compiles, runs (java ColorView), and all that's required to see the problems is simply press the space bar each time a window opens and each time the focus shifts.

The program opens up with it's main window in the background and its optionDialog in focus in the foreground, and the optionDialog's rgbButton in focus. This works.

When the rgbButton is pressed, focus shifts to the continueButton. This works.

When the continueButton is pressed, the optionDialog goes invisible, and the the main window's addColorsButton is in focus. This works, more or less (but see 2nd problem below).

When the addColorsButton is pressed, the optionDialog becomes visible (this works) and the optionDialog's continueButton is supposed to be in focus.
Here's the 1st problem: after the addColorsButton is pressed for the first time , the rgbButton is still in focus. The next time, and every time thereafter, the continueButton is in focus. But, why doesn't this work correctly the first time the addColorsButton is pressed (or in other words the second appearance of the optionDialog)?

The 2nd problem is the focus on the addColorsButton itself. Actually, EVERY time the main window is in focus, so is the addColorsButton. So, the text on the button should be outlined to show that it is in focus. But many times, it is not outlined even though it is in focus. You can see this by repeatedly pressing the space bar to cycle back and forth between the dialog and the main window. The space bar always works, proving that the button actually is in focus, but many times the text on the addColorsButton is not outlined. Why is this, and how can I fix it?

Thanks for looking.
ColorView.java:

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

public class ColorView extends JFrame implements ActionListener {
  public static final Dimension INPUT_SZ         = new Dimension( 40, 20 );

  public static final Dimension BUTTON_SZ        = new Dimension( 160, 30 );

  public static final Dimension DIALOG_SZ        = new Dimension( 500, 200 );

  public static final Dimension OUTPUT_SZ        = new Dimension( 800, 600 );

  static final String           ADD_COLORS       = new String( "add_colors" );

  static final String           NEW_COLORS       = new String( "new_colors" );

  static final String           QUIT             = new String( "quit" );

  boolean                       initOptionDialog = false;

  boolean                       initInputDialog  = false;

  CVOptionDialog                optionDialog;

  JPanel                        outputPanel, buttonPanel;

  Container                     colorDisplayPane;

  public ColorView() {
    super( "Color Viewer" );
  }

  private void showOptionDialog() {

    if( !initOptionDialog ) {
      initOptionDialog = true;
      optionDialog = new CVOptionDialog( this );
      optionDialog.setDefaultCloseOperation( DISPOSE_ON_CLOSE );
      optionDialog.setVisible( true );
      optionDialog.rgbButton.requestFocusInWindow();
    } else {
      optionDialog.setVisible( true );
      optionDialog.continueButton.requestFocusInWindow();
    }
  }


  void showColors() {
    colorDisplayPane = getContentPane();
    outputPanel = new JPanel();
    buttonPanel = new JPanel();
    JButton addColorsButton = new JButton( "Add More Colors" );
    JButton newColorsButton = new JButton( "Input New Colors" );
    JButton quitButton = new JButton( "Quit ColorView" );

    colorDisplayPane.setLayout( new BorderLayout() );
    outputPanel.setLayout( new FlowLayout() );

    addColorsButton.addActionListener( this );
    newColorsButton.addActionListener( this );
    quitButton.addActionListener( this );

    addColorsButton.setActionCommand( ADD_COLORS );
    newColorsButton.setActionCommand( NEW_COLORS );
    quitButton.setActionCommand( QUIT );

    buttonPanel.add( addColorsButton );
    buttonPanel.add( newColorsButton );
    buttonPanel.add( quitButton );
    colorDisplayPane.add( outputPanel, BorderLayout.CENTER );
    colorDisplayPane.add( buttonPanel, BorderLayout.SOUTH );
    setVisible( true );
    addColorsButton.requestFocusInWindow();
    
  }

  public void actionPerformed( ActionEvent e ) {
    String command = e.getActionCommand();
    if( command.equals( ADD_COLORS ) ) {
      optionDialog.setVisible( true );
      optionDialog.continueButton.requestFocusInWindow();
    } else if( command.equals( NEW_COLORS ) ) {
      setVisible( false );
      colorDisplayPane.removeAll( );
      setVisible( true );
      optionDialog.setVisible( true );
    } else if( command.equals( QUIT ) ) {
      System.exit( 0 );
    }
  }

  private static void createAndShowGUI() {
    ColorView frame = new ColorView();
    frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

    frame.setSize( OUTPUT_SZ );
    frame.setLocationRelativeTo( null );
    frame.setVisible( true );
    frame.showOptionDialog();
  }

  public static void main( String[] args ) {
    javax.swing.SwingUtilities.invokeLater( new Runnable() {
      public void run() {
        createAndShowGUI();
      }
    } );
  }

}

CVOptionDialog.java:

/* CVOptionDialog is the JDialog used to choose input options:
 * rgb or ycb values, specific colors or color ranges
 */

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

class CVOptionDialog extends JDialog implements ActionListener {

  ColorView    parent;

  JRadioButton rgbButton;

  JButton      continueButton;

  CVOptionDialog( ColorView owner ) {
    super( owner );
    setModal( true );
    setTitle( "ColorView - Input Options" );
    parent = owner;

    JLabel label1 = new JLabel( "Select color space:" );
    rgbButton = new JRadioButton();
    rgbButton.setText( "RGB" );

    continueButton = new JButton( "Continue" );
    continueButton.setPreferredSize( ColorView.BUTTON_SZ );


    JPanel colorOptionPanel = new JPanel( new FlowLayout() );
    colorOptionPanel.setAlignmentX( Component.CENTER_ALIGNMENT );
    colorOptionPanel.add( label1 );
    colorOptionPanel.add( rgbButton );

    JPanel continuePanel = new JPanel( new FlowLayout() );
    continuePanel.setAlignmentX( Component.CENTER_ALIGNMENT );
    continuePanel.add( continueButton );
    
    JPanel optionPanel = new JPanel();
    optionPanel.setLayout( new BoxLayout( optionPanel, BoxLayout.Y_AXIS ) );
    optionPanel.add( colorOptionPanel );
    optionPanel.add( new JSeparator( SwingConstants.HORIZONTAL ) );
    optionPanel.add( continuePanel );

    optionPanel.setPreferredSize( ColorView.DIALOG_SZ );

    rgbButton.addActionListener( this );
    continueButton.addActionListener( this );

    rgbButton.setActionCommand( "rgb_selected" );
    continueButton.setActionCommand( "continue" );

    setContentPane( optionPanel );
    pack();
    setSize( ColorView.DIALOG_SZ );
    setLocationRelativeTo( null );
  }

  public void actionPerformed( ActionEvent e ) {
    String command = e.getActionCommand();
    if( command.equals( "rgb_selected" ) ) {
      continueButton.requestFocusInWindow();
    } else if( command.equals( "continue" ) ) {
      setVisible( false );
      parent.showColors();
    }
  }
}
Member Avatar for r.stiltskin

I found a partial solution:

I can direct the focus to the correct button in the optionDialog by adding a WindowFocusListener, so that solves the rgbButton/continueButton issue.

But my problem with the addColorsButton in the main window remains -- the focus is on that button whenever the window is visible, but about 1/3 of the time there is no visual cue to show which button has the focus.

I should mention that I have been running this in Linux, but I just tested it under WindowsXP and found the exact same behavior again.

Following is the revised code. Apparently it is too late to edit my original post.

ColorView.java:

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

public class ColorView extends JFrame implements ActionListener {
  public static final Dimension INPUT_SZ         = new Dimension( 40, 20 );

  public static final Dimension BUTTON_SZ        = new Dimension( 160, 30 );

  public static final Dimension DIALOG_SZ        = new Dimension( 500, 200 );

  public static final Dimension OUTPUT_SZ        = new Dimension( 800, 600 );

  static final String           ADD_COLORS       = new String( "add_colors" );

  static final String           NEW_COLORS       = new String( "new_colors" );

  static final String           QUIT             = new String( "quit" );

  boolean                       initOptionDialog = false;

  boolean                       initInputDialog  = false;

  CVOptionDialog                optionDialog;

  JPanel                        outputPanel, buttonPanel;

  Container                     colorDisplayPane;

  public ColorView() {
    super( "Color Viewer" );
  }

  private void showOptionDialog() {

    if( !initOptionDialog ) {
      initOptionDialog = true;
      optionDialog = new CVOptionDialog( this );
      optionDialog.setDefaultCloseOperation( DISPOSE_ON_CLOSE );
      optionDialog.setVisible( true );
//      optionDialog.rgbButton.requestFocusInWindow();
    } else {
      optionDialog.setVisible( true );
//      optionDialog.continueButton.requestFocusInWindow();
    }
  }


  void showColors() {
    colorDisplayPane = getContentPane();
    outputPanel = new JPanel();
    buttonPanel = new JPanel();
    JButton addColorsButton = new JButton( "Add More Colors" );
    JButton newColorsButton = new JButton( "Input New Colors" );
    JButton quitButton = new JButton( "Quit ColorView" );

    colorDisplayPane.setLayout( new BorderLayout() );
    outputPanel.setLayout( new FlowLayout() );

    addColorsButton.addActionListener( this );
    newColorsButton.addActionListener( this );
    quitButton.addActionListener( this );

    addColorsButton.setActionCommand( ADD_COLORS );
    newColorsButton.setActionCommand( NEW_COLORS );
    quitButton.setActionCommand( QUIT );

    buttonPanel.add( addColorsButton );
    buttonPanel.add( newColorsButton );
    buttonPanel.add( quitButton );
    colorDisplayPane.add( outputPanel, BorderLayout.CENTER );
    colorDisplayPane.add( buttonPanel, BorderLayout.SOUTH );
    setVisible( true );
    addColorsButton.requestFocusInWindow();
    
  }

  public void actionPerformed( ActionEvent e ) {
    String command = e.getActionCommand();
    if( command.equals( ADD_COLORS ) ) {
      optionDialog.setVisible( true );
//      optionDialog.continueButton.requestFocusInWindow();
    } else if( command.equals( NEW_COLORS ) ) {
      setVisible( false );
      colorDisplayPane.removeAll( );
      setVisible( true );
      optionDialog.setVisible( true );
    } else if( command.equals( QUIT ) ) {
      System.exit( 0 );
    }
  }

  private static void createAndShowGUI() {
    ColorView frame = new ColorView();
    frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

    frame.setSize( OUTPUT_SZ );
    frame.setLocationRelativeTo( null );
    frame.setVisible( true );
    frame.showOptionDialog();
  }

  public static void main( String[] args ) {
    javax.swing.SwingUtilities.invokeLater( new Runnable() {
      public void run() {
        createAndShowGUI();
      }
    } );
  }

}

CVOptionDialog.java:

/* CVOptionDialog is the JDialog used to choose input options:
 * rgb or ycb values, specific colors or color ranges
 */

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

class CVOptionDialog extends JDialog implements ActionListener {

  ColorView    parent;
  
  boolean initialDisplay = true;

  JRadioButton rgbButton;

  JButton      continueButton;

  CVOptionDialog( ColorView owner ) {
    super( owner );
    setModal( true );
    setTitle( "ColorView - Input Options" );
    parent = owner;

    JLabel label1 = new JLabel( "Select color space:" );
    rgbButton = new JRadioButton();
    rgbButton.setText( "RGB" );

    continueButton = new JButton( "Continue" );
    continueButton.setPreferredSize( ColorView.BUTTON_SZ );


    JPanel colorOptionPanel = new JPanel( new FlowLayout() );
    colorOptionPanel.setAlignmentX( Component.CENTER_ALIGNMENT );
    colorOptionPanel.add( label1 );
    colorOptionPanel.add( rgbButton );

    JPanel continuePanel = new JPanel( new FlowLayout() );
    continuePanel.setAlignmentX( Component.CENTER_ALIGNMENT );
    continuePanel.add( continueButton );
    
    JPanel optionPanel = new JPanel();
    optionPanel.setLayout( new BoxLayout( optionPanel, BoxLayout.Y_AXIS ) );
    optionPanel.add( colorOptionPanel );
    optionPanel.add( new JSeparator( SwingConstants.HORIZONTAL ) );
    optionPanel.add( continuePanel );

    optionPanel.setPreferredSize( ColorView.DIALOG_SZ );

    rgbButton.addActionListener( this );
    continueButton.addActionListener( this );

    rgbButton.setActionCommand( "rgb_selected" );
    continueButton.setActionCommand( "continue" );

    // the following block solves the problem in the optionDialog
    addWindowFocusListener( new WindowAdapter() {
      public void windowGainedFocus(WindowEvent e) {
        if( initialDisplay ) {
          initialDisplay = false;
          rgbButton.requestFocusInWindow();
        } else { 
          continueButton.requestFocusInWindow();
        }
      }
    });
    
    setContentPane( optionPanel );
    pack();
    setSize( ColorView.DIALOG_SZ );
    setLocationRelativeTo( null );
  }

  public void actionPerformed( ActionEvent e ) {
    String command = e.getActionCommand();
    if( command.equals( "rgb_selected" ) ) {
      continueButton.requestFocusInWindow();
    } else if( command.equals( "continue" ) ) {
      setVisible( false );
      parent.showColors();
    }
  }
}
Member Avatar for r.stiltskin

LOL, I finally found the solution, which turns out to be -- call addColorsButton.requestFocusInWindow only the first time the window is displayed. I added a member variable boolean initialDisplay = true; to the class, added

if( initialDisplay ) {
  initialDisplay = false;
  addColorsButton.requestFocusInWindow();
  }

to the constructor, and deleted all other calls to requestFocusInWindow(), and everything seems to work correctly.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.