【问题标题】:Resize components on frame resize Java在框架调整大小 Java 上调整组件大小
【发布时间】:2012-10-13 23:50:18
【问题描述】:

我在调整 GUI 大小时尝试调整 GUI 中组件的大小时遇到​​了一些问题。现在,当我调整 GUI 大小时,组件的大小不会改变,它们保持我设置的静态大小。当我调整 GUI 的大小通过显示它们所需的最小尺寸时,它们不再显示。我希望它们在调整 GUI 大小时调整大小并保持纵横比。

这是我的 GUI 代码:

import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.*;
import java.net.*;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.text.*;
import javax.swing.text.html.*;

public class DraftGUI implements MouseListener {

private JPanel jpPack;
private JPanel jpCards;
private JPanel jpInfo;
private JPanel jpChat;
private TextField tf;
private StyledDocument doc;
private JTextPane tp;
private JScrollPane sp;

public void mousePressed(MouseEvent e) {
}

public void mouseReleased(MouseEvent e) {
}

public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

public void mouseClicked(MouseEvent e) {
    e.getComponent().setVisible(false);
}

private Client client;


public GUI(Client client) throws IOException {

    JFrame frame = new JFrame("Draft");

    //set the size to fullscreen to start
    frame.setSize(Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit.getDefaultToolkit().getScreenSize().height);

    //set the content pane, we'll add everything to it and then add it to the frame
    JPanel contentPane = new JPanel();
    contentPane.setSize(Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit.getDefaultToolkit().getScreenSize().height);
    contentPane.setLayout(new GridBagLayout());

    //creates some panels with some default values for now
    JPanel jpCards = new JPanel(new BorderLayout());
    jpCards.setOpaque(true); //ensures it paints every pixel
    jpCards.setBackground(Color.BLUE);

    JPanel jpInfo = new JPanel();
    jpInfo.setOpaque(true);
    jpInfo.setBackground(Color.GREEN);

    JPanel jpPack = new JPanel(new GridBagLayout());
    jpPack.setOpaque(true);
    jpPack.setBackground(Color.RED);

    //grab some info to make the JTextPane and make it scroll
    this.client = client;
    tf = new TextField();
    doc = new DefaultStyledDocument();
    tp = new JTextPane(doc);
    tp.setEditable(false);
    tf.addActionListener(this.client);
    sp = new JScrollPane(tp);

    //adding the quantities to the chat panel
    JPanel jpChat = new JPanel();
    jpChat.setLayout(new BorderLayout());
    jpChat.add("North", tf);
    jpChat.add("Center", sp);

    //a new GridBagConstraints used to set the properties/location of the panels
    GridBagConstraints c = new GridBagConstraints(); 

    //adding some panels to the content pane
    //set it to start from the top left of the quadrant if it's too small
    c.anchor = GridBagConstraints.FIRST_LINE_START; 
    c.fill = GridBagConstraints.BOTH; //set it to fill both vertically and horizontally
    c.gridx = 0; //set it to quadrant x=0 and
    c.gridy = 0; //set it to quadrant y=0
    c.weightx = 0.7;
    c.weighty = 0.3;
    contentPane.add(jpCards, c);

    c.gridx = 1;
    c.gridy = 0;
    c.weightx = 0.3;
    c.weighty = 0.3;
    contentPane.add(jpInfo, c);

    c.gridx = 0;
    c.gridy = 1;
    c.weightx = 0.7;
    c.weighty = 0.7;
    contentPane.add(jpPack, c);

    c.gridx = 1;
    c.gridy = 1;
    c.weightx = 0.3;
    c.weighty = 0.7;
    contentPane.add(jpChat, c);

    //set some necessary values 
    frame.setContentPane(contentPane);
    frame.setLocationByPlatform(true);
    frame.setVisible(true);

    //This code works for adding an Image
    //need to learn how to specify a path not dependent on the specific users's machine
    //this is not a high priority for now though
    GridBagConstraints d = new GridBagConstraints();
    d.gridx = 0;
    d.gridy = 0;

    ImageLabel imageLabel1 = new ImageLabel("path-to-file");

    imageLabel1.setPreferredSize(new Dimension(223, 310));
    jpPack.add(imageLabel1, d);

    ImageLabel imageLabel2 = new ImageLabel("path-to-file");
    imageLabel2.setPreferredSize(new Dimension(223, 310));
    ImageLabel imageLabel3 = new ImageLabel("path-to-file");
    imageLabel3.setPreferredSize(new Dimension(223, 310));
    d.gridx = 1;
    jpPack.add(imageLabel2, d);
    d.gridy = 1;
    jpPack.add(imageLabel3, d);

    imageLabel1.addMouseListener(this);
    imageLabel2.addMouseListener(this);
    imageLabel3.addMouseListener(this);

    //223, 310 are the aspect values for a card image, width, height
    //these need to be maintained as the GUI size changes

    }

}


class ImageLabel extends JLabel {
   Image image;
   ImageObserver imageObserver; 

   // constructor with filename     
   ImageLabel(String filename) {
      ImageIcon icon = new ImageIcon(filename);
      image = icon.getImage();
      imageObserver = icon.getImageObserver();
   }

