当setMaximumSize()和setPrefferedSize()不起作用时,如何在JComponent上设置硬限制?

我正在尝试使image processing框架类似于像Photoshop或Paint Shop Pro中发现的image processing框架,我遇到了问题。

现在我有一个JDesktopPane的JFrame窗口。 当我点击一个button,一个JInternalFrame是由其中的以下组件:

imageLabel = new JLabel("picture.png"); scrollPane.setViewPort(imageLabel); internalFrame.add(scrollPane); // I also tried with a BorderLayout() desktopPane.add(internalFrame); 

我的问题是这样的:如果JLabel小于JInternalFrame,我不希望JLabel或JScrollPane拉伸到JInternalFrame的大小。

我已经尝试用“空”JLabel填充JLabel周围的空间。 我试过切换JScrollPane的布局样式。 我已经尝试将JLabel和JScrollPane的首选和最大尺寸设置为picture.png的尺寸。 没有任何工作,我需要什么。 我不希望JLabel周围的空白“空格”成为JScrollPane或JLabel的一部分,这样我就可以使用各种MouseEvent触发图片本身,而不是每当“拉伸的”JLabel或JScrollPane留下的空间我调整了JInternalFrame的大小。

提前致谢。

编辑1:这是一些突出显示问题的代码。

 import java.awt.*; import java.awt.event.*; class fooFrame extends JFrame implements MouseListener { private static fooFrame frame; JLabel fooLabel; public fooFrame() { JDesktopPane background = new JDesktopPane(); JInternalFrame internalFrame = new JInternalFrame("Internal Frame", true, true, true, true); internalFrame.setSize(500, 500); internalFrame.setLocation(20, 20); internalFrame.setVisible(true); Image image = Toolkit.getDefaultToolkit().getImage("test.gif"); fooLabel = new JLabel(new ImageIcon("test.gif")); fooLabel.setPreferredSize(new Dimension(image.getWidth(null), image.getHeight(null))); JScrollPane fooScrollPane = new JScrollPane(fooLabel, JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); fooScrollPane.setPreferredSize(new Dimension(fooLabel.getWidth(), fooLabel.getHeight())); fooScrollPane.setViewportView(fooLabel); // add JLabel to JScrollPane internalFrame.add(fooScrollPane); // add JScrollPane to JInternalFrame background.add(internalFrame); // add JInternalFrame to JDesktopPanel this.setContentPane(background); // add JDesktopPanel to JFrame fooLabel.addMouseListener(this); } public void mouseClicked(MouseEvent me) { if (me.getSource() == fooLabel) System.out.println("Clicked the picture."); } public void mouseEntered(MouseEvent me) { if (me.getSource() == fooLabel) System.out.println("Entered the picture."); } public void mouseExited(MouseEvent me) { if (me.getSource() == fooLabel) System.out.println("Exited the picture."); } public void mousePressed(MouseEvent me){} public void mouseReleased(MouseEvent me){} public static void createAndShowGUI() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { } frame = new fooFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setTitle("foo"); frame.setSize(800,600); frame.setLocationRelativeTo(null); frame.setVisible(true); } } 

你将不得不得到你自己的“test.gif”,如果你使内部框架大于图片,用标签填充剩余的空间。 由于所有的mouseEvents都是在我穿过内部框架时触发的,而不是像我想要发生的那样。

Edit2:用Kleopatra的build议修改的代码。

 import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.LineBorder; public class a1 { public static void main(String[] args) { fooFrame.createAndShowGUI(); } } class fooFrame extends JFrame implements MouseListener { private static fooFrame frame; JLabel fooLabel; public fooFrame() { JDesktopPane background = new JDesktopPane(); JInternalFrame internalFrame = new JInternalFrame("Internal Frame", true, true, true, true); internalFrame.setLocation(20, 20); internalFrame.setVisible(true); internalFrame.pack(); Image image = Toolkit.getDefaultToolkit().getImage("test.gif"); fooLabel = new JLabel(new ImageIcon(image)); fooLabel.setBorder(new LineBorder(Color.PINK)); JScrollPane fooScrollPane = new JScrollPane((fooLabel), JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); internalFrame.setLayout(new BoxLayout(internalFrame.getContentPane(), BoxLayout.LINE_AXIS)); fooScrollPane.setViewportView(fooLabel); // add JLabel to JScrollPane internalFrame.add(fooScrollPane); // add JScrollPane to JInternalFrame background.add(internalFrame); // add JInternalFrame to JDesktopPanel this.setContentPane(background); // add JDesktopPanel to JFrame fooLabel.addMouseListener(this); } public void mouseClicked(MouseEvent me) { if (me.getSource() == fooLabel) System.out.println("Clicked the picture."); } public void mouseEntered(MouseEvent me) { if (me.getSource() == fooLabel) System.out.println("Entered the picture."); } public void mouseExited(MouseEvent me) { if (me.getSource() == fooLabel) System.out.println("Exited the picture."); } public void mousePressed(MouseEvent me) { } public void mouseReleased(MouseEvent me) { } @Override public Dimension getMaximumSize() { return getPreferredSize(); } public static void createAndShowGUI() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { } frame = new fooFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setTitle("foo"); frame.setSize(800, 600); frame.setLocationRelativeTo(null); frame.setVisible(true); } } 

在这个例子中,内部框架最初不会超过MAX_SIZE像素。 较小的图片将被resize,以便不需要滚动。

附录:更仔细地阅读标题,您可能还想限制内部框架的最大尺寸:

 internalFrame.setMaximumSize(new Dimension(fooLabel.getPreferredSize())); 

附录:这种变化可能有助于澄清问题。 使用默认的布局, BorderLayout.CENTER ,滚动条显示为需要,但MouseListener不符合要求。 对于首选大小的布局FlowLayoutMouseListener正确报告,但滚动条永不出现,因为标签的首选大小不会更改。 为了方便,我添加了合成图像。

在这里输入图像描述

 import java.awt.*; import java.awt.event.*; import java.awt.image.BufferedImage; import javax.swing.*; class PictureFrame extends JFrame { private static final String NAME = "image.jpg"; public PictureFrame() { JDesktopPane dtp = new JDesktopPane(); dtp.add(new MyFrame("Large", FauxImage.create(300, 500), 50)); dtp.add(new MyFrame("Small", FauxImage.create(200, 200), 25)); this.add(dtp); } private static class MyFrame extends JInternalFrame { private static final int MAX_SIZE = 256; public MyFrame(String title, Image image, int offset) { super(title, true, true, true, true); //this.setLayout(new FlowLayout()); final JLabel label = new JLabel(new ImageIcon(image)); this.add(new JScrollPane(label)); this.pack(); int w = Math.min(MAX_SIZE, image.getWidth(null)); int h = Math.min(MAX_SIZE, image.getHeight(null)); Insets i = this.getInsets(); this.setSize(w + i.left + i.right, h + i.top + i.bottom); this.setLocation(offset, offset); this.setVisible(true); label.addMouseListener(new MouseAdapter() { @Override public void mouseEntered(MouseEvent me) { if (me.getSource() == label) { System.out.println("Entered."); } } @Override public void mouseExited(MouseEvent me) { if (me.getSource() == label) { System.out.println("Exited."); } } }); } } private static class FauxImage { static public Image create(int w, int h) { BufferedImage bi = new BufferedImage( w, h, BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = bi.createGraphics(); g2d.setPaint(Color.lightGray); g2d.fillRect(0, 0, w, h); g2d.setColor(Color.black); String s = w + "\u00D7" + h; int x = (w - g2d.getFontMetrics().stringWidth(s)) / 2; g2d.drawString(s, x, 24); g2d.dispose(); return bi; } } public static void createAndShowGUI() { PictureFrame frame = new PictureFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setTitle("PictureFrame"); frame.setSize(640, 400); frame.setLocationRelativeTo(null); frame.setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { createAndShowGUI(); } }); } } 

布局问题的答案是LayoutManager。 总是。 它从来没有setXXSize (尽pipe没有绝对的绝对:-)

只是为了确定我明白你在做什么:

  • 总是有标签在它的pref大小(默认是它的图标的大小)
  • 允许滚动,如果internalFrame小于pref,那就是scrollpane被调整到更小,label保持在它的pref
  • 如果内部框架大于pref,则禁止缩放scrollPane及其内容

在这种情况下,重要的LayoutManager是控制scrollpane大小的LayoutManager:这是internalFrame的contentPane的LayoutManager。 默认pipe理器是一个BorderLayout:将其中心的大小设置为任何可用的空间。 我们需要用一个尊重最大值并使中心组件(滚动窗格) 报告最大值(通常是Short.MAX)

  internalFrame.setLayout(new BoxLayout(internalFrame.getContentPane(), BoxLayout.LINE_AXIS)); Image image = Toolkit.getDefaultToolkit().getImage("test.gif"); fooLabel = new JLabel(new ImageIcon(image)); JScrollPane fooScrollPane = new JScrollPane(fooLabel), JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER) { @Override public Dimension getMaximumSize() { return getPreferredSize(); } }; internalFrame.add(fooScrollPane); // add JScrollPane to JInternalFrame