无法从控制器中使用主类中的stage。

4

我正在尝试使用JavaFX制作屏幕录制器。我在谷歌上搜索如何制作屏幕录制器时,看到了这篇文章,我尝试了一下,很喜欢它,所以决定使用提供的代码制作JavaFX FXML应用程序。

@FXML
void startOnAction(ActionEvent event) {
    FXMLDocumentController FXML = new FXMLDocumentController();
    FXML.console.setText("######### Starting Screen Recorder #########");
    try {
        Thread.sleep(250);
    } catch (InterruptedException  ex) {
    }
    Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
    FXML.console.appendText("Your Screen [Width, Height]: " + "[" + screen.getWidth() + "," + screen.getHeight() + "]\nWhen the Recording starts, this window will minimize, to stop them recording, open this window.");
    try {
        Thread.sleep(1000);
    } catch (InterruptedException ex) {
    }
    FXML.console.appendText("The recording will start in 5 seconds");
    int num = 5;
    for (int i = 0; i <= 5; i++) {
        System.out.print(num);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
        }
        num = num - 1;
    }
    FXML.console.appendText("Start!");
    File f = new File(store);
    if (!f.exists()) {
        f.mkdir();
    }
    startRecord();
    Recorder R = new Recorder();
    R.stage.setIconified(true);
    R.stage.focusedProperty().addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
        focusState(newValue);
    });
}

这是FXMLDocumentController中的一个方法,我想让我的TextArea使用变量“console”打印出我想要的文本。然而,在我使用对象的所有行中,这些“FXMLDocumentController FXML = new FXMLDocumentController();”和“Recorder R = new Recorder();”都出现了错误。以下是错误信息:
    Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1774)
    at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1657)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Node.fireEvent(Node.java:8413)
    at javafx.scene.control.Button.fire(Button.java:185)
    at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
    at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
    at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:380)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:294)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:416)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:415)
    at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
    at com.sun.glass.ui.View.notifyMouse(View.java:937)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1769)
    ... 48 more
Caused by: java.lang.NullPointerException
    at recorder.FXMLDocumentController.startOnAction(FXMLDocumentController.java:127)
    ... 58 more

Line 127 is `Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1774)
    at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1657)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Node.fireEvent(Node.java:8413)
    at javafx.scene.control.Button.fire(Button.java:185)
    at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
    at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
    at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:380)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:294)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:416)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:415)
    at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
    at com.sun.glass.ui.View.notifyMouse(View.java:937)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1769)
    ... 48 more
Caused by: java.lang.NullPointerException
    at recorder.FXMLDocumentController.startOnAction(FXMLDocumentController.java:127)
    ... 58 more`

第127行是我上面发布的代码中的第4行。


完整代码如下...

主要类:

    package recorder;

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Recorder extends Application {

    public Stage stage;

    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

        Scene scene = new Scene(root);
        stage.setResizable(false);
        stage.setScene(scene);
        stage.show();
    }

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

}

FXML文档:

    <?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>

<GridPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="639.0" prefWidth="578.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="recorder.FXMLDocumentController">
    <columnConstraints>
        <ColumnConstraints hgrow="SOMETIMES" minWidth="578.0" prefWidth="578.0" />
    </columnConstraints>
    <rowConstraints>
        <RowConstraints maxHeight="1.7976931348623157E308" minHeight="10.0" prefHeight="95.0" vgrow="SOMETIMES" />
        <RowConstraints maxHeight="245.0" minHeight="9.0" prefHeight="12.0" vgrow="SOMETIMES" />
        <RowConstraints maxHeight="481.0" minHeight="10.0" prefHeight="478.0" vgrow="SOMETIMES" />
    </rowConstraints>
    <children>
        <Button fx:id="start" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#startOnAction" prefHeight="220.0" prefWidth="578.0" text="Start Recording" />
        <TextArea fx:id="console" editable="false" prefHeight="200.0" prefWidth="200.0" promptText="Console" wrapText="true" GridPane.rowIndex="2" />
        <TextField fx:id="input" prefHeight="105.0" prefWidth="578.0" promptText="File Name" GridPane.rowIndex="1" />
    </children>
</GridPane>

FXMLDocumentController(代码片段来源):

package recorder;

import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javax.imageio.ImageIO;
import javax.media.MediaLocator;
import javax.swing.JOptionPane;

public class FXMLDocumentController implements Initializable {

    File file;
    /**
     * Screen Width.
     */
    public static int screenWidth = (int) Toolkit.getDefaultToolkit()
            .getScreenSize().getWidth();

    /**
     * Screen Height.
     */
    public static int screenHeight = (int) Toolkit.getDefaultToolkit()
            .getScreenSize().getHeight();

    /**
     * Interval between which the image needs to be captured.
     */
    public static int captureInterval = 50;

    /**
     * Temporary folder to store the screenshot.
     */
    public static String store = "tmp";

    /**
     * Status of the recorder.
     */
    public static boolean record = false;

    @FXML
    private Button start;

