【问题标题】:When is a timer needed for moving objects in GUI?何时需要在 GUI 中移动对象的计时器?
【发布时间】:2021-10-28 17:35:59
【问题描述】:

在 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();
        
        
    }


}

【问题讨论】:

  • 一些示例代码可以改进这个问题。
  • 1) 不要覆盖绘画。 Swing 中的自定义绘制是通过覆盖paintComponent(...) 来完成的 2) 不要使用空布局。 3) 所有 Swing 组件都应确定自己的首选尺寸。在进行自定义绘画时,您会覆盖 getPreferredSize()。 4) 一种绘画方法仅用于绘画。不要在绘画方法中启动 Timer。
  • GUI 是事件驱动的。通常,用户使用鼠标或键盘生成事件,GUI 会做出反应。因此,只要用户按下一个键,您就可以轻松移动您的对象 - 无需计时器。 Timer 仅用于在没有用户交互的情况下以设定的时间间隔生成事件。然后,您可以在生成事件时做任何您想做的事情。通常这用于动画。因此,例如,您可以不断地为围绕框架移动的对象设置动画。有关完整示例,请参阅:stackoverflow.com/a/54028681/131872
  • Timer 的另一个用途是允许您处理多个键。只会为最后按下的键生成 KeyEvent。如果您想在游戏中同时通过举起/向右进行对角线运动怎么办?在这种情况下,您需要在按下每个键时对其进行跟踪,然后使用 Timer 以在两个方向上对对象应用移动。查看Motion Using the Keyboard中的KeyboardAnimation.java示例

标签: java user-interface timer


【解决方案1】:

只要你是一个人

  • 直接响应一个事件
  • 并且只更新一次显示

...不使用计时器完全可以。

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

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-31
    • 2012-04-16
    • 1970-01-01
    • 2018-02-26
    • 2011-09-14
    • 1970-01-01
    相关资源
    最近更新 更多