java - JPanel 大小在开始时未知

标签 java swing jframe jpanel

当我从我的 Square 实例创建一个 Board 实例时,我尝试将窗口的大小分配给整数 x 和 y。我没有这样做,因为开始时大小似乎为 0。在 Board.java 的构造函数中,x 和 y 不应该像现在这样结束 -50。

方形.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();
    }
}

棋盘.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);
    }
}

澄清的完整代码: 方形.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);
    }
}

棋盘.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 中使用会减慢速度的代码,但这些调用不应造成太大的损失。此外,如果您的程序是可调整大小的,您将需要能够像这样随时随地重新计算事物的大小:

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

但是当然在你的真实程序中,你会想要避免“魔数(Magic Number)”

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


例如:

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

此外,检查来自 this answer 的键绑定(bind)动画代码我的。

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

}

关于java - JPanel 大小在开始时未知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30226301/

相关文章:

java - 如何在 Swing 中实现同时在 Windows 和 Linux 下运行的弹出菜单

java - JTable 服务器端排序

java - 使用 jframe 时找不到符号错误

java - Java中如何使用Jframe登录成功后显示用户信息[登录表单]

java - 将图像添加到 JFrame

java - 从桌面图标启动时 JNLP 不显示启动画面

java - 如何使用 "stop"作为关键字来停止 for 循环?

java - 无效类异常

java - 使用反射从列表中获取对象

java gui 使用 split 函数在文本区域中显示