简体   繁体   中英

JLabels and TextFields don't appear when declared in separate method/class

I'm having some trouble making JLabels and textFields appear on the JPanel. If I put all of this code in the main method it works fine, however when I move the JLabels and TextFields into their own methods or classes the JPanel remains empty. The image I use is shown.

package gui;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ImageIcon;
import javax.swing.JPanel;

@SuppressWarnings("serial")
class ImagePanel extends JPanel {

    private Image img;

    public ImagePanel(String img) {
        this(new ImageIcon(img).getImage());
    }

    public ImagePanel(Image img) {
        this.img = img;
        Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
        setPreferredSize(size);
        setMinimumSize(size);
        setMaximumSize(size);
        setSize(size);
        setLayout(null);
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(img,  0,  0,  null);
    }
}

public class EquippedInput {

    private JPanel panel;

    public static void main(String[] args){
        ImagePanel panel = new ImagePanel(new ImageIcon("Images/Crusader Background.jpg").getImage());
        JScrollPane scrollBar = new JScrollPane(panel,
                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        panel.setLayout(null);
        JFrame frame = new JFrame();
        frame.getContentPane().add(scrollBar);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(1160, 1000);
        frame.setVisible(true);
        panel.setPreferredSize(new Dimension(1125, 1210));
        scrollBar.getVerticalScrollBar().setUnitIncrement(20);
    }

    public EquippedInput() {
        initialize();
    }

    private void initialize() {

        /**
         * Stats and slots labels.
         */
        JLabel lblWeaponAttacksPerSecond = new JLabel("Weapon Attacks Per Second");
        JLabel lblWeaponAttackSpeed = new JLabel("Attack Speed");
        JLabel lblMainHand = new JLabel("Main Hand");
        JLabel lblOffHand = new JLabel("Off Hand");

        JLabel stats[] = {lblWeaponAttacksPerSecond, lblWeaponAttackSpeed};
        JLabel slots[] = {lblMainHand, lblOffHand};

        /**
         * Place stats and slots labels.
         */
        for (int i = 0; i < stats.length; i++) {
            stats[i].setBounds(10, (40 + 30 * i), 200, 20);
            panel.add(stats[i]);
        }
        for (int i = 0; i < slots.length; i++) {
            slots[i].setBounds((220 +  70 * i), 10, 60, 20);
            panel.add(slots[i]);
        }

        /**
         * Text fields.
         */
        JTextField textField0 = new JTextField();
        JTextField textField1 = new JTextField();

        JTextField mainHandTextField[] = {textField0, textField1};

        /**
         * Arrays of whether a stat can roll on an item. 1 = can roll. 0 = can't roll.
         */
        int mainHandAvailableStats[] =  {0, 1};

        /**
         * Text field builders, each loop is a single slot.
         */
        for (int i = 0; i < mainHandTextField.length; i++) {
            panel.add(mainHandTextField[i]);
            if(mainHandAvailableStats[i] == 1) {
                int textFieldVerticalPosition = 40 + 30 * i;
                mainHandTextField[i].setBounds(220, textFieldVerticalPosition, 60, 20);
                panel.add(mainHandTextField[i]);
            }
        }
    }
}

The actual code has a lot more content for the JPanel, but this produces the exact same result.

I am going to have to explain this code and this answer later, but it shows:

  1. Getting data from a text file and creating a table model from it
  2. Creating and displaying a JTable with null cells opaque
  3. Showing a background image in a JPanel

The data file is this:

                        Main_Hand       Off_Hand        Head            Shoulder        Neck
Weapon_Attacks_per_sec  5               null            null            null            null 
Attack_Speed            20              null            null            null            null
Damage_%                30              null            null            null            null
Min_Bonus_Damage        3               null            null            null            null
Max_Bonus_Damage        40              null            null            null            null
Min_Weapon_Damage       30              null            null            null            null
Max_Weapon_Damage       80              null            null            null            null
Strength                70              50              20              30              30

It must be named TableFunData.txt and be in the same directory/package as the code is in.

The code is:

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Scanner;
import java.util.Vector;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;

@SuppressWarnings("serial")
public class TableFun extends JPanel {
    private static final String IMG_PATH = "https://upload.wikimedia.org/"
            + "wikipedia/commons/d/d1/Ozanne-Brest.jpg";
    private JTable table = new JTable();
    private BufferedImage img;

    public TableFun(BufferedImage img, TableModel model) {
        this.img = img;
        table = new JTable(model);
        table.setDefaultRenderer(Object.class, new MyCellRenderer());
        table.setOpaque(false);
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        table.setShowGrid(false);
        JScrollPane scrollPane = new JScrollPane(table);
        scrollPane.setOpaque(false);
        scrollPane.getViewport().setOpaque(false);

        setLayout(new BorderLayout());
        add(scrollPane, BorderLayout.CENTER);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (img != null) {
            g.drawImage(img, 0, 0, this);
        }
    }

