我是Java和OO编程的新手,这里是移动黑白球问题的代码。首先让我在输出中解释我想要的程序:窗口上有n个球(例如6个球),一个黑色和一个白色,每次移动我们只允许移动一个球并且 < em>这个动作应该显示在屏幕上 ,最后所有的白球应该在一侧,所有的黑球应该在另一侧。这是六个球的例子:
我已经编写了程序,看起来效果很好而且算法没有任何缺陷,但我的问题是我无法显示球的运动动画,在每个动作中,一个球应该用它交换位置它的邻居球,但我得到的只是球的最终安排。请有人帮我搞动画部分。我真的很感激。
代码:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.*;
public class DrawPanel extends JPanel implements ActionListener
{
Timer myTimer = new Timer(2000, this);
public static final int NUMBER_OF_CIRCLES = 10; //number of circles which are to moved
static int[] circles = new int[NUMBER_OF_CIRCLES];
public void paintComponent(Graphics g)
{
int x = 0; //start point of circles;
int length = 40; //diagonal of the circles
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Ellipse2D circle;
//painting n circles based on the array
for(int index = 0; index<10; index++)
{
if(circles[index] == 0){ //if the element of the arrayy is 0 then draw a void circle
circle = new Ellipse2D.Double(x, 120, length, length);
g2.draw(circle);
}
else if(circles[index] == 1){ //if the element of the array is 1 them draw a filled circle
circle = new Ellipse2D.Double(x, 120, length, length);
g2.fill(circle);
}
x += 45; //increas start pont of the next circle 45 pixles
}
myTimer.start();
}
public void actionPerformed(ActionEvent e)
{
int tmp; //template for swaping elements
int condition; //condition of the forS
arrayFill(circles); //fills the array based on the writen method, one 1 and one 0 like: 0 1 0 1 0 1 0 1
//here is the part which works good, it changes palces of an elemen at time.
//at the end of this part the array would be like: 1 1 1 1 0 0 0 0
if(NUMBER_OF_CIRCLES % 2 == 0)
condition = circles.length/2 -1;
else
condition = circles.length/2;
for(int i = circles.length-1, k = 1; i>condition; i--, k++)
{
for(int j = i - k; j<i ;j++)
{
tmp = circles[j];
circles[j] = circles[j+1];
circles[j+1] = tmp;
//if we call arrayPrint method it will print the array but I don't know why repaint is not working here
//arrayPrint(circles);
repaint();
}
}
}
//fills the array, one 1 and one 0. Example: 0 1 0 1 0 1 0 1 0 1
public static void arrayFill(int[] array)
{
for(int i = 0; i<array.length; i++)
{
if( i%2 == 0)
array[i] = 0;
else
array[i] = 1;
}
}
}//end of class
主要班级:
import javax.swing.JFrame;
public class BlackAndWhiteBallsMoving {
public static void main(String[] args)
{
DrawPanel myPanel = new DrawPanel();
JFrame myFrame = new JFrame();
myFrame.add(myPanel);
myFrame.setSize(600, 500);
myFrame.setTitle("Black And White Balls Moving");
myFrame.setVisible(true);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}//end of class
答案 0 :(得分:1)
由Timer
触发的事件在与重绘相同的事件线程上执行。调用repaint
不会主动执行绘制事件,而是将其排队等待以后。当您在计时器事件中调用重新绘制时,它们将仅在计时器事件完成后执行。
您需要做的是重构循环,以便每次定时器触发时只执行一次交换。我已经为你做了这个例子:
public class DrawPanel extends JPanel implements ActionListener {
public static final int NUMBER_OF_CIRCLES = 10;
Timer myTimer = new Timer(500, this);
int[] circles = new int[NUMBER_OF_CIRCLES];
public DrawPanel() {
arrayFill(circles);
if(NUMBER_OF_CIRCLES % 2 == 0) {
condition = circles.length/2 -1;
} else {
condition = circles.length/2;
}
i = circles.length - 1;
k = 1;
myTimer.start();
}
int i, j, k;
int condition;
boolean outer = true;
@Override
public void actionPerformed(ActionEvent e) {
if(outer) {
if(i > condition) {
j = i - k; // set j
outer = false; // and move to the inner loop swap
} else {
myTimer.stop(); // the outer loop is done so stop the timer
}
}
if(!outer) {
int tmp = circles[j];
circles[j] = circles[j+1];
circles[j+1] = tmp;
repaint();
j++;
if(j >= i) {
i--;
k++;
outer = true; // move to the outer condition
} // next time the timer triggers
}
}
@Override
protected void paintComponent(Graphics g) {
int x = 0;
int length = 40;
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Ellipse2D circle;
for(int index = 0; index<10; index++) {
if(circles[index] == 0){
circle = new Ellipse2D.Double(x, 120, length, length);
g2.draw(circle);
} else if(circles[index] == 1){
circle = new Ellipse2D.Double(x, 120, length, length);
g2.fill(circle);
}
x += 45;
}
//myTimer.start();
}
public static void arrayFill(int[] array) {
for(int i = 0; i<array.length; i++) {
if( i%2 == 0) {
array[i] = 0;
} else {
array[i] = 1;
}
}
}
}
(我确定它可以用另一种方式考虑。)
此外:
@Override
注释。当你犯某些错误时,这样做会警告你。 (如拼写错误的方法名称或错误地声明其签名。)circles
移动到了一个实例变量,因为我没有看到它应该是静态的原因。它是DrawPanel
实例状态的一部分。circles
。paintComponent
是一种protected
方法,除非有理由将其推广到public
,否则它应保持不变。(我删除了你的评论并改变了支撑方式,只是为了压缩我的答案的代码。)
作为旁注,您应该阅读教程Initial Threads。您没有在Swing事件线程上创建GUI。基本上,您需要在main
的调用中将代码包装在invokeLater
中:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// create and show your GUI
}
});
}
答案 1 :(得分:0)
基本问题在于您的actionPerformed
方法。您的两个for
循环正在非常快速地将阵列重新排列到其最终排列。每次循环迭代都需要几毫秒到几毫秒才能完成(这取决于repaint()方法的工作方式)。整个过程在不到50毫秒左右的时间内完成。这太快了,你的眼睛跟不上。
基本上,repaint()方法正在运行,但它的工作速度太快,人眼无法跟上。
如果你将for
循环分解成每次调用算法的一步,你就可以从计时器触发,并以人类可检测的速度看动画。
答案 2 :(得分:0)
添加绘画线程。它应该总是调用repaint(),
new Thread(){ // this can be started on main or constructor of object
public void run(){
while(true){
repaint();
try {
Thread.sleep(50);
} catch(Exception e){ }
}
}
}.start();
然后,在执行的操作中,标记移动对象(如movingObjects),保持animate_x = 0并保留一个布尔变量,如existAnimation
然后在paintComponent上增加animate_x
animate_x = animate_x + 1;
if (animate_x >= MAX_WIDTH_OF_ANIMATION){
existAnimation = false;
}
并使用此existsAnimation,animate_x和movingObjects
等
public void paintComponent(Graphics g)
{
int x = 0; //start point of circles;
int length = 40; //diagonal of the circles
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Ellipse2D circle;
//painting n circles based on the array
for(int index = 0; index<10; index++)
{
int paint_x = x;
if (movingObjects.has(circles[index])){
paint_x += animate_x;
}
if(circles[index] == 0){ //if the element of the arrayy is 0 then draw a void circle
circle = new Ellipse2D.Double(paint_x, 120, length, length);
g2.draw(circle);
}
else if(circles[index] == 1){ //if the element of the array is 1 them draw a filled circle
circle = new Ellipse2D.Double(paint_x, 120, length, length);
g2.fill(circle);
}
x += 45; //increas start pont of the next circle 45 pixles
}
myTimer.start();
}