为什么在音频片段来回拖动时,它们就会失效?

后端开发 2026-07-12

我想做一个音频播放器,仅仅是为了更好地理解Java中的栈和GUI。原本我预计选中音频文件后它会播放,之前是会的,但现在并没有播放。我又回到过去的代码里查看差异,但没有发现任何应该导致它无法工作的差异,在终端也没有报错。

我也尝试通读Java SE 8的文档,以及一些关于Java中音频剪辑的视频,似乎都和我所知的一样正确,不过不确定问题出在哪里;另外,为了测试,我从代码中移除了 current = numberofClips;,结果只有两段音频中的其中一个能播放,原因不明。

以下是代码:

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.io.File;
import java.util.Stack;
import javax.imageio.ImageIO;
import javax.sound.sampled.*;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;

public class MusicPlayerGui extends JFrame implements ActionListener {

  // Image centered
  BufferedImage image = null;

  // Colors
  public static final Color BG_Color = Color.BLACK;
  public static final Color FG_Color = Color.WHITE;

  // Song
  JLabel songImage;
  JLabel songTitle;
  JSlider playbackSlider;

  // Toolbar
  JToolBar toolbar;
  JMenuBar menuBar;
  JMenu songMenu;
  JMenuItem loadMusic;
  JMenuItem loadPlaylist;

  // Button
  JPanel playbackBtns;
  JButton prevButton;
  JButton playButton;
  JButton pauseButton;
  JButton nextButton;

  // Music stuff
  Stack<Clip> clips = new Stack<>();
  int next;
  int prev;
  long frames;
  int current = 0;
  float frameRate;
  int numberofClips;
  AudioFormat format;
  boolean play = true;
  boolean first = true;
  double durationInSeconds;
  long seconds;
  boolean playlist;

  public MusicPlayerGui() {
    super("Music Player");
    setSize(400, 600);

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setLocationRelativeTo(null);
    setResizable(false);
    setLayout(null);

    getContentPane().setBackground(BG_Color);
    addUiComponents();
  }

  private void addUiComponents() {
    addToolbar();
    addPlaybackBtns();

    songImage = new JLabel(loadImage("./res/record.png"));
    songImage.setBounds(0, 50, getWidth() - 20, 225);
    add(songImage);

    songTitle = new JLabel("Song title");
    songTitle.setBounds(0, 285, getWidth() - 10, 30);
    songTitle.setFont(new Font("Dialog", Font.BOLD, 24));
    songTitle.setForeground(FG_Color);
    songTitle.setHorizontalAlignment(SwingConstants.CENTER);
    add(songTitle);

    playbackSlider = new JSlider();
    playbackSlider.setBounds(getWidth() / 2 - 300 / 2, 365, 300, 40);
    playbackSlider.setBackground(null);
    add(playbackSlider);
  }

  private void addToolbar() {
    toolbar = new JToolBar();
    toolbar.setBounds(0, 0, getWidth(), 30);
    toolbar.setFloatable(false);
    add(toolbar);

    menuBar = new JMenuBar();
    toolbar.add(menuBar);

    songMenu = new JMenu("Song");
    menuBar.add(songMenu);

    loadMusic = new JMenuItem("Load music from directory");
    loadMusic.addActionListener(this);
    songMenu.add(loadMusic);

    loadPlaylist = new JMenuItem("Load playlist from directory");
    loadPlaylist.addActionListener(this);
    songMenu.add(loadPlaylist);
  }

