Problem : So basically the problem is that when I do change background color at 12pt font size and then I increase the font size to let's say 36pt then the background color is not properly rendered in HTMLEditor. Here is the video on action : Video showing how I generate the issue.
Here is the sample fxml file :
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.ToolBar?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.web.HTMLEditor?>
<TabPane xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="AppController">
<tabs>
<Tab text="Editor">
<content>
<GridPane minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="366.0" vgrow="ALWAYS" />
</rowConstraints>
<children>
<HTMLEditor fx:id="htmleditor" htmlText="<html><head></head><body contenteditable="true"></body></html>" GridPane.hgrow="ALWAYS" GridPane.vgrow="ALWAYS" />
</children>
</GridPane>
</content>
</Tab>
<Tab text="Raw">
<content>
<GridPane minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="195.0" minHeight="10.0" prefHeight="34.0" vgrow="NEVER" />
<RowConstraints minHeight="10.0" prefHeight="366.0" vgrow="ALWAYS" />
</rowConstraints>
<children>
<ToolBar prefHeight="40.0" prefWidth="200.0">
<items>
<Button mnemonicParsing="false" onAction="#onRawHTMLButtonClick" text="Raw HTML" />
<Button mnemonicParsing="false" onAction="#onUpdateButtonClick" text="Update" />
</items>
</ToolBar>
<TextArea fx:id="rawHTMLViewer" prefHeight="200.0" prefWidth="200.0" GridPane.rowIndex="1" />
</children>
</GridPane>
</content>
</Tab>
</tabs>
</TabPane>
Here is the code for running the gui:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class App extends Application {
public static void main(String[] args) {
launch();
}
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(App.class.getResource("/View/App.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 900, 600);
primaryStage.setTitle("Basic HtmlEditor");
primaryStage.setScene(scene);
primaryStage.show();
}
}
What I have tried to solve the problem : So basically I tried to retrive webengine reference and from there I have extracted the webpage. Webpage has a method to refresh and it also has a method to force to repaint. But still it doesn't solve the problem. Here is the code of that : @FXML private HTMLEditor htmleditor;
@FXML
private TextArea rawHTMLViewer;
private WebEngine engine;
@Override
public void initialize(URL location, ResourceBundle resources) {
Platform.runLater(() -> {
engine = HTMLEditorUtility.findWebView(htmleditor).getEngine();
int backgroundColorNodeIndex = 16;
ColorPicker colorPicker = (ColorPicker) HTMLEditorUtility.findNthNodeOfTopToolBar(htmleditor, backgroundColorNodeIndex);
colorPicker.valueProperty().addListener((observable, oldValue, newValue) -> {
System.out.println("Color has been changed");
repaint();
});
ComboBox fontSizeComboBox = (ComboBox) HTMLEditorUtility.findNthNodeOfBottomToolBar(htmleditor, 2);
fontSizeComboBox.valueProperty().addListener((observable, oldValue, newValue) -> {
System.out.println("Font size has been changed");
repaint();
});
});
}
And here is the repaint method code :
private void repaint() {
WebPage webPage = Accessor.getPageFor(engine);
webPage.refresh(webPage.getMainFrame());
webPage.forceRepaint();
}
Also I have read in this post that we may overcome the screen refreshing problem by changing scene size. I have tried that also but it doesn't solve the problem. Please if anyone know any solution to this.
Here is the HTMLEditorUtility.java code :
import javafx.scene.Node;
import javafx.scene.control.ToolBar;
import javafx.scene.web.HTMLEditor;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import lombok.NonNull;
import java.util.function.Function;
/**
* @author : Md. Ismail Hosen
* @version : 1.0
*/
public class HTMLEditorUtility {
static final String TOP_TOOLBAR_SELECTOR = ".top-toolbar";
static final String BOTTOM_TOOLBAR_SELECTOR = ".bottom-toolbar";
static final String WEB_VIEW_SELECTOR = "WebView";
/**
* @param htmlEditor from which top toolbar will be founded.
* @return this return the top toolbar.
*/
public static ToolBar findTopToolBar(HTMLEditor htmlEditor) {
return findToolBar(htmlEditor, TOP_TOOLBAR_SELECTOR);
}
/**
* @param htmlEditor from which bottom toolbar will be founded.
* @return this return the bottom toolbar.
*/
public static ToolBar findBottomToolBar(HTMLEditor htmlEditor) {
return findToolBar(htmlEditor, BOTTOM_TOOLBAR_SELECTOR);
}
/**
* @param htmlEditor from which Webview will be founded.
* @return this return the webview of the HTMLEditor
*/
public static WebView findWebView(@NonNull HTMLEditor htmlEditor) {
return (WebView) htmlEditor.lookup(WEB_VIEW_SELECTOR);
}
/**
* @param htmlEditor from which we need to find the toolbar
* @param toolbarSelector this is the selector for finding the node
* @return it returns the toolbar based on the selector
*/
private static ToolBar findToolBar(@NonNull HTMLEditor htmlEditor, String toolbarSelector) {
Node node = htmlEditor.lookup(toolbarSelector);
if (node instanceof ToolBar) {
return (ToolBar) node;
}
return null;
}
/**
* @param htmlEditor from which we need to find the node
* @param N node index(0 based)
* @return This will return top tollbar node based on the index(N)
*/
public static Node findNthNodeOfTopToolBar(HTMLEditor htmlEditor, int N) {
return findNthNodeOfToolBar(htmlEditor, N, HTMLEditorUtility :: findTopToolBar);
}
/**
* @param htmlEditor from which we need to find the node
* @param N node index(0 based)
* @return This will return bottom toolbar node based on the index(N)
*/
public static Node findNthNodeOfBottomToolBar(HTMLEditor htmlEditor, int N) {
return findNthNodeOfToolBar(htmlEditor, N, HTMLEditorUtility :: findBottomToolBar);
}
/**
* @param htmlEditor from which we need to find the node
* @param N node index(0 based)
* @param nodeFinder (functional intrface to run the code based on the finding section)
* @return This will return the node based on the nodeFinder method and index(N)
*/
private static Node findNthNodeOfToolBar(@NonNull HTMLEditor htmlEditor, int N,
Function<HTMLEditor, ToolBar> nodeFinder) {
ToolBar toolBar = nodeFinder.apply(htmlEditor);
return toolBar.getItems().get(N);
}
/**
* @param htmlEditor for which top tollbar details will be printed.
*/
public static void printTopToolbarNode(@NonNull HTMLEditor htmlEditor) {
printToolBarNode(htmlEditor, HTMLEditorUtility :: findTopToolBar);
}
/**
* @param htmlEditor for which bottom toolbar details will be printed.
*/
public static void printBottomToolbarNode(@NonNull HTMLEditor htmlEditor) {
printToolBarNode(htmlEditor, HTMLEditorUtility :: findBottomToolBar);
}
private static void printToolBarNode(HTMLEditor htmlEditor, Function<HTMLEditor, ToolBar> nodeFinder) {
ToolBar topToolBar = nodeFinder.apply(htmlEditor);
final int[] positionIndex = {0};
topToolBar.getItems().forEach((node -> {
System.out.println("position Index : " + positionIndex[0]);
positionIndex[0] += 1;
System.out.println("Style Class : " + node.getStyleClass());
System.out.println("Class Name : " + node.getClass().getName());
System.out.println("Type Selector: " + node.getTypeSelector());
System.out.println("");
}));
}
/**
* @param htmlEditor from which we need to find the webengine
* @return Webengine of that given html editor
*/
public static WebEngine findWebEngine(@NonNull HTMLEditor htmlEditor) {
WebView webView = HTMLEditorUtility.findWebView(htmlEditor);
return webView.getEngine();
}
}