2

我正在编写一个程序,部分只是为了好玩,部分是为了帮助我处理一堆我想划分为打印类别的数字图片。主要思想是它应该在单列中显示图片,并在每张图片旁边有一组带有类别名称的复选框。我检查了所需的复选框,按“开始!” 按钮,图片会被复制到子文件夹中,具体取决于所选的复选框。

现在,一切都差不多完成了——除了一件事。有问题的图片是大 jpg,每张大约 7-8MB,大约有 700 张。如果我尝试一次全部加载它们,自然地,将它们全部加载需要大量的内存和时间。那么,有没有很好的解决问题的办法呢?我的两个想法如下。

1) 一次加载 10 张图片并在某处设置下一个/上一个按钮。我不喜欢这个想法,因为它添加了不需要的元素。2)让应用程序在您滚动到新图片时加载它们并卸载您滚动过去的那些。我真的喜欢这个主意。

有人可以为我指出正确的方向,至于我如何实施后一个想法吗?我只在 Google 上找到了一个相关链接,但我不能说它对我有帮助,我对代码的某些部分感到有些困惑。

4

4 回答 4

2

如果缩略图就足够了,这个答案包括一个简单的重采样方法,并引用了一些权衡。如果没有,此答案概述了显示和缓存最近图像的一般方法。

在任何一种情况下,默认的Boolean 渲染器/编辑JTable器都是JCheckBox. CheckOne是一个例子。

于 2012-11-25T00:10:20.767 回答
1

您必须为所有图片创建缩略图,您可以将缩略图保存在内存中。这可能需要很多时间。

然后你要么准备好了pronblem。否则缩略图将无法全部放入内存。如果是这种情况:您加载其中的 30-40 个,在滚动期间您检测滚动方向,并将下一组加载到单独的线程中。

如果加载速度比用户滚动速度慢,那么您将为此类“尚未加载的图片”显示默认占位符图像

于 2012-11-25T01:11:00.580 回答
0

如果这是一个“使用一次就扔掉”的程序,我不会费心去解决这个问题。我会使用命令行为每张图片生成缩略图,并在我的程序中使用这些生成的缩略图。在内存中保留 700 个缩略图应该是可行的。

如果这不是一个选项,我会从JTable. 您可以创建一个TableModel而无需将所有图像加载到内存中。你只需要知道图像数量。将JTable只想渲染当时可见的图像。需要注意的是,在渲染器请求图像时加载图像可能为时已晚。我可以想象,JTable当您必须加载几 MB 大小的图像时,它不会顺利运行。但这可能可以通过使用填充有工作线程的缓存来解决。因此,如果渲染器请求第 5 张图像,您还将前 5 张图像和后 5 张图像加载到缓存中。

另请注意,如果您正在移动图片 iso 复制它们,这可能会影响您TableModel,因为目录中的图像数量会发生变化。一定要考虑到这一点!

于 2012-11-25T07:11:06.943 回答
0

您可以缩小所有图像以使用更少的 RAM。例如,此代码将所有图像缩小到 200x200。这样,您可以在 100MB 中容纳 1000 张图像。

import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import javax.imageio.ImageIO;
import java.io.File;

public class Scroll extends JPanel {
    public static void main(String[] args) throws Exception {
        JFrame frame = new JFrame();
        JPanel panel = new Scroll();

        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

        for(int i = 0; i < 10; i++) {
            JPanel buttonPanel = new JPanel();
            JRadioButton b1 = new JRadioButton("button 1");
            JRadioButton b2 = new JRadioButton("button 2");
            JRadioButton b3 = new JRadioButton("button 3");
            ButtonGroup group = new ButtonGroup();
            group.add(b1);
            group.add(b2);
            group.add(b3);
            buttonPanel.add(b1);
            buttonPanel.add(b2);
            buttonPanel.add(b3);

            BufferedImage buffer = new BufferedImage(200,200,BufferedImage.TYPE_INT_RGB);
            Graphics2D g = buffer.createGraphics();

            BufferedImage image = ImageIO.read(new File("image.jpg"));
            g.scale(buffer.getWidth()*1.0/image.getWidth(),
                    buffer.getHeight()*1.0/image.getHeight());
            g.drawImage(image, 0, 0, null);
            g.dispose();
            JLabel imageLabel = new JLabel(new ImageIcon(buffer));
            JSplitPane splitPane = new JSplitPane();
            splitPane.add(imageLabel, JSplitPane.LEFT);
            splitPane.add(buttonPanel, JSplitPane.RIGHT);
            panel.add(splitPane);
        }
        JScrollPane spane = new JScrollPane(panel);
        frame.add(spane);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(500,600);
        frame.setVisible(true);
    }
}

如果要在图像可见时动态加载图像,则必须为每个图像使用空的 JPanel 而不是 ImageIcons,然后覆盖这些 JPanel 的绘制方法。只有当 JPanel 可见时才会调用paint 方法。因此,最简单的解决方案是始终以绘制方法从磁盘加载图像,然后将其绘制到屏幕上。

import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import javax.imageio.ImageIO;
import java.io.File;

public class Scroll extends JPanel {
    public static void main(String[] args) throws Exception {
        JFrame frame = new JFrame();
        JPanel panel = new Scroll();

        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

        for(int i = 0; i < 10; i++) {
            JPanel buttonPanel = new JPanel();
            JRadioButton b1 = new JRadioButton("button 1");
            JRadioButton b2 = new JRadioButton("button 2");
            JRadioButton b3 = new JRadioButton("button 3");
            ButtonGroup group = new ButtonGroup();
            group.add(b1);
            group.add(b2);
            group.add(b3);
            buttonPanel.add(b1);
            buttonPanel.add(b2);
            buttonPanel.add(b3);

            JPanel imagePanel = new JPanel() {
                {
                    BufferedImage image = ImageIO.read(new File("image.jpg"));
                    setPreferredSize(new Dimension(image.getWidth(), image.getHeight()));
                    image.flush();
                }
                @Override
                public void paint(Graphics g) {
                    try {
                        BufferedImage image = ImageIO.read(new File("image.jpg"));
                        g.drawImage(image, 0, 0, null);
                        image.flush();
                    } catch(Exception e) {
                    }
                }
            };

            JSplitPane splitPane = new JSplitPane();
            splitPane.add(imagePanel, JSplitPane.LEFT);
            splitPane.add(buttonPanel, JSplitPane.RIGHT);
            panel.add(splitPane);
        }
        JScrollPane spane = new JScrollPane(panel);
        frame.add(spane);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(500,600);
        frame.setVisible(true);
    }
}
于 2012-11-25T01:35:07.477 回答