  private void addPlaybackBtns() {
    playbackBtns = new JPanel();
    playbackBtns.setBounds(0, 435, getWidth() - 10, 80);
    playbackBtns.setBackground(null);

    prevButton = new JButton(loadImage("./res/previous.png"));
    prevButton.setBorderPainted(false);
    prevButton.setBackground(null);
    prevButton.addActionListener(this);
    playbackBtns.add(prevButton);

    playButton = new JButton(loadImage("./res/play.png"));
    playButton.setBorderPainted(false);
    playButton.setBackground(null);
    playButton.addActionListener(this);
    playbackBtns.add(playButton);

    pauseButton = new JButton(loadImage("./res/pause.png"));
    pauseButton.setBorderPainted(false);
    pauseButton.setBackground(null);
    pauseButton.setVisible(false);
    pauseButton.addActionListener(this);
    playbackBtns.add(pauseButton);

    nextButton = new JButton(loadImage("./res/next.png"));
    nextButton.setBorderPainted(false);
    nextButton.setBackground(null);
    playbackBtns.add(nextButton);

    add(playbackBtns);
  }

  private ImageIcon loadImage(String imagePath) {
    try {
      BufferedImage image = ImageIO.read(new File(imagePath));
      return new ImageIcon(image);
    } catch (IOException e) {
      e.printStackTrace();
    }
    return null;
  }

  @Override
  public void actionPerformed(ActionEvent e) {
    if (e.getSource() == loadMusic) {
      JFileChooser fileChooser = new JFileChooser();
      fileChooser.setFileFilter(new FileNameExtensionFilter("Music Files", "wav"));
      int response = fileChooser.showOpenDialog(null);
      if (response == JFileChooser.APPROVE_OPTION) {
        File file = new File(fileChooser.getSelectedFile().getAbsolutePath());

        try (AudioInputStream aS = AudioSystem.getAudioInputStream(file)) {
          if (play == true) {
            enablePlayButton();
            clips.get(current).stop();
          }

          numberofClips++;
          Clip clip = AudioSystem.getClip();
          current = numberofClips;


          format = aS.getFormat();
          frames = aS.getFrameLength();
          durationInSeconds = frames / format.getFrameRate();
          seconds = (long) (durationInSeconds % 60);

          clip.open(aS);
          clips.push(clip);

        } catch (UnsupportedAudioFileException | IOException | LineUnavailableException ex) {
          System.out.println(ex);
        }
      }
    }

    if (e.getSource() == loadPlaylist) {
      JFileChooser fileChooser = new JFileChooser();
      fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);

      int response = fileChooser.showOpenDialog(null);
      if (response == JFileChooser.APPROVE_OPTION) {
        File files = new File(fileChooser.getSelectedFile().getAbsolutePath());

        for (File file : files.listFiles()) {

          try (AudioInputStream aS = AudioSystem.getAudioInputStream(file)) {
            if (play == true) {
              enablePlayButton();
              clips.get(current).stop();
            }

            numberofClips++;
            Clip clip = AudioSystem.getClip();

            format = aS.getFormat();
            frames = aS.getFrameLength();
            durationInSeconds = frames / format.getFrameRate();
            seconds = (long) (durationInSeconds % 60);

            playlist = true;
            clip.open(aS);
            clips.push(clip);

          } catch (UnsupportedAudioFileException | IOException | LineUnavailableException ex) {
            System.out.println(ex);
          }
        }
      }
    }

    if (e.getSource() == playButton) {
      enablePauseButton();
      clips.get(current).start();

      next = current + 1;
      prev = current - 1;

      if (playlist) {
        if ((clips.empty() && clips.get(current).isRunning() != false) && next > numberofClips) {
          enablePauseButton();
          clips.get(next).start();
          current = next;
        }
      }
    }

    if (e.getSource() == pauseButton) {
      enablePlayButton();
      clips.get(current).stop();
    }

    if (e.getSource() == prevButton) {
      if (first != true && prev < 0) {
        enablePlayButton();
        clips.get(current).stop();
        clips.get(prev).start();
        current = prev;
        next = current + 1;
        prev = current - 1;
      }
    }
  }

  void enablePauseButton() {
    JButton playBtn = (JButton) playbackBtns.getComponent(1);
    JButton pauseBtn = (JButton) playbackBtns.getComponent(2);

    playBtn.setVisible(false);
    playBtn.setEnabled(false);

    pauseBtn.setVisible(true);
    pauseBtn.setEnabled(true);
    play = true;
  }

  void enablePlayButton() {
    JButton playBtn = (JButton) playbackBtns.getComponent(1);
    JButton pauseBtn = (JButton) playbackBtns.getComponent(2);

    playBtn.setVisible(true);
    playBtn.setEnabled(true);

    pauseBtn.setVisible(false);
    pauseBtn.setEnabled(false);
    play = false;
  }
}

另外,这里是主文件,便于运行:

import javax.swing.SwingUtilities;

public class Main {

  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {

      @Override
      public void run() {
        new MusicPlayerGui().setVisible(true);;
      }
    });
  }
}

解决方案

在实现了几个缺失的方法(addPlaybackBtnsenablePlayButtonenablePauseButton)之后,我觉得这个最小可复现示例大致实现如下代码:

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.Stack;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileNameExtensionFilter;

public class AssumedMRE {

    public static class MusicPlayerGui extends JFrame implements ActionListener {

        JMenu songMenu;
        JMenuItem loadMusic;
        JMenuItem loadPlaylist;

        // Button
        JPanel playbackBtns;
        JButton prevButton;
        JButton playButton;
        JButton pauseButton;
        JButton nextButton;

        // Music stuff
        Stack<Clip> clips = new Stack<>();
        int next;
        int prev;
        int current = 0;
        float frameRate;
        int numberofClips;
        boolean play = true;
        boolean first = true;
        boolean playlist;

        public MusicPlayerGui() {
            super("Music Player");
            setSize(400, 600);

            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setLocationRelativeTo(null);
            setResizable(false);
            //setLayout(null);
            setLayout(new GridLayout(0, 1));

            //getContentPane().setBackground(BG_Color);

            // Ignore this
            addUiComponents();
        }

        private void addUiComponents() {
            addToolbar();
            addPlaybackBtns();
            // removed the rest of the function
        }

        //Modified method.
        private void addToolbar() {
            //toolbar = new JToolBar();
            //toolbar.setBounds(0, 0, getWidth(), 30);
            //toolbar.setFloatable(false);
            //add(toolbar);

            //menuBar = new JMenuBar();
            //toolbar.add(menuBar);
            final JMenuBar menuBar = new JMenuBar();
            super.setJMenuBar(menuBar);

            songMenu = new JMenu("Song");
            menuBar.add(songMenu);

            loadMusic = new JMenuItem("Load music from directory");
            loadMusic.addActionListener(this);
            songMenu.add(loadMusic);

            loadPlaylist = new JMenuItem("Load playlist from directory");
            loadPlaylist.addActionListener(this);
            songMenu.add(loadPlaylist);
        }

        //Assumed method body...
        private void addPlaybackBtns() {
            playbackBtns = new JPanel();
            super.add(playbackBtns);

            prevButton = new JButton("Previous");
            prevButton.addActionListener(this);
            playbackBtns.add(prevButton);

            playButton = new JButton("Play");
            playButton.addActionListener(this);
            playbackBtns.add(playButton);

            pauseButton = new JButton("Pause");
            pauseButton.addActionListener(this);
            playbackBtns.add(pauseButton);

            nextButton = new JButton("Next");
            nextButton.addActionListener(this);
            playbackBtns.add(nextButton);
        }

        //Assumed method body...
        private void enablePlayButton() {
            playButton.setEnabled(true);
            pauseButton.setEnabled(false);
        }

        //Assumed method body...
        private void enablePauseButton() {
            playButton.setEnabled(false);
            pauseButton.setEnabled(true);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == loadMusic) {
                JFileChooser fileChooser = new JFileChooser();
                fileChooser.setFileFilter(new FileNameExtensionFilter("Music Files", "wav"));
                int response = fileChooser.showOpenDialog(null);
                if (response == JFileChooser.APPROVE_OPTION) {
                    File file = new File(fileChooser.getSelectedFile().getAbsolutePath());

                    try (AudioInputStream aS = AudioSystem.getAudioInputStream(file)) {
                        if (play == true) {
                            enablePlayButton();
                            clips.get(current).stop();
                        }

                        numberofClips++;
                        Clip clip = AudioSystem.getClip();
                        current = numberofClips;

                        clip.open(aS);
                        clips.push(clip);

                    } catch (UnsupportedAudioFileException | IOException | LineUnavailableException ex) {
                        System.out.println(ex);
                    }
                }
            }

