java - 在单独的方法/类中声明时,JLabels 和 TextFields 不会出现

标签 java swing jpanel jlabel textfield

我在使 JLabels 和 textFields 显示在 JPanel 上时遇到一些问题。 如果我将所有这些代码放在主方法中,它可以正常工作,但是当我将 JLabels 和 TextFields 移动到它们自己的方法或类中时,JPanel 仍然为空。显示了我使用的图像。

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]);
            }
        }
    }
}

实际代码为 JPanel 提供了更多内容,但这会产生完全相同的结果。

最佳答案

稍后我将不得不解释此代码和此答案,但它显示:

  1. 从文本文件获取数据并从中创建表格模型
  2. 创建并显示包含不透明空单元格的 JTable
  3. 在 JPanel 中显示背景图像

数据文件是这样的:

                        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

它必须命名为 TableFunData.txt 并且与代码位于同一目录/包中。

代码是:

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;
    }

}

GUI 看起来像:

enter image description here

<小时/>

现在进行一些解释:

好的,这段代码的作用是:

首先,我使用外部图像,该图像可以从 Wikipedia/Wikimedia 免费获取,以便我的代码可以从任何计算机运行并演示 JPanel 中图像的使用。图片路径可以在这里找到:

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

这里用它来创建图像:

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

然后在 JPanel 的 PaintComponent 方法中进行绘制:

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

我的代码还扩展了 JPanel,因为这为我的 GUI 程序提供了比扩展 JFrame 更大的灵 active :

public class TableFun extends JPanel {

我重写 JPanel 的 getPreferredSize 方法,以便其大小适合图像,除非它需要更大。这就是为什么我首先获得 super 的首选尺寸,并尝试使我的 GUI 足够大以显示图像,如果需要显示更多组件则更大:

@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);
}

为了简化代码,我尝试将代码与数据分开,并将数据放在文本文件中。 DataIO 类是一个小型实用程序类,用于读取文件保存的文本,然后逐行解析数据以创建并填充 DefaultTableModel 对象。请注意,我获取的文件不是作为"file",而是作为类资源,因为这样,如果我愿意,我可以将其包含在 jar 文件中。我使用扫描仪读取每一行,就像读取文本文件一样。

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

一旦我得到一行文本,我就用空格分割它,这会创建一个字符串数组,所有空格都被修剪掉:

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

JTable 使用名为 MyCellRenderer 的表格单元格渲染器

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

如果单元格包含数据,则单元格不透明;如果单元格包含空值,则单元格不透明(透明):

renderer.setOpaque(value != null);

我还确保 JTable 本身、JScrollPane 和滚动 Pane 的视口(viewport)都是非透明的,以便图像可以显示:

    table.setOpaque(false);

    // ....

    scrollPane.setOpaque(false);
    scrollPane.getViewport().setOpaque(false);
<小时/>

您提到抛出了 NPE,这可能意味着您的 Java 程序找不到文本文件。同样,它必须与您的类文件放在一起。您应该使用 Eclipse 在与 java 文件相同的目录中创建一个文本文件,将其精确命名为 TableFunData.txt(拼写和大小写很重要),然后完成后,Eclipse 应该类似于:

enter image description here

使用 Eclipse 的包资源管理器可以在同一个包中看到代码和数据文本(以蓝色和红色突出显示),并且代码的包声明应该显示它实际上位于该包内(以绿色显示)。

关于java - 在单独的方法/类中声明时,JLabels 和 TextFields 不会出现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37630082/

相关文章:

java - 如何将请求从同一个 JSP 文件发送到多个 Servlet?

java - JFrame : Printing not working with malayalam text

Java 在一帧中绘制线条

Java JFrame 方法 pack()

java - 使用 JPA 存储库查询三个属性

java - 是否可以获得该对象的名称?

java - java中循环梯度和非循环梯度的区别

java - (java) 应用程序启动时 GUI 偶尔卡住

java - 在 Nimbus LaF 中更改 JButton 的默认键值

java - 使用 Java Swing 和 AWT 获得完全相同的代码的不同输出