【问题标题】:JavaFX 2.1 and threads? -or- Ending a JavaFX application gracefully?JavaFX 2.1 和线程? - 或 - 优雅地结束 JavaFX 应用程序?
【发布时间】:2012-06-09 19:04:43
【问题描述】:

我想要一种非常简单的方法来从 Java 应用程序播放 mp3 文件。经过一番研究,我发现最新版本的 Java 7 SE 是用 JavaFX 打包的,所以我想我会尝试一下。这个问题不是关于播放 mp3 文件,而是关于让 JavaFX 以一种良好的方式工作。

因此,在我对 JavaFX 的第一次实验中,我使用了在 stackoverflow (see here) 的帖子中建议的一些代码,并创建了以下测试程序:

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;

public class progtest extends Application
{

    /*---------------------------------------------------------*\
        FUNCTION:  main()
    \*---------------------------------------------------------*/
    public static void main(String args[])
    {

        launch(args);

    } /* END:  main() */

    /*---------------------------------------------------------*\
        FUNCTION:  start()
    \*---------------------------------------------------------*/
    @Override
    public void start(Stage stage)
    {

        Media medMsg 
            = 
            new Media(getClass().getResource("msg.mp3").toExternalForm());
        MediaPlayer medplMsg = new MediaPlayer(medMsg);
        medplMsg.play();

        System.out.println("Here.\n");

    } /* END:  start() */

}

(这比我原来的测试程序稍微复杂一点:这个版本是在jewelsea 提出的建议之后提出的,以回应我之前发布的关于让程序运行的问题(see here)。)

为了编译我使用的这段代码:

javac -cp "c:\Program Files\Oracle\JavaFX 2.1 Runtime\lib\jfxrt.jar";..\bin -d ..\bin ..\src\progtest.java

为了运行代码,我进入了我的 ..\bin 目录并使用了:

java -cp .;"c:\Program Files\Oracle\JavaFX 2.1 Runtime\lib\jfxrt.jar" progtest

此程序运行并播放剪辑播放。但是,除非我按 Ctrl-C,否则程序不会返回到命令提示符。

这种行为似乎是某种线程问题。我已经多次看到这种行为与 Java 线程一起使用(遗憾的是,在允许程序优雅退出时存在真正的问题)。

所以,我想,也许如果我将代码放在它自己的线程中,然后在该线程结束时结束程序的主线程,一切都会好起来的。 (我可以看出这并不完全是一个有说服力的想法,但无论如何,我想我会尝试。)所以,我编写了以下代码的第二个版本:

这里是主线程:

import javafx.application.Application;
import javafx.stage.Stage;
import Msg.*;

public class progtest2 extends Application
{

    /*---------------------------------------------------------*\
        FUNCTION:  main()
    \*---------------------------------------------------------*/
    public static void main(String args[])
    {

        launch(args);

    } /* END:  main() */

    /*---------------------------------------------------------*\
        FUNCTION:  start()
    \*---------------------------------------------------------*/
    @Override
    public void start(Stage stage)
    {

        Msg msgTime = new Msg();
        msgTime.passClass(getClass());
        msgTime.start();

        try
        {
            msgTime.join();
        }
        catch (InterruptedException e)
        {
        }

        System.out.println("Here.\n");

    } /* END:  start() */

}

下面是实际播放 mp3 文件的 Msg 线程的代码:

package Msg;

import KeyIO.*;
import javafx.application.Application;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;

public class Msg extends Thread
{

    private Class classRt = null;

    /*--------------------------------------------------------*\
        FUNCTION:  passClass()
    \*--------------------------------------------------------*/
    public void passClass(Class rt)
    {

        classRt = rt;

    } /* END:  passClass() */

    /*--------------------------------------------------------*\
        FUNCTION:  run()
    \*--------------------------------------------------------*/
    public void run()
    {

        Media medMsg
            = new Media(classRt.getResource("msg.mp3").toExternalForm());
        MediaPlayer medplMsg = new MediaPlayer(medMsg);
        medplMsg.play();

        System.out.println("Leaving Msg thread.\n");

    } /* END:  run() */

}

(我使用与上述相同的命令(比照文件名和类名)构建和运行这些文件。)

