【问题标题】:Making image scrollable in JFrame contentpane在 JFrame 内容窗格中使图像可滚动
【发布时间】:2011-11-10 01:26:15
【问题描述】:

我试图在 JFrame 的内容窗格中显示一个大图像。我想让图像或内容窗格可滚动,因为图像很大。我尝试使用 Jscrollpane 将其添加到内容窗格中,但它不起作用。做了一些寻找解决方案,但最终未能找到一个。有人可以指导我吗?我的代码如下

FinalEnvironment.java

package environment;

import java.awt.*;
import java.net.URL;

import javax.swing.*;

public class FinalEnvironment{

public FinalEnvironment(){

    Image Eastlake;
    URL EastlakeURL = null;

    EastlakeURL = FinalEnvironment.class.getResource("/image1/eastlake_night.png");
    Eastlake = Toolkit.getDefaultToolkit().getImage(EastlakeURL);

    JFrame frame = new JFrame("UniCat World");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(800, 600);
    frame.setResizable(false);
    frame.setLocationRelativeTo(null);

    JMenuBar yellowMenuBar = new JMenuBar();
    Map map = new Map(800, 550, Eastlake);
    yellowMenuBar.setOpaque(true);
    yellowMenuBar.setBackground(Color.YELLOW);
    yellowMenuBar.setPreferredSize(new Dimension(800, 50));
    frame.setJMenuBar(yellowMenuBar);
    JScrollPane scroller = new JScrollPane(map);
    scroller.setAutoscrolls(true);
    scroller.setPreferredSize(new Dimension(800, 550));
    frame.getContentPane().add(scroller, BorderLayout.CENTER);


    frame.setSize(800, 600);
    frame.setVisible(true);
}

public static void main(String[] args){
    FinalEnvironment fe = new FinalEnvironment();
}
}

这是我的 map.java

package environment;

import java.awt.*;

import javax.swing.*;


public class Map extends JPanel{

    private int width;
    private int height;
    private Image img;

    public Map(int width, int height, Image img){

        this.width = width;
        this.height = height;
        this.img = img;
    }

    protected void  paintComponent(Graphics g)
    {
        super.paintComponents(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.drawImage(img,0,0,2624,1696,null);
    }

}

最后,我想在这张图片上放置 Jbuttons。我应该调用一个 Rectangle 并将其放在内容窗格中的图像顶部,然后我使用 Point 来定位我的按钮,还是应该立即使用图像或组件本身来完成它?我需要按钮能够在滚动而不是内容窗格中的静态图像时与图像同步。

谢谢

【问题讨论】:

  • 不,这是我在项目中尝试编写的众多代码之一。
  • 试试我自己的建议。那么如果你还有问题,我可以发一个代码示例。
  • @noble,不要重新发明轮子,只需使用 JLabel。

标签: java image swing jscrollpane


【解决方案1】:

我会在这里做什么:

1.有一个面板(画布),它的唯一职责是在覆盖的方法paintComponent()中绘制独立于实际图像大小的给定图像@

    super.paintComponent(g);
    g.drawImage(image, 0, 0, null);

2.确保画布首选大小等于图像实际大小。

3. 有第二个面板作为框架的内容面板。

4.在其中你将设置一个JScrollPane作为它的中心。

5.在滚动窗格中,视口将是步骤 1 中的组件。

6.将您的按钮从步骤 1 添加到画布面板。它将与图像一起滚动。

7.将内容窗格(步骤 3 中的面板)添加到框架中,然后运行应用程序。

编辑: 将按钮添加到画布的代码示例,该按钮始终保持在原位,与滚动位置或帧大小无关。

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

public class ScrollImageTest extends JPanel {
    private static final long serialVersionUID = 1L;
    private BufferedImage image;
    private JPanel canvas;

    public ScrollImageTest() {
        try {
            this.image = ImageIO.read(new URL("http://interviewpenguin.com/wp-content/uploads/2011/06/java-programmers-brain.jpg"));
        }catch(IOException ex) {
            Logger.getLogger(ScrollImageTest.class.getName()).log(Level.SEVERE, null, ex);
        }

        this.canvas = new JPanel() {
            private static final long serialVersionUID = 1L;
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.drawImage(image, 0, 0, null);
            }
        };
        canvas.add(new JButton("Currently I do nothing"));
        canvas.setPreferredSize(new Dimension(image.getWidth(), image.getHeight()));
        JScrollPane sp = new JScrollPane(canvas);
        setLayout(new BorderLayout());
        add(sp, BorderLayout.CENTER);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JPanel p = new ScrollImageTest();
                JFrame f = new JFrame();
                f.setContentPane(p);
                f.setSize(400, 300);
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.setVisible(true);
            }
        });
    }
}

