【问题标题】:Unable to draw manually to JPanel无法手动绘制到 JPanel
【发布时间】:2016-01-14 14:49:56
【问题描述】:

我正在尝试制作一个轨道模拟器,但我遇到了这个问题。我已经检查了整个 Stack Overflow,但我找不到解决方案。我只是想手动绘制到JPanel,但它没有出现在上面。我已将布局设置为 null,使其可见,将其添加到 JFrame,将正文添加到 Plane,以及您通常会做的所有事情。

这是 Body 类:

package viperlordx.orbitsimulator;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;

import javax.swing.JLabel;

@SuppressWarnings("serial")
public class Body extends JLabel {
    private double mass;
    private Point location;
    private Vector velocity;
    private Color color;
    private Plane plane;
    public Body(double mass, Point location, Vector velocity, Color color) {
        this.mass = mass;
        this.location = location;
        this.velocity = velocity;
        this.color = color;
        this.setVisible(true);
        this.setBounds(location.x, location.y, 100, 100);
    }
    public void moveTick() {

        velocity.addTo(location);
    }
    public void setPlane(Plane plane) {
        this.plane = plane;
    }
    public Plane getPlane() {
        return plane;
    }
    @Override
    public void paintComponent(Graphics g) {
        System.out.println("Painting");
        super.paintComponent(g);
        if (plane != null && g != null) {
            g.setColor(color);
            g.fillOval(location.x, location.y, getWidth(), getHeight());
        }
    }
    public Point getLocation() {
        return location;
    }
    public void setLocation(Point location) {
        this.location = location;
    }
    public Vector getVelocity() {
        return velocity;
    }
    public void setVelocity(Vector vector) {
        velocity = vector;
    }
}

还有平面类:

package viperlordx.orbitsimulator;

import java.awt.Graphics;
import java.util.HashSet;
import java.util.Set;

import javax.swing.JPanel;

@SuppressWarnings("serial")
public class Plane extends JPanel {
    private HashSet<Body> bodies = new HashSet<Body>();
    public void addBody(Body body) {
        this.add(body);
        bodies.add(body);
    }
    public Plane() {
        this.setLayout(null);
    }
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (bodies != null) {
            for (Body body : bodies) {
                body.paintComponent(g);
            }
        }
    }
    public Set<Body> getBodies() {
        return bodies;
    }
}

现在是主类:

package viperlordx.orbitsimulator;

import java.awt.Color;
import java.awt.Point;

import javax.swing.JFrame;

public class Main {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(1000, 1000);
        frame.setLocationRelativeTo(null);
        Plane plane = new Plane();
        frame.add(plane);
        plane.setVisible(true);
        frame.setLayout(null);
        plane.setBounds(0, 0, 1000, 1000);
        plane.setBackground(Color.WHITE);
        plane.addBody(new Body(10.0, new Point(10, 10), new Vector(0, 0), Color.GREEN));
        frame.setVisible(true);
        frame.setTitle("Orbit");
        plane.repaint();
    }
}

【问题讨论】:

  • 在哪里实例化 Plane,在哪里以及如何将它添加到容器中?
  • 我会在主课上折腾。
  • 尝试删除“frame.setLayout(null);”
  • 我添加了这个,因为我认为它会有所帮助。这不是问题的根源。它发生在我添加之前。执行 frame.setLayout(null) 只允许您使用绝对坐标而不是限制性布局。
  • 刚刚用普通的JPanel而不是Plane进行了测试,它可以工作。您能否更改背景颜色以检查面板是否可见?

标签: java swing jpanel paintcomponent


【解决方案1】:

您正在混合组件上的绘图形状并将组件添加到容器中。您的Body 不应该是一个组件,而只是一个保存要绘制的对象数据的类。此数据用于在“目标”组件上绘制相应的形状 - 在您的情况下为Plane

我删除了不相关的代码并根据我上面的解释进行了更改:

public class Main {

    public static void main(String[] args) {

        SwingUtilities.invokeLater(() -> {

            JFrame frame = new JFrame();
            Plane plane = new Plane();
            frame.add(plane);
            plane.setBackground(Color.WHITE);
            plane.addBody(new Body(10.0, new Point(10, 10), new Vector(0, 0), Color.GREEN));

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

@SuppressWarnings("serial")
class Plane extends JPanel {

    private HashSet<Body> bodies = new HashSet<>();

    public void addBody(Body body) {

        bodies.add(body);
    }

    @Override
    public void paintComponent(Graphics g) {

        super.paintComponent(g);
        for (Body body : bodies) {
            // Might want to call all needed accessors before getting to work.
            g.setColor(body.getColor());
            g.fillOval(body.getLocation().x, body.getLocation().y, getWidth(), getHeight());
        }
    }

    @Override
    public Dimension getPreferredSize() {

        // Calculate the size
        return new Dimension(1000, 500);
    }
}

class Body {

    private Point location;
    private Vector velocity;
    private Color color;

    public Body(double mass, Point location, Vector velocity, Color color) {

        this.location = location;
        this.velocity = velocity;
        this.color = color;
    }

    public Point getLocation() {

        return location;
    }

    public Color getColor() {

        return color;
    }
}

注意事项:

  • Start Swing on the EDT
  • 不要设置框架的大小(如果我的屏幕没有 1000 像素的高度怎么办?),而是调用 pack() 并确保您绘制的组件 @ 987654327@ 适当。这意味着您需要根据所绘制的内容进行计算。
  • 一般来说,setVisible(true) 应该是您做的最后一件事。之后无需重新粉刷。
  • 从 Java 7 开始,您可以编写 HashSet&lt;Body&gt; bodies = new HashSet&lt;&gt;() 而无需在 RHS 中指定泛型类型。
  • 不要使用原始类型Vector。事实上,根本没有理由使用这个类。 SetList 通常会做得更好。如果他们持有用于计算的数字,那么他们的泛型类型应该是FloatDouble

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-02
    • 2012-12-12
    • 1970-01-01
    相关资源
    最近更新 更多