Я бы порекомендовал отделить графический интерфейс от его управления путем реализации MVC Pattern .Имейте модель, которая содержит всю информацию, которая необходима представлению (графическому интерфейсу):
/*
* The model contains the information for the view and information from the view
* The model is independent of the user interface.
*/
class Model{
private final int WIDTH = 600;
private final int HEIGHT = 400;
private int x,y, delay;
private final int radius;
Model(int radius) {
this.radius = radius;
x= radius; y= radius; delay = 30; //default values
}
void move(int moveX, int moveY) {
x += moveX; y+= moveY;
}
int getX() { return x; }
void setX(int x) { this.x = x; }
int getY() {return y;}
void setY(int y) { this.y = y; }
int getRaduis() {return radius;}
int getDelay() {return delay;}
void setDelay(int delay) {this.delay = delay;}
int getWidth() {return WIDTH;}
int getHeiht() {return HEIGHT; }
}
Имейте представление, которое использует модель для отображения графического интерфейса.Обратите внимание, что ползунок и анимация находятся на двух отдельных JPanel
с, предложенных Hovercraft Full Of Eels :
/*
* View is just that: a dumb as possible display
*/
class View extends JPanel {
View(Model model) {
setLayout (new BorderLayout());
add(new BallPane(model)); //as explained in Hovercraft Full Of Eels
add(new SliderPane(model), BorderLayout.PAGE_END); //answer
}
class BallPane extends JPanel {
private final Model model;
BallPane(Model model) {
this.model = model;
setPreferredSize (new Dimension (model.getWidth(), model.getHeiht()));
setBackground(Color.black);
}
// ---------------------
// Draw the ball
// ---------------------
@Override
public void paintComponent (Graphics page) {
super.paintComponent (page);
page.setColor(Color.CYAN);
page.fillOval(model.getX(), model.getY(), model.getRaduis()*2, model.getRaduis()*2);
}
}
class SliderPane extends JPanel {
private final Model model;
private final JSlider sSpeeder;
SliderPane(Model model) {
this.model = model;
sSpeeder = new JSlider(JSlider.HORIZONTAL, 0, 200, 30);
sSpeeder.setMajorTickSpacing(40);
sSpeeder.setMinorTickSpacing(10);
sSpeeder.setPaintTicks(true);
sSpeeder.setPaintLabels(true);
sSpeeder.setAlignmentX(Component.LEFT_ALIGNMENT);
sSpeeder.addChangeListener(new SlideListener());
add(sSpeeder);
}
// ***************************************************
// A change listener for the slider.
// ***************************************************
private class SlideListener implements ChangeListener
{
// ------------------------------------------------
// Called when the state of the slider has changed;
// resets the delay on the timer.
// ------------------------------------------------
@Override
public void stateChanged (ChangeEvent event)
{
model.setDelay(sSpeeder.getValue());
}
}
}
}
Собираем все вместе: см. Следующее mvce: добавлен контроллер, управляющий моделью и видом.Для удобства и простоты следующий код можно скопировать в один файл с именем BouncingBall.java
и запустить.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.Timer;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/*
* The controller wires the view and model, and does the processing.
*/
public class BouncingBall {
private final int BALL_SIZE = 25;
private int moveX =5, moveY =5; // increment to move each time
private final Timer timer;
private final Model model;
private JPanel view;
BouncingBall() {
model = new Model(BALL_SIZE);
timer = new Timer(model.getDelay(), new ReboundListener());
makeAndShowGui();
timer.start();
}
private void makeAndShowGui() {
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
view = new View(model);
window.add(view);
window.pack();
window.setResizable(false);
window.setVisible(true);
}
private void updateGui() {
// change direction if ball hits a side
int x = model.getX();
int y = model.getY();
if (x < 0 || x >= model.getWidth() - model.getRaduis()*2) {
moveX = moveX * -1;
}
if (y <= 0 || y >= model.getHeiht() - model.getRaduis()*2) {
moveY = moveY * -1;
}
model.setX(x+moveX);
model.setY(y+moveY);
timer.setDelay(model.getDelay()); //update timer
view.repaint();
}
// ***************************************************
// An action listener for the timer
// ***************************************************
public class ReboundListener implements ActionListener {
// ----------------------------------------------------
// actionPerformed is called by the timer -- it updates
// the position of the bouncing ball
// ----------------------------------------------------
@Override
public void actionPerformed(ActionEvent action) {
updateGui();
}
}
public static void main(String[] args) {
new BouncingBall();
}
}
/*
* The model contains the information for the view and information from the view
* The model is independent of the user interface.
*/
class Model{
private final int WIDTH = 600;
private final int HEIGHT = 400;
private int x,y, delay;
private final int radius;
Model(int radius) {
this.radius = radius;
x= radius; y= radius; delay = 30; //default values
}
void move(int moveX, int moveY) {
x += moveX; y+= moveY;
}
int getX() { return x; }
void setX(int x) { this.x = x; }
int getY() {return y;}
void setY(int y) { this.y = y; }
int getRaduis() {return radius;}
int getDelay() {return delay;}
void setDelay(int delay) {this.delay = delay;}
int getWidth() {return WIDTH;}
int getHeiht() {return HEIGHT; }
}
/*
* View is just that: a dumb as possible display
*/
class View extends JPanel {
View(Model model) {
setLayout (new BorderLayout());
add(new BallPane(model)); //as explained in Hovercraft Full Of Eels
add(new SliderPane(model), BorderLayout.PAGE_END); //answer
}
class BallPane extends JPanel {
private final Model model;
BallPane(Model model) {
this.model = model;
setPreferredSize (new Dimension (model.getWidth(), model.getHeiht()));
setBackground(Color.black);
}
// ---------------------
// Draw the ball
// ---------------------
@Override
public void paintComponent (Graphics page) {
super.paintComponent (page);
page.setColor(Color.CYAN);
page.fillOval(model.getX(), model.getY(), model.getRaduis()*2, model.getRaduis()*2);
}
}
class SliderPane extends JPanel {
private final Model model;
private final JSlider sSpeeder;
SliderPane(Model model) {
this.model = model;
sSpeeder = new JSlider(JSlider.HORIZONTAL, 0, 200, 30);
sSpeeder.setMajorTickSpacing(40);
sSpeeder.setMinorTickSpacing(10);
sSpeeder.setPaintTicks(true);
sSpeeder.setPaintLabels(true);
sSpeeder.setAlignmentX(Component.LEFT_ALIGNMENT);
sSpeeder.addChangeListener(new SlideListener());
add(sSpeeder);
}
// ***************************************************
// A change listener for the slider.
// ***************************************************
private class SlideListener implements ChangeListener
{
// ------------------------------------------------
// Called when the state of the slider has changed;
// resets the delay on the timer.
// ------------------------------------------------
@Override
public void stateChanged (ChangeEvent event)
{
model.setDelay(sSpeeder.getValue());
}
}
}
}