【发布时间】:2020-09-20 07:02:54
【问题描述】:
在我的程序中,我将用作画布的 JPanel 添加到 JFrame。问题是 JPanel#setSize() 的大小不是它显示的大小。 我第一次遇到或多或少像这样的问题,我在这里问 Java questions about coordinates with Graphics 他们告诉我添加 JPanel 并使用 pack() 方法,它工作但我现在无法让它工作,因为 JFrame 比我正在绘制的 JPanel 大。 我查看了一些线程,看看我是否能找到答案,但我没有成功。以下是我查看的主题:
- Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?
- Why the JProgressBar doesn't respect the setSize()?
- Component setSize method in FlowLayout object
- setSize() not working?
- setSize not influencing size of button
- Why does the JFrame setSize() method not set the size correctly?
- java.AWT - setSize() method
- Java JPannel not Visible
我用 setSize(600, 400); 创建了一个 JFrame;我添加了窗格。这是代码
import java.awt.Dimension;
import javax.swing.JFrame;
import me.nemo_64.particlessimulation.util.Canvas;
public class Frame extends JFrame {
private Frame(String title) {
super(title);
setResizable(false);
setSize(600, 400);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(null);
init();
}
private void init() {
canvas = new Canvas();
canvas.setSize(400, 400);
canvas.setLocation(0, 0);
canvas.setPreferredSize(new Dimension(400, 400));
canvas.startDrawing();
add(canvas);
}
private Canvas canvas;
public static Frame getInstance() {
if (instance == null)
throw new IllegalAccessError("instanceFrame must be callen at least ones before this method");
return instance;
}
public static Frame instanceFrame(String title) {
if (instance != null)
return getInstance();
instance = new Frame(title);
return getInstance();
}
private static Frame instance;
private static final long serialVersionUID = 1L;
}
这是画布类
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
public class Canvas extends ACanvas {
Vector p, dir;
float v;
public Canvas() {
p = new Vector(0, getHeight() / 2);
dir = new Vector(50f, 50f);
v = 50;
}
@Override
public void update(float delta) {
if (p.x <= 0 && dir.x < 0)
dir.x *= -1;
if (p.y <= 0 && dir.y < 0)
dir.y *= -1;
if (p.x + 100 >= getWidth() && dir.x > 0)
dir.x *= -1;
if (p.y + 100 >= getWidth() && dir.y > 0)
dir.y *= -1;
Vector a = dir.clone().multiply(delta);
p.add(a);
}
@Override
public void mouseClicked(MouseEvent e) {
System.out.println(e.getX() + " " + e.getY());
}
@Override
public void draw(Graphics2D g) {
System.out.println(g);
fill(255, 0, 0);
fillRectangle(p.x, p.y, 100, 100);
}
}
这里是 ACanvas 类
package me.nemo_64.particlessimulation.util;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JPanel;
import javax.swing.event.MouseInputListener;
public abstract class ACanvas extends JPanel
implements KeyListener, MouseInputListener, MouseWheelListener, Drawable, Updateable, FigureDrawer {
private Graphics2D g;
private Thread drawThread;
private Color backgroundColor;
private Color actualColor;
private long lastTime = 0;
private float delta = 0;
public ACanvas() {
setFocusable(true);
addKeyListener(this);
addMouseListener(this);
addMouseWheelListener(this);
lastTime = System.currentTimeMillis();
drawThread = new Thread(() -> {
while (true)
repaint();
}, "Drawing thread");
}
@Override
/**
* Used to update all the components to be drawn
*/
public abstract void update(float delta);
/**
* Draws all the comsponents
*/
public void draw(Graphics2D g) {}
@Override
public Graphics2D getGraphics2D() {
return this.g;
}
@Override
/**
* Draws all the comsponents
*/
public void draw(Graphics g) {
this.g = (Graphics2D) g;
draw(this.g);
}
@Override
public void paint(Graphics g) {
super.paint(g);
delta = (System.currentTimeMillis() - lastTime) * 0.001f;
lastTime = System.currentTimeMillis();
clearBackground(g);
update(delta);
g.setColor(actualColor);
draw(g);
}
public void clearBackground(Graphics g) {
g.setColor(backgroundColor);
g.fillRect(0, 0, getWidth(), getHeight());
}
public void startDrawing() {
if (!drawThread.isAlive())
drawThread.start();
}
public void stopDrawing() {
if (drawThread.isAlive())
drawThread.interrupt();
}
public void background(Color c) {
backgroundColor = c;
}
public void background(int c) {
backgroundColor = new Color(c);
}
public void background(int r, int g, int b) {
backgroundColor = new Color(r, g, b);
}
public void background(float r, float g, float b) {
backgroundColor = new Color(r, g, b);
}
public void fill(Color c) {
actualColor = c;
g.setColor(c);
}
public void fill(int c) {
fill(new Color(c));
}
public void fill(float r, float g, float b) {
fill(new Color(r, g, b));
}
public void fill(int r, int g, int b) {
fill(new Color(r, g, b));
}
@Override
public void mouseClicked(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseExited(MouseEvent e) {}
@Override
public void mousePressed(MouseEvent e) {}
@Override
public void mouseReleased(MouseEvent e) {}
@Override
public void mouseDragged(MouseEvent e) {}
@Override
public void mouseMoved(MouseEvent e) {}
@Override
public void mouseWheelMoved(MouseWheelEvent e) {}
@Override
public void keyPressed(KeyEvent e) {}
@Override
public void keyReleased(KeyEvent e) {}
@Override
public void keyTyped(KeyEvent e) {}
}
它似乎在高度上不起作用。在画布类中,我有一个显示单击位置的鼠标单击事件。我单击的宽度和输出是左侧的坐标(0,?)和右侧的(400,?)。问题是高度,在顶部我得到 (?, 0) 但在底部我能得到的最高值是 (?, 370) 而不是 (?, 400)。我的问题是:为什么底部不去(?,400)? 感谢您的帮助,如果有不清楚的地方,请询问它
编辑: 该计划的其他类别是: 一个向量类:
public class Vector {
public float x, y, z;
public Vector(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}
public Vector(float x, float y) {
this(x, y, 0);
}
public Vector() {
this(0f, 0f, 0f);
}
public Vector multiply(float... values) {
for (float f : values) {
x *= f;
y *= f;
z *= f;
}
return this;
}
public Vector divide(float... values) {
for (float f : values) {
x /= f;
y /= f;
z /= f;
}
return this;
}
public Vector add(Vector... vectors) {
for (Vector v : vectors)
add(v.x, v.y, v.z);
return this;
}
public Vector add(float x, float y, float z) {
this.x += x;
this.y += y;
this.z += z;
return this;
}
public Vector add(float x, float y) {
return add(x, y, 0);
}
public Vector remove(Vector... vectors) {
for (Vector v : vectors)
remove(v.x, v.y, v.z);
return this;
}
public Vector remove(float x, float y, float z) {
this.x -= x;
this.y -= y;
this.z -= z;
return this;
}
public Vector remove(float x, float y) {
return remove(x, y, 0);
}
public Vector normalize() {
double mod = module();
this.x /= mod;
this.y /= mod;
this.z /= mod;
return this;
}
public double module() {
return Math.sqrt(moduleSquared());
}
public double moduleSquared() {
return (double) (x * x + y * y + z * z);
}
public Vector clone() {
return new Vector(x, y, z);
}
@Override
public String toString() {
return "[ " + x + ", " + y + ", " + z + "]";
}
}
绘图界面:
package me.nemo_64.particlessimulation.util;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
public interface FigureDrawer {
default public void fillRectangle(float x, float y, float width, float height) {
getGraphics2D().fill(new Rectangle2D.Float(x, y, width, height));
}
default public void drawRectangle(float x, float y, float width, float height) {
getGraphics2D().draw(new Rectangle2D.Float(x, y, width, height));
}
default public void fillCircle(float x, float y, float r) {
fillCircle(x, y, r, r);
}
default public void drawCircle(float x, float y, float r) {
drawCircle(x, y, r, r);
}
default public void fillCircle(float x, float y, float r1, float r2) {
getGraphics2D().fill(new Ellipse2D.Float(x, y, r1, r2));
}
default public void drawCircle(float x, float y, float r1, float r2) {
getGraphics2D().draw(new Ellipse2D.Float(x, y, r1, r2));
}
public Graphics2D getGraphics2D();
}
还有 Drawable 和 Updateable 接口:
package me.nemo_64.particlessimulation.util;
public interface Updateable {
/**
* Called when the component must be updated
* @param delta The seconds that past between calls
*/
public void update(float delta);
}
package me.nemo_64.particlessimulation.util;
import java.awt.Graphics;
public interface Drawable {
/**
* Called when the component must be drawn
*/
public void draw(Graphics g);
}
【问题讨论】:
-
当您将 JDK 中的类名用于您自己的类时,会让人感到困惑。例如,您发布的代码中的类
Vector不是java.util.Vector,是吗?那么你的班级Vector的代码在哪里? -
您使用 setPreferredSize 方法请求 JPanel 的大小。
-
不,它不是java.util.Vector,我认为没有必要发布Vector类,我会放代码。如果您需要更多课程,请告诉我
-
@GilbertLeBlanc 你能解释一下吗?
-
所以首先让面板尺寸正确。一旦可行,您就开始添加您的绘画逻辑。编码大约是一次一步。写一段代码,测试一下。然后添加更多并测试。不要尝试使用所有额外代码来测试面板的基本尺寸。如果您仍然有问题,那么您有一个 minimal reproducible example 可以发布。