How to insert HTML text inside a JavaFX shape? - java

I want to create a tree-based algorithm visualization in JavaFx, and there are many sub scripts and super scripts in the notations. I want to add these notations to shapes like circles.
I have tried using WebView object for doing that, but it just covers up the entire screen.
public void start(Stage primaryStage) throws Exception{
primaryStage.setTitle("Shape Text");
Group circles = new Group();
Circle circle = new Circle(50, Color.web("white", 0.7));
circle.setCenterX(500.0f);
circle.setCenterY(200.0f);
circle.setStrokeType(StrokeType.OUTSIDE);
circle.setStroke(Color.web("white", 0.16));
circle.setStrokeWidth(4);
circles.getChildren().add(circle);
WebView webView = new WebView();
WebEngine webEngine = webView.getEngine();
webEngine.loadContent("<h1>B<sub>0</sub></h1>");
StackPane stack = new StackPane();
stack.getChildren().addAll(circles, webView);
Scene scene = new Scene(stack, 1000, 800, Color.BLACK);
primaryStage.setScene(scene);
primaryStage.show();
}
The above code replaces the entire view with HTML text. I also tried javafx.scene.text.Text class, but it does not support the HTML content.
Thank you in advance!

There are three things you might want to do:
Size the WebView to the HTML content (or the inner display region of the shape).
Make the background of the WebView pages transparent.
Center the HTML content in the WebView, with the WebView centered in the Shape.
Code below demonstrates some of these tricks:
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.StrokeType;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import java.lang.reflect.Field;
public class ShapedHTML extends Application {
#Override
public void start(Stage stage) throws Exception{
stage.setTitle("Shape Text");
Group circles = new Group();
Circle circle = new Circle(50, Color.web("white", 0.7));
circle.setCenterX(500.0f);
circle.setCenterY(200.0f);
circle.setStrokeType(StrokeType.OUTSIDE);
circle.setStroke(Color.web("white", 0.16));
circle.setStrokeWidth(4);
circles.getChildren().add(circle);
WebView webView = new WebView();
WebEngine webEngine = webView.getEngine();
webView.maxWidthProperty().bind(circle.radiusProperty().multiply(2));
webView.maxHeightProperty().bind(circle.radiusProperty().multiply(2));
webEngine.documentProperty().addListener(observable -> {
try {
// Use reflection to retrieve the WebEngine's private 'page' field.
Field f = webEngine.getClass().getDeclaredField("page");
f.setAccessible(true);
com.sun.webkit.WebPage page = (com.sun.webkit.WebPage) f.get(webEngine);
page.setBackgroundColor((new java.awt.Color(0, 0, 0, 0)).getRGB());
} catch (Exception e) {
System.out.println("Difficulty to make WebView background transparent");
e.printStackTrace();
}
});
webEngine.loadContent("<h1 id='root' style='background : rgba(0,0,0,0); margin: 0; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);'>B<sub>0</sub></h1>");
StackPane stack = new StackPane();
stack.getChildren().addAll(circles, webView);
Scene scene = new Scene(stack, 1000, 800, Color.BLACK);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Note on com.sun class usage
The above code uses com.sun classes (which is usually not recommended as it is not publicly supported API). But, it worked for me (on Java 8) and I don't know a better way to accomplish the transparency of the WebView background.
If you are using later versions of Java (e.g. Java 11+), then you will need to provide some VM arguments to allow usage of the relevant com.sun classes to work. See, for instance, the stack overflow question Cannot access JavaFX class "WebPage" in IntelliJ-IDEA for resolving accessibility issues for com.sun.webkit.WebPage in Java 11+. An answer to that question suggests using the following VM arguments (which I haven't tried):
--add-exports javafx.web/com.sun.webkit=projectname
where the last argument is your module name as declared in the module-info.java of your project.

Try setting the maxSize of the WebView.
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class JavaFXTestingGround extends Application
{
#Override
public void start(Stage primaryStage) throws Exception
{
Circle circle = new Circle(100, Color.web("white", 0.7));
WebView webView = new WebView();
WebEngine webEngine = webView.getEngine();
webEngine.loadContent("<h1>B<sub>0</sub></h1>");
webView.setMaxSize(50, 50);
StackPane stack = new StackPane();
stack.getChildren().addAll(circle, webView);
Scene scene = new Scene(stack, 1000, 800, Color.BLACK);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args)
{
launch(args);
}
}

Related

RichTextFx VirtualizedScrollPane flickers when text wraps as you type

I have a flickering issue with RichTextFx StyleClassedTextArea and VirtualizedScrollPane. When you wrap text and keep typing, it flickers so much that you are unable to read while you type. This is a stark contrast to the regular TextArea scrolling. It's more pronounced than the gif above (gif fps doesn't give it justice).
I'm not sure if this is because of the GridPane...
Java8u212
<dependency>
<groupId>org.fxmisc.richtext</groupId>
<artifactId>richtextfx</artifactId>
<version>0.10.6</version>
</dependency>
Code:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import org.fxmisc.flowless.VirtualizedScrollPane;
import org.fxmisc.richtext.StyleClassedTextArea;
public class NewFXMain extends Application
{
#Override
public void start(Stage primaryStage)
{
StyleClassedTextArea textArea = new StyleClassedTextArea();
textArea.setWrapText(true);
TextArea textAreaFx = new TextArea();
textAreaFx.setWrapText(true);
VirtualizedScrollPane scrollpane = new VirtualizedScrollPane(textArea);
scrollpane.setPrefWidth(300);
GridPane notePane = new GridPane();
notePane.setVgap(2);
notePane.setHgap(6);
notePane.add(textAreaFx, 0, 0);
notePane.add(scrollpane, 0, 1);
Scene scene = new Scene(notePane, 600, 400);
primaryStage.setScene(scene);
primaryStage.setTitle("Scroll flickering demo");
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
}
Found out how to fix the text flickering, although the scrollbars still flicker which is way more acceptable:
textArea.requestFollowCaret();

Is there a way to "autofit" elements on a page so they take up the entire canvas

In JavaFX, is there a way to "autofit" elements on a page so they take up the entire thing?
Currently, I'm trying to make the window have two buttons that together take up the entire canvas, but I am not sure how to do that, given that it is possible to stretch the window, etc. I've tried playing around with Button.setPrefSize, but the button size stays the same, it just shows you a window with two outsized buttons, the text of which is not visible.
What I currently have
What I want (but for any window size)
Here's one way (code here but also possible in Scene Builder and FXML):
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;
public class TestApplication extends Application {
#Override
public void start(Stage stage) throws Exception {
Button button1 = new Button("Button1");
HBox.setHgrow(button1, Priority.SOMETIMES);
button1.setMaxWidth(Double.MAX_VALUE);
button1.setMaxHeight(Double.MAX_VALUE);
Button button2 = new Button("Button2");
HBox.setHgrow(button2, Priority.SOMETIMES);
button2.setMaxWidth(Double.MAX_VALUE);
button2.setMaxHeight(Double.MAX_VALUE);
HBox hBox = new HBox(button1, button2);
AnchorPane.setLeftAnchor(hBox, 0.0);
AnchorPane.setRightAnchor(hBox, 0.0);
AnchorPane.setTopAnchor(hBox, 0.0);
AnchorPane.setBottomAnchor(hBox, 0.0);
AnchorPane rootContainer = new AnchorPane(hBox);
Scene scene = new Scene(rootContainer, 600, 600);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}

Javafx 8 Font converts text to upper case A's

I have a problem using custom Fonts in Javafx 8.
Whenever I try to display a text it gets convertet to upper case A's
my code goes as follows:
package main;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class Main extends Application {
private Canvas can;
private GraphicsContext gc;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
Pane root = new Pane();
Scene scene = new Scene(root, 800, 400);
stage.setTitle("Test");
can = new Canvas(scene.getWidth(), scene.getHeight());
gc = can.getGraphicsContext2D();
root.getChildren().add(can);
stage.setResizable(false);
stage.setScene(scene);
stage.show();
InputStream is = Main.class.getResourceAsStream("Font/SSF4ABUKET.ttf");
Font font = Font.loadFont(is, 30);
gc.setFont(font);
gc.setFill(Color.RED);
gc.fillText("This is a test", 10, 200);
}
}
If I try this Font in a normal Text Editor (e.g. Open Office) it works perfectly fine.
Thanks for your help in advance.

Is it possible to, in JavaFX, have a scene, stage, and control that are all transparent?

I have a custom control which is 3 simple buttons. The control handles operations for the application to which it is tied, but it must reside on an external stage for reasons.
The thing that is annoying about it is that between all buttons is a white background.
I've tried all of the following to eliminate it:
Init StageStyle to Transparent
Declare Scene with a transparent background : new Scene(Node, X, Y, Color.TRANSPARENT);
Declare Scene with a NULL background : new Scene(Node, X, Y, null);
Have the control (which extends an HBox) .setStyle("-fx-background-color : rgba(0, 0, 0, 0);");
All of these have failed to eliminate the appearance of the background.
I've done this with Windows Forms, but is it possible to do with JavaFX?
You need to set the transparency of
the stage
the scene
the root class (or in my case the hbox, i prefer root)
This works for me:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
HBox hbox = new HBox();
hbox.setSpacing(12);
Button button1 = new Button("Button 1");
Button button2 = new Button("Button 2");
Button button3 = new Button("Button 3");
hbox.getChildren().addAll(button1, button2, button3);
Scene scene = new Scene(hbox, Color.TRANSPARENT);
// scene.getStylesheets().add( getClass().getResource("application.css").toExternalForm());
scene.getRoot().setStyle("-fx-background-color: transparent");
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
That's the direct solution. Of course instead of setting the style directly it's better practice to use a stylesheet application.css:
.root {
-fx-background-color: transparent;
}
Here's a screenshot with the application being over the code:

How to create tabs with icons in JavaFX

I want to create tabs panel with icons similar to the Firefox configuration panel with JavaFX:
Is there any example which I can use to see how to implement this?
Tabs, like many other elements in JavaFX, have a method called setGraphic(Node value), in which you can put any JavaFX node. Example:
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class TabPaneTest extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Tabs");
Group root = new Group();
Scene scene = new Scene(root, 400, 250, Color.WHITE);
TabPane tabPane = new TabPane();
BorderPane borderPane = new BorderPane();
for (int i = 0; i < 5; i++) {
Tab tab = new Tab();
tab.setGraphic(new Circle(0, 0, 10));
HBox hbox = new HBox();
hbox.getChildren().add(new Label("Tab" + i));
hbox.setAlignment(Pos.CENTER);
tab.setContent(hbox);
tabPane.getTabs().add(tab);
}
// bind to take available space
borderPane.prefHeightProperty().bind(scene.heightProperty());
borderPane.prefWidthProperty().bind(scene.widthProperty());
borderPane.setCenter(tabPane);
root.getChildren().add(borderPane);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Result:
I know its an old thread, but i didnt find a direct answer anywhere. So i thought of posting it some that it will be helpfull for some searching for it.
This is what i did to get a tab like firefox preferences screen.
Add the image to the tab with setGraphics and add the following code to the application css file. My image size was 48x48. So i went for height as 70.
.tab-label {
-fx-content-display: top;
}
.tab-pane {
-fx-tab-min-height: 70;
-fx-tab-max-height: 70;
}
How to add image directly from image url:
Tab tab = new Tab();
tab.setGraphic(buildImage("patch/to/image");
// Helper method to create image from image patch
private static ImageView buildImage(String imgPatch) {
Image i = new Image(imgPatch);
ImageView imageView = new ImageView();
//You can set width and height
imageView.setFitHeight(16);
imageView.setFitWidth(16);
imageView.setImage(i);
return imageView;
}

Categories