【问题标题】:2D array of ImageIcon's displays inconsistently and only partially in JPanelImageIcon 的二维数组显示不一致且仅部分显示在 JPanel 中
【发布时间】:2019-07-16 02:22:36
【问题描述】:

我正在尝试使用 ImageIcons、JLabels 和 JPanel 创建一个充满 16x16 地砖的屏幕。我的问题是,每当我尝试使用 2D 数组显示这些图块时——即使重复循环绘制方法——它们也不会完全显示。相反,它们只显示几个图块,而不是完整的数组值。此外,每次运行程序时,显示的图块数量都会发生变化!

这是我正在使用的代码:

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class JFrameTest {

    static BufferedImage buf;
    static JPanel panel;


    public static void main(String[] args) {
        createWindow();
        loadImage();
        showImage();
    }



    public static void createWindow() {
        JFrame frame = new JFrame();
        panel = new JPanel();
        frame.setSize(1000, 1000);
        frame.setTitle("Tester");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.add(panel);
        frame.setVisible(true);
        panel.setLayout(null);

    }




    public static void loadImage() {
        try {
            buf = ImageIO.read(new File("res/test.png"));
        } catch (IOException ex) {
            System.out.println("NOT FOUND");
        }

    }

    public static void showImage() {

        final int[][] MAP =
                {
                        {1, 1, 1, 1, 1, 1, 1, 1, 1},
                        {1, 1, 1, 1, 1, 1, 1, 1, 1},
                        {1, 1, 1, 1, 1, 1, 1, 1, 1},
                        {1, 1, 1, 1, 1, 1, 1, 1, 1},
                        {1, 1, 1, 1, 1, 1, 1, 1, 1},
                        {1, 1, 1, 1, 1, 1, 1, 1, 1},
                        {1, 1, 1, 1, 1, 1, 1, 1, 1},
                        {1, 1, 1, 1, 1, 1, 1, 1, 1},
                        {1, 1, 1, 1, 1, 1, 1, 1, 1},
                        {1, 1, 1, 1, 1, 1, 1, 1, 1}
                };

        ImageIcon test = new ImageIcon(buf);

        panel.setBackground(Color.WHITE);
        System.out.println(test.getIconWidth());
        System.out.println(test.getIconHeight());

        JLabel[][] labelGrid = new JLabel[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].setSize(test.getIconWidth(), test.getIconWidth());
                labelGrid[r][c].setLocation(test.getIconWidth() * r, test.getIconHeight() * c);
                labelGrid[r][c].setIcon(test);
                panel.add(labelGrid[r][c]);
            }
        }
        panel.revalidate();
    }

}

这里是关于通常打印的内容:

似乎程序只是放弃了显示图像。但是,请注意,每次显示的图像数量都会发生变化!有时可能只出现 5 张图像,有时 22 张。

当我尝试使用较小的地图时,例如:,

final int[][] MAP =
                {
                        {1, 1, 1},
                        {1, 1, 1},
                        {1, 1, 1}
                };

整个 3x3 网格的图像将显示大约一半的时间,另一半只显示一到两个图像。

可以实施哪些变通方法来解决此问题?

电脑规格:

Windows 10

i8-8700

1080 钛

16GB 内存

【问题讨论】:

  • panel.setLayout(null); ???? ...这将使panel.revalidate()变得多余
  • 如果你不想使用布局管理器,使用自定义绘画路线可能会更好
  • 就布局管理器而言,GridLayout 可能是此 GUI 的最佳选择。但除了@MadProgrammer 的建议外,请注意,设置顶级容器可见,应该在所有组件添加之后完成。

标签: java swing multidimensional-array jframe jpanel


【解决方案1】:

你的基本问题是误解之一......欢迎来到我的世界?

使用panel.setLayout(null); 意味着您对布局承担全部责任,这很好,当您知道自己在做什么时。

在您建立 UI 之前调用 setVisible 并使用用于运行布局传递的 revalidate 将其组合起来,这样您就会遇到麻烦。

您应该使用 repaint 而不是 revalidate,来触发新的绘制通道(注意,在正常的事件过程中,您应该在更新 UI 时同时使用这两者,但由于您不再使用布局管理器,你不需要revalidate)

