JavaFX调用statge.show()和mediaPlayer.play()的正确方法

egmofgnx  于 2023-10-14  发布在  Java
关注(0)|答案(1)|浏览(81)

我正试图在窗口的右上角显示通知,我正在播放动画和声音。当我第一次启动Test.main()时,下面的代码工作得很好,但是当我试图播放相同的动画和声音时,它不工作。请帮帮我。thanks in advance
Test.java

public class Test {
    public static void main(String[] args) {
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(4);
        executor.scheduleAtFixedRate(new NotificationRunnable(), 0, 2 * 60, TimeUnit.SECONDS);

        executor.scheduleAtFixedRate(new NotificationRunnable(), 0, 4 * 60, TimeUnit.SECONDS);

        executor.scheduleAtFixedRate(new NotificationRunnable(), 0, 9 * 60, TimeUnit.SECONDS);

        executor.scheduleAtFixedRate(new NotificationRunnable(), 0, 13 * 60, TimeUnit.SECONDS);
       
        //Launching application first time
        NotificationApp.runFromScheduledExecutor();
        
    }

}

NotificationRunnable.java

public class NotificationRunnable implements Runnable{
    @Override
    public void run() {
        Platform.runLater(() -> {
            NotificationApp.playAnimation();
        });
        System.out.println("Done");
    }
}

Notification.java

public class NotificationApp extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    static Stage primaryStage = null;
    static MediaPlayer mediaPlayer = null;

    @Override
    public void start(Stage primaryStage) {
        // Create a custom dialog with an ImageView
        Image gifImage = new Image(String.valueOf(new File("img/giphy.gif"))); // Replace with your GIF file path
        ImageView gifImageView = new ImageView(gifImage);
        Pane pane = new Pane(gifImageView);
        Scene scene = new Scene(pane);

        // Set stage properties
        primaryStage.initStyle(StageStyle.TRANSPARENT); // Hide the window decoration
        primaryStage.setAlwaysOnTop(true);

        // Determine screen dimensions
        double screenWidth = Screen.getPrimary().getVisualBounds().getWidth();
        double screenHeight = Screen.getPrimary().getVisualBounds().getHeight();
        double stageWidth = gifImage.getWidth();
        double stageHeight = gifImage.getHeight();

        // Set the stage position to the right corner
        double xOffset = screenWidth - stageWidth;
        double yOffset = screenHeight - stageHeight;
        primaryStage.setX(xOffset);
        primaryStage.setY(yOffset);

        primaryStage.setScene(scene);
        this.primaryStage = primaryStage;

        Media sound = new Media(new Test().getClass().getResource("/snd/Notification.mp3").toExternalForm());
        mediaPlayer = new MediaPlayer(sound);
        //Play animation and Sound during application start
        Platform.runLater(() -> {
            playAnimation();
        });
    }

    public static void playAnimation(){
        Platform.runLater(() -> {
            mediaPlayer.play();
            primaryStage.show();
        });
        // Schedule closing the stage after 5 seconds
        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.schedule(() -> {
            Platform.runLater(() -> {
                mediaPlayer.stop();
                primaryStage.close();
            });
        }, 5, TimeUnit.SECONDS);
    }
    public static void runFromScheduledExecutor() {
        Application.launch(NotificationApp.class);
    }

}

我试图通过调用playAnimation()从Runnable播放动画和声音。但此代码不播放动画,当我第一次启动应用程序,它播放动画和声音按requirment,但第二次不工作。

fykwrbwg

fykwrbwg1#

我将删除所有使用static字段,并删除所有使用ScheduledExecutorService。
我意识到静态字段是必要的,因为Test的main方法无法访问JavaFX创建的NotificationApp示例,但更好的方法是只有一个main方法,因此您无需担心从其他类访问NotificationApp示例。
如果您希望NotificationApp能够执行不同的操作,请使用其命令行参数。使用PauseTransition的setOnFinished方法而不是ScheduledExecutorService.schedule,这将消除对Platform.runLater的需要。不使用ScheduledExecutorService.scheduleAtFixedRate,而是使用单个KeyFrame创建一个时间轴,其侦听器执行该任务。

import java.io.File;

import java.util.List;

import javafx.animation.Animation;
import javafx.animation.PauseTransition;
import javafx.animation.Timeline;
import javafx.animation.KeyFrame;

import javafx.application.Application;
import javafx.application.Platform;

import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.Screen;

import javafx.scene.Scene;

import javafx.scene.image.Image;
import javafx.scene.image.ImageView;

import javafx.scene.layout.Pane;

import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;

import javafx.util.Duration;

public class NotificationApp extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    private Stage primaryStage;
    private MediaPlayer mediaPlayer;

    // Schedule closing the stage after 5 seconds
    private Animation closer;

    @Override
    public void start(Stage primaryStage) {
        // Create a custom dialog with an ImageView
        Image gifImage = new Image(String.valueOf(new File("img/giphy.gif"))); // Replace with your GIF file path
        ImageView gifImageView = new ImageView(gifImage);
        Pane pane = new Pane(gifImageView);
        Scene scene = new Scene(pane);

        // Set stage properties
        primaryStage.initStyle(StageStyle.TRANSPARENT); // Hide the window decoration
        primaryStage.setAlwaysOnTop(true);

        // Determine screen dimensions
        double screenWidth = Screen.getPrimary().getVisualBounds().getWidth();
        double screenHeight = Screen.getPrimary().getVisualBounds().getHeight();
        double stageWidth = gifImage.getWidth();
        double stageHeight = gifImage.getHeight();

        // Set the stage position to the right corner
        double xOffset = screenWidth - stageWidth;
        double yOffset = screenHeight - stageHeight;
        primaryStage.setX(xOffset);
        primaryStage.setY(yOffset);

        primaryStage.setScene(scene);
        this.primaryStage = primaryStage;

        Media sound = new Media(NotificationApp.class.getResource("/snd/Notification.mp3").toExternalForm());
        mediaPlayer = new MediaPlayer(sound);

        closer = new PauseTransition(Duration.seconds(5));
        closer.setOnFinished(e -> {
            mediaPlayer.stop();
            primaryStage.close();
        });

        List<String> args = getParameters().getRaw();
        if (args.isEmpty()) {
            //Play animation and Sound during application start
            Platform.runLater(() -> playAnimation());
        } else {
            Platform.setImplicitExit(false);
            for (String arg : args) {
                Duration interval = Duration.valueOf(arg);
                Timeline repeater = new Timeline(
                    new KeyFrame(interval, e -> playAnimation()));
                repeater.setCycleCount(Animation.INDEFINITE);
                repeater.play();
            }
        }
    }

    private void playAnimation() {
        mediaPlayer.play();
        primaryStage.show();

        closer.playFromStart();
    }

}

PauseTransition和时间轴的事件处理程序在JavaFX应用程序线程中调用,因此不需要Platform.runLater。
可以这样调用应用程序:

java -p /opt/java/javafx/lib --add-modules javafx.graphics,javafx.media NotificationApp 2m 4m 9m 13m

2m这样的参数的含义在Duration.valueOf的文档中有解释。注意,这是javafx.util.Duration类,而不是java.time.Duration。

**注意:**使用2分钟的间隔已经保证通知将每4分钟显示一次。同时显示2分钟 * 和 * 4分钟意味着每隔4分钟,两个通知将同时显示,彼此重叠。而且,正如您可能想象的那样,指定2分钟和9分钟意味着每18分钟将同时出现两个通知。如果同时设置2分钟和13分钟,则意味着每26分钟将同时出现两个通知。

在测试时,您可能应该只指定单个间隔,如2m

相关问题