Java平臺下的Media Player

實驗四  windows或java平臺下的Media Player(6學時)

基本要求

l  實現media player,支持多種媒體類型的播放

l  視頻:avi

l  音頻:wav、midi

l  圖象序列:圖象瀏覽,幻燈

l  播放列表功能

l  Generic list

l  自定義的複雜播放

Bonus

界面美觀-skin,可更換?

更豐富的媒體類型:

MP3,WMA,MPEG4,JPEG,PNG,WMF,Flash……

這些附加媒體類型的播放可以使用控件

這個實驗參考了網上的一些相關資料,https://github.com/Al-assad

在實現這個實驗的時候用到了JavaFX,需要現在eclipse中安裝JavaFX插件。安裝完成之後,新建一個JavaFX Project。


最後的視頻播放效果如下所示,這是從網易雲音樂下載的周杰倫的《七里香》MV,效果還不錯,可以調節音量和進度。




音頻播放效果如下所示


主要代碼如下所示

package application;

public class Log {

	public static void i(String tag, String content) {
        System.out.println("[INFO][" + tag + "]: " + content);
    }

    public static void e(String tag, String content) {
        System.out.println("[ERROR][" + tag + "]: " + content);
    }
}
package application;
	
import javafx.application.Application;
import javafx.scene.*;
import javafx.event.*;
import javafx.geometry.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.*;
import javafx.stage.*;

import player.*;

import java.io.*;
import java.net.*;

public class Main extends Application {
	
	MyMediaPlayer player;
    FileChooser fileChooser;
    MenuBar menuBar;
    BorderPane pane;
    Group root;
    
    public static final String[] IMAGE_POSTFIX = {
            "bmp", "dib",
            "png",
            "jpeg", "jpg"
    };

    public static final String[] AUDIO_POSTFIX = {
            "mp3",
            "wav"
    };

    public static final String[] VIDEO_POSTFIX = {
            "avi",
            "mp4"
    };

    public static final String FILENAME = "69_output_2.mp4";
	
    public static String getPostfix(File file) {
        String filename = file.getName();
        String ret;
        if (filename == null || filename.length() == 0) {
            ret = null;
        } else {
            char[] curName = filename.toCharArray();
            int indexDot = -1;
            for (int i = curName.length - 1; i >= 0; i--) {
                if (curName[i] == '.') {
                    indexDot = i;
                    break;
                }
            }
            if (indexDot == -1) {
                ret = null;
            } else {
                ret = filename.substring(indexDot + 1);
            }
        }
        return ret;
    }

    public static boolean isThisType(String postfix, String[] postfixList) {
        for (String item: postfixList) {
            if (postfix.compareToIgnoreCase(item) == 0) {
                return true;
            }
        }
        return false;
    }

    public class UnknownFileTypeException extends Exception {
        public UnknownFileTypeException() {
            super("Cannot determine the file type. ");
        }
        public UnknownFileTypeException(String message) {
            super(message);
        }
    }

