首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Swing 滑動條實戰:JSlider 控制動畫播放速度

     編輯:Java 程式設計入門

功能描述

水平滑動條(範圍 0-30,初始 15)控制定時器間隔,驅動 14 幀小狗圖片循環播放。滑動條刻度標籤、主/次刻度、邊框美化。視窗最小化自動暫停,恢復自動繼續。

核心邏輯:滑動值 ↔ 定時器延遲

fps = slider.getValue()          // 幀率 0-30
delay = 1000 / fps               // 毫秒延遲
timer.setDelay(delay)            // 熱更新定時器間隔
fps == 0 → timer.stop()          // 0 幀率 = 暫停

完整實現:SliderDemo

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

public class SliderDemo extends JPanel implements ActionListener, ChangeListener, WindowListener {
    private static final int FPS_MIN = 0, FPS_MAX = 30, FPS_INIT = 15;
    private static final int FRAMES = 14;

    private JLabel pictureLabel;
    private Timer timer;
    private int frameIndex = 0;
    private boolean paused = false;
    private ImageIcon[] frames = new ImageIcon[FRAMES];

    public SliderDemo() {
        setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));

        // 1. 提示標籤
        JLabel hint = new JLabel("拖動滑動條調整播放速度", JLabel.CENTER);
        hint.setAlignmentX(Component.CENTER_ALIGNMENT);
        add(hint);

        // 2. 滑動條配置
        JSlider slider = new JSlider(JSlider.HORIZONTAL, FPS_MIN, FPS_MAX, FPS_INIT);
        slider.addChangeListener(this);
        slider.setMajorTickSpacing(10);
        slider.setMinorTickSpacing(1);
        slider.setPaintTicks(true);
        slider.setPaintLabels(true);
        slider.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0));
        add(slider);

        // 3. 圖片顯示區
        pictureLabel = new JLabel();
        pictureLabel.setHorizontalAlignment(JLabel.CENTER);
        pictureLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
        pictureLabel.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLoweredBevelBorder(),
            BorderFactory.createEmptyBorder(10, 10, 10, 10)
        ));
        add(pictureLabel);

        // 4. 載入幀圖片(此處假設 resources/frames/frame0.gif ... frame13.gif)
        for (int i = 0; i < FRAMES; i++) {
            frames[i] = createIcon("images/frames/frame" + i + ".gif");
        }
        updateFrame(0);

        // 5. 定時器:初始延遲 1000/15 ≈ 66ms
        int delay = 1000 / FPS_INIT;
        timer = new Timer(delay, this);
        timer.setInitialDelay(delay * 7); // 首輪額外停頓
        timer.setCoalesce(true); // 合併延遲事件
        timer.start();
    }

    // --- ChangeListener: 滑動條變化 ---
    @Override
    public void stateChanged(ChangeEvent e) {
        JSlider src = (JSlider) e.getSource();
        if (!src.getValueIsAdjusting()) {
            int fps = src.getValue();
            if (fps == 0) {
                if (!paused) stopAnimation();
            } else {
                int delay = 1000 / fps;
                timer.setDelay(delay);
                timer.setInitialDelay(delay * 10);
                if (paused) startAnimation();
            }
        }
    }

    // --- ActionListener: 定時器觸發幀切換 ---
    @Override
    public void actionPerformed(ActionEvent e) {
        frameIndex = (frameIndex + 1) % FRAMES;
        updateFrame(frameIndex);
    }

    private void updateFrame(int idx) {
        if (frames[idx] != null) {
            pictureLabel.setIcon(frames[idx]);
            pictureLabel.setText(null);
        } else {
            pictureLabel.setIcon(null);
            pictureLabel.setText("幀 " + idx + " 缺失");
        }
    }

    private void startAnimation() { timer.start(); paused = false; }
    private void stopAnimation() { timer.stop(); paused = true; }

    // --- WindowListener: 視窗狀態聯動 ---
    @Override public void windowIconified(WindowEvent e) { stopAnimation(); }
    @Override public void windowDeiconified(WindowEvent e) { startAnimation(); }
    @Override public void windowOpened(WindowEvent e) {}
    @Override public void windowClosing(WindowEvent e) {}
    @Override public void windowClosed(WindowEvent e) {}
    @Override public void windowActivated(WindowEvent e) {}
    @Override public void windowDeactivated(WindowEvent e) {}

    // 輔助:為頂級視窗註冊 WindowListener
    void addWindowListener(Window w) { w.addWindowListener(this); }

    protected static ImageIcon createIcon(String path) {
        java.net.URL url = SliderDemo.class.getResource(path);
        return (url != null) ? new ImageIcon(url) : null;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame f = new JFrame("SliderDemo");
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            SliderDemo demo = new SliderDemo();
            f.setContentPane(demo);
            demo.addWindowListener(f); // 關鍵:註冊到 JFrame
            f.pack();
            f.setVisible(true);
        });
    }
}

關鍵設計點

機制實現細節
滑動條即時性getValueIsAdjusting() 過濾拖動中間狀態,僅在釋放鼠標後應用新延遲
定時器熱更新timer.setDelay() 運行中動態修改間隔,無需重建
幀循環取模運算 (index + 1) % FRAMES 實現無縫循環
視窗生命周期實現 WindowListener,最小化停止、還原繼續,節省資源
資源加載構造階段預載所有幀至數組,播放期零 I/O,保證流暢

擴展方向

  • 雙滑動條:獨立控制播放速度與當前幀(求閱模式)
  • 音頻同步:javax.sound.sampled.Clip 配合幀時間戳
  • 導出 GIF/MP4:AnimatedGifEncoder / Xuggler
  • JavaFX 遷移:Slider + Timeline + ImageView,聲明式關鍵幀動畫
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved