获取文件资源的静态方法

Posted

技术标签:

【中文标题】获取文件资源的静态方法【英文标题】:static way of getting the resource of a file 【发布时间】:2016-06-07 18:17:36 【问题描述】:

更新: 我想让媒体播放器保持静态,但如果我制作的是静态的,它就不起作用。 请注意,我想要 mediaPlayer 静态的原因是我想从其他类访问它。(该行已注释。) 这是我的代码:

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.text.Font;
import javafx.stage.Stage;

import java.net.URL;

public class Main extends Application 
    static boolean isSoundOn = false;
    static double soundVolume = .5;
    MediaPlayer mediaPlayer = new MediaPlayer(new Media(Main.class.getResource("song.mp3").toString()));

public static void main(String[] args) 
    Application.launch(args);


@Override
public void start(Stage primaryStage) 
    mediaPlayer.play();
    primaryStage.setTitle("duet by what");

//        primaryStage.setFullScreen(true);


    //Group gamePaused = new Group();
    //Scene _gamePaused = new Scene(gamePaused, 1200, 700);
    //Group gameOver = new Group();
    //Scene _gameOver = new Scene(gameOver, 1200, 700);
    //Group game = new Group();
    //Scene _game = new Scene(game, 1200, 700);

    GUI gui = new GUI();
    primaryStage.setScene(gui.getMainMenu().getScene());
    primaryStage.show();



class GUI 
    private MainMenu mainMenu = new MainMenu();



 public class MainMenu 
        private Scene scene;

        private MainMenu() 
            VBox vBox = new VBox();
            scene = new Scene(vBox, 400, 500);
            scene.getStylesheets().add("stylesheet.css");

            Label info = new Label(
                    "welcome the the what version\n" +
                            "of the well known Duet game!\n\n" +
                            "press \"I wanna play!\" to begin the game.\n\n" +
                            "please note that you can change\n" +
                            "the sound settings.");
            info.setId("info");
            vBox.getChildren().add(info);

            Button startGame = new Button("i wanna play right now!");
            startGame.setOnAction(new EventHandler<ActionEvent>() 
                @Override
                public void handle(ActionEvent event) 
                    System.out.println("game started!");
                
            );
            vBox.getChildren().add(startGame);

            Label highScore = new Label("__highScore should be added here__");
            highScore.setId("highScore");
            vBox.getChildren().add(highScore);

            Button quitGame = new Button("get me out of this game!");
            quitGame.setOnAction(new EventHandler<ActionEvent>() 
                @Override
                public void handle(ActionEvent event) 
                    System.out.println("game quitted!");
                
            );
            vBox.getChildren().add(quitGame);

            CheckBox soundOn = new CheckBox("soundOn?");
            Tooltip tooltip = new Tooltip("if this box is checked, music will be played!");
            tooltip.setFont(new Font("Arial", 16));
            soundOn.setTooltip(tooltip);
            soundOn.selectedProperty().addListener(new ChangeListener<Boolean>() 
                public void changed(ObservableValue<? extends Boolean> ov,
                                    Boolean old_val, Boolean new_val) 
                    Main.isSoundOn = soundOn.isSelected();
                    System.out.println(Main.isSoundOn);
                
            );
            vBox.getChildren().add(soundOn);

            HBox changeVolumeWrapper = new HBox();
            changeVolumeWrapper.setId("hBox");
            Label sliderLabel = new Label("sound volume: ");
            changeVolumeWrapper.getChildren().add(sliderLabel);

            Slider soundVolume = new Slider(0, 1, .5);
            soundVolume.valueProperty().addListener(new ChangeListener<Number>() 
                public void changed(ObservableValue<? extends Number> ov,
                                    Number old_val, Number new_val) 
                    Main.soundVolume = new_val.doubleValue();
                    //Main.mediaPlayer.setVolume(Main.soundVolume);  here is why i need media player static.
                    System.out.printf("%.2f\n", Main.soundVolume);
                
            );
            changeVolumeWrapper.getChildren().add(soundVolume);
            vBox.getChildren().add(changeVolumeWrapper);
        

        public Scene getScene() 
            return scene;
        
    

    public MainMenu getMainMenu() 
        return mainMenu;
    

对我的代码的任何其他修复将不胜感激。 顺便说一句,这些是我得到的错误:

线程“Thread-0”java.lang.IllegalStateException 中的异常: 工具包未在 com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:273) 在 com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:268) 在 javafx.application.Platform.runLater(Platform.java:83) 在 javafx.scene.media.Media$_MetadataListener.onMetadata(Media.java:541) 在 com.sun.media.jfxmediaimpl.MetadataParserImpl.done(MetadataParserImpl.java:120) 在 com.sun.media.jfxmediaimpl.platform.java.ID3MetadataParser.parse(ID3MetadataParser.java:237) 在 com.sun.media.jfxmediaimpl.MetadataParserImpl.run(MetadataParserImpl.java:103) 线程“主”java.lang.ExceptionInInitializerError 中的异常 java.lang.Class.forName0(本机方法)在 java.lang.Class.forName(Class.java:264) 在 com.intellij.rt.execution.application.AppMain.main(AppMain.java:122) 原因:java.lang.IllegalStateException:工具包未初始化 在 com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:273) 在 com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:268) 在 javafx.application.Platform.runLater(Platform.java:83) 在 javafx.scene.media.MediaPlayer.init(MediaPlayer.java:515) 在 javafx.scene.media.MediaPlayer.(MediaPlayer.java:414) 在 Main.(Main.java:22) ... 还有 3 个

【问题讨论】:

您的 MediaPlayer 在这里不需要是静态的。请参阅下面 James_D 的答案。尽可能避免使用静态变量。 是的,这不是我的全部代码,我也想从其他类访问这个媒体播放器:) 正如我在下面发布的,static 与可访问性/可见性无关 @aran 你意识到一个对象不必是静态的才能传递给其他类,对吧?静态对象有非常具体的应用,如果你不需要静态定义的变量,你应该经常避免它们。如果您愿意,只需在其构造函数中或通过方法传递对需要访问 MediaPlayer 对象的子对象的引用。在这种情况下,完全不需要静态定义。 【参考方案1】:

在没有上下文对象的情况下调用 getClass() 的解释与任何其他实例方法相同:this.getClass()

在静态上下文中,您可以使用ClassName.class 引用该类;即你可以做

static URL resource = Main.class.getResource("a.mp3");

但是,在这种情况下,您为什么希望这些变量是静态的并不清楚;每个 JVM 实例只能创建一个 Application 子类的实例,这些是该实例的固有属性。

在您(更新的)问题的具体示例中,我将定义一个单独的类来封装 MediaPlayer 和您当前设为静态的其他属性。请注意,MediaPlayer 本身定义了一个 volume 属性和一个 muted 属性。所以你可以这样做:

public class SoundPlayer 

    private final MediaPlayer mediaPlayer ;

    public SoundPlayer(URL url) 
        this.mediaPlayer = new MediaPlayer(new Media(url));
    

    public void play() 
        mediaPlayer.play();
    

    public double getVolume() 
        return mediaPlayer.getVolume();
    

    public void setVolume(double volume) 
        mediaPlayer.setVolume(volume);
    

    public boolean isSoundOn() 
        return ! mediaPlayer.isMuted();
    

    public void setSoundOn(boolean soundOn) 
        mediaPlayer.setMuted(! soundOn);
    

现在你的Main 类可以是:

public class Main extends Application 

    public static void main(String[] args) 
        Application.launch(args);
    

    @Override
    public void start(Stage primaryStage) 

        SoundPlayer soundPlayer = new SoundPlayer(getClass().getResource("song.mp3"));
        soundPlayer.play();


        primaryStage.setTitle("duet by Aran Mohyeddin");

        GUI gui = new GUI(soundPlayer);

        primaryStage.setScene(gui.getMainMenu().getScene());
        primaryStage.show();
    


并更新您的 GUIMainMenu 类以引用 SoundPlayer

public class MainMenu 
        private Scene scene;

        private final SoundPlayer soundPlayer ;

        private MainMenu(SoundPlayer soundPlayer) 

            this.soundPlayer = soundPlayer ;

            // existing code omitted...

            CheckBox soundOn = new CheckBox("soundOn?");
            Tooltip tooltip = new Tooltip("if this box is checked, music will be played!");
            tooltip.setFont(new Font("Arial", 16));
            soundOn.setTooltip(tooltip);
            soundOn.selectedProperty().addListener(new ChangeListener<Boolean>() 
                public void changed(ObservableValue<? extends Boolean> ov,
                                    Boolean old_val, Boolean new_val) 

                    soundPlayer.setSoundOn(new_val);
                
            );

            // ...


            Slider soundVolume = new Slider(0, 1, .5);
            soundVolume.valueProperty().addListener(new ChangeListener<Number>() 
                public void changed(ObservableValue<? extends Number> ov,
                                    Number old_val, Number new_val) 

                    soundPlayer.setVolumn(new_val.doubleValue());
                    System.out.printf("%.2f\n", Main.soundVolume);
                
            );
            changeVolumeWrapper.getChildren().add(soundVolume);
            vBox.getChildren().add(changeVolumeWrapper);
        

        public Scene getScene() 
            return scene;
        
    

    public MainMenu getMainMenu() 
        return mainMenu;
    

另请注意,如果您从SoundPlayer 公开实际的属性对象,例如:

public class SoundPlayer 

    private final MediaPlayer mediaPlayer ;

    // ...


    public DoubleProperty volumeProperty() 
        return mediaPlayer.volumeProperty();
    

    // ...

那么您可以简化一些代码:

    Slider soundVolume = new Slider(0, 1, .5);
    // instead of the listener, just do:
    soundPlayer.volumeProperty().bindBidirectional(soundVolume.valueProperty());

(将mutedProperty 转换为soundOnProperty 不太优雅。)

【讨论】:

非常感谢!好吧,我只想在没有封装的情况下从其他类访问媒体播放器并传递主 bc 的实例,我认为媒体播放器也应该是最终的 static 与访问字段无关,完全独立于字段是否为最终字段。将变量设为静态只是为了避免强制进行适当的封装是非常糟糕的做法。

以上是关于获取文件资源的静态方法的主要内容,如果未能解决你的问题,请参考以下文章

获取 /resources 目录资源文件的 9 种方法,还有谁不会?!

获取 /resources 目录资源文件的 9 种方法,还有谁不会?!

获取 /resources 目录资源文件的 9 种方法,还有谁不会?!

很想在 Spring Boot 中获取静态资源文件,部署为 .jar? [复制]

获取springboot项目static目录的静态资源

Node访问服务器端静态资源