用Java绘制并移动一个圆圈

时间:2014-11-21 22:02:05

标签: java swing user-interface jframe jpanel

我正在使用Swing在Java中创建一个小型GUI。我试图让它做的就是取ArrayList Circle个并绘制它们。我遇到了两个问题:

1)我必须在绘制圆圈之前反复调用draw方法。如果我只是在没有任何反应时调用我的draw方法,我会得到一张空白的图纸。如果我在一个运行时间小于30毫秒的循环中调用它,它只会绘制我想要绘制的两个圆圈中的第一个。最后,如果我将其调用超过30毫秒,则会绘制我想要绘制的两个圆圈。

2)当我移动其中一个圆圈时,我在图纸上出现“闪烁”。

我对Swing编程不太熟悉。我查看了示例代码并观看了一些视频 - 以及我对我的看法。但我认为我一定搞砸了,因为在我看过的视频中看起来并不像这样。

这是我的GUI课程:

package gui;

import draw.*;
import java.util.List;
import javax.swing.*;

public class GUI extends JFrame {
    private CirclePainter drawingBoard = new CirclePainter();

    public GUI()
    {
        setSize(500, 500);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        this.setVisible(true);
        this.add(drawingBoard);
        drawingBoard.setVisible(true);
    }

    public void draw(List<Circle> circles)
    {
        drawingBoard.paintComponent(drawingBoard.getGraphics(), circles);
    }
}

我的CirclePainter

package gui;

import draw.Circle;

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

class CirclePainter extends JPanel
{
    public void paintComponent(Graphics graphics, List<Circle> circles)
    {
        super.paintComponent(graphics);
        for(Circle circle : circles)
            graphics.fillOval(circle.getX(), circle.getY(), circle.getRadius() * 2, circle.getRadius() * 2);
    }
}

编辑:编辑了一些代码,因为这是针对学校项目的。剩下的代码应该足以让将来访问的人仍然能够理解这个问题。

2 个答案:

答案 0 :(得分:7)

  1. 从不直接拨打paintComponent(...)
  2. 在必要时通过在组件上调用repaint()来建议绘制。
  3. 不要使用通过组件getGraphics()调用获得的Graphics对象进行绘制。而是使用paintComponent方法中提供的Graphics对象进行绘制。
  4. 避免在Swing GUI中使用while (true)循环,因为您可能会占用Swing事件线程并冻结GUI。使用Swing Timer进行简单的动画制作。
  5. 您可能甚至不需要Swing Timer,因为您的动画可以由MouseListener / MouseMotionListener驱动。
  6. 大多数很重要 - 请阅读Swing绘画和其他教程,因为大部分信息都可以在那里找到。看起来你在猜测如何编写一些代码,在绘制或动画GUI时这是一件危险的事情。您可以在Swing info链接中找到大多数教程。
  7. 考虑使用Shape对象来表示Circle,例如ellipse2D。这有助于它有一些非常有用的方法,包括contains(Point p)方法,可以帮助您确定鼠标点击是否落入您的圈内。
  8. 您需要决定_x和_y在哪里代表您圈子的中心点。如果是这样,那么你需要通过向左和向上移动_radius量来调整你的绘图。
  9. 考虑将Graphics对象转换为Graphics2D对象,以便使用其额外的方法和属性。
  10. 其中一个属性是RenderingHings。设置你的Graphics2D RenderingHints以允许消除锯齿以摆脱你的图像“锯齿”。这可以通过以下方式完成:g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);其中g2是您的Graphics2D对象。
  11. 您的paintComponent方法不是真正的paintComponent覆盖,因此无法正常工作。它应该是protected方法,而不是public,它应该有一个参数,Graphics对象和n到第二个参数,您应该在上面放置@Override注释它。
  12. 例如,请查看我的this answer类似问题。

    使用_x和_y将圆圈居中并使用渲染提示的paintComponent方法示例:

    class CirclePainter extends JPanel implements Iterable<Circle> {
       private static final int PREF_W = 500;
       private static final int PREF_H = PREF_W;
       private CircleList circleList = new CircleList();
    
       @Override
       protected void paintComponent(Graphics graphics) {
          super.paintComponent(graphics);
          Graphics2D g2 = (Graphics2D) graphics;
          g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
          for (Circle circle : circleList) {
             // if x and y are the center points, then you must subtract the radius.
             int x = circle.getX() - circle.getRadius();
             int y = circle.getY() - circle.getRadius();
             int width = circle.getRadius() * 2;
             int height = width;
             g2.fillOval(x, y, width, height);
          }
       }
    

答案 1 :(得分:4)

在您的代码和Hovercraft Full Of Eels的建议的基础上,通过对GUI和CirclePainter类的这些修改,可以朝着正确的方向迈出一小步:

// GUI.draw
public void draw(List<Circle> circles)
{
//    drawingBoard.paintComponent(drawingBoard.getGraphics(), circles);
    drawingBoard.setCircles(circles);
    drawingBoard.repaint();
}


class CirclePainter extends JPanel
{
//    public void paintComponent(Graphics graphics, List<Circle> circles)
//    {
//        super.paintComponent(graphics);
//        for(Circle circle : circles)
//            graphics.fillOval(circle.getX(), circle.getY(), circle.getRadius() * 2, circle.getRadius() * 2);
//    }

    private List<Circle> circles;

    public void setCircles(final List<Circle> circles) {
        this.circles = circles;
    }

    @Override
    protected void paintComponent(final Graphics graphics) {
        super.paintComponent(graphics);
        for (Circle circle : circles)
            graphics.fillOval(circle.getX(), circle.getY(), circle.getRadius() * 2, circle.getRadius() * 2);
    }
}

通过这种方式,您可能无法解决所有基本问题,但只需稍作修改即可使程序正常运行。 Swing是一个非常好的图书馆,可以非常有趣地了解更多信息。