Java Swing JScrollPane shows different output than the one the book shows. The row labels just vanish in Java

The following code does not give me the output that it should. The output that it should give is shown below:

Output that I want to get

Instead of that output I got an output which is like the one below:

Wrong output that I get now

Things that I have noted that I'm not getting are:

  1. I don't get the ScrollBars both vertical and horizontal.
  2. I don't get the row headers for each row which are in the panel 'p'.
  3. The format also seems disturbed. And when the program starts, the radio buttons are not visible until I move the mouse over them.

This code is from the Java Swing book of O'REILLY (Chapter 11) using Eclipse IDE.


package khan.ajmal.oreilly.swing;

import java.awt.Window;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class BasicWindowMonitor extends WindowAdapter {

    @Override
    public void windowClosing(WindowEvent e) {
        Window w = e.getWindow();
        w.setVisible(false);
        w.dispose();
        System.exit(0);
    }
}

/A JScrollPane with a component larger than the application window./ package khan.ajmal.oreilly.swing.Chapter11_SpecialtyPanesAndLayoutManagers;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.ScrollPaneConstants;

import khan.ajmal.oreilly.swing.BasicWindowMonitor;

public class ScrollDemo2 extends JFrame {
    JScrollPane scrollPane = new JScrollPane();

// Constructor
    public ScrollDemo2() {
        super("JScrollPane Demonstration");

    /* Add in some JViewports for the column and row headers */
        JViewport jv1 = new JViewport();
        jv1.setView(new JLabel(
            new ImageIcon(
                       "C:/Users/Ajmal/workspace/OreillySwing/src/khan/ajmal/oreilly/swing/Chapter11_SpecialtyPanesAndLayoutManagers/columnLabel.jpg")));

        scrollPane.setColumnHeader(jv1);

        JViewport jv2 = new JViewport();
        jv2.setView(new JLabel(
            new ImageIcon(
                    "C:/Users/Ajmal/workspace/OreillySwing/src/khan/ajmal/oreilly/swing/Chapter11_SpecialtyPanesAndLayoutManagers/rowLabel.jpg")));
    scrollPane.setRowHeader(jv2);

    /* And throw in an information button */
    JButton jb1 = new JButton(
            new ImageIcon(
                    "C:/Users/Ajmal/workspace/OreillySwing/src/khan/ajmal/oreilly/swing/Chapter11_SpecialtyPanesAndLayoutManagers/question.jpg"));
    jb1.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            String message = "This is an active corner!";
            String title = "Information";
            int type = JOptionPane.INFORMATION_MESSAGE;
            JOptionPane.showMessageDialog(null, message, title, type);
        }// method actionPerformed ends here.
    }// Definition of inner class ActionListener ends here.
    );/* Passing arguments to method addActionListener ends here. */
    scrollPane.setCorner(ScrollPaneConstants.UPPER_LEFT_CORNER, jb1);
    setSize(300, 200);
    addWindowListener(new BasicWindowMonitor());
    init();
    setVisible(true);
}// Constructor ends here.

private void init() {
    JRadioButton form[][] = new JRadioButton[12][5];
    String counts[] = { " ", "0-1", "2-5", "6-10", "11-100", "101+" };
    String categories[] = { "Household", "Office", "Extended Family",
            "Company (US)", "Company (World)", "Team", "Will",
            "Birthday Card List", "High School", "Country", "Continent",
            "Planet" };
    JPanel p = new JPanel();
    p.setSize(600, 400);
    p.setLayout(new GridLayout(13, 6, 10, 0));

    for (int row = 0; row < 13; row++) {
        // creating a button group in each iteration of the row loop
        ButtonGroup bg = new ButtonGroup();
        for (int col = 0; col < 6; col++) {
            // We need to create column headers in the first row
            if (row == 0)
                p.add(new JLabel(counts[col]));
            else {
                /*
                 * When the control moves to a new row, check for the
                 * column. In the first column put row headers
                 */
                if (col == 0) {
                    p.add(new JLabel(categories[row - 1]));/*
                                                             * row will have
                                                             * at least
                                                             * value of 1
                                                             * when control
                                                             * is at this
                                                             * line.
                                                             */
                } else {
                    form[row - 1][col - 1] = new JRadioButton();
                    bg.add(form[row - 1][col - 1]);/*
                                                     * add this button to
                                                     * the button group
                                                     */
                    p.add(form[row - 1][col - 1]);
                }
            }
        }// col for loop ends here.
    }// row for loop ends here.

    // Adding the panel to a scrollpane
    // scrollPane = new JScrollPane(p);
    scrollPane.add(p);
    // adding the scrollpane to the contentpane of the frame
    getContentPane().add(scrollPane, BorderLayout.CENTER);
}// method init ends here.

