开始时不知道JPanel大小 [英] JPanel size is not known on start

查看:102
本文介绍了开始时不知道JPanel大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我从Square实例创建Board实例时,我尝试将窗口的大小分配给整数x和y.我无法执行此操作,因为它似乎在开始时大小为0.在Board.java的构造函数中,x和y不应像现在结束一样为-50.

When I create a Board instance from my Square instance, I try to assign the size of the window to the integers x and y. I fail to do this because it seems like on start the size is 0. In the constructor in Board.java, x and y shouldn't be -50 like they end up now.

Square.java:

Square.java:

package Square;

import javax.swing.*;

public class Square extends JFrame {

    public Square(){
        add(new Board());
        setSize(800, 800);
        setVisible(true);
    }

    public static void main(String[] args){
        new Square();
    }
}

Board.java

Board.java

package Square;

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

public class Board extends JPanel{
    int x,y;

    public Board(){
        x = width-50;
        y = height-50;
    }

    public int width = (int) getSize().getWidth();
    public int height = (int) getSize().getHeight();

    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.fillRect(x,y, 100, 100);
    }
}

完整代码说明: Square.java

Full Code for clarification: Square.java

package Square;

import javax.swing.*;

public class Square extends JFrame {

    public Square(){
        Board board = new Board();
        board.start();
        add(board);
        setTitle("Square");
        setSize(800, 800);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }

    public static void main(String[] args){
        Square square = new Square();
        square.setVisible(true);
        square.setLocation(2000, 150);
    }
}

Board.java

Board.java

package Square;

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

public class Board extends JPanel implements ActionListener{

    Timer timer;
    int x, y;
    int velX = 0;
    int velY = 0;

    public Board(){
        setFocusable(true);
        timer = new Timer(1, this);
        addKeyListener(new TAdapter());
    }

    class TAdapter extends KeyAdapter{

        public void keyPressed(KeyEvent e) {
            int keyCode = e.getKeyCode();

            switch(keyCode){
                case KeyEvent.VK_ESCAPE: x = width()/2-50; y = height()/2-50; break;
                case KeyEvent.VK_RIGHT: velX = 1; break;
                case KeyEvent.VK_DOWN: velY = 1; break;
                case KeyEvent.VK_LEFT: velX = -1; break;
                case KeyEvent.VK_UP: velY = -1; break;
            }
        }

        public void keyReleased(KeyEvent e){
            velX = 0;
            velY = 0;
        }
    }
    public int width(){ return (int) getSize().getWidth();}
    public int height(){ return (int) getSize().getHeight();}

    public void start(){
        timer.setInitialDelay(100);
        timer.start();
        x = width()/2-50;
        y = height()/2-50;
    }



    @Override
    public void actionPerformed(ActionEvent e) {
        x += velX;
        y += velY;
        repaint();
    }

    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.setColor(Color.RED);
        g.fillRect(x,y, 100, 100);
    }
}

推荐答案

将计算结果放入paintComponent方法中.通常,您要避免在paintComponent中包含会降低其速度的代码,但是这些调用不应给您带来太多的损失.另外,如果您的程序可调整大小,则需要能够重新计算旅途中事物的大小,如下所示:

Put the calculation into your paintComponent method. In general you want to avoid having code in paintComponent that will slow it down, but these calls shouldn't give too much penalty. Also, if your program is re-sizable, you'll need to be able to re-calculate the sizes of things on the go like this:

public void paintComponent(Graphics g){
    super.paintComponent(g);
    int x = getWidth() - 50;
    int y = getHeight() - 50;
    g.fillRect(x, y, 100, 100);
}

但是,当然,在您的实际程序中,您将希望避免使用魔术"数字

but of course in your real program, you will want to avoid "magic" numbers

另一个问题:不要在JFrame上调用setSize().相反,如果要指定硬尺寸,请在JPanel中通过覆盖其getPreferredSize()方法来指定.然后,这还会为您提供建议的参数,这些参数可用于您的计算.

Another issue: don't call setSize() on your JFrame. Instead, if you want to specify a hard size, do so in the JPanel by overriding its getPreferredSize() method. This will also then give you the suggested parameters that can be used for your calculations.

例如:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