【讨论】:

  • 我现在可以使图像可滚动了。谢谢!虽然仍在处理按钮。如果我遇到问题,将在此处或在此主题中发表评论。谢谢!
  • @Noble 很乐意为您提供帮助。尝试将按钮添加到画布,在您的情况下为map,例如map.add(new JButton("OK")); 如果我正确理解与图像同步,它应该可以按您的意愿工作。我认为随着它的移动而移动,对吗?。
  • @Noble:如果您在程序中遇到新问题并需要我们的帮助,那么最好的办法是提出关于 SO 的新问题。如果需要,您可以链接到此问题,但为新问题创建新问题会增加您获得及时帮助的机会。
  • 不,我只想根据图像本身将某些按钮放置在某些位置。我上次尝试过,我只能根据帧大小而不是图像来定位按钮。为了简化我想说的话,假设我在图像的右下角放置了一个按钮,即使我将图像滚动到顶部或左侧,我也希望它保持在该位置。另一个小困惑,如果我想根据基于我的代码的间隔重新绘制图像或组件本身,整个 map.java 本身,我应该在哪里编码?
  • @Noble:请检查我的编辑与我添加按钮的代码示例。它始终保持在开始时设置的位置。
【解决方案2】:

如果您使用自己的尺寸来设置地图的首选尺寸会怎样。例如,给 Map 这个方法:

// method in the Map class
@Override
public Dimension getPreferredSize() {
  return new Dimension(width, height);
}

这样 Map JPanel 将占用必要的空间来显示整个图像。另外,为什么您在paintComponent 方法中的drawImage 方法有很大的magic 数字?为什么不在那里也使用宽度和高度? 编辑 1: 或者甚至不按照 Boro 在他的回答中建议的那样指定图像大小(对他来说是 1+)。

【讨论】:

  • 嗨@Hovercraft Full Of Eels 我认为你的建议应该这样做。或者在构造函数中,他可以使用setPreferredSize(...) 而不是覆盖它。无论如何,在重新阅读代码之后,OP 的真正问题是setPreferredSize() 方法没有应用于ScrollPane 内部的面板。相反,我看到它设置为ScrollPane,在这种情况下这是不必要的,因为它被设置为边框布局的中心,并且它忽略了组件的宽度和高度。
  • 是的,我改变了我的代码,没有像 Boro 建议的那样指定图像大小。大魔术数字实际上是由我硬编码用于测试的。
【解决方案3】:

为什么每个人都在重新发明轮子???不需要自定义面板来绘制图像!!!

您需要做的就是创建一个 JLabel 并将一个 ImageIcon 添加到标签中,您不会有任何问题。标签将:

  1. 在 (0, 0) 处以原始大小绘制图像(这正是自定义代码所做的)。

  2. 根据图像大小确定图像的首选大小。现在滚动会自动发生。

此外,几乎没有任何理由使用 setPreferredSize() 方法,因为所有组件都有默认的首选大小。所以你不应该设置菜单栏的默认大小。我设置首选大小的唯一时间是在 JScrollPane 上。这将允许框架以合理的大小打包,然后滚动条将根据标签中图像的大小自动出现。

【讨论】:

  • 好点。在自定义组件中,是否有理由更喜欢覆盖 getPreferredSize() 而不是调用 getPreferredSize()
  • 在自定义组件中,您应该始终覆盖 getPreferredSize(),因为尺寸可能会随着组件属性的变化而动态变化。
  • ImageIcon 似乎有一个相当低的维度限制,似乎甚至依赖于平台。在 Win 10 下,我可以将 32768x400 RGB 图像显示为嵌入在 JLabel 中的 ImageIcon,在 Ubuntu 16.10 下,最大宽度似乎在 16384 和 32768 之间。很酷的东西是这不会引发错误,你开始搜索.....
【解决方案4】:

除了其他有用的答案之外,您可能还想研究这个使用鼠标手势滚动任意内容的example

【讨论】:

  • +1 有趣。起初我认为这是模仿智能手机滚动(即拖动)的东西。顺便说一句,您知道这种模仿手机行为的 API 吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-11-05
  • 1970-01-01
  • 2014-12-13
  • 1970-01-01
  • 2013-05-11
  • 2017-11-07
  • 1970-01-01
相关资源
最近更新 更多