public static void main(String[] args) {
    new ScrollDemo2();
}// method main ends here.

}// class ScrollDemo2 ends here.

Answers


There are some issues with the order in which components are initialized in your code. Those are a bit hard to pick out, so I took the liberty of re-organizing your code to make things more clear. I think you'll find this code more workable. (Note: I removed the import of the BasicWindowAdapter and your calls to ImageIcon)

Some take-away tips:

  1. Try to use a given component in only one method. Your code was accessing scrollPane from both the Constructor and from init().
  2. Don't hesitate to create methods that do something very specific, that take specific input, and provide specific output. For example, createScrollPane() below takes a JPanel and returns a JScrollPane. It's clear what the method does, and it does not require the use of variables with class scope.
  3. Try not to build the UI in the constructor. A good practice is to create an init() method, and have init() call other methods to build specific parts of the UI.

Here's your revamped code:

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.ScrollPaneConstants;

public class ScrollDemo2 extends JFrame {

// Constructor
public ScrollDemo2() {
    super("JScrollPane Demonstration");
    init();
    setSize(300, 200);
    setVisible(true);
}// Constructor ends here.

private void init() {
    JPanel panel = createFormPanel();
    JScrollPane scrollPane = createScrollPane(panel);
    this.getContentPane().add(scrollPane, BorderLayout.CENTER);
}// method init ends here.


private JPanel createFormPanel() {
    JRadioButton form[][] = new JRadioButton[12][5];

    JPanel p = new JPanel();
    p.setSize(600, 400);
    p.setLayout(new GridLayout(13, 6, 10, 0));

    for (int row = 0; row < 13; row++) {
        // creating a button group in each iteration of the row loop
        ButtonGroup bg = new ButtonGroup();
        for (int col = 0; col < 6; col++) {
            // We need to create column headers in the first row
            if (row == 0)
                p.add(new JLabel(COUNTS[col]));
            else {
                /*
                 * When the control moves to a new row, check for the
                 * column. In the first column put row headers
                 */
                if (col == 0) {
                    p.add(new JLabel(CATEGORIES[row - 1]));/*
                                                             * row will have
                                                             * at least
                                                             * value of 1
                                                             * when control
                                                             * is at this
                                                             * line.
                                                             */
                } else {
                    form[row - 1][col - 1] = new JRadioButton();
                    bg.add(form[row - 1][col - 1]);/*
                                                     * add this button to
                                                     * the button group
                                                     */
                    p.add(form[row - 1][col - 1]);
                }
            }
        }// col for loop ends here.
    }// row for loop ends here.
    return p;
}

private JScrollPane createScrollPane(JPanel panel) {
    JScrollPane scrollPane = new JScrollPane(panel);

    /* Add in some JViewports for the column and row headers */
    JViewport jv1 = new JViewport();
    jv1.setView(new JLabel("COL LABEL"));

    scrollPane.setColumnHeader(jv1);

    JViewport jv2 = new JViewport();
    jv2.setView(new JLabel("ROW LABEL"));
    scrollPane.setRowHeader(jv2);

    /* And throw in an information button */
    JButton jb1 = new JButton("?");
    jb1.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            String message = "This is an active corner!";
            String title = "Information";
            int type = JOptionPane.INFORMATION_MESSAGE;
            JOptionPane.showMessageDialog(null, message, title, type);
        }// method actionPerformed ends here.
    }// Definition of inner class ActionListener ends here.
    );/* Passing arguments to method addActionListener ends here. */
    scrollPane.setCorner(ScrollPaneConstants.UPPER_LEFT_CORNER, jb1);

    return scrollPane;
}


public static void main(String[] args) {
    new ScrollDemo2();
}// method main ends here.

public static final String[] COUNTS = { " ", "0-1", "2-5", "6-10", "11-100", "101+" };
public static final String[] CATEGORIES = { "Household", "Office", "Extended Family",
        "Company (US)", "Company (World)", "Team", "Will",
        "Birthday Card List", "High School", "Country", "Continent",
        "Planet" };


}// class ScrollDemo2 ends here.

Need Your Help

Move a JLabel to Front

java image jlabel image-manipulation

I am placing two images. One is supposed to be the background picture and the other one a picture of a stick-figure. I'd like to get the stick figure in front of the background. I can accomplish...

Extracting a shape/polygon from a binary image?

python python-2.7 opencv computer-vision computational-geometry

I'm trying to construct navigation meshes from mapping data. One of the steps involves converting a binary image (where 0 represents occupied space and 1 represents free space) into a planar strai...