Изменение размера компонентов при изменении размера кадра Java

У меня возникли проблемы с изменением размера компонентов в графическом интерфейсе при изменении размера графического интерфейса. Прямо сейчас, когда я изменяю размер графического интерфейса, размер компонентов не меняется, они сохраняют статический размер, который я им установил. Когда я изменяю размер графического интерфейса, передающего минимальный размер, необходимый для их отображения, они больше не отображаются. Я хочу, чтобы они изменяли размер и сохраняли соотношение сторон при изменении размера графического интерфейса.

Вот код, который у меня есть для графического интерфейса:

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, поэтому я не уверен, почему оно создает вокруг них рамку.

Спасибо.

РЕДАКТИРОВАТЬ для Гийома:

Я знаю, что основной необходим, если я хочу запустить его как отдельное приложение, в настоящее время оно является частью другого приложения и вызывается отдельно из него. Вероятно, было не лучшим решением опубликовать его без основного для полноты картины, но в любом случае это не может быть такой уж большой проблемой.

Ваш код удалил ту часть, где изображение фактически отображалось. «путь к файлу» должен был быть заменен фактическим путем к файлу изображения, чтобы вы отображали изображение. На самом деле трудно увидеть проблему, когда это просто текст.

Когда изображение отображается правильно и вы пытаетесь изменить размер всего графического интерфейса, вы заметите, что изображение не сжимается. Он сохраняет свой предпочтительный размер и имеет проблемы, когда становится меньше, чем он. В моем коде он полностью перестает отображать изображение, когда оно не может отображать хотя бы предпочтительный размер. В вашем коде он обрезает часть картинки при сжатии.

Я хочу, чтобы он фактически изменил размер JLabel, содержащего изображение, чтобы по мере изменения размера графического интерфейса изменялось и изображение. Это необходимо, чтобы изображение уменьшалось соответственно для моей программы. Пользователь в конечном итоге получит функциональность, основанную на нажатии на изображения, поэтому отображение только некоторых изображений или их частей просто не годится.

Пожалуйста, попробуйте свой код/мой код еще раз и воспроизведите проблему, с которой я столкнулся, проверив с помощью изображений, чтобы мы могли найти правильное решение. Спасибо.


person Michael Yousef    schedule 23.10.2012    source источник
comment
Вам нужно будет использовать другой менеджер компоновки, отличный от компоновки сетки сетки, так как он соблюдает предпочтительный размер, где это возможно. Навскидку не могу порекомендовать. Проблема в том, как определить соотношение сторон   -  person MadProgrammer    schedule 24.10.2012
comment
Взгляните на мой обновленный ответ.   -  person Guillaume Polet    schedule 25.10.2012
comment
одно различие между вашим и @GuillaumePolet заключается в том, что вы активно сокращаете самоопределение метки: общее правило состоит в том, чтобы никогда не вызывать любой из методов setXXSize. Тем не менее: изображение имеет фиксированный размер, если вы хотите масштабировать его, вы должны реализовать это масштабирование самостоятельно.   -  person kleopatra    schedule 25.10.2012
comment
снова смотрю, некоторые проблемы: а) imageLabel.setIcon(ImageIcon) не переопределяет label.setIcon(Icon) б) в качелях переопределяет paintComponent not paint   -  person kleopatra    schedule 25.10.2012
comment
Вы решили это? Не стесняйтесь ответить на свой вопрос   -  person Igor L.    schedule 22.10.2013


Ответы (1)


  1. JFrame.setVisible(true) должна быть последней линией, которую вы вызываете.
  2. GridBagLayout может адаптировать размер ваших компонентов в соответствии с размером кадра, если вы используете weightx/weighty и fill

ОБНОВИТЬ:

  1. Забудьте об установке предпочтительного размера, это просто приведет к проблемам с графическим интерфейсом.
  2. Если вы используете LayoutManager (и это очень хорошая идея), забудьте о вызове setSize()/setBounds()/setLocation(), LayoutManager все равно переопределит их.
  3. Вам нужно позаботиться об изменении размера изображения, чтобы сохранить исходное соотношение изображения.
  4. Если вы используете weightx/weighty, вы также должны использовать anchor и/или fill
  5. Используйте frame.pack(), чтобы правильно подобрать размер кадра.
  6. Используйте setExtendedState(), чтобы максимизировать кадр

Кстати, SSCCE означает, что вы создаете работающий пример для других, это включает в себя изменение локального пути к изображениям на URL-адреса в Интернете (см. пример ниже).

Со следующим фрагментом все работает нормально:

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);
        }
    }
}
person Guillaume Polet    schedule 24.10.2012
comment
Я попробовал код, и он не сработал. AFAICT, он ничем не отличается от того, что у меня уже было. Свойства веса и заливки уже были установлены, поэтому все, что вам нужно было сделать, это добавить setVisible и main (что было ненужным, я вызывал его другими способами). Вы также убрали код для ImageLabel, который я добавил, чтобы изображения сами меняли размер внутри панелей. Любые другие идеи? - person Michael Yousef; 24.10.2012
comment
@MichaelYousef Для меня это работает. Я отбросил все ненужные части и добавил main (что очень важно!), что на самом деле было частью вашей работы: покажите только то, что необходимо, и приведите работающий пример (см. что такое SSCCE ). Если это не работает для вас, сосредоточьтесь на объяснении того, что не работает и чего вы ожидаете. - person Guillaume Polet; 24.10.2012
comment
Я обновил исходный пост, чтобы отразить то, что мне нужно, потому что у меня недостаточно места, чтобы разместить его здесь. - person Michael Yousef; 25.10.2012
comment
Большое спасибо, Гийом, код работает как шарм. Мне все еще придется делать некоторые вещи максимального и минимального размера, но это не должно быть так уж плохо. Похоже, мы немного ошиблись страницей ранее. Он отлично изменяет размер, и я очень взволнован. Еще раз спасибо. - person Michael Yousef; 25.10.2012
comment
@МайклЮсеф Нет проблем. Рад, что смог тебе помочь. - person Guillaume Polet; 26.10.2012