可能更好的解决方案是使用自定义绘画路线,例如...

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static class TestPane extends JPanel {

        protected static final int[][] MAP
                = {
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1}
                };
        protected static Dimension GRID_SIZE = new Dimension(20, 20);
        private Rectangle buf; // This represents your image

        private Dimension preferredSize;
        public TestPane() {
            buf = new Rectangle(0, 0, GRID_SIZE.width, GRID_SIZE.height);

            int max = 0;
            for (int row = 0; row < MAP.length; row++) {
                max = Math.max(max, MAP[row].length);
            }
            preferredSize = new Dimension(GRID_SIZE.width * MAP.length, GRID_SIZE.height * max);
        }

        @Override
        public Dimension getPreferredSize() {
            return preferredSize;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            for (int row = 0; row < MAP.length; row++) {
                for (int col = 0; col < MAP[row].length; col++) {
                    int x = GRID_SIZE.width * row;
                    int y = GRID_SIZE.height * col;
                    Graphics2D translated = (Graphics2D) g2d.create();
                    translated.translate(x, y);
                    translated.draw(buf);
                    translated.dispose();
                }
            }
            g2d.dispose();
        }

    }
}

GridLayout

另一种选择是使用GridLayout

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static class TestPane extends JPanel {

        protected static final int[][] MAP
                = {
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1}
                };
        protected static Dimension GRID_SIZE = new Dimension(20, 20);
        private BufferedImage buf; // This represents your image

        public TestPane() {
            int max = 0;
            for (int row = 0; row < MAP.length; row++) {
                max = Math.max(max, MAP[row].length);
            }

            setLayout(new GridLayout(MAP.length, max));

            buf = makeBuffer();
            for (int row = 0; row < MAP.length; row++) {
                for (int col = 0; col < MAP[row].length; col++) {
                    add(new JLabel(new ImageIcon(buf)));
                }
            }
        }

        protected BufferedImage makeBuffer() {
            BufferedImage img = new BufferedImage(GRID_SIZE.width, GRID_SIZE.height, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2d = img.createGraphics();
            g2d.setColor(Color.DARK_GRAY);
            g2d.drawRect(0, 0, img.getWidth() - 1, img.getHeight() - 1);
            g2d.dispose();
            return img;
        }

    }
}

但这会调整单元格的大小,这可能不适合您使用 ...

GridBagLayout

这将更好地尊重组件的首选大小,并且根据当前配置的方式,当窗口大小发生变化时不会调整组件大小

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static class TestPane extends JPanel {

        protected static final int[][] MAP
                = {
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1},
                    {1, 1, 1, 1, 1, 1, 1, 1, 1}
                };
        protected static Dimension GRID_SIZE = new Dimension(20, 20);
        private BufferedImage buf; // This represents your image

        public TestPane() {
            int max = 0;
            for (int row = 0; row < MAP.length; row++) {
                max = Math.max(max, MAP[row].length);
            }

            setLayout(new GridBagLayout());

            buf = makeBuffer();
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridy = 0;
            for (int row = 0; row < MAP.length; row++) {
                gbc.gridx = 0;
                for (int col = 0; col < MAP[row].length; col++) {
                    add(new JLabel(new ImageIcon(buf)), gbc);
                    gbc.gridx++;
                }
                gbc.gridy++;
            }
        }

        protected BufferedImage makeBuffer() {
            BufferedImage img = new BufferedImage(GRID_SIZE.width, GRID_SIZE.height, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2d = img.createGraphics();
            g2d.setColor(Color.DARK_GRAY);
            g2d.drawRect(0, 0, img.getWidth() - 1, img.getHeight() - 1);
            g2d.dispose();
            return img;
        }

    }
}

【讨论】:

  • 感谢您不仅提供了详尽的答案,还感谢您提供了如此多的有用知识!但是,我不得不问 - 为什么要为许多变量添加受保护的和静态的?在我的测试中,没有这些修饰符它工作得很好。
  • 首先,它们仅在TestPane 的上下文中才有意义,我认为不需要任何其他类来访问/修改它们,其次,它们永远不会改变(或者永远不应该改变),所以它们可以是static,这样可以节省一点内存,但说明了你应该如何使用它们的意图;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-03
  • 1970-01-01
  • 2017-05-04
  • 1970-01-01
  • 2011-05-26
  • 1970-01-01
相关资源
最近更新 更多