You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GUI中移动图形对象时需要使用Timer定时器的场景有哪些?

Swing 中GUI移动对象时Timer的使用场景

你目前基于按键事件直接更新位置的实现,在「仅需要用户单次点击/按键触发位移」的简单场景下确实可以正常运行,但是存在明显的适用局限,以下场景必须使用Timer实现:

  • 存在无需用户操作的自动运动元素:比如自动移动的NPC、弹幕、反弹小球、滚动背景、帧动画等,这类元素不需要用户触发事件也要持续更新位置,不用Timer无法实现对应效果。
  • 需要流畅的按住持续移动效果:系统自带的按键重复触发有固定首延迟,且重复频率由系统设置决定,会导致按住按键时移动先卡顿再启动,速度不稳定。用Timer可以固定间隔更新位移,仅需要在按键事件里修改移动方向标志位,就能实现均匀流畅的按住移动效果,操作手感更好。
  • 有大量统一更新的全局逻辑:如果把碰撞检测、状态刷新、计分、属性变更等逻辑分散到每个按键事件回调中,会产生大量重复代码,维护成本高。将所有全局更新逻辑放到Timer的回调中统一执行,代码结构更清晰,扩展性更强。
  • 需要统一控制渲染帧率:可以通过调整Timer的触发间隔(比如设置为16ms对应约60帧),固定整个界面的更新频率,避免不同设备上运行速度差异过大的问题。

无Timer实现代码示例(仅按键触发移动)

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
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()) {
                label3.setText("OVER");
                velY=0;
                velX=0;
            }
        }
    }

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

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

    public class WAction extends AbstractAction{
        @Override
        public void actionPerformed(ActionEvent e) {
            y2-=velY;
            repaint();
            checkCollision();
            if(checkCollision()) {
                label3.setText("OVER");
                velY=0;
                velX=0;
            }
        }
    }
    public class AAction extends AbstractAction{
        @Override
        public void actionPerformed(ActionEvent e) {
            x2-=velX;
            repaint();
            checkCollision();
            if(checkCollision()) {
                label3.setText("OVER");
                velY=0;
                velX=0;
            }
        }
    }
    public class DAction extends AbstractAction{
        @Override
        public void actionPerformed(ActionEvent e) {
            x2+=velY;
            repaint();
            checkCollision();
            if(checkCollision()) {
                label3.setText("OVER");
                velY=0;
                velX=0;
            }
        }
    }
    public class SAction extends AbstractAction{
        @Override
        public void actionPerformed(ActionEvent e) {
            y2+=velY;
            repaint();
            checkCollision();
            if(checkCollision()) {
                label3.setText("OVER");
                velY=0;
                velX=0;
            }
        }
    }
    public boolean checkCollision() {
        return (Math.pow(Math.abs(x2-x),2)+Math.pow(Math.abs(y2-y), 2))<=1600;
    }
}

Timer实现代码示例(支持自动运动)

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
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();
    }
}

内容的提问来源于stack exchange,提问作者user16743592

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 17:09:03