程序运行并播放 mp3 文件。在您听到文件之前,您会看到“Leaving Msg thread”。然后是“Here.”,如您所见,它分别来自 Msg 线程和主线程。但是,同样,程序并没有结束。我必须按 Ctrl-C 才能返回命令提示符。

我在主线程的末尾放了一个 System.exit() 调用,只是为了看看行为会是什么。行为是没有听到剪辑。似乎 System.exit() 调用在播放剪辑之前结束了进程。

所以,接下来我尝试将以下几行放在 System.out.println("Here.\n"); 之间以及我进行的 System.exit() 调用:

System.out.print("Press ENTER to end...");
KeyIO.ReadLine();

(KeyIO是我做的一个类,只是简单的做键盘输入输出,细节在这里不重要。)

我认为这只会阻止主线程继续前进,直到播放剪辑。

但是,没有。相反,该剪辑没有播放。当我按 ENTER 时,程序退出而不播放剪辑。

好的,现在我保留了键盘输入阻止代码,但我取消了 System.exit() 调用。现在音频片段播放了,但程序没有再次结束。

啊!

任何想法如何优雅地让它以一种显而易见的方式工作?我只想打电话播放剪辑,然后我希望能够结束程序。

提前谢谢你!

【问题讨论】:

    标签: java multithreading javafx-2 exit


    【解决方案1】:

    在第一个 progtest 类中,您不创建窗口,因此不会调用关闭最后一个窗口时的implicitExit 操作。这意味着程序将继续运行,直到您调用应用程序的退出方法,您不这样做。

    要让程序在您的 mp3 播放完毕后退出,请调用 mediaPlayer.setOnEndOfMedia(runnable) 并在可运行回调中调用 Platform.exit() 方法。

    medplMsg.setOnEndOfMedia(new Runnable() {
      @Override public void run() {
        Platform.exit();
      }
    });
    

    您问题中的所有其他线程内容都不是必需的(无论如何也不能解决您的问题......)。我不建议使用自定义线程,除非你真的需要它(你不需要)。

    JavaFX 2.2 增加了以下 api:

    Platform.setImplicitExit(boolean implicitExit)
    

    将implicitExit 属性设置为指定值。如果这 属性为 true 时,JavaFX 运行时将隐式关闭 最后一个窗口关闭; JavaFX 启动器将调用 Application.stop() 方法并终止 JavaFX 应用程序线程。 如果此属性为 false,应用程序将继续运行 通常即使在最后一个窗口关闭后,直到应用程序 调用 exit()。默认值为 true。

    这应该会给你一些关于你遇到的问题的线索。

    【讨论】:

    • 太棒了!它就像一个魅力。我将在下面发布整个代码。谢谢珠宝海!!!非常有帮助。它给了我很多关于如何在未来自己弄清楚这些东西的见解。谢谢。
    【解决方案2】:

    我自己的问题的这个答案是给出一个最终解决问题的代码的明确示例,该问题来自于 Jewelsea 在这个线程中的出色回复以及我在原始帖子中提到的另一个。

    好的,所以下面的代码有效(jewelsea 正确地评论说线程是不必要的,而且这里没有任何意义):

    import javafx.application.Application;
    import javafx.application.Platform;
    import javafx.stage.Stage;
    import javafx.scene.media.Media;
    import javafx.scene.media.MediaPlayer;
    
    public class progtest6 extends Application
    {
    
        /*---------------------------------------------------------*\
            FUNCTION:  main()
        \*---------------------------------------------------------*/
        public static void main(String args[])
        {
    
            launch(args);
    
        } /* END:  main() */
    
        /*---------------------------------------------------------*\
            FUNCTION:  start()
        \*---------------------------------------------------------*/
        @Override
        public void start(Stage stage)
        {
    
            Media medMsg 
                = 
                new Media(getClass().getResource("msg.mp3").toExternalForm());
            MediaPlayer medplMsg = new MediaPlayer(medMsg);
            medplMsg.setOnEndOfMedia(new Runnable() {
                @Override
                public void run()
                {
                    Platform.exit();
                }
            });
            medplMsg.play();
    
            System.out.println("Here.\n");
    
        } /* END:  start() */
    
    }
    

    谢谢珠宝海。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-30
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多