    @Override
    public void start(Stage primaryStage) throws Exception{

        //添加菜單欄,用於打開文件
        MenuItem open = new MenuItem("Open");
        Menu menuFile = new Menu("File");
        menuBar = new MenuBar();

        menuFile.getItems().add(open);
        menuBar.getMenus().add(menuFile);

        fileChooser = new FileChooser();

        open.setOnAction(new EventHandler<ActionEvent>(){
            public void handle(ActionEvent e){
                File file = fileChooser.showOpenDialog(primaryStage);
                if (file != null){
                    try {
                        Log.i("File", file.toURI().toURL().toExternalForm());
                        String postfix = getPostfix(file);
                        if (postfix == null) {
                            throw new UnknownFileTypeException();
                        }
                        if (isThisType(postfix, IMAGE_POSTFIX)) {
                            //測試嵌入式調用
                            MyMediaPlayer.popup(file.toURI().toURL().toExternalForm());
                        } else if (isThisType(postfix, AUDIO_POSTFIX)) {
                            //測試嵌入式調用
                            MyMediaPlayer.popup(file.toURI().toURL().toExternalForm());

                        } else if (isThisType(postfix, VIDEO_POSTFIX)) {
                            //測試嵌入式調用
                            MyMediaPlayer.popup(file.toURI().toURL().toExternalForm());
                        } else {
                            throw new UnknownFileTypeException();
                        }
                    } catch (MalformedURLException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    } catch (Exception e2) {
                        e2.printStackTrace();
                    }
                }
            }
        });

        //創建測試窗口
        root = new Group();
        pane = new BorderPane();
        root.getChildren().add(pane);

//        HBox hbox = new HBox();
//        hbox.setAlignment(Pos.CENTER);
//        pane.setBottom(hbox);
//        Button popup = new Button("Popup");
//        Button popup2 = new Button("Popup small");
//        hbox.getChildren().addAll(popup,popup2);

        //System.out.println(System.getProperty("user.dir"));
//        player = new SimpleMediaPlayer();
        pane.setTop(menuBar);					 //Set bar at the top


        //測試彈窗式調用
//        popup.setOnAction((ActionEvent e)->{
//            SimpleMediaPlayer.popup(getClass().getResource(FILENAME).toString());
//        });
//        popup2.setOnAction((ActionEvent e)->{
//            SimpleMediaPlayer.popup(getClass().getResource(FILENAME).toString(),550,400);
//        });

        primaryStage.setScene(new Scene(root, 300, 100, Color.WHITESMOKE));
        primaryStage.setTitle("My Media Player");
        primaryStage.show();
    }

	
	public static void main(String[] args) {
		launch(args);
	}
}
package player;

import javafx.event.*;
import javafx.fxml.*;
import javafx.scene.*;
import javafx.scene.layout.*;
import javafx.stage.*;

import java.io.*;

public class MyMediaPlayer extends AnchorPane{
	//TODO 修改player.fxml 使其爲自適應的大小,使用AnchorBar或者修改底部工具欄高度

    private static MyMediaPlayer myMediaPlayer;   //創建實例保存到私有域中
    private PlayerController controller;     //儲存每個實例的控制器對象


    protected PlayerController getController(){   //提供控制器對象的調用接口
        return this.controller;
    }


    //構造函數私有,實例保存在靜態域,只向外部提供靜態調用
    private MyMediaPlayer(String mediaUrl){
        try {
            FXMLLoader fxmlloader = new FXMLLoader(getClass().getResource("player.fxml"));
            Parent root = fxmlloader.load();   //將fxml節點添加到根節點中
            controller = fxmlloader.getController();
            this.getChildren().add(root);   //主類節點加入根節點


        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    //TODO setSize失效
    //設置播放器大小:暫不支持 popup 產生的實例調用該方法
    public void setSize(int width,int height){
        if(myMediaPlayer.getController().getPopup())
            return ;
        myMediaPlayer.getController().setMediaPlayer(width,height);
    }

    //實例化調用:默認大小500*400
    public static MyMediaPlayer  newInstance(String mediaUrl){
        return newInstance(mediaUrl,600,400);
    }
    public static MyMediaPlayer newInstance(String mediaUrl,int width,int height){
        myMediaPlayer = new MyMediaPlayer(mediaUrl);
        myMediaPlayer.getController().start(mediaUrl,false,width,height);   //非窗口化啓動播放器控件
        return myMediaPlayer;
    }

    //彈窗式調用:默認大小800*600
    public static MyMediaPlayer popup(String mediaUrl){
        return popup(mediaUrl,800,600);
    }
    public static MyMediaPlayer  popup(String mediaUrl,int width,int height){
    	myMediaPlayer = new MyMediaPlayer(mediaUrl);
    	myMediaPlayer.getController().start(mediaUrl,true,width,height);
        Scene scene = new Scene(myMediaPlayer,width,height);
        myMediaPlayer.getController().setScene(scene);

        Stage primaryStage = new Stage();
        primaryStage.setTitle("Media Player");
        primaryStage.setScene(scene);

        //檢測彈出窗口關閉事件,手動銷燬simpleMediaPlayer對象;
        primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>(){
            @Override
            public void handle(WindowEvent event) {
            	myMediaPlayer.getController().destroy();
            }
        });
        primaryStage.show();
        return myMediaPlayer;
    }

}

package player;

import javafx.application.*;
import javafx.beans.value.*;
import javafx.event.*;
import javafx.fxml.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.effect.*;
import javafx.scene.image.*;
import javafx.scene.input.*;
import javafx.scene.layout.*;
import javafx.scene.media.*;
import javafx.stage.*;
import javafx.util.*;

public class PlayerController {

