【问题标题】:How to combine images in a JFrame?如何在 JFrame 中组合图像?
【发布时间】:2020-06-06 16:08:11
【问题描述】:

我一直在做一个项目,该项目显示 16 x 16 的图像网格,根据用户交互,该网格在动态更大的基础上跟随用户(例如,50 x 50 的基础)比16 x 16 显示屏。 但是,我使用JLabel 组件来显示这些图像,并且每次用户交互时,我都必须移动 256 个图像中的每一个,并删除那些不再在 16 x 16 显示网格中的图像。这导致每次按键时的延迟接近一秒,并且接近于无法正常工作。

我希望尝试做的是在地面的总宽度中将这些图像链接在一起,并将焦点移动到 16 x 16 网格内的部分,从而使该过程不再需要使用嵌套用于显示的 for 循环。

我是否可以动态存储和创建这些链接图像以使用标签显示?是否有其他方法可以在 Java 中显示 .png 文件,并且可以以类似的方式存储和使用?

我当前在每次用户交互时都必须绘制每张图像的方法示例:

User user = game.user;

int floorWidth = game.floorWidth;
int floorHeight = game.floorHeight;

int pX = user.getTile().getX();
int pY = user.getTile().getY();

int minX = Math.max(pX - GameConstants.USER_DRAW_DISTANCE, 0);
int maxX = Math.min(floorWidth, pX + GameConstants.USER_DRAW_DISTANCE);

int minY = Math.max(pY - GameConstants.USER_DRAW_DISTANCE, 0);
int maxY = Math.min(floorHeight, pY + GameConstants.USER_DRAW_DISTANCE);
for (int i = minY; i < maxY; i++)
{
  for (int x = minX; x < maxX; x++)
  {
    Tile tile = floor.getTile(x, i);
    if (tile.getHasSeen())
    {
      JLabel cLabel = tile.imageLabel;
      cLabel.setLocation(340 + x * 32, 140 + i * 32);
      cLabel.setSize(64, 64);
      cLabel.setVisible(true);
      panel.add(cLabel, 1);
    }
  }
}

【问题讨论】:

  • 避免创建和添加新的 JLabels,而只需更改当前 JLabels 中的图像图标。如果您经常读取图像文件,请避免这样做,如果可能,将图像读入图像图标一次并保存。如需更多帮助,请考虑创建并发布一个minimal reproducible example 计划并提出您的问题。
  • 我觉得JScrollPane 在这里很合适。创建一个大的JPanel 并将您所有的JLabels 放在上面。然后将JPanel 设为JScrollPane 的可滚动客户端,并将JScrollPane 的首选大小设置为足够大以显示您的16x16 网格。
  • 除了使用 JScrollPane 进行滚动外,您还可以使用带有 GridLayout 的 JPanel,您可以将网格配置为在 16 个图像处自动换行。阅读 How to Use GridLayout 上的 Swing 教程。不要尝试设置组件的大小/位置。布局管理器的工作是设置大小/位置。另一种选择是使用 JList 并将 ImageIcons 添加到列表中。该列表也可以配置为换行。该教程还有一个关于How to Use Lists的部分。
  • 另一种方法是将您的图像用作图块。这是一个例子。 stackoverflow.com/questions/30004538/…

标签: java image swing nested-loops jlabel


【解决方案1】:

原则上你的想法应该可行。所以你可能做错了什么。

我做了一个示例,它显示了 256x256 个 JLabels 中的一个 16x16 正方形的 JLabels。当您将鼠标移到面板上时,它会更改布局以显示一组新的 16x16 JLabel。变化非常快,绝对不会延迟 1 秒。

import javax.swing.*;
import java.awt.EventQueue;
import java.awt.Dimension;
import java.awt.Color;
import java.awt.event.*;
import java.util.*;

public class GridViewer{
    int x0, y0;
    int N = 256;
    int display = 16;
    int length = 32;
    List<JLabel> showing = new ArrayList<>();
    List<JLabel> available = new ArrayList<>();
    JPanel panel = new JPanel(){
        Dimension sz = new Dimension(length*display, length*display);
        @Override
        public Dimension getPreferredSize(){
            return sz;
        }
    };
    public void showGui(){
        JFrame frame = new JFrame();
        panel.setLayout(null);

        panel.addMouseMotionListener( new MouseAdapter(){
            Random r = new Random();
            @Override
            public void mouseMoved(MouseEvent evt){
                int x = evt.getX();
                int y = evt.getY();
                //map to position on the image to the position on the grid.
                x0 = x/2;
                x0 = Math.min(x0, N-display);

                y0 = y/2;
                y0 = Math.min(y0, N-display);
                updateLayout();
            }
        });

        for(int i = 0; i<N*N; i++){
            available.add(createItem(i));
        }

        updateLayout();

        frame.setContentPane(panel);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
    /**
     * Creates a solid color jlabel, could be used to load an image
     * as an icon.
     **/
    JLabel createItem(int i){
        JLabel l = new JLabel("");
        int r = (i/256);
        int g = (0)&255;
        int b = (i%256);
        int c = (r << 16 ) + ( g << 8 ) + b;
        l.setBackground(new Color(c));
        l.setOpaque(true);
        l.setSize(length, length);

        return l;
    }
    public void updateLayout(){
        for(JLabel l: showing){
            panel.remove(l);
        }

        for(int i = 0; i<display; i++){
            for(int j = 0; j<display; j++){
                JLabel l = available.get((i + x0) + (j+y0)*N);
                panel.add(l);
                l.setLocation( i*length, j*length);
                showing.add(l);
            }
        }        
    }
    public static void main(String[] args){
        EventQueue.invokeLater( () -> new GridViewer().showGui() );

    }
}

一些变化。

使用网格布局

使用布局管理器有很多优点。尤其是在使用不同的显示器、字体和平台时?添加和删​​除元素时,可能会使部分显示元素变得困难。

使用带有 ScrollPane 的大型 JPanel

我们可以创建一个单一的 JPanel 并向其中添加所有 256x256 的组件,然后使用滚动窗格来设置视图。这将具有完全分离布局和视图的优点。有人想要一个更大的窗口,你不必改变布局,视图变得更大,你只看到更多的布局。对于 256x256 组件,它应该表现良好,但如果您有太多组件,您可能需要重新考虑它。

使用 JPanel 并覆盖paintComponent

这将涉及将您的“png”文件加载为 awt Images(可能是 BufferedImages)并使用图形对象绘制它们。您需要处理所有的布局和渲染。它为您提供了相当多的权力来决定如何渲染您的组件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-20
    • 2012-10-13
    • 1970-01-01
    • 2015-07-23
    • 1970-01-01
    • 2013-09-23
    • 2020-11-22
    • 1970-01-01
    相关资源
    最近更新 更多