我已经完成了一个程序,该程序以数值方式解决了一组微分方程,该微分方程描述了“任意”疾病如何在孤立且恒定的人群中运动,这是我前一段时间上一堂课的编程任务。我所做的扩展是添加一些可以暂停,重置和“播放”模拟的图形组件,以及允许我更改方程式中某些常量的某些组件。

所有这些都是编程中的一项练习,因为我发现它很有趣,令人兴奋并希望变得更好。

但是,目前我还很困惑,现在我想做的是制作一个非常简单的动画形式。我想以网格形式可视化获得的感染,易感性和耐药性数量数据。我设法创建了网格,并对如何放置点有了一个想法。

我的问题是如何在程序运行时绘制点,我可以在网格中绘制一个点,但是仅在创建网格时就可以。我需要能够在网格中的特定位置创建一个点,直到点的数量达到有限的数量(例如30)为止。在这一点上,我想删除第一个点,左边的那个点,所有点都移到左侧,然后将新点放置在网格的最右端,然后重复整个过程。

我想我可以通过有关paintComponent()方法的帮助/提示以及是否完全需要使用repaint()方法来解决问题,由于某种原因,我无法解决这些问题。我已经阅读了有关Java的课程文献,但是尽管他在很多章节中解释了大多数不同的图形组件,但他并没有对这些方法说太多,只是您不要求使用paintComponent()方法,而是是自动完成的。

如果有不清楚的地方,请告诉我,我会尽力澄清。

提前致谢。

//
福克斯·穆尔德

最佳答案

我想我可以通过有关paintComponent()方法的帮助/提示以及是否完全需要使用repaint()方法来弄清问题,由于某种原因,我无法解决这些问题。


基本上,说您通过扩展JPanel创建一个自定义组件。当您@Override paintComponent()方法时,它会隐式地为您调用,因此您不必调用它。因此,无论您在方法内部进行什么绘制,都将在您的表面上绘制。例如

public class DrawingPanel extends JPanel {
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.fillOval(x, y, 10, 10);
    }
}


调用repaint()时,基本上是在隐式调用paintComponent方法。因此,要回答您的问题,是的,如果要进行动画处理,则需要调用它,因为您需要在paintComponent()方法中更新某种变量(例如x和y),以查看图形中的任何更改。 。

您可以在Performing Custom Painting上看到更多信息

为了不处理实际的动画,您需要使用javax.swing.Timer。您可以在How to use Swing Timers上看到更多信息。这是基本构造

Timer ( int delayInMillis, ActionListener listener )


其中delayInMillis是刻度之间的延迟时间(在本例中为动画),而ActionListener监听“刻度”。每次打勾时,都会调用actionPerformedActionListener。在这里,您可以放置​​代码来更新用于动画的任何变量。

例如,您更新actionPerformed中的x和y,然后调用repaint()

public class DrawingPanel extends JPanel {

    int x = 50;
    int y = 50;

    public DrawingPanel() {
        Timer timer = new Timer(40, new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                x += 5;
                y += 5;
                repaint();
            }
        });
        timer.start();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.fillOval(x, y, 10, 10);
    }
}


现在,这只是一个简单的例子。但是在您的情况下,您希望为散点图设置动画。因此,您可以做的是拥有一个Point列表,在actionPerformed中,您可以从该列表中添加拉点,然后将它们推入另一个要绘制的列表中。所以说你有这个

List<Point> originalPoints;
List<Point> pointsToDraw;
...
@Override
protected void paintComponent(Grapchics g) {
    super.paintComponent(g);
    for (Point point : pointsToDraw) {
        g.fillOval(point.x - 5, point.y - 5, 10, 10);
    }
}


基本上,将绘制pointsToDraw列表中的所有点。最初它将是空的。在计时器中,您可以添加到列表中,直到originalPoints列表用完为止。例如。

List<Point> originalPoints;
List<point> pointsToDraw;

private int currentIndex = 0;

public DrawingPanel(List<Point> originalPoints) {
    this.originalPoints = originalPoints;
    pointsToDraw = new ArrayList<>();

    Timer timer = new Timer(40, new ActionListener(){
        @Override
        public void actionPerformed(ActionEvent e) {
            if (currentIndex == originalPoints.size() - 1) {
                ((Timer)e.getSource()).stop();
            } else {
                pointsToDraw.add(originalPoints.get(currentIndex));
                currentIndex++;
            }
            repaint();
        }
    });
    timer.start();
}


所以基本来说,您只需保留一个当前索引。当索引达到原始列表的大小时,您将停止计时器。否则,您只需从originalPoints弹出并推送到pointsToDraw。对于每个添加pointsToDraw的点,都会调用一个repaint(),并且paintComponent还会有另一个点用来绘制一个圆。

结束



UDPATE

我只是重新阅读了您的问题,我认为我已经误解了。如果要绘制所有点,则基本上只有一个列表。并最初绘制所有点。每次打勾时,只需删除第一个索引,将其余所有索引推进,然后在末尾添加一个新索引。尽管这是LinkedList的实现,所以您可能只想使用它

关于java - 图形组件,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24311781/

10-13 06:49