	@FXML Button playBT;
    @FXML Button stopBT;
    @FXML Button maxBT;
    @FXML Button volumeBT;
    @FXML Label timeLB;
    @FXML Slider processSD;
    @FXML Slider volumeSD;
    @FXML MediaView mediaView;
    @FXML VBox controlBar;
    @FXML BorderPane mediaPane;
    @FXML AnchorPane  anchorPane;


    //控件素材圖片
    private String playIcon  = getClass().getResource("icon/play.png").toString();
    private String pauseIcon  = getClass().getResource("icon/pause.png").toString();
    private String stopIcon  = getClass().getResource("icon/stop.png").toString();
    private String volOffIcon  = getClass().getResource("icon/volume_off.png").toString();
    private String volOnIcon  = getClass().getResource("icon/volume_On.png").toString();
    private String maxIcon  = getClass().getResource("icon/max.png").toString();

    private MediaPlayer mediaPlayer;
    private Media media;
    private String url;     //資源的url地址
    private boolean popup;   //窗口彈出方式
    private Scene scene ;  //父類窗口

    private boolean atEndOfMedia = false;    //記錄視頻是否處播放到結束
    private final boolean repeat = false;   //記錄視頻是否重複播放
    private double volumeValue;      //儲存靜音操作前的音量數據
    private Duration duration ;        //記錄視頻持續時間
    private int mediaHeight;        //視頻資源的尺寸
    private int mediaWidth;

    private int currentHeight;    //當前整個播放器的尺寸
    private int currentWidth;

    public void setScene(Scene scene){
        this.scene = scene;
    }


    //程序初始化:設置按鈕圖標
    public void initialize(){
        //設置各控件圖標
        setIcon(playBT,playIcon,25);
        setIcon(stopBT,stopIcon,25);
        setIcon(volumeBT,volOnIcon,15);
        setIcon(maxBT,maxIcon,25);

    }

    //程序啓動項,傳入必要參數
    public void start(String url,boolean popup,int width,int height){
        this.url = url;
        this.popup = popup;

        //MediaView設置
        media = new Media(url);
        mediaPlayer = new MediaPlayer(media);
        mediaView.setMediaPlayer(mediaPlayer);

        //設置播放器,在媒體資源加載完畢後,獲取相應的數據,設置組件自適應佈局
        setMediaPlayer(width,height);

        //設置各組件動作事件
        setMediaViewOnClick();
        setPlayButton();
        setStopButton();
        setVolumeButton();
        setVolumeSD();
        setProcessSlider();
        setMaximizeButton();

    }