    @Override
    public Dimension getPreferredSize() {
        Dimension superSize = super.getPreferredSize();
        if (isPreferredSizeSet() || img == null) {
            return superSize;
        }
        int supW = superSize.width;
        int supH = superSize.height;
        int imgW = img.getWidth();
        int imgH = img.getHeight();
        int w = Math.max(imgW, supW);
        int h = Math.max(imgH, supH);
        return new Dimension(w, h);
    }

    private class MyCellRenderer extends DefaultTableCellRenderer {
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
                int row, int column) {
            DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            if (column != 0) {
                renderer.setHorizontalAlignment(JLabel.CENTER);
            } else {
                renderer.setHorizontalAlignment(JLabel.LEADING);
            }
            renderer.setOpaque(value != null);
            return renderer;
        }
    }

    private static void createAndShowGui() {
        BufferedImage img = null;
        try {
            URL imageUrl = new URL(IMG_PATH);
            img = ImageIO.read(imageUrl);
        } catch (IOException e1) {
            e1.printStackTrace();
            System.exit(-1);
        }
        String dataPath = "TableFunData.txt";
        DataIO dataIO = new DataIO(dataPath);
        TableModel model = null;
        try {
            model = dataIO.createTableModel();
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(-1);
        }

        JFrame frame = new JFrame("Table Fun");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new TableFun(img, model));
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }


    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

class DataIO {

    private static final String NULL = "null";
    private String dataPath;

    public DataIO(String dataPath) {
        this.dataPath = dataPath;
    }

    public TableModel createTableModel() throws IOException {
        InputStream inputStream = getClass().getResourceAsStream(dataPath);
        Scanner scanner = new Scanner(inputStream);
        Vector<String> columnNames = new Vector<>();
        Vector<Vector<Object>> data = new Vector<>();

        while (scanner.hasNext()) {
            String line = scanner.nextLine();
            if (columnNames.size() == 0) {
                columnNames = createColumnNames(line);
            } else {
                Vector<Object> dataRow = createDataRow(line);
                data.add(dataRow);
            }
        }
        if (scanner != null) {
            scanner.close();
        }
        DefaultTableModel model = new DefaultTableModel(data, columnNames);
        return model;
    }

    private Vector<String> createColumnNames(String line) {
        String[] tokens = line.split("\\s+");
        Vector<String> columnNames = new Vector<>();
        columnNames.add(" "); // first name is blank
        for (String token : tokens) {
            if (!token.trim().isEmpty()) {
                token = token.replace("_", " "); // add spaces
                columnNames.add(token);
            }
        }
        return columnNames;
    }

    private Vector<Object> createDataRow(String line) {
        String[] tokens = line.split("\\s+");
        Vector<Object> dataRow = new Vector<>();
        for (String token : tokens) {
            token = token.trim();
            if (!token.isEmpty()) {
                // first token is the title
                if (dataRow.size() == 0) {
                    token = token.replace("_", " "); // add spaces
                    dataRow.add(token);
                } else {
                    // if title already added
                    if (token.equalsIgnoreCase(NULL)) {
                        dataRow.add(null);
                    } else {
                        int value = Integer.parseInt(token);
                        dataRow.add(value);
                    }
                }
            }
        }
        return dataRow;
    }

}

The GUI looks like:

在此处输入图片说明


Now for some explanation:

OK, what this code does:

First I use an external image, one that is freely available from Wikipedia / Wikimedia, so that my code can be run from any computer and demonstrate the use of images in a JPanel. The image path can be found here:

private static final String IMG_PATH = "https://upload.wikimedia.org/"
        + "wikipedia/commons/d/d1/Ozanne-Brest.jpg";

and it's used here to create an image:

        URL imageUrl = new URL(IMG_PATH);
        img = ImageIO.read(imageUrl);

Which is then drawn within the JPanel's paintComponent method:

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    if (img != null) {
        g.drawImage(img, 0, 0, this);
    }
}

My code also extends JPanel as this gives my GUI programs much greater flexibility than they'd have if I extended JFrame:

