Bazooka Bazooka - 1 month ago 19
Java Question

My .getHtml text method always returns null even there is text in the HTMLEditor

I am making a basic text editor in JavaFX and decided to utilize the power of HtmlEditor. I have added my own icons for save and load in the toolbar for the user to use.

I am using FileChooser to allow the user to pick a directory to save in and then the program creates a file in said directory and then writes the data in the HTMLEditor into the created file. This is where I have noticed that the .getHtmltext() method keeps on returning a null value even though I enter text into the HtmlEditor.

How do I solve this?

SRC CODE:

Main Launcher:

package application;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;

public class Main extends Application {
@Override
public void start(Stage primaryStage) {
FXMLLoader fl = new FXMLLoader(getClass().getResource("style.fxml"));

try {
AnchorPane ap = fl.load();
Scene scn = new Scene(ap);
primaryStage.setScene(scn);
} catch(Exception e) {

}
Control c = fl.getController();
c.setup(primaryStage);

primaryStage.setTitle("Postey");
primaryStage.show();

}

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


FXML Document:

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

<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.web.HTMLEditor?>


<AnchorPane prefHeight="431.0" prefWidth="631.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.60" fx:controller="application.Control">
<children>
<HTMLEditor fx:id="mainField" htmlText="&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body contenteditable=&quot;true&quot;&gt;&lt;/body&gt;&lt;/html&gt;" layoutX="12.0" layoutY="7.0" prefHeight="409.0" prefWidth="604.0" />
</children>
</AnchorPane>


AND FINALLY, the Controller:

package application;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.ToolBar;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.web.HTMLEditor;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

public class Control {
@FXML
private HTMLEditor mainField;

public void setup(Stage stg) {
Control c = new Control();

Node node = mainField.lookup(".top-toolbar");
if (node instanceof ToolBar) {
ToolBar bar = (ToolBar) node;

ImageView graphic = new ImageView(new Image("save.png", 32, 16, true, true));
graphic.setEffect(new DropShadow());
Button b2 = new Button("", graphic);
b2.setOnAction(e -> {
c.save(stg);
});
bar.getItems().add(b2);

ImageView iv = new ImageView(new Image("load.png", 32, 16, true, true));
iv.setEffect(new DropShadow());
Button b1 = new Button("", iv);
b1.setOnAction(e -> {
c.load();
});
bar.getItems().add(b1);
}
}

private void load() {
//ignore for now
}

private void save(Stage stg) {
FileChooser fc = new FileChooser();
FileChooser.ExtensionFilter txtFilter = new FileChooser.ExtensionFilter("txt files (*.txt)", "*.txt");
FileChooser.ExtensionFilter htmlFilter = new FileChooser.ExtensionFilter("html files (*.html)", "*.html");
FileChooser.ExtensionFilter cssFilter = new FileChooser.ExtensionFilter("css files (*.css)", "*.css");
fc.getExtensionFilters().addAll(txtFilter, htmlFilter, cssFilter);

fc.setInitialDirectory(new File("C://"));
fc.setTitle("Choose Save Location");
File f = fc.showSaveDialog(stg);
String dir = f.getAbsolutePath();

File omega = new File(dir);
try {
FileOutputStream fos = new FileOutputStream(omega);
PrintWriter pw = new PrintWriter(fos);

pw.write(mainField.getHtmlText());
pw.flush();

pw.close();

} catch (Exception e) {
e.printStackTrace();
}
}
}


Also, the images for the icons if they are needed:

Save Icon

Load Icon

Oh and another thing. While searching up on probable solutions for this problem, I found out that I could use something called Optionals from
java.util.Optional
I tried to use them as I heard that they can except null values but it returned a null pointer exception too. Please help me.

Answer

It makes no sense to create a whole new instance of Control in the setup(...) method. The fields injected by the FXML loader will not be initialized in that instance. Just use the existing instance:

public void setup(Stage stg) {

    Node node = mainField.lookup(".top-toolbar");
    if (node instanceof ToolBar) {
        ToolBar bar = (ToolBar) node;

        ImageView graphic = new ImageView(new Image("save.png", 32, 16, true, true));
        graphic.setEffect(new DropShadow());
        Button b2 = new Button("", graphic);
        b2.setOnAction(e -> {
            save(stg);
        });
        bar.getItems().add(b2);

        ImageView iv = new ImageView(new Image("load.png", 32, 16, true, true));
        iv.setEffect(new DropShadow());
        Button b1 = new Button("", iv);
        b1.setOnAction(e -> {
            load();
        });
        bar.getItems().add(b1);
    }
}