【问题标题】:JLabel images arrayJLabel 图像数组
【发布时间】:2012-07-18 04:50:59
【问题描述】:

我试图将相同的 jlabel 存储图像两次加载到网格布局面板中,但是不是创建图像的两个实例,而是图像仅显示一次然后移动。

如何将pieces数组中相同的JLabel位置存储到boardLabels数组中的多个JLabel中。

谢谢:)

public static JPanel boardPanel = new JPanel(new GridLayout(4, 0));
public static JLabel pieces[] = new JLabel[2];
private static JLabel[] boardLabels = new JLabel[4];

public MainFrame() {
    pieces[0] = new JLabel(new ImageIcon(System.getProperty("user.dir") + "/images/piece1.png"));
    pieces[1] = new JLabel(new ImageIcon(System.getProperty("user.dir") + "/images/piece2.png"));

    this.add(boardPanel);
    displayGUIboard();
}


public static void displayGUIboard() {

    //ERROR - the label in pieces[0] is not copied into both boardLabels [0] and [1]
    boardLabels[0] = pieces[0];
    boardLabels[1] = pieces[0];

    boardPanel.add(boardLabels[0]);
    boardPanel.add(boardLabels[1]);
}

public static void main(String[] args) {
    MainFrame frame = new MainFrame();
    frame.setVisible(true);
    frame.setSize(600, 600);
    frame.setLocationRelativeTo(null);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

这行得通

    boardLabels[0] = new JLabel(pieces[1]);
    boardLabels[1] = new JLabel(pieces[1]);

使用 ImageIcons 时,但我想避免这种情况,因为要更新电路板,我必须删除然后重新加载 JLabels。我宁愿只更新已经加载的标签。

编辑 我之前试过这个,但是它抛出了一个空指针异常......

    boardLabels[0].setIcon(pieces[1]);
    boardLabels[1].setIcon(pieces[1]);

    boardPanel.add(boardLabels[0]);
    boardPanel.add(boardLabels[1]);

【问题讨论】:

  • 从相对于user.dir 的路径获取应用程序资源是非常脆弱的。由于这些图像显然是应用程序固有的,因此应将它们作为 embedded resource 添加到 Jar 中。

标签: java swing jlabel imageicon


【解决方案1】:

为了比较,我重新分解了@HFOE 的example,以便Ground implements Icon 并索引values() 返回的数组。由于value 是一个实现细节,所以int[][] MAP 可以改为Ground[][] MAP

更新:此变体说明了Ground[][] MAP 并添加了TexturePaint

import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.TexturePaint;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.*;

/** @see https://stackoverflow.com/a/11556441/230513 */
public class GridExample extends JPanel {

    public static final Ground[][] MAP = {
        {Ground.GRASS, Ground.GRASS, Ground.DIRT, Ground.WATER, Ground.WATER},
        {Ground.GRASS, Ground.DIRT, Ground.CITY, Ground.WATER, Ground.WATER},
        {Ground.GRASS, Ground.DIRT, Ground.CITY, Ground.WATER, Ground.WATER},
        {Ground.GRASS, Ground.DIRT, Ground.DIRT, Ground.DIRT, Ground.WATER},
        {Ground.GRASS, Ground.GRASS, Ground.DIRT, Ground.WATER, Ground.WATER},
    };
    private JLabel[][] labelGrid = new JLabel[MAP.length][MAP[0].length];

    public GridExample() {
        setLayout(new GridLayout(MAP.length, MAP[0].length));
        for (int r = 0; r < labelGrid.length; r++) {
            for (int c = 0; c < labelGrid[r].length; c++) {
                labelGrid[r][c] = new JLabel();
                labelGrid[r][c].setIcon(MAP[r][c]);
                add(labelGrid[r][c]);
            }
        }
    }

    private static void createAndShowGui() {
        GridExample mainPanel = new GridExample();
        JFrame frame = new JFrame("GridExample");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(mainPanel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                createAndShowGui();
            }
        });
    }
}

enum Ground implements Icon {

