我已经完成了一个程序,该程序以数值方式解决了一组微分方程,该微分方程描述了“任意”疾病如何在孤立且恒定的人群中运动,这是我前一段时间上一堂课的编程任务。我所做的扩展是添加一些可以暂停,重置和“播放”模拟的图形组件,以及允许我更改方程式中某些常量的某些组件。
所有这些都是编程中的一项练习,因为我发现它很有趣,令人兴奋并希望变得更好。
但是,目前我还很困惑,现在我想做的是制作一个非常简单的动画形式。我想以网格形式可视化获得的感染,易感性和耐药性数量数据。我设法创建了网格,并对如何放置点有了一个想法。
我的问题是如何在程序运行时绘制点,我可以在网格中绘制一个点,但是仅在创建网格时就可以。我需要能够在网格中的特定位置创建一个点,直到点的数量达到有限的数量(例如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
监听“刻度”。每次打勾时,都会调用actionPerformed
的ActionListener
。在这里,您可以放置代码来更新用于动画的任何变量。例如,您更新
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/