   // constructor with icon
   ImageLabel(ImageIcon icon) {
      image = icon.getImage();
      imageObserver = icon.getImageObserver();
   }

   // overload setIcon method
   void setIcon(ImageIcon icon) {
      image = icon.getImage();
      imageObserver = icon.getImageObserver();
   }

   // overload paint()
   public void paint( Graphics g ) {
       super.paint( g );
       g.drawImage(image,  0 , 0 , getWidth() , getHeight() , imageObserver);

   }

}

由于某种原因,框架的组件没有默认的调整大小属性,所以当框架调整大小时,组件不会做任何事情。我不确定我做错了什么或错过了什么,但显然我遗漏了一些东西。

另外,如果有人知道的话,ImageLabels 会占用它们周围的额外空间。默认情况下,填充设置为 0,所以我不确定为什么它会像围绕它们的边框一样创建。

谢谢。

纪尧姆编辑:

我知道如果我想独立运行 main 是必要的,它目前是另一个应用程序的一部分,并且在其中单独调用。为了完整起见,在没有 main 的情况下发布它可能不是最好的决定,但无论如何,这不是什么大问题。

您的代码取出了实际显示图片的部分。 “路径到文件”应该被实际的图像文件路径替换,因此您将显示图像。当它只是文本时,很难真正看到手头的问题。

当您正确显示图像并尝试调整整个 GUI 的大小时,您会注意到图像并没有缩小。它保持其首选大小,并且当它变得小于它时会出现问题。在我的代码中,当它至少不能显示首选尺寸时,它会完全停止显示图片。在您的代码中,它会在缩小时切断部分图片。

我想要的是它实际调整包含图片的 JLabel 的大小,以便 GUI 调整大小时,图像也会调整大小。对于我的程序,图像有必要相应地缩小。用户最终将获得基于单击图像的功能,因此仅显示某些图像或其中的一部分根本行不通。

请再次尝试您的代码/我的代码并重现我遇到的问题,用图片进行测试,以便我们找到正确的解决方案。谢谢。

【问题讨论】:

  • 您需要使用除网格包布局之外的其他布局管理器,因为它可以尽可能地尊重首选尺寸。在我的脑海中,我不能推荐一个。手头的问题是如何确定“纵横比”
  • 看看我更新的答案。
  • 你的和@GuillaumePolet 之间的一个区别是你主动短路了标签的自我调整大小:一般规则是永远不要打电话给any of the setXXSize methods。也就是说:图像有一个固定大小,如果你想缩放它,你必须自己实现缩放
  • 再看,有些问题:a) imageLabel.setIcon(ImageIcon) not 覆盖 label.setIcon(Icon) b) 在swing中,覆盖paintComponent not 绘画
  • 你解决了吗?随意回答您自己的问题

标签: java swing user-interface resize gridbaglayout


【解决方案1】:
  1. JFrame.setVisible(true) 应该是您调用的最后一行。
  2. GridBagLayout可以根据框架大小调整你的组件大小,只要你使用weightx/weightyfill

更新:

  1. 忘记设置首选大小,这只会导致 GUI 问题
  2. 如果您使用 LayoutManager(这是一个非常好的主意),请忘记调用 setSize()/setBounds()/setLocation(),无论如何 LayoutManager 都会覆盖它们
  3. 您需要注意调整图像大小以保持原始图像比例
  4. 如果你使用 weightx/weighty,你也应该使用anchor 和/或fill
  5. 使用frame.pack() 调整框架的大小
  6. 使用setExtendedState() 最大化框架

顺便说一句,SSCCE 意味着您为其他人制作了一个可运行的示例,这包括将图像的本地路径更改为在线 URL(参见下面的示例)。

使用以下 sn-p,一切似乎都正常:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.TextField;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.net.MalformedURLException;
import java.net.URL;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.StyledDocument;

public class DraftGUI implements MouseListener {

    private static final String IMAGE_URL = "http://images.paramountbusinessjets.com/space/spaceshuttle.jpg";
    private JPanel jpPack;
    private JPanel jpCards;
    private JPanel jpInfo;
    private JPanel jpChat;
    private TextField tf;
    private StyledDocument doc;
    private JTextPane tp;
    private JScrollPane sp;

    @Override
    public void mousePressed(MouseEvent e) {
    }

    @Override
    public void mouseReleased(MouseEvent e) {
    }

    @Override
    public void mouseEntered(MouseEvent e) {
    }

    @Override
    public void mouseExited(MouseEvent e) {
    }

    @Override
    public void mouseClicked(MouseEvent e) {
    }