            if (e.getSource() == loadPlaylist) {
                JFileChooser fileChooser = new JFileChooser();
                fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);

                int response = fileChooser.showOpenDialog(null);
                if (response == JFileChooser.APPROVE_OPTION) {
                    File files = new File(fileChooser.getSelectedFile().getAbsolutePath());

                    for (File file : files.listFiles()) {

                        try (AudioInputStream aS = AudioSystem.getAudioInputStream(file)) {
                            if (play == true) {
                                enablePlayButton();
                                clips.get(current).stop();
                            }

                            numberofClips++;
                            Clip clip = AudioSystem.getClip();

                            playlist = true;
                            clip.open(aS);
                            clips.push(clip);

                        } catch (UnsupportedAudioFileException | IOException | LineUnavailableException ex) {
                            System.out.println(ex);
                        }
                    }
                }
            }

            if (e.getSource() == playButton) {
                enablePauseButton();
                clips.get(current).start();

                next = current + 1;
                prev = current - 1;

                if (playlist) {
                    if ((clips.empty() && clips.get(current).isRunning() != false) && next > numberofClips) {
                        enablePauseButton();
                        clips.get(next).start();
                        current = next;
                    }
                }
            }

            if (e.getSource() == pauseButton) {
                enablePlayButton();
                clips.get(current).stop();
            }

            if (e.getSource() == prevButton) {
                if (first != true && prev < 0) {
                    enablePlayButton();
                    clips.get(current).stop();
                    clips.get(prev).start();
                    current = prev;
                    next = current + 1;
                    prev = current - 1;
                }
            }

            //Assumed extra code:
            if (e.getSource() == nextButton) {
                if (!clips.isEmpty() && next < clips.size()) {
                    enablePlayButton();
                    clips.get(current).stop();
                    clips.get(next).start();
                    current = next;
                    next = current + 1;
                    prev = current - 1;
                }
            }
        }
    }

    public static void main(final String[] args) {
        SwingUtilities.invokeLater(() -> new MusicPlayerGui().setVisible(true));
    }
}

需要修复的一些问题包括:

  • 变量 play 在初始时应以 false 作为起点,因为没有正在播放的音轨。如果使用 true,在加载音乐文件时应用程序会崩溃,因为它试图从剪辑栈中停止当前正在播放的剪辑(但 clips 栈是空的,因此会得到一个 ArrayIndexOutOfBoundsException)。而且该变量的值在代码中没有在任何地方改变,这就使它的作用失效。最后如果该变量用来指示当前是否正在播放歌曲,那么这个变量是冗余的(不需要),因为我们可以在当前剪辑上使用 isActive() 来进行判断。
  • 变量 first,我猜,是用来表示我们是在播放第一首歌还是栈中还有歌曲。任一情况都可以从 clips 栈和 current 索引中检查到,因此这个变量并不需要。
  • 变量 numberofClips 可以省略,因为它总是反映 clips.size(),所以在需要使用 numberofClips 的地方,只要改用 clips.size() 即可。
  • 变量 nextprev 可以省略,因为它们总是等于 current 加一或减一,因此我们始终可以分别改用 current + 1current - 1,以避免始终让它们与 current 同步。

所以关于所假定的最小可复现示例的核心问题在于 current 的数值在加载/播放/暂停歌曲时没有被正确赋值(这导致了 ArrayIndexOutOfBoundsException),以及播放器状态检查条件(导致原本应执行的代码未被执行)。

修复上述问题以及一些其他的小改动后,播放器就能工作。以下是可工作的代码(最小改动):

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.Stack;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileNameExtensionFilter;

