Я пытаюсь написать простой графический интерфейс в java.switch, который активирует анимацию при нажатии кнопки. Анимация работает, когда я удаляю кнопку и просто запускаю анимацию напрямую, но когда я помещаю код анимации в класс ActionListener, который запускается при нажатии кнопки, он больше не работает. В чем причина этого?
Код, рабочая анимация без кнопки:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.concurrent.TimeUnit;
class SimpleGUI {
private JFrame frame;
private JPanel panel;
private int xPos = 70;
private int yPos = 70;
class DrawPanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.green);
g.fillOval(xPos, yPos, 40, 40);
}
}
public void go() {
frame = new JFrame();
panel = new DrawPanel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(BorderLayout.CENTER, panel);
//frame.getContentPane().add(BorderLayout.SOUTH, button);
frame.setSize(300,300);
frame.setVisible(true);
for(int i = 0; i < 100; i++) {
xPos++;
yPos++;
panel.repaint();
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
class GUITest {
public static void main(String[] args) {
SimpleGUI gui = new SimpleGUI();
gui.go();
}
}
Код, неработающая анимация с кнопкой:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.concurrent.TimeUnit;
class SimpleGUI {
private JFrame frame;
private JPanel panel;
private int xPos = 70;
private int yPos = 70;
class DrawPanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.green);
g.fillOval(xPos, yPos, 40, 40);
}
}
class AnimationListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
for(int i = 0; i < 100; i++) {
xPos++;
yPos++;
panel.repaint();
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
public void go() {
frame = new JFrame();
panel = new DrawPanel();
JButton button = new JButton("Start Animation");
button.addActionListener(event -> button.setText("Animation starts"));
button.addActionListener(new AnimationListener());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(BorderLayout.CENTER, panel);
frame.getContentPane().add(BorderLayout.SOUTH, button);
frame.setSize(300,300);
frame.setVisible(true);
}
}
class GUITest {
public static void main(String[] args) {
SimpleGUI gui = new SimpleGUI();
gui.go();
}
}
Я ожидал, что код класса ActionListener будет выполнен полностью при нажатии кнопки. Я также попытался удалить цикл for в классе ActionListener, чтобы круг перемещался на один шаг при каждом нажатии кнопки. Это работает, и я могу переместить круг на все 100 шагов, несколько раз нажимая кнопку.
Таймер качания также работает в потоке диспетчеризации событий, однако, если он просто анимирует один шаг, а затем завершает работу, это возможно.




У вас проблема с потоками.
Работающий:
Вы запускаете приложение в основном потоке. Он создает пользовательский интерфейс, который вызывает Event Dispatching Thread для обновления пользовательского интерфейса. Параллельно ваше приложение запускает go() в основном потоке, и, похоже, оно работает. Хотя конструктивный недостаток все же есть.
Не работает:
Метод go() запускается нажатием кнопки, которая сама вызывается в Event Dispatching Thread. Поскольку метод go() не завершается, поток остается занятым и у него нет времени на обновление пользовательского интерфейса.
Решение:
Есть хороший учебник: https://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html
Вам нужен Timer. например
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class SimpleGUI {
private JButton bnStart;
private JFrame frame;
private DrawPanel panel;
private int xPos = 70;
private int yPos = 70;
private Timer timer;
class DrawPanel extends JPanel implements ActionListener {
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.green);
g.fillOval(xPos, yPos, 40, 40);
}
@Override
public void actionPerformed(ActionEvent event) {
xPos++;
yPos++;
panel.repaint();
if (xPos > 170) {
timer.stop();
bnStart.setText("Start Animation");
}
}
}
public void go() {
frame = new JFrame();
panel = new DrawPanel();
bnStart = new JButton("Start Animation");
bnStart.addActionListener(event -> {
xPos = yPos = 70;
bnStart.setText("Animation starts");
timer = new Timer(50, panel);
timer.start();
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(BorderLayout.CENTER, panel);
frame.getContentPane().add(BorderLayout.SOUTH, bnStart);
frame.setSize(300, 300);
frame.setVisible(true);
}
}
public class GUITest {
public static void main(String[] args) {
SimpleGUI gui = new SimpleGUI();
gui.go();
}
}
Вы пытались найти Java-анимацию свинга ? Я думаю, вам стоит использовать Таймер качания.