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

时间:2011-11-11 02:10:17

标签: java swing layout

我正在尝试制作一个类似于Photoshop或Paint Shop Pro中的图像处理框架,我遇到了问题。

现在我有一个带有JDesktopPane的JFrame窗口。当我单击一个按钮时,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的大小。

提前致谢。

Edit1:这里有一些突出问题的代码。

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”,如果你使internalFrame大于图片,它会用标签填充剩余的空间。因为所有的mouseEvents都会在我穿过内部框架时触发,而不是像我想要的那样触发到图片上。

Edit2:使用Kleopatra的建议修改了代码。

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);
}
}

2 个答案:

答案 0 :(得分:2)

在此示例中,内部框架最初不会超过MAX_SIZE像素。较小的图片将被调整大小,以便不需要滚动。

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

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

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

enter image description here

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();
            }
        });
    }
}

答案 1 :(得分:1)

布局问题的答案是LayoutManager。总是。这是never setXXSize(虽然没有什么绝对是绝对的: - )

为了确保我理解你的目标:

  • 始终将标签置于其首选大小(默认情况下为其图标的大小)
  • 如果internalFrame小于pref,则允许滚动,即滚动窗格调整为较小,标签保留在其pref
  • 如果内部框架大于pref
  • ,则禁止对scrollPane及其内容进行拉伸

此场景中的重要LayoutManager是控制滚动窗格大小的布局管理器:它是internalFrame的contentPane的LayoutManager。默认管理器是BorderLayout:将其中心调整为可用空间。我们需要将其替换为一个尊重max 使中心组件(滚动窗格)报告最大化(通常为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