    @FXML
    private TextArea console;

    @FXML
    private TextField input;

    public static void startRecord() {
        Thread recordThread = new Thread() {
            @Override
            public void run() {
                Robot rt;
                int cnt = 0;
                try {
                    rt = new Robot();
                    while (cnt == 0 || record) {
                        BufferedImage img = rt.createScreenCapture(new Rectangle(screenWidth, screenHeight));
                        ImageIO.write(img, "jpeg", new File("./" + store + "/"
                                + System.currentTimeMillis() + ".jpeg"));
                        if (cnt == 0) {
                            record = true;
                            cnt = 1;
                        }
                        Thread.sleep(captureInterval);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        recordThread.start();
    }

    /**
     * @throws MalformedURLException
     *
     */
    public static void makeVideo(String movFile) throws MalformedURLException {
        FXMLDocumentController FXML = new FXMLDocumentController();
        FXML.console.appendText("Processing Video... please wait");
        JpegImagesToMovie imageToMovie = new JpegImagesToMovie();
        Vector<String> imgLst = new Vector<String>();
        File f = new File(store);
        File[] fileLst = f.listFiles();
        for (int i = 0; i < fileLst.length; i++) {
            imgLst.add(fileLst[i].getAbsolutePath());
        }
        // Generate the output media locators.
        MediaLocator oml;
        if ((oml = imageToMovie.createMediaLocator(movFile)) == null) {
            FXML.console.appendText("Error in processing");
            System.exit(0);
        }
        imageToMovie.doIt(screenWidth, screenHeight, (1000 / captureInterval), imgLst, oml);

    }

    @FXML
    void setOnAction(ActionEvent event) {
        String path = JOptionPane.showInputDialog("Type in the File Path", "C:/Users/" + System.getProperty("user.name") + "/Desktop");
        file = new File(path);
    }

    @FXML
    void startOnAction(ActionEvent event) {
        FXMLDocumentController FXML = new FXMLDocumentController();
        FXML.console.setText("######### Starting Screen Recorder #########");
        try {
            Thread.sleep(250);
        } catch (InterruptedException  ex) {
        }
        Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
        FXML.console.appendText("Your Screen [Width, Height]: " + "[" + screen.getWidth() + "," + screen.getHeight() + "]\nWhen the Recording starts, this window will minimize, to stop them recording, open this window.");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
        }
        FXML.console.appendText("The recording will start in 5 seconds");
        int num = 5;
        for (int i = 0; i <= 5; i++) {
            System.out.print(num);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
            }
            num = num - 1;
        }
        FXML.console.appendText("Start!");
        File f = new File(store);
        if (!f.exists()) {
            f.mkdir();
        }
        startRecord();
        Recorder R = new Recorder();
        R.stage.setIconified(true);
        R.stage.focusedProperty().addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
            focusState(newValue);
        });
    }

    ;

    private void focusState(boolean value) {
        if (value) {
            System.out.println("Focus Gained");
            record = false;
            try {
                makeVideo(input.getText() + ".mov");
            } catch (MalformedURLException ex) {
            }
        } else {
        }
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {

    }

}

我希望我按照您的指引以及相关要求进行了正确的操作。

以下是需要翻译的内容:

1个回答

1
你只是创建了一个名为FXMLDocumentController的实例,它与任何已使用FXMLLoader加载的fxml没有连接。
然而,FXMLLoader负责注入字段值,并且仅在加载fxml文件时(即由FXMLLoader自己创建的基于fx:controller属性的控制器类或使用setController提供的控制器类)注入到与FXMLLoader一起使用的控制器类的实例中;在两种情况下,可以在调用load之后直接使用FXMLLoader.getController检索实例。
从未修改的字段仍包含默认值null,这会导致例如在此处发生NPE:
FXMLDocumentController FXML = new FXMLDocumentController();
FXML.console.setText("######### Starting Screen Recorder #########");

this.console.setText("######### Starting Screen Recorder #########");

您的代码可能会成功,但请注意,您正在使用 Thread.sleep 阻塞应用程序线程数秒钟,这将导致应用程序在此期间冻结...

在场景添加后,要检索 Window,你可以使用场景中的一个 Node

Stage stage = (Stage) this.console.getScene().getWindow();
stage.setIconified(true);
stage.focusedProperty()...

这部分怎么样?Recorder R = new Recorder(); R.stage.setIconified(true); R.stage.focusedProperty().addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> { focusState(newValue); }); - Gamer818
“this” 不起作用,因为它来自不同的类。 - Gamer818
@Gamer818 你可以通过显示场景的节点获取该舞台,该节点包含在此场景中。请注意,您从未将任何内容分配给Recorder.stage,即使在Recorder类本身中也是如此,这意味着它永远不会与null不同;我已编辑答案。 - fabian
感谢您的所有帮助!屏幕录制器现在完美运行,除了它没有记录我的鼠标...但这将是另一天的问题。感谢您的所有帮助! - Gamer818

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接