Java JPanel中的移动图形

Java JPanel中的移动图形,java,graphics,Java,Graphics,当点击按钮时,我想在JPanel中从一个地方移动到另一个地方。这是我想出的密码。然而,当我点击按钮时,一切都会立即发生,没有明显的移动,从开始到结束都很慢。椭圆形只是出现在一个新的位置 import java.awt.Color; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.*; import javax.

当点击按钮时,我想在JPanel中从一个地方移动到另一个地方。这是我想出的密码。然而,当我点击按钮时,一切都会立即发生,没有明显的移动,从开始到结束都很慢。椭圆形只是出现在一个新的位置

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.JPanel;
public class testtest implements ActionListener{
    JButton button;
    MyDrawPanel panel;
    int x = 0;
    int y = 0;
    public static void main(String[]args){
        testtest test = new testtest();
        test.go();
    }
    public void go(){
        JFrame frame = new JFrame("Balloon Balls");
        panel = new MyDrawPanel();
        button = new JButton("Restart");
        button.addActionListener(this);
        panel.add(button);
        frame.setSize(300, 300);
        frame.add(panel);
        frame.setVisible(true);
    }

    @Override
    public void actionPerformed (ActionEvent e){
        for(int i=0;i<130;i++){
            x++;
            y++;
            panel.repaint();
            try {
                Thread.sleep(100);
            } catch(Exception ex) { }
        }
    }
    class MyDrawPanel extends JPanel{
        @Override
        public void paintComponent(Graphics g){
            g.fillOval(x, y, 30, 30);
            g.setColor(Color.BLACK);

        }
    }
}
导入java.awt.Color;
导入java.awt.Graphics;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入javax.swing.*;
导入javax.swing.JPanel;
公共类testtest实现ActionListener{
按钮;
MyDrawPanel;
int x=0;
int y=0;
公共静态void main(字符串[]args){
testtest=新的testtest();
test.go();
}
公开作废go(){
JFrame=新JFrame(“气球”);
panel=新的MyDrawPanel();
按钮=新按钮(“重新启动”);
addActionListener(这个);
面板。添加(按钮);
框架。设置尺寸(300300);
框架。添加(面板);
frame.setVisible(true);
}
@凌驾
已执行的公共无效操作(操作事件e){

对于(int i=0;ipaintComponent)来说,它就是这样绘制面板的。最初,面板在开始x y处绘制椭圆形。按下按钮,窗口将被擦除,并在新的XY处重新绘制

移动是一个概念,你需要教计算机。如果我们每秒更新面板多次,然后慢慢移动x和y,我们会产生移动的错觉


制作一个每10毫秒刷新一次的计时器。每次刷新时,稍微增加x和y值,然后重新绘制面板。

Swing是单线程的,不支持线程安全

ActionListener
中使用
Thread.sleep(100)
会阻止事件调度线程,阻止绘制任何内容。只有在
actionPerformed
方法存在后,才会出现新的绘制过程

有关更多详细信息,请参阅

Swing也不是线程安全的,这意味着您永远不应该在EDT上下文之外对UI进行更改

最简单的解决方案是使用,它将允许建立定期定时回调,这些回调在事件调度线程内执行,但不会阻止EDT

您还缺少OO的一个重要概念,即封装。
x
/
y
属性实际上应该由
MyDrawPanel
管理,而不是
testtest

例如

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class testtest implements ActionListener {

    JButton button;
    MyDrawPanel panel;

    public static void main(String[] args) {
        testtest test = new testtest();
        test.go();

    }

    public void go() {
        JFrame frame = new JFrame("Balloon Balls");
        panel = new MyDrawPanel();
        button = new JButton("Restart");
        button.addActionListener(this);
        panel.add(button);
        frame.add(panel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

    }

    private Timer timer;

    public void actionPerformed(ActionEvent e) {
        if (timer != null) {
            return;
        }
        timer = new Timer(100, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent evt) {
                if (panel.update()) {
                    timer.stop();
                    timer = null;
                }
            }
        });
        timer.start();
    }

    class MyDrawPanel extends JPanel {

        private int xPosy = 0;
        private int yPosy = 0;

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(300, 300);
        }

        public boolean update() {
            xPosy++;
            yPosy++;
            repaint();

            return xPosy > getWidth() || yPosy > getHeight();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);            
            g.fillOval(xPosy, yPosy, 30, 30);
            g.setColor(Color.BLACK);
        }
    }
}

除了MadProgrammer中关于Swing线程问题的解释之外,我建议通过实现将gui与其控件分离。
这提供了更好的封装、更好的职责分离,并使线程更容易用于非edt处理。

具有保存视图(gui)需要的所有信息的模型:

在这种情况下,添加了同步以允许线程使用模型。
侦听器的定义如下:

/*
* A simple interface used to link View and Model 
*/
interface Listener {
    void onChange();
}
视图就是这样。它实现了
侦听器
,因此可以侦听
模型
更改:

/*
 * View is just that: a dumb as possible display 
 */
public class View implements Listener{

    private final JButton button;
    private final MyDrawPanel panel;
    private final Model model;

    public View(Model model) {
        this.model = model;
        panel = new MyDrawPanel();
        button = new JButton("Restart");
        panel.add(button);
    }

    public void go(){
        JFrame frame = new JFrame("Balloon Balls");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300, 300);
        frame.add(panel);
        frame.setVisible(true);
    }

    class MyDrawPanel extends JPanel{
        @Override
        public void paintComponent(Graphics g){
            super.paintComponent(g); //always call super
            g.fillOval(model.getX(), model.getY(), 30, 30);
            g.setColor(Color.BLACK);
        }
    }

    @Override
    public void onChange() {
        panel.repaint();
    }

    void addActionListener(ActionListener listener){
        button.addActionListener(listener);
    }
}
总而言之:请参见以下内容:它添加了一个控制模型和视图的控制器。
为了方便和简单,可以将以下代码复制粘贴到名为
View.java
的文件中,然后运行

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

/*
 * View is just that: a dumb as possible display 
 */
public class View implements Listener{

    private final JButton button;
    private final MyDrawPanel panel;
    private final Model model;

    public View(Model model) {
        this.model = model;
        panel = new MyDrawPanel();
        button = new JButton("Restart");
        panel.add(button);
    }

    public void go(){
        JFrame frame = new JFrame("Balloon Balls");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300, 300);
        frame.add(panel);
        frame.setVisible(true);
    }

    class MyDrawPanel extends JPanel{
        @Override
        public void paintComponent(Graphics g){
            super.paintComponent(g); //always call super
            g.fillOval(model.getX(), model.getY(), 30, 30);
            g.setColor(Color.BLACK);
        }
    }

    @Override
    public void onChange() {
        panel.repaint();
    }

    void addActionListener(ActionListener listener){
        button.addActionListener(listener);
    }

    public static void main(String[]args){
        new Controller();
    }
}

/*
 * A simple interface used to link View and Model 
 */
interface Listener {
    void onChange();
}

/*
 * The model contains the information for the view and information from the view
 * The model is independent of the user interface.
 * It notifies Listener on changes. 
 */
class Model {

    private Listener listener;
    private int x = 0,  y = 0;

    synchronized int getX() {return x;}

    synchronized void setX(int x) { this.x = x; }

    synchronized int getY() {return y;}

    synchronized void setY(int y) { this.y = y; }

    void setListener(Listener listener){
        this.listener = listener;
    }
    //notify listener when changed 
    void notifyListener(){
        if(listener != null) {
            listener.onChange();
        }
    }
}

/*
 * The controller "wires" the view and model, and does the processing.
 */
class Controller implements ActionListener{

    private final Model model;
    private final View view;

    public Controller() {
        model = new Model();
        view = new View(model);
        model.setListener(view);
        view.addActionListener(this);
        view.go();
    }

    @Override
    public void actionPerformed (ActionEvent e){

        new Thread(()->{
            for(int i=0;i<130;i++){
                model.setX(model.getX()+1);
                model.setY(model.getY()+1);
                model.notifyListener();
                System.out.println(model.getX()+" - "+ model.getY());
                try {
                    Thread.sleep(100);
                } catch(Exception ex) { }
            }
        }).start();
    }
}
导入java.awt.Color;
导入java.awt.Graphics;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入javax.swing.JButton;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
/*
*视图就是这样:一个尽可能愚蠢的显示
*/
公共类视图实现侦听器{
私人最终按钮;
私人小组;
私有最终模型;
公共视图(模型){
this.model=模型;
panel=新的MyDrawPanel();
按钮=新按钮(“重新启动”);
面板。添加(按钮);
}
公开作废go(){
JFrame=新JFrame(“气球”);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
框架。设置尺寸(300300);
框架。添加(面板);
frame.setVisible(true);
}
类MyDrawPanel扩展了JPanel{
@凌驾
公共组件(图形g){
super.paintComponent(g);//始终调用super
g、 fillOval(model.getX(),model.getY(),30,30);
g、 设置颜色(颜色为黑色);
}
}
@凌驾
更改后的公共无效(){
panel.repaint();
}
void addActionListener(ActionListener侦听器){
addActionListener(listener);
}
公共静态void main(字符串[]args){
新控制器();
}
}
/*
*用于链接视图和模型的简单界面
*/
接口侦听器{
void onChange();
}
/*
*模型包含视图的信息和来自视图的信息
*该模型独立于用户界面。
*它会在更改时通知侦听器。
*/
类模型{
私人倾听者;
私有整数x=0,y=0;
synchronized int getX(){return x;}
同步的void setX(int x){this.x=x;}
synchronized int getY(){return y;}
同步的void setY(int y){this.y=y;}
void setListener(侦听器侦听器){
this.listener=listener;
}
//更改时通知侦听器
void notifyListener(){
if(侦听器!=null){
listener.onChange();
}
}
}
/*
*控制器“连接”视图和模型,并进行处理。
*/
类控制器实现ActionListener{
私有最终模型;
私人最终视图;
公共控制员(){
模型=新模型();
视图=新视图(模型);
model.setListener(视图);
view.addActionListener(this);
view.go();
}
@凌驾
已执行的公共无效操作(操作事件e){
新线程(()->{
对于(inti=0;我猜是一个小错误):
if(!pan
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

/*
 * View is just that: a dumb as possible display 
 */
public class View implements Listener{

    private final JButton button;
    private final MyDrawPanel panel;
    private final Model model;

    public View(Model model) {
        this.model = model;
        panel = new MyDrawPanel();
        button = new JButton("Restart");
        panel.add(button);
    }

    public void go(){
        JFrame frame = new JFrame("Balloon Balls");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300, 300);
        frame.add(panel);
        frame.setVisible(true);
    }

    class MyDrawPanel extends JPanel{
        @Override
        public void paintComponent(Graphics g){
            super.paintComponent(g); //always call super
            g.fillOval(model.getX(), model.getY(), 30, 30);
            g.setColor(Color.BLACK);
        }
    }

    @Override
    public void onChange() {
        panel.repaint();
    }

    void addActionListener(ActionListener listener){
        button.addActionListener(listener);
    }

    public static void main(String[]args){
        new Controller();
    }
}

/*
 * A simple interface used to link View and Model 
 */
interface Listener {
    void onChange();
}

/*
 * The model contains the information for the view and information from the view
 * The model is independent of the user interface.
 * It notifies Listener on changes. 
 */
class Model {

    private Listener listener;
    private int x = 0,  y = 0;

    synchronized int getX() {return x;}

    synchronized void setX(int x) { this.x = x; }

    synchronized int getY() {return y;}

    synchronized void setY(int y) { this.y = y; }

    void setListener(Listener listener){
        this.listener = listener;
    }
    //notify listener when changed 
    void notifyListener(){
        if(listener != null) {
            listener.onChange();
        }
    }
}

/*
 * The controller "wires" the view and model, and does the processing.
 */
class Controller implements ActionListener{

    private final Model model;
    private final View view;

    public Controller() {
        model = new Model();
        view = new View(model);
        model.setListener(view);
        view.addActionListener(this);
        view.go();
    }

    @Override
    public void actionPerformed (ActionEvent e){

        new Thread(()->{
            for(int i=0;i<130;i++){
                model.setX(model.getX()+1);
                model.setY(model.getY()+1);
                model.notifyListener();
                System.out.println(model.getX()+" - "+ model.getY());
                try {
                    Thread.sleep(100);
                } catch(Exception ex) { }
            }
        }).start();
    }
}