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>




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