    DIRT(new Color(205, 133, 63)), GRASS(new Color(0, 107, 60)),
    WATER(new Color(29, 172, 214)), CITY(Color.lightGray);
    private static final int SIZE = 42;
    private Random random = new Random();
    private TexturePaint paint;

    private Ground(Color color) {
        this.paint = initPaint(color);
    }

    private TexturePaint initPaint(Color color) {
        BufferedImage image = new BufferedImage(
            SIZE, SIZE, BufferedImage.TYPE_INT_ARGB);
        Rectangle2D.Double rect = new Rectangle2D.Double(0, 0, SIZE, SIZE);
        for (int row = 0; row < SIZE; row++) {
            for (int col = 0; col < SIZE; col++) {
                if (random.nextBoolean()) {
                    image.setRGB(col, row, color.getRGB());
                } else {
                    if (random.nextBoolean()) {
                        image.setRGB(col, row, color.darker().getRGB());
                    } else {
                        image.setRGB(col, row, color.brighter().getRGB());
                    }
                }
            }
        }
        return new TexturePaint(image, rect);
    }

    @Override
    public void paintIcon(Component c, Graphics g, int x, int y) {
        Graphics2D g2d = (Graphics2D) g;
        g2d.setPaint(paint);
        g.fillRect(0, 0, SIZE, SIZE);
    }

    @Override
    public int getIconWidth() {
        return SIZE;
    }

    @Override
    public int getIconHeight() {
        return SIZE;
    }
}