public class TableFun extends JPanel {

I override the JPanel's getPreferredSize method so that it sizes to the image, unless it needs to be bigger. That's why I first get the super's preferred size, and try to make my GUI big enough to show the image, and bigger if it needs to be to show more components:

@Override
public Dimension getPreferredSize() {
    Dimension superSize = super.getPreferredSize();
    if (isPreferredSizeSet() || img == null) {
        return superSize;
    }
    int supW = superSize.width;
    int supH = superSize.height;
    int imgW = img.getWidth();
    int imgH = img.getHeight();
    int w = Math.max(imgW, supW);
    int h = Math.max(imgH, supH);
    return new Dimension(w, h);
}

In order to simplify code, I try to separate code from data, and place my data inside of a text file. The DataIO class is a small utility class that exists to read in the text held by the file, and then to parse the data line by line to create and fill a DefaultTableModel object. Note that I get the file not as a "File" but rather as a class resource, since this way I can include it within the jar file if I desire to do so. I use a Scanner to read in each line, exactly as you'd do for a text file.

public TableModel createTableModel() throws IOException {
    InputStream inputStream = getClass().getResourceAsStream(dataPath);
    Scanner scanner = new Scanner(inputStream);

Once I get a line of text, I split it by white space, which creates an array of Strings with all the white space trimmed off:

String[] tokens = line.split("\\s+");

The JTable uses a table cell renderer called MyCellRenderer

table.setDefaultRenderer(Object.class, new MyCellRenderer());

that makes the cells opaque if they hold data, and non-opaque (clear) if they hold null values:

renderer.setOpaque(value != null);

I also make sure that the JTable itself, the JScrollPane and the scrollpane's viewport are all non-opaque, so that the image can show through:

    table.setOpaque(false);

    // ....

    scrollPane.setOpaque(false);
    scrollPane.getViewport().setOpaque(false);

You mention a NPE being thrown, which likely means that your Java program is not finding the text file. Again it must be placed with your class files. You should create a text file with Eclipse in the same directory as your java file , name it precisely TableFunData.txt (spelling and capitalization matter), and when you're done, Eclipse should look something like:

在此处输入图片说明

where the code and the data text are seen in the same package using Eclipse's package explorer (highlighted in blue and red), and the code's package statement should show that it is in fact inside this package (in green).

Here is a simple implementation of JTable, as @Hovercraft Full Of Eels suggested. Background colors are rendered based on data. 1 will cause background color to be blue, while 0 will render as red. (The demo is based on https://docs.oracle.com/javase/tutorial/displayCode.html?code=https://docs.oracle.com/javase/tutorial/uiswing/examples/components/SimpleTableDemoProject/src/components/SimpleTableDemo.java )

public class TableDemo extends JPanel {

    public TableDemo() {
        super(new GridLayout(1,0));

        String[] columnNames = {"         ",
                "Main Hand",
                "Off Hand",
                "Head",
                "Shoulder",
        "Neck"};

        Object[][] data = {
                {"Weapon Attacks Per Second", new Integer(1), new Integer(0), new Integer(0),new Integer(0),new Integer(0)},
                {"Attack Speed", new Integer(1), new Integer(0), new Integer(1),new Integer(0),new Integer(0)},
                {"Damage%", new Integer(1), new Integer(0), new Integer(0),new Integer(0),new Integer(0)},
                {"Min Bonus Damage", new Integer(1), new Integer(0), new Integer(0),new Integer(1),new Integer(0)},
                {"Max Bonus Damage", new Integer(1), new Integer(1), new Integer(0),new Integer(0),new Integer(0)},
                {"Min Weapon Damage", new Integer(1), new Integer(0), new Integer(0),new Integer(1),new Integer(0)},
                {"Max Weapon Damage", new Integer(1), new Integer(0), new Integer(1),new Integer(0),new Integer(0)},
        };

        final JTable table = new JTable(data, columnNames);
        table.setPreferredScrollableViewportSize(new Dimension(600, 70));


        table.getColumnModel().getColumn(1).setCellRenderer(new ColorRenderer());
        table.getColumnModel().getColumn(2).setCellRenderer(new ColorRenderer());
        table.getColumnModel().getColumn(3).setCellRenderer(new ColorRenderer());
        table.getColumnModel().getColumn(4).setCellRenderer(new ColorRenderer());
        table.getColumnModel().getColumn(5).setCellRenderer(new ColorRenderer());

        //Create the scroll pane and add the table to it.
        JScrollPane scrollPane = new JScrollPane(table);

        //Add the scroll pane to this panel.
        add(scrollPane);
    }

    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("TableDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        TableDemo newContentPane = new TableDemo();
        newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);

        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

class ColorRenderer extends DefaultTableCellRenderer {

    public ColorRenderer() {

        setOpaque(true); //MUST do this for background to show up.
    }

    @Override
    public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected,
            boolean hasFocus,int row, int column) {
        if((int)value == 1) {
            setBackground(Color.BLUE);
        }else {
            setBackground(Color.RED);
        }

        return this;
    }
}

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM