How to resize frame dynamically with Timer?

2020-04-16 05:05发布

问题:

I'm trying to resize a window dynamically using a Timer object, but not succeeding... I set the preferred size of the panel in the constructor, which sets the size of the window nicely, though only once. The preferred size changes after the program is initialized, but the window size stays the same. Why? Because the constructor is initialized only once and therefore isn't affected by the size change? If so, how could I get around this to resize the window in real-time?

I know this won't solve the problem in the exercise given in the beginning comments, so please ignore that :-)

/*
 * Exercise 18.15
 * 
 * "(Enlarge and shrink an image) Write an applet that will display a sequence of
 * image files in different sizes. Initially, the viewing area for this image has
 * a width of 300 and a height of 300. Your program should continuously shrink the
 * viewing area by 1 in width and 1 in height until it reaches a width of 50 and
 * a height of 50. At that point, the viewing area should continuously enlarge by 
 * 1 in width and 1 in height until it reaches a width of 300 and a height of 300. 
 * The viewing area should shrink and enlarge (alternately) to create animation
 * for the single image."
 * 
 * Created: 2014.01.07
 */



import javax.swing.*;
import java.awt.*;
import java.awt.event.*;


public class Ex_18_15 extends JApplet {


    // Main method
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        Ex_18_15 applet = new Ex_18_15();
        applet.isStandalone = true;
        frame.add(applet);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }







    // Data fields

    private boolean isStandalone = false;

    private Image image = new ImageIcon("greenguy.png").getImage();

    private int xCoordinate = 360;
    private int yCoordinate = 300;

    private Timer timer = new Timer(20, new TimerListener());

    private DrawPanel panel = new DrawPanel();


    // Constructor
    public Ex_18_15() {
        panel.setPreferredSize(new Dimension(xCoordinate, yCoordinate));
        add(panel);

        timer.start();
    }



class DrawPanel extends JPanel {

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        g.drawImage(image, 0, 0, this);
    }
}



class TimerListener implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        if(yCoordinate <= 50) {
            yCoordinate++;
            xCoordinate++;
        }

        else if(yCoordinate >= 300) {
            yCoordinate--;
            xCoordinate--;
        }

        panel.setPreferredSize(new Dimension(xCoordinate, yCoordinate));
        repaint();
    }
}

}

回答1:

You need to re-pack your JFrame to resize it. For instance at the end of your ActionListener:

Window win = SwingUtilities.getWindowAncestor(panel);
win.pack();

A question for you though: Why in heaven's name is your class extending JApplet and not JPanel? Or if it needs to be an applet, why are you stuffing it into a JFrame?


Edit
Regarding your comment:

Wouldn't it usually be extending JFrame not JPanel? I'm stuffing it into a JFrame to allow it to run as an application as well as an applet. That's how 'Introduction to Java Programming' tells me how to do it :p Adding your code at the end of the actionPerformed method didn't do anything for me ;o

Most of your GUI code should be geared towards creating JPanels, not JFrames or JApplets. You can then place your JPanels where needed and desired without difficulty. Your book has serious issues and should not be trusted if it is telling you this.


Edit 2
Works for me:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

@SuppressWarnings("serial")
public class ShrinkingGui extends JPanel {
   private static final int INIT_W = 400;
   private static final int INIT_H = INIT_W;
   private static final int TIMER_DELAY = 20;
   private int prefW = INIT_W;
   private int prefH = INIT_H;

   public ShrinkingGui() {
      new Timer(TIMER_DELAY, new TimerListener()).start();;
   }

   public Dimension getPreferredSize() {
      return new Dimension(prefW, prefH);
   }

   private class TimerListener implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         if (prefW > 0 && prefH > 0) {
            prefW--;
            prefH--;
            Window win = SwingUtilities.getWindowAncestor(ShrinkingGui.this);
            win.pack();
         } else {
            ((Timer)e.getSource()).stop();
         }
      }
   }

   private static void createAndShowGUI() {
      ShrinkingGui paintEg = new ShrinkingGui();

      JFrame frame = new JFrame("Shrinking Gui");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(paintEg);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGUI();
         }
      });
   }
}