Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Customize the JavaFX HTMLEditor
import java.util.List;
import java.util.regex.Pattern;
import javafx.application.*;
import javafx.collections.FXCollections;
import javafx.event.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.effect.*;
import javafx.scene.image.*;
import javafx.scene.web.HTMLEditor;
import javafx.stage.Stage;
public class HTMLEditorCustomizationSample extends Application {
// limits the fonts a user can select from in the html editor.
private static final List<String> limitedFonts = FXCollections.observableArrayList("Arial", "Times New Roman", "Courier New", "Comic Sans MS");
public static void main(String[] args) { launch(args); }
@Override public void start(Stage stage) {
// create a new html editor and show it before we start modifying it.
final HTMLEditor htmlEditor = new HTMLEditor();
stage.setScene(new Scene(htmlEditor));
stage.show();
// hide controls we don't need.
hideImageNodesMatching(htmlEditor, Pattern.compile(".*(Cut|Copy|Paste).*"), 0);
Node seperator = htmlEditor.lookup(".separator");
seperator.setVisible(false); seperator.setManaged(false);
// modify font selections.
int i = 0;
for (Node candidate: (htmlEditor.lookupAll("MenuButton"))) {
// fonts are selected by the second menu in the htmlEditor.
if (candidate instanceof MenuButton && i == 1) {
// limit the font selections to our predefined list.
MenuButton menuButton = (MenuButton) candidate;
List<MenuItem> removalList = FXCollections.observableArrayList();
final List<MenuItem> fontSelections = menuButton.getItems();
for (MenuItem item: fontSelections) {
if (!limitedFonts.contains(item.getText())) {
removalList.add(item);
}
}
fontSelections.removeAll(removalList);
// Select a font from out limited font selection.
// Selection done in Platform.runLater because if you try to do
// the selection immediately, it won't take place.
Platform.runLater(new Runnable() {
@Override public void run() {
boolean fontSelected = false;
for (final MenuItem item: fontSelections) {
if ("Comic Sans MS".equals(item.getText())) {
if (item instanceof RadioMenuItem) {
((RadioMenuItem) item).setSelected(true);
fontSelected = true;
}
}
}
if (!fontSelected && fontSelections.size() > 0 && fontSelections.get(0) instanceof RadioMenuItem) {
((RadioMenuItem) fontSelections.get(0)).setSelected(true);
}
}
});
}
i++;
}
// add a custom button to the top toolbar.
Node node = htmlEditor.lookup(".top-toolbar");
if (node instanceof ToolBar) {
ToolBar bar = (ToolBar) node;
ImageView graphic = new ImageView(new Image("http://bluebuddies.com/gallery/title/jpg/Smurf_Fun_100x100.jpg", 32, 32, true, true));
graphic.setEffect(new DropShadow());
Button smurfButton = new Button("", graphic);
bar.getItems().add(smurfButton);
smurfButton.setOnAction(new EventHandler<ActionEvent>() {
@Override public void handle(ActionEvent arg0) {
htmlEditor.setHtmlText("<font face='Comic Sans MS' color='blue'>Smurfs are having fun :-)</font>");
}
});
}
}
// hide buttons containing nodes whose image url matches a given name pattern.
public void hideImageNodesMatching(Node node, Pattern imageNamePattern, int depth) {
if (node instanceof ImageView) {
ImageView imageView = (ImageView) node;
String url = imageView.getImage().impl_getUrl();
if (url != null && imageNamePattern.matcher(url).matches()) {
Node button = imageView.getParent().getParent();
button.setVisible(false); button.setManaged(false);
}
}
if (node instanceof Parent)
for (Node child : ((Parent) node).getChildrenUnmodifiable())
hideImageNodesMatching(child, imageNamePattern, depth + 1);
}
}
@jewelsea

This comment has been minimized.

@jewelsea

This comment has been minimized.

Copy link
Owner Author

@jewelsea jewelsea commented Apr 28, 2012

@jewelsea

This comment has been minimized.

Copy link
Owner Author

@jewelsea jewelsea commented Aug 17, 2013

https://forums.oracle.com/thread/2562169 "How to insert image into HTMLEditor content pane?"

@jewelsea

This comment has been minimized.

Copy link
Owner Author

@jewelsea jewelsea commented Aug 17, 2013

README The example makes use of internal introspection on the structure of the HTMLEditor which doesn't really form part of the JavaFX public API and may change between different JavaFX versions. For example, the hideImageNodesMatching method will not work out of the box in Java 8.

@ghost

This comment has been minimized.

Copy link

@ghost ghost commented Jan 1, 2014

Hello Jewelsea, Thank you for all your efforts in answering questions on StockOverflow. May I request you to please address this:

http://stackoverflow.com/questions/20810995/how-to-get-the-ids-of-nodes-inside-htmleditor-javafx

From which reference did you get ".separator", "MenuButton", and ".top-toolbar" which you used in the lookup() method in your above code?

@jewelsea

This comment has been minimized.

Copy link
Owner Author

@jewelsea jewelsea commented Jan 9, 2015

I determined the ids by running a recursive dump of all the nodes in the scene graph and printing out the style classes and ids of the nodes to System.out as part of the dump (see the dump(node) function in this DebugUtil class). Alternately SceneBuilder has a CSS analyzer, or ScenicView will show the CSS style classes and ids for nodes.

@MenaiAla

This comment has been minimized.

Copy link

@MenaiAla MenaiAla commented Aug 15, 2017

Hi @jewelsea ,thank you for your gist ,it helped me for my project ,but i have a question we have two tool bars ,i need the name of class (css) of second bar ?

@TurekBot

This comment has been minimized.

Copy link

@TurekBot TurekBot commented Oct 11, 2017

@jewelsea, I'm so sad that this well-thought out example is broken!

I tried it and none of the Copy, Cut, Paste buttons disappear now.

Do we need to hide them by style class? Like "html-editor-copy"?

How can I help?

@purringpigeon

This comment has been minimized.

Copy link

@purringpigeon purringpigeon commented Oct 10, 2019

Hello - I was hoping to use this example as well, and it does't seem to work with the Java8 version - any thoughts or updates to this code?

@jewelsea

This comment has been minimized.

Copy link
Owner Author

@jewelsea jewelsea commented Oct 30, 2019

This example was written a long time ago. From the comments it would seem that it no longer works with more recent JavaFX versions. If somebody would like to spend the effort to get it working or provide a similar example, they can fork the gist and add their modifications and place a link to the modified gist, noting what they did, in a comment here.

@segreeeen

This comment has been minimized.

Copy link

@segreeeen segreeeen commented Nov 4, 2019

Did you by any chance encounter a rich text javafx component?

@jewelsea

This comment has been minimized.

Copy link
Owner Author

@jewelsea jewelsea commented Nov 4, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment