首页 > 解决方案 > 何时需要在 GUI 中移动对象的计时器?

问题描述

在 GUI 中移动对象时,我看到很多使用计时器的视频和教程,但我尝试在没有它的情况下做一些事情,它似乎工作正常。我不太明白什么时候需要一个计时器。非常感谢任何帮助

带有两个移动物体但没有计时器的代码示例

import java.awt.Color;
import java.awt.Event;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;







public class Test2 extends JPanel{
    int x=100,y=200,velX=5,velY=5;
    int x2=300,y2=200;
    Action upAction;
    Action downAction;
    Action leftAction;
    Action rightAction;
    Action wAction;
    Action aAction;
    Action sAction;
    Action dAction;
    JLabel label3 = new JLabel();
    
    public Test2() {
        
        
        this.setLayout(null);
        this.setFocusable(true);
        this.setBackground(Color.LIGHT_GRAY);
        JLabel label1 = new JLabel("Press WASD to control Green Circle");
        label1.setBounds(40, 30, 250, 20);
        label1.setForeground(Color.GREEN);
        this.add(label1);
        JLabel label2 = new JLabel("Press Arrows to control Blue Circle");
        label2.setBounds(250, 30, 250, 20);
        label2.setForeground(Color.BLUE);
        this.add(label2);
        label3 = new JLabel("");
        label3.setBounds(200, 200, 250, 20);
        label3.setForeground(Color.RED);
        this.add(label3);
        upAction= new upAction();
        downAction= new downAction();
        leftAction = new leftAction();
        rightAction = new rightAction();
        wAction= new WAction();
        aAction = new AAction();
        sAction = new SAction();
        dAction= new DAction();
        
        
        
        
        
        this.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("UP"), "uplol");;
        this.getActionMap().put("uplol", upAction);
        this.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("DOWN"), "downlol");
        this.getActionMap().put("downlol", downAction);
        this.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("LEFT"), "leftlol");
        this.getActionMap().put("leftlol", leftAction);
        this.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("RIGHT"), "rightlol");
        this.getActionMap().put("rightlol", rightAction);

        this.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke('w'), "moveup");;
        this.getActionMap().put("moveup", wAction);
        this.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke('a'),"moveleft");
        this.getActionMap().put("moveleft", aAction);
        this.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke('s'), "movedown");
        this.getActionMap().put("movedown", sAction);
        this.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke('d'), "moveright");
        this.getActionMap().put("moveright", dAction);
    }
    
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.GREEN);
        g.fillOval(x,y, 40, 40);
        g.setColor(Color.BLUE);
        g.fillOval(x2, y2, 40, 40);
        
    }


    
    public class upAction extends AbstractAction{

        @Override
        public void actionPerformed(ActionEvent e) {
            y-=velY;
            repaint();
            checkCollision();
            if(checkCollision()==true) {
                label3.setText("OVER");
                velY=0;
                velX=0;
                
                
            }
            
        }
        
    }

    public class downAction extends AbstractAction{

        @Override
        public void actionPerformed(ActionEvent e) {
            y+=velY;
            repaint();
            checkCollision();
            if(checkCollision()==true) {
                label3.setText("OVER");
                velY=0;
                velX=0;
                
            }
        }
    }
        

    public class rightAction extends AbstractAction{

        @Override
        public void actionPerformed(ActionEvent e) {
            x+=velX;
            repaint();
            checkCollision();
            if(checkCollision()==true) {
                label3.setText("OVER");
                velY=0;
                velX=0;
                
            }
            
        }
        
    }
    public class leftAction extends AbstractAction{

        @Override
        public void actionPerformed(ActionEvent e) {
            x-=velX;
            repaint();
            checkCollision();
            if(checkCollision()==true) {
                label3.setText("OVER");
                velY=0;
                velX=0;
                
            }
            
            
        }
        
    }

    
    public class WAction extends AbstractAction{

        @Override
        public void actionPerformed(ActionEvent e) {
            y2-=velY;
            repaint();
            checkCollision();
            if(checkCollision()==true) {
                label3.setText("OVER");
                velY=0;
                velX=0;
                
            }
            
        }
        
    }public class AAction extends AbstractAction{

        @Override
        public void actionPerformed(ActionEvent e) {
            x2-=velX;
            repaint();
            checkCollision();
            if(checkCollision()==true) {
                label3.setText("OVER");
                velY=0;
                velX=0;
                
            }
            
        }
        
    }public class DAction extends AbstractAction{

        @Override
        public void actionPerformed(ActionEvent e) {
            x2+=velY;
            repaint();
            checkCollision();
            if(checkCollision()==true) {
                label3.setText("OVER");
                velY=0;
                velX=0;
                
            }
            
            
        }
        
    }public class SAction extends AbstractAction{

        @Override
        public void actionPerformed(ActionEvent e) {
            y2+=velY;
            repaint();
            checkCollision();
            if(checkCollision()==true) {
                label3.setText("OVER");
                velY=0;
                velX=0;
                
            }
        }
        
    }
    public boolean checkCollision() {
        if((Math.pow(Math.abs(x2-x),2)+Math.pow(Math.abs(y2-y), 2))<=1600) {
            System.out.println("night");
            return true;
            
        }
        return false;
    }
    
        
    



}

带定时器的代码示例

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.util.Timer;

import javax.swing.*;



public class Move extends JPanel implements ActionListener{
    javax.swing.Timer timer= new javax.swing.Timer(5, this);
    int y=0,x=0,velY=2,velX=2;
    
    
    
    
    @Override
    public void paint(Graphics g) {
        
        super.paint(g);
        
        this.setBackground(Color.MAGENTA);
        Graphics2D graphics2d = (Graphics2D)g;
        
        graphics2d.setColor(Color.BLUE);
        graphics2d.fill3DRect(100, 150, 100, 30, true);
        graphics2d.setColor(Color.RED);
        graphics2d.fillOval(200, 250, 28, 61);
        graphics2d.setColor(Color.BLACK);
        graphics2d.drawString("That boy is a monster", 80, 35);
        
        //timer.start();
    }
    public Move() {
        this.setLayout(null);
        JLabel rotter = new JLabel("fool");
        rotter.setBounds(140, 200, 53, 90);
        this.add(rotter);
        
        
        
    }


    @Override
    public void actionPerformed(ActionEvent e) {
        if(x<0||x>560) {
            velX=-velX;
        }
        if(y<0|y>360) {
            velY=-velY;
        }
        x+=velX;
        y+=velY;
        repaint();
        
        
    }


}

标签: javauser-interfacetimer

解决方案


只要你只是

  • 直接对一个事件做出反应
  • 并且只更新一次显示

...没有计时器就可以做到这一点。

您可以/应该使用计时器的情况是

  • 如果你有一个正在进行的动画
  • 如果您不直接对 UI 事件做出反应,而是从另一个线程调用“更改”。

那为什么要使用定时器呢?

  • Swing(您正在使用的)不是线程安全的,因此从 EDT(事件调度线程)以外的线程更改某些 UI 元素可能会给您的 UI 带来混乱和混乱(非常奇怪的行为)。
  • 如果你有正在进行的动画——通常需要某种循环——并且在 EDT 内执行所有这些操作,那么 UI 将无法对任何输入做出反应,甚至无法正确更新自身。

所以你使用一个自动的计时器:

  • 在自己的线程中运行,因此 UI 不会阻塞
  • 并调用 EDT 更新 UI 以保持线程安全和干净

推荐阅读