    public DraftGUI() throws MalformedURLException {

        final JFrame frame = new JFrame("Draft");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // set the content pane, we'll add everything to it and then add it to the frame
        JPanel contentPane = new JPanel();
        contentPane.setLayout(new GridBagLayout());

        // creates some panels with some default values for now
        JPanel jpCards = new JPanel(new BorderLayout());
        jpCards.setBackground(Color.BLUE);

        JPanel jpInfo = new JPanel();
        jpInfo.setBackground(Color.GREEN);

        JPanel jpPack = new JPanel(new GridBagLayout());
        jpPack.setBackground(Color.RED);

        // grab some info to make the JTextPane and make it scroll
        tf = new TextField();
        doc = new DefaultStyledDocument();
        tp = new JTextPane(doc);
        tp.setEditable(false);
        sp = new JScrollPane(tp);

        // adding the quantities to the chat panel
        JPanel jpChat = new JPanel();
        jpChat.setLayout(new BorderLayout());
        jpChat.add("North", tf);
        jpChat.add("Center", sp);

        // a new GridBagConstraints used to set the properties/location of the panels
        GridBagConstraints c = new GridBagConstraints();

        // adding some panels to the content pane
        // set it to start from the top left of the quadrant if it's too small
        c.anchor = GridBagConstraints.FIRST_LINE_START;
        c.fill = GridBagConstraints.BOTH; // set it to fill both vertically and horizontally
        c.gridx = 0; // set it to quadrant x=0 and
        c.gridy = 0; // set it to quadrant y=0
        c.weightx = 0.7;
        c.weighty = 0.3;
        contentPane.add(jpCards, c);

        c.gridx = 1;
        c.gridy = 0;
        c.weightx = 0.3;
        c.weighty = 0.3;
        contentPane.add(jpInfo, c);

        c.gridx = 0;
        c.gridy = 1;
        c.weightx = 0.7;
        c.weighty = 0.7;
        contentPane.add(jpPack, c);

        c.gridx = 1;
        c.gridy = 1;
        c.weightx = 0.3;
        c.weighty = 0.7;
        contentPane.add(jpChat, c);

        // set some necessary values
        frame.setContentPane(contentPane);
        frame.setLocationByPlatform(true);

        // This code works for adding an Image
        // need to learn how to specify a path not dependent on the specific users's machine
        // this is not a high priority for now though
        GridBagConstraints d = new GridBagConstraints();
        d.weightx = 1.0;
        d.weighty = 1.0;
        d.fill = GridBagConstraints.BOTH;
        d.gridx = 0;
        d.gridy = 0;
        ImageLabel imageLabel1 = new ImageLabel(new ImageIcon(new URL(IMAGE_URL)));
        jpPack.add(imageLabel1, d);
        ImageLabel imageLabel2 = new ImageLabel(new ImageIcon(new URL(IMAGE_URL)));
        d.gridx++;
        jpPack.add(imageLabel2, d);

        ImageLabel imageLabel3 = new ImageLabel(new ImageIcon(new URL(IMAGE_URL)));
        d.gridy++;
        jpPack.add(imageLabel3, d);

        imageLabel1.addMouseListener(this);
        imageLabel2.addMouseListener(this);
        imageLabel3.addMouseListener(this);
        frame.pack();
        // 223, 310 are the aspect values for a card image, width, height
        // these need to be maintained as the GUI size changes
            frame.setExtendedState(frame.getExtendedState() | JFrame.MAXIMIZED_BOTH);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    new DraftGUI();
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public static class ImageLabel extends JPanel {
        private static int counter = 1;
        private ImageIcon icon;
        private int id = counter++;

        public ImageLabel(ImageIcon icon) {
            super();
            setOpaque(false);
            this.icon = icon;
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(icon.getIconWidth(), icon.getIconHeight());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            double zoom = Math.min((double) getWidth() / icon.getIconWidth(), (double) getHeight() / icon.getIconHeight());
            int width = (int) (zoom * icon.getIconWidth());
            int height = (int) (zoom * icon.getIconHeight());
            g.drawImage(icon.getImage(), (getWidth() - width) / 2, (getHeight() - height) / 2, width, height, this);
            g.setFont(g.getFont().deriveFont(36.0f));
            g.drawString(String.valueOf(id), getWidth() / 2, getHeight() / 2);
        }
    }
}

【讨论】:

  • 我尝试了代码,但它不起作用。 AFAICT,它与我已经拥有的并没有什么不同。 weight 和 fill 属性已经设置好了,所以你所做的只是添加一个 setVisible 和一个 main (这是不必要的,我正在以其他方式调用它)。您还取出了我添加的 ImageLabel 代码,以使图片在面板内自行调整大小。还有其他想法吗?
  • @MichaelYousef 对我来说它有效。我删除了所有不相关的部分并添加了一个main(这是基本的!),这实际上是你工作的一部分:只显示必要的部分并提供一个“可运行”的例子(看看什么是SSCCE)。如果它对您不起作用,请重点说明什么不起作用以及您的期望。
  • 我已经更新了原始帖子以反映我的需要,因为我没有足够的空间将它放在这里。
  • 非常感谢 Guillaume,代码就像一个魅力。我仍然需要做一些最大和最小尺寸的东西,但这应该不会太糟糕。看起来我们之前只是在一个错误的页面上。它调整大小很好,我很兴奋。再次感谢。
  • @MichaelYousef 没问题。很高兴能帮到你。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-06
  • 1970-01-01
  • 2022-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多