@SuppressWarnings("serial")
public class DrawRect extends JPanel {
   private static final int PREF_W = 800;
   private static final int PREF_H = PREF_W;
   private static final int DELTA = 50;
   private static final Color RECT_COLOR = Color.red;
   private static final int RECT_WIDTH = 100;
   private static final int TIMER_DELAY = 15;
   private int rectX = PREF_W - DELTA;
   private int rectY = PREF_H - DELTA;

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

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      g.setColor(RECT_COLOR);
      g.fillRect(rectX, rectY, RECT_WIDTH, RECT_WIDTH);
   }

   @Override
   public Dimension getPreferredSize() {
      if (isPreferredSizeSet()) {
         return super.getPreferredSize();
      }
      return new Dimension(PREF_W, PREF_H);
   }

   private class TimerListener implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         rectX--;
         rectY--;
         repaint();
      }
   }

   private static void createAndShowGui() {
      JFrame frame = new JFrame("DrawRect");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(new DrawRect());
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

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


此外,请从我的此答案中查看按键绑定动画代码.


Also, check out the key bindings animation code from this answer of mine.

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;

public class GamePanel extends JPanel {
   private static final int ANIMATION_DELAY = 15;
   private final int HEIGHT = 400;
   private final int WIDTH = 600;
   private Square square;
   private EnumMap<Direction, Boolean> dirMap = new EnumMap<>(Direction.class);
   private Map<Integer, Direction> keyToDir = new HashMap<>();
   // !! private Circle circle;
   private Timer animationTimer;

   public GamePanel() {
      for (Direction dir : Direction.values()) {
         dirMap.put(dir, Boolean.FALSE);
      }
      keyToDir.put(KeyEvent.VK_UP, Direction.UP);
      keyToDir.put(KeyEvent.VK_DOWN, Direction.DOWN);
      keyToDir.put(KeyEvent.VK_LEFT, Direction.LEFT);
      keyToDir.put(KeyEvent.VK_RIGHT, Direction.RIGHT);
      // !! addKeyListener(new DirectionListener());
      setKeyBindings();
      setBackground(Color.white);
      setPreferredSize(new Dimension(WIDTH, HEIGHT));
      setFocusable(true);
      square = new Square();
      animationTimer = new Timer(ANIMATION_DELAY, new AnimationListener());
      animationTimer.start();
   }

   private void setKeyBindings() {
      int condition = WHEN_IN_FOCUSED_WINDOW;
      final InputMap inputMap = getInputMap(condition);
      final ActionMap actionMap = getActionMap();
      boolean[] keyPressed = { true, false };
      for (Integer keyCode : keyToDir.keySet()) {
         Direction dir = keyToDir.get(keyCode);
         for (boolean onKeyPress : keyPressed) {
            boolean onKeyRelease = !onKeyPress; // to make it clear how bindings work
            KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode, 0,
                  onKeyRelease);
            Object key = keyStroke.toString();
            inputMap.put(keyStroke, key);
            actionMap.put(key, new KeyBindingsAction(dir, onKeyPress));
         }
      }
   }

   public void paintComponent(Graphics g) {
      super.paintComponent(g);
      square.display(g);
   }

   private class AnimationListener implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent evt) {
         boolean repaint = false;
         for (Direction dir : Direction.values()) {
            if (dirMap.get(dir)) {
               square.move(dir);
               repaint = true;
            }
         }
         if (repaint) {
            repaint();
         }
      }
   }

   private class KeyBindingsAction extends AbstractAction {
      private Direction dir;
      boolean pressed;

      public KeyBindingsAction(Direction dir, boolean pressed) {
         this.dir = dir;
         this.pressed = pressed;
      }

      @Override
      public void actionPerformed(ActionEvent evt) {
         dirMap.put(dir, pressed);
      }
   }

   private static void createAndShowGUI() {
      GamePanel gamePanel = new GamePanel();
      JFrame frame = new JFrame("GamePanel");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(gamePanel);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
      gamePanel.requestFocusInWindow();
   }

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

enum Direction {
   UP(0, -1), DOWN(0, 1), LEFT(-1, 0), RIGHT(1, 0);
   private int incrX;
   private int incrY;

   private Direction(int incrX, int incrY) {
      this.incrX = incrX;
      this.incrY = incrY;
   }

   public int getIncrX() {
      return incrX;
   }

   public int getIncrY() {
      return incrY;
   }
}

class Square {
   private int x = 0;
   private int y = 0;
   private int w = 20;
   private int h = w;
   private int step = 1;
   private Color color = Color.red;
   private Color fillColor = new Color(255, 150, 150);
   private Stroke stroke = new BasicStroke(3f, BasicStroke.CAP_ROUND,
         BasicStroke.JOIN_ROUND);

   public void display(Graphics g) {
      Graphics2D g2d = (Graphics2D) g.create();
      g2d.setColor(fillColor);
      g2d.fillRect(x, y, w, h);
      g2d.setStroke(stroke);
      g2d.setColor(color);
      g2d.drawRect(x, y, w, h);
      g2d.dispose();
   }

   public void setStep(int step) {
      this.step = step;
   }

   public void move(Direction dir) {
      x += step * dir.getIncrX();
      y += step * dir.getIncrY();
   }

}

这篇关于开始时不知道JPanel大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