public class Main {

    public static class MusicPlayerGui extends JFrame implements ActionListener {

        JMenu songMenu;
        JMenuItem loadMusic;
        JMenuItem loadPlaylist;

        // Button
        JPanel playbackBtns;
        JButton prevButton;
        JButton playButton;
        JButton pauseButton;
        JButton nextButton;

        // Music stuff
        Stack<Clip> clips = new Stack<>();
        //int next; //Removed variable.
        //int prev; //Removed variable.
        int current = 0;
        float frameRate;
        //int numberofClips; //Removed variable.
        //boolean play = true; //Removed variable.
        //boolean first = true; //Removed variable.
        boolean playlist;

        public MusicPlayerGui() {
            super("Music Player");
            setSize(400, 600);

            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setLocationRelativeTo(null);
            setResizable(false);
            //setLayout(null);
            setLayout(new GridLayout(0, 1));

            //getContentPane().setBackground(BG_Color);

            // Ignore this
            addUiComponents();
        }

        private void addUiComponents() {
            addToolbar();
            addPlaybackBtns();
            // removed the rest of the function
        }

        //Modified method.
        private void addToolbar() {
            //toolbar = new JToolBar();
            //toolbar.setBounds(0, 0, getWidth(), 30);
            //toolbar.setFloatable(false);
            //add(toolbar);

            //menuBar = new JMenuBar();
            //toolbar.add(menuBar);
            final JMenuBar menuBar = new JMenuBar();
            super.setJMenuBar(menuBar);

            songMenu = new JMenu("Song");
            menuBar.add(songMenu);

            loadMusic = new JMenuItem("Load music from directory");
            loadMusic.addActionListener(this);
            songMenu.add(loadMusic);

            loadPlaylist = new JMenuItem("Load playlist from directory");
            loadPlaylist.addActionListener(this);
            songMenu.add(loadPlaylist);
        }

        //Assumed method body...
        private void addPlaybackBtns() {
            playbackBtns = new JPanel();
            super.add(playbackBtns);

            prevButton = new JButton("Previous");
            prevButton.addActionListener(this);
            prevButton.setEnabled(false);
            playbackBtns.add(prevButton);

            playButton = new JButton("Play");
            playButton.addActionListener(this);
            playButton.setEnabled(false);
            playbackBtns.add(playButton);

            pauseButton = new JButton("Pause");
            pauseButton.addActionListener(this);
            pauseButton.setEnabled(false);
            playbackBtns.add(pauseButton);

            nextButton = new JButton("Next");
            nextButton.addActionListener(this);
            nextButton.setEnabled(false);
            playbackBtns.add(nextButton);
        }

        //Assumed method body...
        private void enablePlayButton() {
            playButton.setEnabled(true);
            pauseButton.setEnabled(false);
        }

        //Assumed method body...
        private void enablePauseButton() {
            playButton.setEnabled(false);
            pauseButton.setEnabled(true);
        }

        //New method.
        private void validateButtonsState() {
            if (!clips.isEmpty()) {
                prevButton.setEnabled(current - 1 >= 0);
                nextButton.setEnabled(current + 1 < clips.size());
                if (current >= 0 && current < clips.size()) {
                    playButton.setEnabled(!clips.get(current).isActive());
                    pauseButton.setEnabled(clips.get(current).isActive());
                }
                else {
                    playButton.setEnabled(false);
                    pauseButton.setEnabled(false);
                }
            }
            else {
                playButton.setEnabled(false);
                pauseButton.setEnabled(false);
                prevButton.setEnabled(false);
                nextButton.setEnabled(false);
            }
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == loadMusic) {
                JFileChooser fileChooser = new JFileChooser();
                fileChooser.setFileFilter(new FileNameExtensionFilter("Music Files", "wav"));
                int response = fileChooser.showOpenDialog(null);
                if (response == JFileChooser.APPROVE_OPTION) {
                    File file = new File(fileChooser.getSelectedFile().getAbsolutePath());

                    try (AudioInputStream aS = AudioSystem.getAudioInputStream(file)) {
                        if (!clips.isEmpty() && clips.get(current).isActive()) {
                            //enablePlayButton(); //Not needed, since we added the 'validateButtonsState' call at the end of the listener body.
                            clips.get(current).stop();
                        }

                        //numberofClips++;
                        Clip clip = AudioSystem.getClip();
                        //current = numberofClips;

                        clip.open(aS);
                        clips.push(clip);
                        current = clips.size() - 1;

                        ////'current' is updated, so 'next' and 'prev' should also be updated:
                        //prev = current - 1;
                        //next = current + 1;

                    } catch (UnsupportedAudioFileException | IOException | LineUnavailableException ex) {
                        ex.printStackTrace();
                        //System.out.println(ex);
                    }
                }
            }

            if (e.getSource() == loadPlaylist) {
                JFileChooser fileChooser = new JFileChooser();
                fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);

                int response = fileChooser.showOpenDialog(null);
                if (response == JFileChooser.APPROVE_OPTION) {
                    File files = new File(fileChooser.getSelectedFile().getAbsolutePath());

                    for (File file : files.listFiles()) {

                        try (AudioInputStream aS = AudioSystem.getAudioInputStream(file)) {
                            if (!clips.isEmpty() && clips.get(current).isActive()) {
                                //enablePlayButton(); //Not needed, since we added the 'validateButtonsState' call at the end of the listener body.
                                clips.get(current).stop();
                            }

                            //numberofClips++;
                            Clip clip = AudioSystem.getClip();

                            playlist = true;
                            clip.open(aS);
                            clips.push(clip);

                        } catch (UnsupportedAudioFileException | IOException | LineUnavailableException ex) {
                            ex.printStackTrace();
                            //System.out.println(ex);
                        }
                    }
                }
            }

            if (e.getSource() == playButton) {
                enablePauseButton();
                clips.get(current).start();

                //next = current + 1;
                //prev = current - 1;

                ///*You don't need the following commented code, since 'enablePauseButton()'
                //is already called, but also the 'current' song is already playing. If you
                //want to start the next song here, then you should have stopped the
                //'current' one first (as in the action taken by 'prevButton' and 'nextButton')
                //and then update 'next' and 'prev' indices.*/
                //if (playlist) {
                //    if (!clips.isEmpty() && clips.get(current).isActive() && next < clips.size()) { //Fixed condition.
                //        enablePauseButton();
                //        clips.get(next).start();
                //        current = next;
                //    }
                //}
            }

            if (e.getSource() == pauseButton) {
                enablePlayButton();
                clips.get(current).stop();
            }

            if (e.getSource() == prevButton) {
                if (!clips.isEmpty() && current - 1 >= 0) { //Fixed condition.
                    if (clips.get(current).isActive()) {
                        enablePauseButton(); //Changed from enablePlayButton()... But this is not actually needed at all.
                        clips.get(current).stop();
                        clips.get(current - 1).start();
                    }
                    current = current - 1;
                    //next = current + 1;
                    //prev = current - 1;
                }
            }

            //Assumed extra code:
            if (e.getSource() == nextButton) {
                if (!clips.isEmpty() && current + 1 < clips.size()) {
                    if (clips.get(current).isActive()) {
                        clips.get(current).stop();
                        clips.get(current + 1).start();
                    }
                    current = current + 1;
                }
            }

            validateButtonsState();
        }
    }

    public static void main(final String[] args) {
        SwingUtilities.invokeLater(() -> new MusicPlayerGui().setVisible(true));
    }
}

通过添加一个 [addLineListener] 的 LineListener 来检测歌曲结束,并据此重新验证播放与暂停按钮的 enabled 状态,可以进一步提升播放器的功能,但在调试给定代码时这并不关键。

有关如何使用Java Sound API的有用资源包括Java Tutorials,以及当前站点上 javasound 标签的信息。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章