這只是一個簡單的音頻播放器,我正在玩弄它來制作 GUI。您如何有效地將 Java 邏輯和 GUI 元素分離到不同的檔案和包中?我嘗試在主類中創建方法來執行 ActionListeners,但不能全域使用“track”物件。這是我第一次搞亂 Swing 和 GUI。
import javax.sound.sampled.*;
import javax.swing.*;
import java.awt.*;
import java.io.*;
public class Main extends JFrame{
public static void main(String[] args) throws LineUnavailableException, IOException, UnsupportedAudioFileException {
// Audio
File filePath = new File("src/Tracks/Track.wav");
AudioInputStream stream = AudioSystem.getAudioInputStream(filePath);
Clip track = AudioSystem.getClip();
track.open(stream);
// Buttons
JButton playButton = new JButton("Play");
playButton.addActionListener(e -> {track.start();});
playButton.setHorizontalAlignment(SwingConstants.LEFT);
playButton.setFont(new Font("JetBrains Mono", Font.BOLD, 25));
playButton.setBounds(0,0,100,50);
JButton pauseButton = new JButton("Pause");
pauseButton.addActionListener(e -> {track.stop();});
pauseButton.setHorizontalAlignment(SwingConstants.CENTER);
pauseButton.setFont(new Font("JetBrains Mono", Font.BOLD, 25));
pauseButton.setBounds(150,0,100,50);
JButton replayButton = new JButton("Replay");
replayButton.addActionListener(e -> {track.setMicrosecondPosition(0);});
replayButton.setHorizontalAlignment(SwingConstants.RIGHT);
replayButton.setFont(new Font("JetBrains Mono", Font.BOLD, 25));
replayButton.setBounds(300,0,100,50);
// Frame
JFrame frame = new JFrame();
frame.setTitle("MusicPlayer");
frame.setSize(500, 300);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setVisible(true);
frame.getContentPane().setBackground(new Color(123, 100, 250));
frame.setLayout(new FlowLayout());
frame.add(playButton);
frame.add(pauseButton);
frame.add(replayButton);
}
}
uj5u.com熱心網友回復:
我建議使用分解、包和依賴注入。
Swing 鼓勵開發人員將大量代碼放入大型 main 方法中。在我看來,這是一個錯誤。
將該主要方法分解為類。使它們可獨立測驗,并且僅從構成部分組裝 UI。僅JFrame在 main 方法中創建類。在其建構式中給出JFrame一個實體。JPanel
應該有一個/ui包含擴展類的包JPanel。在其建構式中為其提供所需的所有按鈕、文本框和 GUI 資產。
分解是你的朋友。開始將問題分成幾類。
創建一個為您提供跟蹤實體的工廠。如果你這樣做,你可以在任何需要的地方重復使用它。
uj5u.com熱心網友回復:
有很多方法可以實作這一點,但讓我們分解你的問題......
用戶界面自定義...
Swing 通常是高度可定制的,例如,您可以構建自己的自定義外觀和感覺(部分或整體)。我認為為您的問題構建一個全新的外觀可能有點矯枉過正,但您可以為各個組件提供外觀和感覺,例如......
- 如何自定義一個 JProgressBar?
- Java JButton 設定文本背景顏色
- Java:制作漂亮的 JProgressBar
現在,如果您只想更改組件的一些屬性,那么最好簡單地修改外觀默認屬性,例如UIManager.put("Button.font", new Font(...));.
您需要謹慎使用這種方法,因為并非所有 UI 代理都將使用相同的鍵(看著您的 Nimbus),并且還考慮到這將設定用于您創建的所有新組件的默認屬性。
或者,如果您只想修改一組給定的組件,您可以考慮使用“工廠”樣式的作業流程,例如...
public class Style {
public static JButton makeButton() {
JButton btn = new JButton();
// Apply any configuration you need
// by default
return btn;
}
}
然后,這將為您提供創建這些組件的集中位置,以及如果您想要調整它的集中管理作業流程。
或者,您可以使用構建器模式,該模式可用于根據您希望如何使用它來配置組件...
public class ButtonBuilder {
private String title;
private ActionListener actionListener;
public ButtonBuilder withTitle(String title) {
this.title = title;
return this;
}
public ButtonBuilder withActionListener(ActionListener actionListener) {
this.actionListener = actionListener;
return this;
}
// Add any additional properties you might like to configure
public JButton build() {
JButton btn = new JButton();
if (title != null) {
btn.setText(title);
}
if (actionListener != null) {
btn.addActionListener(actionListener);
}
// Configure the button as you see fit
return btn;
}
}
我還會考慮查看如何使用操作,這是一種創建自包含作業流的好方法,但它可以很容易地應用于 UI 的不同區域。
代碼設計...
以下概念適用于您可能進行的幾乎任何型別的編碼。你想解耦代碼,減少類之間的凝聚力——停下來想一想,如果我在這里改變了一些東西,修改代碼有多難?然后努力尋找易于維護和管理的解決方案。
當您遇到問題時,請嘗試將問題分解為盡可能多的小作業單元(如狀態 - 分解)
這些支持單一職責原則
例如,您有一個“媒體播放器”。它負責加載媒體嗎?它是否負責管理媒體的直播周期?它是否關心媒體來自于我們的實際播放方式?
一般來說,答案是,不。它只關心允許用戶選擇一個動作并將該動作應用于當前的“軌道”
讓我們分解一下。從“軌道”的概念開始......
public interface TrackModel {
enum State {
STOPPED, PLAYING, PAUSED;
}
public Clip getClip();
public State getState();
public void open() throws LineUnavailableException, IOException;
public void close();
public boolean isOpen();
public void play() throws IOException;
public void stop();
public void pause();
public void addChangeListener(ChangeListener changeListener);
public void removeChangeListener(ChangeListener changeListener);
}
現在,“軌道”可以管理任何東西,單曲、專輯、播放串列,我們不在乎,我們只關心軌道可以做什么。
它具有控制生命周期(打開/關閉)、狀態(播放/暫停/停止)的功能,并提供了一個觀察者模式,因此我們可以觀察到它的狀態變化。它沒有描述這些操作實際上是如何作業的,只是任何參考了實作的人都可以對其執行這些操作。
就個人而言,我總是喜歡使用abstract實作來定義一些更“常見”或“樣板”的操作,例如,狀態更改的處理將非常普遍,所以,我們將把它們放在外面基礎實作...
public abstract class AbstractTrackModel implements TrackModel {
private State state;
private List<ChangeListener> changeListeners;
public AbstractTrackModel() {
state = State.STOPPED;
changeListeners = new ArrayList<>(8);
}
protected void setState(State state) {
if (this.state == state) {
return;
}
this.state = state;
fireStateDidChange();
}
@Override
public State getState() {
return state;
}
@Override
public void addChangeListener(ChangeListener changeListener) {
changeListeners.add(changeListener);
}
@Override
public void removeChangeListener(ChangeListener changeListener) {
changeListeners.remove(changeListener);
}
protected void fireStateDidChange() {
ChangeEvent evt = new ChangeEvent(this);
for (ChangeListener listener : changeListeners) {
listener.stateChanged(evt);
}
}
}
javax.sound.sampled.AudioSystem接下來,我們需要一個具體的實作,所以下面是一個使用和javax.sound.sampled.CLipAPI的簡單實作
public class AudioSystemClipTrackModel extends AbstractTrackModel {
private Clip clip;
private AudioInputStream stream;
public AudioSystemClipTrackModel(String named) throws UnsupportedAudioFileException, IOException, LineUnavailableException {
this.stream = AudioSystem.getAudioInputStream(getClass().getResource(named));
this.clip = AudioSystem.getClip();
}
protected AudioInputStream getStream() {
return stream;
}
@Override
public Clip getClip() {
return clip;
}
@Override
public boolean isOpen() {
return getClip().isOpen();
}
@Override
public void open() throws LineUnavailableException, IOException {
if (isOpen()) {
return;
}
getClip().open(getStream());
}
@Override
public void close() {
if (!isOpen()) {
return;
}
getClip().close();
}
@Override
public void play() throws IOException {
if (!isOpen()) {
throw new IOException("Track is not open");
}
clip.start();
setState(State.PLAYING);
}
@Override
public void stop() {
getClip().stop();
getClip().setFramePosition(0);
setState(State.STOPPED);
}
@Override
public void pause() {
getClip().stop();
setState(State.PAUSED);
}
}
哇,我們還沒有進入 UI!但這樣做的好處是,沒有它們,這些類都可以很好地作業。
接下來,我們看一下UI...
public class PlayerPane extends JPanel {
private TrackModel model;
private JLabel stateLabel;
private ChangeListener changeListener;
private PlayerControlsPane controlsPane;
public PlayerPane(TrackModel model) {
changeListener = new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
configureState();
}
};
stateLabel = new JLabel("...");
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = gbc.REMAINDER;
controlsPane = new PlayerControlsPane(model);
add(stateLabel, gbc);
add(controlsPane, gbc);
setModel(model);
}
public void setModel(TrackModel model) {
if (this.model != null) {
this.model.removeChangeListener(changeListener);
}
this.model = model;
this.model.addChangeListener(changeListener);
configureState();
controlsPane.setModel(model);
}
public TrackModel getModel() {
return model;
}
protected void configureState() {
switch (getModel().getState()) {
case STOPPED:
stateLabel.setText("Stopped");
break;
case PLAYING:
stateLabel.setText("Playing");
break;
case PAUSED:
stateLabel.setText("Paused");
break;
}
}
}
public class PlayerControlsPane extends JPanel {
private TrackModel model;
private JButton playButton;
private JButton stopButton;
private JButton pauseButton;
private ChangeListener changeListener;
public PlayerControlsPane(TrackModel model) {
changeListener = new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
configureState();
}
};
setLayout(new GridLayout(1, -1));
playButton = Style.makeButton();
playButton.setText("Play");
playButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
model.play();
} catch (IOException ex) {
JOptionPane.showMessageDialog(PlayerControlsPane.this, "Track is not playable");
}
}
});
stopButton = new ButtonBuilder()
.withTitle("Stop")
.withActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
model.stop();
}
})
.build();
pauseButton = Style.makeButton(new PauseAction(model));
add(playButton);
add(stopButton);
add(pauseButton);
setModel(model);
}
public void setModel(TrackModel model) {
if (this.model != null) {
this.model.removeChangeListener(changeListener);
}
this.model = model;
this.model.addChangeListener(changeListener);
configureState();
}
public TrackModel getModel() {
return model;
}
protected void configureState() {
switch (getModel().getState()) {
case STOPPED:
playButton.setEnabled(true);
stopButton.setEnabled(false);
pauseButton.setEnabled(false);
break;
case PLAYING:
playButton.setEnabled(false);
stopButton.setEnabled(true);
pauseButton.setEnabled(true);
break;
case PAUSED:
playButton.setEnabled(true);
stopButton.setEnabled(false);
pauseButton.setEnabled(false);
break;
}
}
}
public class PauseAction extends AbstractAction {
private TrackModel model;
public PauseAction(TrackModel model) {
this.model = model;
putValue(NAME, "Pause");
// Bunch of other possible keys
}
@Override
public void actionPerformed(ActionEvent e) {
model.pause();
}
}
出于演示目的,UI 分為三個元素。
你有一個主要的播放器組件,它包含一個PlayerControlsPane并使用PauseAction(再次,用于演示)。
這里重要的是,播放器和控制組件使我們具有相同的模型。他們每個人都為模型附加了一個“觀察者”,并根據模型的變化獨立更新他們的狀態。
這涉及到依賴注入的概念,例如和示例。
它還允許播放器和控制元件擁有不同的布局管理器,而無需太多雜耍。
現在,您是否需要使用您制作的任何 UI 來做到這一點,不,但您應該盡可能多地做,完美的實踐才能完美??
分手評論...
通常不鼓勵從頂級容器進行擴展JFrame,您不會向類添加任何新功能,而是將自己鎖定在單個用例中。如果您想將播放器放入不同的容器中會發生什么?好吧,在你的情況下,你不能,你被卡住了。
這也支持Composition Over Inheritance,供參考...
- 組合優于繼承
- 更喜歡組合而不是繼承?
...我相信你可以找到更多關于這個主題的討論。
而且,這File filePath = new File("src/Tracks/Track.wav");將是有問題的。永遠不要在你的代碼中參考src,一旦程式被構建和匯出,它就不會存在。
當資源像這樣嵌入時,您將需要使用Class#getResourceor Class#getResourceAsStream,具體取決于您的 API 要求 - 這在代碼示例中進行了演示
您可能還應該查看模型-視圖-控制器概念。
可運行的示例...
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
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.AbstractAction;
import javax.swing.Action;
import static javax.swing.Action.NAME;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
JFrame frame = new JFrame();
TrackModel track = new AudioSystemClipTrackModel("/sound/your embedded audio file");
track.open();
frame.add(new PlayerPane(track));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public interface TrackModel {
enum State {
STOPPED, PLAYING, PAUSED;
}
public Clip getClip();
public State getState();
public void open() throws LineUnavailableException, IOException;
public void close();
public boolean isOpen();
public void play() throws IOException;
public void stop();
public void pause();
public void addChangeListener(ChangeListener changeListener);
public void removeChangeListener(ChangeListener changeListener);
}
public abstract class AbstractTrackModel implements TrackModel {
private State state;
private List<ChangeListener> changeListeners;
public AbstractTrackModel() {
state = State.STOPPED;
changeListeners = new ArrayList<>(8);
}
protected void setState(State state) {
if (this.state == state) {
return;
}
this.state = state;
fireStateDidChange();
}
@Override
public State getState() {
return state;
}
@Override
public void addChangeListener(ChangeListener changeListener) {
changeListeners.add(changeListener);
}
@Override
public void removeChangeListener(ChangeListener changeListener) {
changeListeners.remove(changeListener);
}
protected void fireStateDidChange() {
ChangeEvent evt = new ChangeEvent(this);
for (ChangeListener listener : changeListeners) {
listener.stateChanged(evt);
}
}
}
public class AudioSystemClipTrackModel extends AbstractTrackModel {
private Clip clip;
private AudioInputStream stream;
public AudioSystemClipTrackModel(String named) throws UnsupportedAudioFileException, IOException, LineUnavailableException {
this.stream = AudioSystem.getAudioInputStream(getClass().getResource(named));
this.clip = AudioSystem.getClip();
}
protected AudioInputStream getStream() {
return stream;
}
@Override
public Clip getClip() {
return clip;
}
@Override
public boolean isOpen() {
return getClip().isOpen();
}
@Override
public void open() throws LineUnavailableException, IOException {
if (isOpen()) {
return;
}
getClip().open(getStream());
}
@Override
public void close() {
if (!isOpen()) {
return;
}
getClip().close();
}
@Override
public void play() throws IOException {
if (!isOpen()) {
throw new IOException("Track is not open");
}
clip.start();
setState(State.PLAYING);
}
@Override
public void stop() {
getClip().stop();
getClip().setFramePosition(0);
setState(State.STOPPED);
}
@Override
public void pause() {
getClip().stop();
setState(State.PAUSED);
}
}
public class Style {
public static JButton makeButton() {
JButton btn = new JButton();
// Apply any configuration you need
// by default
return btn;
}
public static JButton makeButton(Action action) {
JButton btn = makeButton();
btn.setAction(action);
return btn;
}
}
public class ButtonBuilder {
private String title;
private ActionListener actionListener;
public ButtonBuilder withTitle(String title) {
this.title = title;
return this;
}
public ButtonBuilder withActionListener(ActionListener actionListener) {
this.actionListener = actionListener;
return this;
}
// And any additional properties you might like to configure
public JButton build() {
JButton btn = new JButton();
if (title != null) {
btn.setText(title);
}
if (actionListener != null) {
btn.addActionListener(actionListener);
}
// Configure the button as you see fit
return btn;
}
}
public class PlayerPane extends JPanel {
private TrackModel model;
private JLabel stateLabel;
private ChangeListener changeListener;
private PlayerControlsPane controlsPane;
public PlayerPane(TrackModel model) {
changeListener = new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
configureState();
}
};
stateLabel = new JLabel("...");
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = gbc.REMAINDER;
controlsPane = new PlayerControlsPane(model);
add(stateLabel, gbc);
add(controlsPane, gbc);
setModel(model);
}
public void setModel(TrackModel model) {
if (this.model != null) {
this.model.removeChangeListener(changeListener);
}
this.model = model;
this.model.addChangeListener(changeListener);
configureState();
controlsPane.setModel(model);
}
public TrackModel getModel() {
return model;
}
protected void configureState() {
switch (getModel().getState()) {
case STOPPED:
stateLabel.setText("Stopped");
break;
case PLAYING:
stateLabel.setText("Playing");
break;
case PAUSED:
stateLabel.setText("Paused");
break;
}
}
}
public class PlayerControlsPane extends JPanel {
private TrackModel model;
private JButton playButton;
private JButton stopButton;
private JButton pauseButton;
private ChangeListener changeListener;
public PlayerControlsPane(TrackModel model) {
changeListener = new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
configureState();
}
};
setLayout(new GridLayout(1, -1));
playButton = Style.makeButton();
playButton.setText("Play");
playButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
model.play();
} catch (IOException ex) {
JOptionPane.showMessageDialog(PlayerControlsPane.this, "Track is not playable");
}
}
});
stopButton = new ButtonBuilder()
.withTitle("Stop")
.withActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
model.stop();
}
})
.build();
pauseButton = Style.makeButton(new PauseAction(model));
add(playButton);
add(stopButton);
add(pauseButton);
setModel(model);
}
public void setModel(TrackModel model) {
if (this.model != null) {
this.model.removeChangeListener(changeListener);
}
this.model = model;
this.model.addChangeListener(changeListener);
configureState();
}
public TrackModel getModel() {
return model;
}
protected void configureState() {
switch (getModel().getState()) {
case STOPPED:
playButton.setEnabled(true);
stopButton.setEnabled(false);
pauseButton.setEnabled(false);
break;
case PLAYING:
playButton.setEnabled(false);
stopButton.setEnabled(true);
pauseButton.setEnabled(true);
break;
case PAUSED:
playButton.setEnabled(true);
stopButton.setEnabled(false);
pauseButton.setEnabled(false);
break;
}
}
}
public class PauseAction extends AbstractAction {
private TrackModel model;
public PauseAction(TrackModel model) {
this.model = model;
putValue(NAME, "Pause");
// Bunch of other possible keys
}
@Override
public void actionPerformed(ActionEvent e) {
model.pause();
}
}
}
uj5u.com熱心網友回復:
介紹
您的代碼在實作 Swing 以及作為一種主要方法方面存在問題。
Oracle 有一個有用的教程,使用 Swing 創建 GUI。跳過使用 NetBeans IDE 學習搖擺部分。
讓我們一步一步來。
步驟1
我做的第一件事是將你的主要 GUI 類重命名為更有意義的名稱,洗掉播放器代碼,并專注于 GUI。
我添加了對該SwingUtilities invokeLater方法的呼叫。此方法確保在Event Dispatch Thread上創建和執行 Swing 組件。
這是該步驟的結果。
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
public class SimpleMusicPlayer implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new SimpleMusicPlayer());
}
@Override
public void run() {
// Buttons
JButton playButton = new JButton("Play");
// playButton.addActionListener(e -> {
// track.start();
// });
playButton.setHorizontalAlignment(SwingConstants.LEFT);
playButton.setFont(new Font("JetBrains Mono", Font.BOLD, 25));
playButton.setBounds(0, 0, 100, 50);
JButton pauseButton = new JButton("Pause");
// pauseButton.addActionListener(e -> {
// track.stop();
// });
pauseButton.setHorizontalAlignment(SwingConstants.CENTER);
pauseButton.setFont(new Font("JetBrains Mono", Font.BOLD, 25));
pauseButton.setBounds(150, 0, 100, 50);
JButton replayButton = new JButton("Replay");
// replayButton.addActionListener(e -> {
// track.setMicrosecondPosition(0);
// });
replayButton.setHorizontalAlignment(SwingConstants.RIGHT);
replayButton.setFont(new Font("JetBrains Mono", Font.BOLD, 25));
replayButton.setBounds(300, 0, 100, 50);
// Frame
JFrame frame = new JFrame();
frame.setTitle("MusicPlayer");
frame.setSize(500, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.getContentPane().setBackground(new Color(123, 100, 250));
frame.setLayout(new FlowLayout());
frame.add(playButton);
frame.add(pauseButton);
frame.add(replayButton);
}
}
這一步使代碼脫離了靜態領域。
第2步
下一步有一些變化。
我創建了一個
JPanel來保存JButtons. 使用JPanelaFlowLayout將按鈕排列成一排。我在按鈕周圍和按鈕之間添加了一些間距。我重新安排了
JFrame方法呼叫。這些方法必須按特定順序呼叫。該setVisible方法必須最后呼叫。
這是該步驟的結果。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class SimpleMusicPlayer implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new SimpleMusicPlayer());
}
@Override
public void run() {
JFrame frame = new JFrame("Music Player");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.setSize(500, 300);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createMainPanel() {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 30, 5));
panel.setBackground(new Color(123, 100, 250));
panel.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
Font font = new Font("JetBrains Mono", Font.BOLD, 25);
JButton playButton = new JButton("Play");
// playButton.addActionListener(e -> {
// track.start();
// });
playButton.setFont(font);
panel.add(playButton);
JButton pauseButton = new JButton("Pause");
// pauseButton.addActionListener(e -> {
// track.stop();
// });
pauseButton.setFont(font);
panel.add(pauseButton);
JButton replayButton = new JButton("Replay");
// replayButton.addActionListener(e -> {
// track.setMicrosecondPosition(0);
// });
replayButton.setFont(font);
panel.add(replayButton);
return panel;
}
}
由于這是一個簡單的 GUI,GUI 清理到此結束。
第 3 步
現在,我們將音頻作為單獨的類重新添加。這個類成為我們 Swing 應用程式的模型。
我沒有對此進行測驗,因為我手邊沒有 WAV 檔案。
這是該步驟的結果。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.io.File;
import java.io.IOException;
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.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class SimpleMusicPlayer implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new SimpleMusicPlayer());
}
private final MusicPlayer player;
public SimpleMusicPlayer() {
this.player = new MusicPlayer("src/Tracks/Track.wav");
}
@Override
public void run() {
JFrame frame = new JFrame("Music Player");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.setSize(500, 300);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createMainPanel() {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 30, 5));
panel.setBackground(new Color(123, 100, 250));
panel.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
Font font = new Font("JetBrains Mono", Font.BOLD, 25);
JButton playButton = new JButton("Play");
playButton.addActionListener(e -> {
player.start();
});
playButton.setFont(font);
panel.add(playButton);
JButton pauseButton = new JButton("Pause");
pauseButton.addActionListener(e -> {
player.stop();
});
pauseButton.setFont(font);
panel.add(pauseButton);
JButton replayButton = new JButton("Replay");
replayButton.addActionListener(e -> {
player.replay();
});
replayButton.setFont(font);
panel.add(replayButton);
return panel;
}
public class MusicPlayer {
private final Clip track;
public MusicPlayer(String filename) {
this.track = openClip(filename);
}
private Clip openClip(String filename) {
try {
File filePath = new File(filename);
AudioInputStream stream = AudioSystem.getAudioInputStream(filePath);
Clip track = AudioSystem.getClip();
track.open(stream);
return track;
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (LineUnavailableException e) {
e.printStackTrace();
}
return null;
}
public void start() {
if (track != null) {
track.start();
}
}
public void stop() {
if (track != null) {
track.stop();
}
}
public void replay() {
if (track != null) {
track.setMicrosecondPosition(0);
}
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/482332.html
上一篇:如何在Java中獲取面板的大小?
下一篇:有沒有辦法在文本欄位中設定所有結果值?它只按預期設定最后一個值,但我希望全部設定在resultTextField
