java - 当 setMaximumSize() 和 setPreferedSize() 不起作用时,如何对 JComponent 设置硬限制?

标签 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 拉伸(stretch)到 JInternalFrame 的大小。

我尝试用“空”JLabel 填充 JLabel 周围的空间。我尝试过切换 JScrollPane 的布局样式。我尝试将 JLabel 和 JScrollPane 的首选尺寸和最大尺寸设置为 picture.png 的尺寸。这些都不能满足我的需要。我不希望 JLabel 周围的空白“空间”成为 JScrollPane 或 JLabel 的一部分,这样我就可以使用各种 MouseEvents 在图片本身上触发,而不是“拉伸(stretch)”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大于图片,它将用标签填充剩余空间。因为当我穿过内部框架时,所有鼠标事件都会触发,而不是像我希望的那样在图片上发生。

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

最佳答案

在此示例中,内部帧最初不超过 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();
            }
        });
    }
}

关于java - 当 setMaximumSize() 和 setPreferedSize() 不起作用时,如何对 JComponent 设置硬限制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8088885/

相关文章:

android - 可滚动和不可滚动的图像

android - 复选框 Material 设计

java - 并行播放相同的声音两次

java - 在 Windows 上通过 Java 运行 GTK

java - FlowLayout 对齐方式更改在 Swing 中不直接可见

java - 如何使用 JButton 在 eclipse 上打开一个小输入框

java - 在 Seam 中,从 EntityHome 注入(inject)的 EntityManager 和 getEntityManager 之间有什么区别

java - 订单保证使用流和减少消费者链

python - Jython Swing : Passing more than self and event on a button press

java - 垂直 Swing 调整一个 Pane 的大小以扩大其他 Pane 的收缩(修改后的BorderLayout)