    //設置mediaPlayer(參數:整個播放器的尺寸)
    void setMediaPlayer(int width,int height){
        mediaPlayer.setCycleCount(repeat ? MediaPlayer.INDEFINITE : 1);
        //視頻就緒時更新 進度條 、時間標籤、音量條數據,設置佈局尺寸
        mediaPlayer.setOnReady(new Runnable(){
            @Override
            public void run() {
                duration = mediaPlayer.getMedia().getDuration();
                volumeValue = mediaPlayer.getVolume();

                mediaHeight = media.getHeight();
                mediaWidth = media.getWidth();

                //設置佈局尺寸
                setSize(width,height);

                //設置尺寸隨窗口改變自適應變化(只使用於彈窗)

                if (scene!= null) {
                    scene.widthProperty().addListener(new ChangeListener<Number>() {
                        @Override
                        public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                            setSize(newValue.intValue(),currentHeight);
                        }
                    });
                    scene.heightProperty().addListener(new ChangeListener<Number>() {
                        @Override
                        public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                            setSize(currentWidth,newValue.intValue());
                        }
                    });
                }
                //設置全屏時的UI變化:工具欄只有在鼠標進入MediaView時纔出現
                EventHandler onScreen = new EventHandler<InputEvent>(){
                    @Override
                    public void handle(InputEvent event) {
                        controlBar.setVisible(true);
                    }
                };
                EventHandler offScreen = new EventHandler<InputEvent>(){
                    @Override
                    public void handle(InputEvent event) {
                        controlBar.setVisible(false);
                    }
                };
                if(scene != null && popup){
                    ((Stage)scene.getWindow()).fullScreenProperty().addListener(new ChangeListener<Boolean>() {
                        @Override
                        public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                            if (newValue.booleanValue()) {
                                controlBar.setVisible(false);
                                mediaPane.addEventHandler(MouseEvent.MOUSE_CLICKED, onScreen);
                                controlBar.addEventHandler(MouseEvent.MOUSE_EXITED, offScreen);
                            }else{
                                controlBar.setVisible(true);
                                mediaPane.removeEventHandler(MouseEvent.MOUSE_CLICKED,onScreen);
                                controlBar.removeEventHandler(MouseEvent.MOUSE_EXITED,offScreen);
                            }
                        }
                    });
                }

                updateValues();


            }
        });
        //mediaPlayer當前進度發生改變時候,進度條 、時間標籤、音量條數據
        mediaPlayer.currentTimeProperty().addListener(new ChangeListener<Duration>(){
            @Override
            public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) {
                updateValues();
            }
        });
    }
    //設置點擊MediaView時暫停或開始
    private void setMediaViewOnClick(){
        mediaView.setOnMouseClicked(event -> {
            if(media == null)
                return;
            MediaPlayer.Status status = mediaPlayer.getStatus();
            if(status == MediaPlayer.Status.UNKNOWN || status == MediaPlayer.Status.HALTED ){
                return;
            }
            //當資源處於暫停或停止狀態時
            if(status == MediaPlayer.Status.PAUSED || status == MediaPlayer.Status.READY || status == MediaPlayer.Status.STOPPED){
                //當資源播放結束時,重繞資源
                if(atEndOfMedia){
                    mediaPlayer.seek(mediaPlayer.getStartTime());
                    atEndOfMedia = false;
                }
                mediaPlayer.play();
                setIcon(playBT,pauseIcon,25);
            }else{   //當資源處於播放狀態時
                mediaPlayer.pause();
                setIcon(playBT,playIcon,25);
            }
        });
    }

    //設置播放按鈕動作
    private void setPlayButton(){
        playBT.setOnAction((ActionEvent e)->{
            if(media == null)
                return;
            MediaPlayer.Status status = mediaPlayer.getStatus();
            if(status == MediaPlayer.Status.UNKNOWN || status == MediaPlayer.Status.HALTED ){
                return;
            }
            //當資源處於暫停或停止狀態時
            if(status == MediaPlayer.Status.PAUSED || status == MediaPlayer.Status.READY || status == MediaPlayer.Status.STOPPED){
                //當資源播放結束時,重繞資源
                if(atEndOfMedia){
                    mediaPlayer.seek(mediaPlayer.getStartTime());
                    atEndOfMedia = false;
                }
                mediaPlayer.play();
                setIcon(playBT,pauseIcon,25);
            }else{   //當資源處於播放狀態時
                mediaPlayer.pause();
                setIcon(playBT,playIcon,25);
            }
        });
    }

    //設置停止按鈕動作
    private void setStopButton(){
        stopBT.setOnAction((ActionEvent e )->{
            if(media == null)
                return;
            mediaPlayer.stop();
            setIcon(playBT,playIcon,25);
        } );
    }

    //設置視頻進度條動作
    private void setProcessSlider(){
        processSD.valueProperty().addListener(new ChangeListener<Number>(){
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                if(processSD.isValueChanging()){     //加入Slider正在改變的判定,否則由於update線程的存在,mediaPlayer會不停地迴繞
                    mediaPlayer.seek(duration.multiply(processSD.getValue()/100.0));
                }
            }
        });
    }


    //設置最大化按鈕動作
    public void setMaximizeButton(){
        maxBT.setOnAction((ActionEvent e)->{
            if(popup){
                ((Stage)scene.getWindow()).setFullScreen(true);
            }else{
                mediaPlayer.pause();
                setIcon(playBT,pauseIcon,25);
                MyMediaPlayer player = MyMediaPlayer.popup(url);
                player.getController().getMediaPlayer().seek(this.mediaPlayer.getCurrentTime());

            }
        });
    }


    //設置音量按鈕動作
    private void setVolumeButton(){
        volumeBT.setOnAction((ActionEvent e)->{
            if(media == null)
                return;

            if(mediaPlayer.getVolume()>0){
                volumeValue = mediaPlayer.getVolume();
                volumeSD.setValue(0);
                setIcon(volumeBT,volOffIcon,25);
            }else{
                mediaPlayer.setVolume(volumeValue);
                volumeSD.setValue(volumeValue * 100);
                setIcon(volumeBT,volOnIcon,15);
            }
        });
    }

    //設置音量滑條動作
    private void setVolumeSD(){
        volumeSD.valueProperty().addListener(new ChangeListener<Number>(){
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                mediaPlayer.setVolume(newValue.doubleValue()/100);
            }
        });
    }

    //更新視頻數據(進度條 、時間標籤、音量條數據)
    protected void updateValues(){
        if(processSD != null && timeLB!=null && volumeSD != null && volumeBT != null){
            Platform.runLater(new Runnable(){
                @Override
                public void run() {
                    Duration currentTime = mediaPlayer.getCurrentTime();
                    timeLB.setText(formatTime(currentTime,duration));    //設置時間標籤
                    processSD.setDisable(duration.isUnknown());   //無法讀取時間是隱藏進度條
                    if(!processSD.isDisabled() && duration.greaterThan(Duration.ZERO) && !processSD.isValueChanging()){
                        processSD.setValue(currentTime.toMillis()/duration.toMillis() * 100);   //設置進度條
                    }
                    if(!volumeSD.isValueChanging()){
                        volumeSD.setValue((int)Math.round(mediaPlayer.getVolume() *100));   //設置音量條
                        if(mediaPlayer.getVolume() == 0){        //設置音量按鈕
                            setIcon(volumeBT,volOffIcon,20);
                        }else{
                            setIcon(volumeBT,volOnIcon,20);
                        }
                    }
                }
            });
        }
    }

    //將Duration數據格式化,用於播放時間標籤
    protected String formatTime(Duration elapsed,Duration duration){
        //將兩個Duartion參數轉化爲 hh:mm:ss的形式後輸出
        int intElapsed = (int)Math.floor(elapsed.toSeconds());
        int elapsedHours = intElapsed / (60 * 60);
        int elapsedMinutes = (intElapsed - elapsedHours *60 *60)/ 60;
        int elapsedSeconds = intElapsed - elapsedHours * 60 * 60 - elapsedMinutes * 60;
        if(duration.greaterThan(Duration.ZERO)){
            int intDuration = (int)Math.floor(duration.toSeconds());
            int durationHours = intDuration / (60 * 60);
            int durationMinutes = (intDuration - durationHours *60 * 60) / 60;
            int durationSeconds = intDuration - durationHours * 60 * 60 - durationMinutes * 60;

            if(durationHours > 0){
                return String.format("%02d:%02d:%02d / %02d:%02d:%02d",elapsedHours,elapsedMinutes,elapsedSeconds,durationHours,durationMinutes,durationSeconds);
            }else{
                return String.format("%02d:%02d / %02d:%02d",elapsedMinutes,elapsedSeconds,durationMinutes,durationSeconds);
            }
        }else{
            if(elapsedHours > 0){
                return String.format("%02d:%02d:%02d / %02d:%02d:%02d",elapsedHours,elapsedMinutes,elapsedSeconds);
            }else{
                return String.format("%02d:%02d / %02d:%02d",elapsedMinutes,elapsedSeconds);
            }
        }
    }

    //爲按鈕獲取圖標
    private void setIcon(Button button,String path,int size){
        Image icon = new Image(path);
        ImageView imageView = new ImageView(icon);
        imageView.setFitWidth(size);
        imageView.setFitHeight((int)(size * icon.getHeight() / icon.getWidth()));
        button.setGraphic(imageView);
        //設置圖標點擊時發亮
        ColorAdjust colorAdjust = new ColorAdjust();
        button.setOnMousePressed(event ->  {
            colorAdjust.setBrightness(0.5);
            button.setEffect(colorAdjust);
        });
        button.setOnMouseReleased(event -> {
            colorAdjust.setBrightness(0);
            button.setEffect(colorAdjust);
        });
    }

    public MediaPlayer getMediaPlayer(){
        return this.mediaPlayer;
    }


    //設置關閉窗口時的動作,手動釋放資源,回收內存
   public void destroy(){
       if(mediaPlayer.getStatus() == MediaPlayer.Status.PLAYING){
           mediaPlayer.stop();
       }
       mediaPlayer.dispose();   //釋放meidaPlayer的Media資源
       media = null;
       mediaPlayer = null;
       System.gc();    //通知JVM垃圾回收器

   }


   //設置播放器尺寸
    public void setSize(int width,int height){
        currentWidth = width;
        currentHeight  = height;
        setUISuitable();

    }
    //UI控件自適應大小
    private void setUISuitable(){
        anchorPane.setPrefSize(currentWidth,currentHeight);
        anchorPane.setBottomAnchor(controlBar, 0.0);    //設置控制條位置
        anchorPane.setTopAnchor(mediaPane,((double)currentHeight  - (double)currentWidth *(double)mediaHeight / (double)mediaWidth - 50)/2);  //設置視頻面板位置
        mediaView.setFitWidth(currentWidth);       //設置MediaView尺寸
        mediaView.setFitHeight((double)currentWidth*(double)mediaHeight / (double)mediaHeight);
        controlBar.setPrefWidth(currentWidth);  //設置工具條寬度


    }

    public boolean getPopup(){
        return this.popup;
    }
}
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Slider?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.media.MediaView?>