【讨论】:

    【解决方案2】:

    不要这样做,因为您不能将同一个组件多次添加到可视化容器中。最好使用多个 JLabel,但让它们使用相同的 ImageIcon。 ImageIcons 可以轻松地多次使用:

    public MainFrame() {
        pieceIcon[0] = new ImageIcon(System.getProperty("user.dir") + 
            "/images/piece1.png");
        pieceIcon[1] = new ImageIcon(System.getProperty("user.dir") + 
            "/images/piece2.png");
    
        this.add(boardPanel);
        displayGUIboard();
    }
    
    
    public void displayGUIboard() {
        boardPanel.add(new JLabel(pieceIcon[0]);
        boardPanel.add(new JLabel(pieceIcon[0]);
    }
    

    顺便说一句:请注意,none 变量应该是静态的。

    编辑:关于您最近的编辑:

    这行得通

    boardLabels[0] = new JLabel(pieces[1]);
    boardLabels[1] = new JLabel(pieces[1]);
    

    使用 ImageIcons 时,但我想避免这种情况,因为要更新电路板,我必须删除然后重新加载 JLabels。我宁愿只更新已经加载的标签。”

    解决方案
    不,您根本不必更改 JLabels。将您的 JLabel 保留在原处,但只需使用 JLabel setIcon(...) 方法交换它们持有的图标。

    编辑
    另外,不要将变量与对象混淆。即使您创建了一堆 JLabel 变量,如果它们都引用同一个 JLabel 对象,您仍然不能将 JLabel 对象多次添加到容器中。

    编辑您说:

    代码是游戏显示功能的一部分。一个整数数组将代表被解释的棋盘(但不是在上面的代码中),正确的 Jlabel 图像将被放置到 gridlayout 面板中以显示棋盘的 gui。我已经让显示代码正常工作,但是在我当前的版本中,它从板上删除了 jlabels,然后创建了新的 JLabels(piece...)...但我更希望它从整数数组中更新自身而不是删除标签,读取数组,然后重新创建标签。

    所以创建一个使用 GridLayout 的 JPanel 并用不变的 JLabels 填充它。然后只需根据 int 数组保存的值更改 JLabels 保存的图标。您可以创建一种方法来简化和自动化此过程。

    编辑关于:

    edit 我之前试过这个,但是它抛出了一个空指针异常。

    然后像解决任何 NPE 一样解决这个问题。找出哪一行抛出NPE,检查该行的变量,至少有一个为null,然后修复它,以便在尝试使用之前初始化变量。

    编辑
    例如:

    import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.GridLayout;
    import java.awt.image.BufferedImage;
    
    import javax.swing.*;
    
    @SuppressWarnings("serial")
    public class GridExample extends JPanel {
       public static final int[][] MAP = {
          {1, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2},
          {1, 1, 0, 0, 2, 2, 2, 2, 2, 2, 2},
          {1, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2},
          {1, 1, 1, 0, 0, 2, 2, 2, 2, 2, 2},
          {1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 2},
          {1, 1, 1, 0, 0, 0, 2, 2, 2, 2, 2},
          {1, 1, 0, 0, 0, 2, 2, 2, 2, 2, 2},
          {1, 1, 1, 0, 0, 0, 2, 2, 2, 2, 2},
          {1, 1, 1, 1, 1, 0, 0, 0, 0, 2, 2},
          {1, 1, 1, 1, 1, 0, 0, 0, 2, 2, 2},
          {1, 1, 1, 1, 1, 1, 0, 0, 0, 2, 2}
       };
    
       public static final Color[] COLORS = {};
       private JLabel[][] labelGrid = new JLabel[MAP.length][MAP[0].length];
    
       public GridExample() {
          setLayout(new GridLayout(MAP.length, MAP[0].length));
          for (int r = 0; r < labelGrid.length; r++) {
             for (int c = 0; c < labelGrid[r].length; c++) {
                labelGrid[r][c] = new JLabel();
                labelGrid[r][c].setIcon(Ground.getGround(MAP[r][c]).getIcon());
                add(labelGrid[r][c]);            
             }
          }
       }
    
       private static void createAndShowGui() {
          GridExample mainPanel = new GridExample();
    
          JFrame frame = new JFrame("GridExample");
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.getContentPane().add(mainPanel);
          frame.pack();
          frame.setLocationByPlatform(true);
          frame.setVisible(true);
       }
    
       public static void main(String[] args) {
          SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                createAndShowGui();
             }
          });
       }
    }
    
    enum Ground {
       DIRT(0, new Color(205,133, 63)), GRASS(1, new Color(0, 107, 60)), 
       WATER(2, new Color(29, 172, 214));
       private int value;
       private Color color;
       private Icon icon;
    
       private Ground(int value, Color color) {
          this.value = value;
          this.color = color;
    
          icon = createIcon(color);
       }
    
       private Icon createIcon(Color color) {
          int width = 24; // how to use const in enum? 
          BufferedImage img = new BufferedImage(width, width, BufferedImage.TYPE_INT_ARGB);
          Graphics g = img.getGraphics();
          g.setColor(color);
          g.fillRect(0, 0, width, width);
          g.dispose();
          return new ImageIcon(img);
       }
    
       public int getValue() {
          return value;
       }
    
       public Color getColor() {
          return color;
       }
    
       public Icon getIcon() {
          return icon;
       }
    
       public static Ground getGround(int value) {
          for (Ground ground : Ground.values()) {
             if (ground.getValue() == value) {
                return ground;
             }
          }
          return null;
       }
    
    }
    

    显示 GUI 网格:

    【讨论】:

    • 我在 boardLabel 数组中创建了多个 JLabel,但由于无法将片段数组中的 Jlabel 添加两次,因此没有从片段数组中为这些 JLabel 分配相同的 JLabel,对吗?
    • 因此不可能更新一定数量的 JLabel,因为它们都指向同一个对象,但不起作用。
    • 代码是游戏显示功能的一部分。一个整数数组将代表被解释的棋盘(但不是在上面的代码中),正确的 Jlabel 图像将被放置到 gridlayout 面板中以显示棋盘的 gui。我已经让显示代码正常工作,但是在我当前的版本中,它从板上删除了 jlabels,然后创建了新的 JLabels(piece...)...但我更希望它从整数数组中更新自身而不是删除标签,读取数组,然后重新创建标签。
    • 已修复!我没有将初始 JLabels 添加到 boardLabels 数组中。谢谢气垫船。
    • @user1334130:请参阅编辑以获取显示我所描述内容的示例代码。
    猜你喜欢
    • 2013-07-03
    • 1970-01-01
    • 2015-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多