<AnchorPane fx:id="anchorPane" style="-fx-background-color: #3c3c3c;" xmlns="http://javafx.com/javafx/8.0.92" xmlns:fx="http://javafx.com/fxml/1" fx:controller="player.PlayerController">
   <children>
      <BorderPane fx:id="mediaPane">
         <center>
            <MediaView fx:id="mediaView" fitHeight="530.0" fitWidth="800.0" nodeOrientation="INHERIT" />
         </center>
      </BorderPane>
      <VBox fx:id="controlBar" alignment="BOTTOM_CENTER" maxHeight="-Infinity" minHeight="-Infinity" prefHeight="70.0" style="-fx-background-color: #636363;">
         <children>
            <Slider fx:id="processSD" style="-fx-background-color: #4b4b4b;" VBox.vgrow="ALWAYS" />
            <BorderPane fx:id="controlBorderPane" maxHeight="-Infinity" minHeight="-Infinity" prefHeight="50.0">
               <center>
                  <HBox alignment="CENTER" spacing="20.0" BorderPane.alignment="CENTER">
                     <children>
                        <Button fx:id="playBT" mnemonicParsing="false" style="-fx-background-color: #636363;" HBox.hgrow="ALWAYS" />
                        <Button fx:id="stopBT" mnemonicParsing="false" style="-fx-background-color: #636363;" HBox.hgrow="ALWAYS" />
                     </children>
                  </HBox>
               </center>
               <left>
                  <HBox alignment="CENTER_LEFT" prefHeight="100.0" prefWidth="200.0" spacing="20.0" BorderPane.alignment="CENTER">
                     <children>
                        <Button fx:id="maxBT" mnemonicParsing="false" style="-fx-background-color: #636363;" HBox.hgrow="ALWAYS" />
                        <Label fx:id="timeLB" text="Time" textFill="#dadada" HBox.hgrow="ALWAYS" />
                     </children>
                     <BorderPane.margin>
                        <Insets left="30.0" />
                     </BorderPane.margin>
                  </HBox>
               </left>
               <right>
                  <HBox alignment="CENTER_RIGHT" minHeight="-Infinity" prefWidth="200.0" spacing="10.0" BorderPane.alignment="CENTER">
                     <children>
                        <Button fx:id="volumeBT" mnemonicParsing="false" style="-fx-background-color: #636363;" HBox.hgrow="ALWAYS" />
                        <Slider fx:id="volumeSD" minHeight="-Infinity" prefWidth="150.0" HBox.hgrow="ALWAYS" />
                     </children>
                     <padding>
                        <Insets right="30.0" />
                     </padding>
                  </HBox>
               </right>
            </BorderPane>
         </children>
      </VBox>
   </children>
</AnchorPane>




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章