JavaFX Canvas Rendering Performance - performance

I work on a JavaFX application and have to draw a lot (4000) of arc's.
I'm using the JavaFX Canvas method strokeArc of the graphic context.
The application performs very weak, but not the calls of the methods strokeArc, I think the delay occurs later, maybe at the rendering.
The results is, that the application does take a delay about 5 seconds to show the arc's on the gui.
Is there a faster way to draw the arc's in JavaFX?

No, there isn't. Canvas is the fastest.
You didn't provide a MCVE. I just tried a simple application. Works pretty fast, 4000 arcs drawn in 6ms. The application window shows up immediately. Here's the code:
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
import javafx.scene.shape.ArcType;
import javafx.stage.Stage;
public class ArcTest extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Group root = new Group();
Canvas canvas = new Canvas(300, 250);
GraphicsContext gc = canvas.getGraphicsContext2D();
root.getChildren().add(canvas);
primaryStage.setScene(new Scene(root));
primaryStage.show();
drawShapes(gc);
}
private void drawShapes(GraphicsContext gc) {
long time = System.currentTimeMillis();
gc.setFill(Color.GREEN);
gc.setStroke(Color.BLUE);
gc.setLineWidth(5);
for( int i=0; i < 4000; i++) {
gc.strokeArc(10, 160, 30, 30, 45, 240, ArcType.OPEN);
}
System.out.println( System.currentTimeMillis() - time);
}
}
Unless you provide some code with more information (BlendMode, etc) it's hard to help you.

Related

Change a circle to a square to fill a square in JavaFX

I found an amazing animation in which there is transition from circle/ellipse to square and just before the end of the animation, the square protrudes out a little and then adjusts itself it back to the correct size.
Source: https://clementmihailescu.github.io/Pathfinding-Visualizer/#
I tried to recreate it but I am not able to get the transition effect from a drop of ink to square.
package sample;
import javafx.animation.*;
import javafx.application.Application;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.effect.Lighting;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.text.Text;
import javafx.util.Duration;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
Pane root = new Pane();
Rectangle originalRectangle = new Rectangle(100,100);
originalRectangle.setFill(Color.WHITE);
originalRectangle.setStroke(Color.BLUE);
Rectangle substituteRectangle = new Rectangle(25,25,50,50);
substituteRectangle.setOpacity(0.0);
substituteRectangle.setFill(Color.TURQUOISE);
substituteRectangle.setStroke(Color.TURQUOISE);
Rectangle yellowRectangle = new Rectangle(100,100);
yellowRectangle.setFill(Color.YELLOW);
root.getChildren().addAll(originalRectangle,substituteRectangle,yellowRectangle);
FadeTransition fadeOutTransition = new FadeTransition(Duration.millis(3000),yellowRectangle); //Make the duration as 1ms to get the instant
fadeOutTransition.setFromValue(1.0);
fadeOutTransition.setToValue(0.0);
FadeTransition fadeInTransition = new FadeTransition(Duration.millis(1),substituteRectangle);
fadeInTransition.setFromValue(0.0);
fadeInTransition.setToValue(0.8);
//To make the square protrute out a bit
ScaleTransition scaleTransition = new ScaleTransition(Duration.seconds(4),substituteRectangle);
scaleTransition.setToX(2.1);
scaleTransition.setToY(2.1);
ParallelTransition parallelTransition = new ParallelTransition(scaleTransition,fadeInTransition);
fadeOutTransition.play();
fadeOutTransition.setOnFinished(e -> {
parallelTransition.setOnFinished(event -> {
root.getChildren().removeAll(substituteRectangle,yellowRectangle);
originalRectangle.setOpacity(1.0);
originalRectangle.setFill(Color.RED);
});
parallelTransition.play();
});
Scene scene = new Scene(root,800,600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
The probably simplest way of achieving this kind of animation would be to simply animate the radius of the circle and constrain it's size using a Rectangle as clip. Also often Timeline provides a animation that is well suited to replace multiple transitions. In this case the fact that it allows for animations between colors as well as animations for a DoubleProperty makes this a good choice for simplifying the animations:
#Override
public void start(Stage primaryStage) throws Exception {
Pane root = new Pane();
Rectangle bounds = new Rectangle(50, 50, 100, 100);
Circle circle = new Circle(bounds.getX() + 0.5 * bounds.getWidth(), bounds.getY() + 0.5 * bounds.getHeight(),
0);
circle.setClip(bounds);
root.getChildren().add(circle);
Timeline animation = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(circle.fillProperty(), Color.BLUE),
new KeyValue(circle.radiusProperty(), 0d)),
new KeyFrame(Duration.seconds(5), new KeyValue(circle.fillProperty(), Color.RED), new KeyValue(
circle.radiusProperty(), 0.5 * Math.hypot(bounds.getWidth(), bounds.getHeight())))); // at the end of the animation the circle should reach the corners -> diameter = diagonale of rect
root.setOnMouseClicked(evt -> animation.playFromStart());
Scene scene = new Scene(root, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
}

How to model a bending straw in JavaFX

My goal is to make it so that when a user slides a Slider, an object that is like a straw bends from its middle.
Sort of like this:
http://s.hswstatic.com/gif/bendy-straw-a-1.jpg
I've spent days searching for ways to model this with JavaFX shapes, but maybe I'm missing something obvious. When the Slider is at zero, the shape should be a straight line, whereas when the Slider is bent all the way, the shape should resemble an arm of a hyperbola.
Thank you so much.
You'll have to figure out the math correctly, but something like this is what I had in mind. You can even try just leaving the control point Y in the middle of the line, I moved it up since I figured it's more realistic, like it will start to bend at the bottom. You also have to do some calculus to figure out the end point. The length shouldn't change.
package curve;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Slider;
import javafx.scene.paint.Color;
import javafx.scene.shape.QuadCurve;
import javafx.stage.Stage;
public class Curve extends Application {
#Override
public void start(Stage primaryStage) {
QuadCurve qc = new QuadCurve(100, 500, 100, 250, 100, 0);
qc.setStroke(Color.BLUE);
qc.setStrokeWidth(5);
qc.setFill(Color.TRANSPARENT);
Slider slider = new Slider(0, 200, 0);
qc.endXProperty().bind(slider.valueProperty().add(100));
qc.endYProperty().bind(slider.valueProperty().add(100).divide(1.2));
qc.controlYProperty().bind(slider.valueProperty().multiply(-1).add(500));
Group group = new Group(qc,slider);
Scene scene = new Scene(group, 500,500);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

When Loading Image Using BufferdImage and ImageIO it Clears my Whole Frame and Does Not Display Image

I and making a program using basic GUI involving buttons, frames, and panels, and everything was fine until I tried to load an image from my project folder. When i add the line of code
try{
titleImage = ImageIO.read(new File("mouse_title_resize.png"));
}
catch(Exception e){}
After I run the program my whole frame just becomes blank whereas before I had some JButtons on it.All the code I had before the try-catch line worked perfectly fine and I tested to see that the only thing that breaks it is this line of code. I receive no errors or anything and I have the image in my project folder and it seems that the image loaded fine, except it wont show up on the frame, and everything else on the frame disappears. I just don't understand why it clears my whole frame when i load the image.
Here is the full code:
This is the class that extends JFrame
package mouse.click.game;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Toolkit;
import javax.swing.JFrame;
public class MouseClickGame extends JFrame {
//Constants to define the frame width and height including borders
public final int FRAME_WIDTH = 600;
public final int FRAME_HEIGHT = 600;
//Dimension from Toolkit to be able to get width and height of screen
public Dimension sizeTool = Toolkit.getDefaultToolkit().getScreenSize();
//Using sizeTool to get width of screen
public double xResolution = sizeTool.getWidth();
//Using sizeTool to get height of screen
public double yResolution = sizeTool.getHeight();
//Creating a point object that is defined as the center of the screen
public Point middleOfScreen = new Point((int) (xResolution / 2) - (FRAME_WIDTH / 2), (int) (yResolution / 2) - (FRAME_HEIGHT / 2));
public MouseClickGame() {
super("WELCOME :D");
setSize(FRAME_WIDTH, FRAME_HEIGHT);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setLocation(middleOfScreen);
add(new MouseClickPanel());
}
public static void main(String[] args) {
//Calling constructor
MouseClickGame mainClickGame = new MouseClickGame();
}
}
And here is the class that extends JPanel (these are the only two classes in my project)
package mouse.click.game;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class MouseClickPanel extends JPanel {
JButton buttonPlay = new JButton("Play");
JButton buttonContinue = new JButton("Continue");
JButton buttonOptions = new JButton("Options");
JButton buttonExit = new JButton("Exit");
BoxLayout boxLay = new BoxLayout(this, BoxLayout.Y_AXIS);
Dimension menuButtonSize = new Dimension(300, 30);
Dimension spacingBetweenButtons = new Dimension(0, 30);
BufferedImage titleImage;
public MouseClickPanel() {
try {
titleImage = ImageIO.read(new File("C:\\Users\\Justin\\Desktop\\mouse_title.png"));
} catch (IOException e) {
}
setLayout(boxLay);
add(Box.createVerticalGlue());
add(new JLabel(new ImageIcon(titleImage)));
//Adding glue to force buttons away from top of panel
add(Box.createVerticalGlue());
add(buttonPlay);
//Vertical spacing between buttons
add(Box.createRigidArea(spacingBetweenButtons));
add(buttonContinue);
add(Box.createRigidArea(spacingBetweenButtons));
add(buttonOptions);
add(Box.createRigidArea(spacingBetweenButtons));
add(buttonExit);
//Adding glue to force buttons away from bottom of panel
add(Box.createVerticalGlue());
//Aligning all buttons to centered horizontally
buttonPlay.setAlignmentX(Box.CENTER_ALIGNMENT);
buttonContinue.setAlignmentX(Box.CENTER_ALIGNMENT);
buttonOptions.setAlignmentX(Box.CENTER_ALIGNMENT);
buttonExit.setAlignmentX(Box.CENTER_ALIGNMENT);
//Setting button sizes
buttonPlay.setMaximumSize(menuButtonSize);
buttonContinue.setMaximumSize(menuButtonSize);
buttonOptions.setMaximumSize(menuButtonSize);
buttonExit.setMaximumSize(menuButtonSize);
}
}
Literally if i get ride of the titleImage = and add(new JLabel) lines everything goes back to normal
My guess is that you've just got the path wrong -- a common mistake. In that case, you should be getting an exception like:
Exception in thread "main" javax.imageio.IIOException: Can't read input file!
at javax.imageio.ImageIO.read(ImageIO.java:1301)
at jonathanrmiproject.MyProject.main(JonathanRmiProject.java:24)
This simple example works for me:
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.naming.NamingException;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class MyProject {
public static void main(String[] args) throws NamingException, IOException {
BufferedImage img = ImageIO.read(new File("myimage.jpg"));
JLabel label = new JLabel(new ImageIcon(img));
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(label);
f.pack();
f.setLocation(200, 200);
f.setVisible(true);
}
}
I am using Netbeans IDE, and I have saved the image file to "C:\Users\David.Sharpe\MyProject\myimage.jpg".
I should add that if this is not the case, and you do have the correct path, then you need to post a more detailed question so that someone can help you. Include the code to reproduce the problem.
UPDATE: Wow literally the reason it wasn't showing up was because i called setVisble(true) too early. I can't believe it was something that simple. I guess that explains why one time everything would show up and it would be fine but then every time after nothing showed up.
So in my constructor I had
public class MouseClickGame extends JFrame {
public MouseClickGame() {
super("WELCOME :D");
setSize(FRAME_WIDTH, FRAME_HEIGHT);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocation(middleOfScreen);
setVisible(true);
add(new MouseClickPanel());
}
public static void main(String[] args) {
//Calling constructor
MouseClickGame mainClickGame = new MouseClickGame();
}
}
when all I had to do was put the setVisble() after the add(newMouseClickPanel())
Thank you DavidS for your suggestions :D

JavaFX 8 - How to wrap text in new line in several controls?

I want to wrap text in a new line in some controls.
For example when there is not enough space to display the whole text of a checkbox, there should be a new line for that. I don't want these dots ("...").
The same behaviour I would like in a TableCell (not editable) and in a TextField or TextArea.
I tested .setWrapText(true) but this didn't help...
Can anybody help me please?
Best regards
It looks like it depends on the layout you are using.
For example this code wraps the CheckBox text no problem:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class CheckBoxTest extends Application {
#Override
public void start(Stage stage) throws Exception {
BorderPane pane = new BorderPane();
Scene scene = new Scene(pane, 300, 200);
stage.setScene(scene);
CheckBox checkBox = new CheckBox("This is a really really really really really really really really long string");
checkBox.setWrapText(true);
pane.setCenter(checkBox);
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
But if I were to change the BorderPane to a FlowPane, the wrapping would not work.

Swing apllication with embedded JavaFX WebView won't play html5 video only sound

In my Swing application I needed support for rendering html. So I embedded a JavaFX WebView in my Swing application. Now on some html pages I use the new html5 -Tag to play a video. This works perfectly on Windows and Linux. But on MacOS I only hear the sound and see a black video frame and the time track in the bottom.
Here is an SSCCE I got from github. I just changed the url to one that contains a html5 video-tag example. Would be great, if you MacOS users could try it and tell me if the same happens on you computer. And of course any idea to fix this is appreciated.
SSCCE:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import com.sun.javafx.application.PlatformImpl;
/**
* SwingFXWebView
*/
public class JavaFXTest extends JPanel
{
private Stage stage;
private WebView browser;
private JFXPanel jfxPanel;
private JButton swingButton;
private WebEngine webEngine;
private Object geo;
public JavaFXTest()
{
this.initComponents();
}
public static void main(final String... args)
{
// Run this later:
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
final JFrame frame = new JFrame();
frame.getContentPane().add(new JavaFXTest());
frame.setMinimumSize(new Dimension(640, 480));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
private void initComponents()
{
this.jfxPanel = new JFXPanel();
this.createScene();
this.setLayout(new BorderLayout());
this.add(this.jfxPanel, BorderLayout.CENTER);
this.swingButton = new JButton();
this.swingButton.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(final ActionEvent e)
{
Platform.runLater(new Runnable()
{
#Override
public void run()
{
JavaFXTest.this.webEngine.reload();
}
});
}
});
this.swingButton.setText("Reload");
this.add(this.swingButton, BorderLayout.SOUTH);
}
/**
* createScene Note: Key is that Scene needs to be created and run on
* "FX user thread" NOT on the AWT-EventQueue Thread
*/
private void createScene()
{
PlatformImpl.startup(new Runnable()
{
#Override
public void run()
{
JavaFXTest.this.stage = new Stage();
JavaFXTest.this.stage.setTitle("Hello Java FX");
JavaFXTest.this.stage.setResizable(true);
final Group root = new Group();
final Scene scene = new Scene(root, 80, 20);
JavaFXTest.this.stage.setScene(scene);
// Set up the embedded browser:
JavaFXTest.this.browser = new WebView();
JavaFXTest.this.webEngine = JavaFXTest.this.browser.getEngine();
JavaFXTest.this.webEngine.load("http://camendesign.com/code/video_for_everybody/test.html");
final ObservableList<Node> children = root.getChildren();
children.add(JavaFXTest.this.browser);
JavaFXTest.this.jfxPanel.setScene(scene);
}
});
}
}
Here is a semi-answer, which might help:
The oracle website states:"At this time, Online Installation and Java Update features are not available for 64-bit architectures"
For me this caused lots of problems, because Java seems up to date, but actually isn't. On some machines I could solve the actual issue by just manually updating the Java 64bit VM. On Mac however, the video still isn't playing, only sound.
The 64bit/32bit issue gets even worse, since a double click on a jar might start it in the 64bit JVM, but via console it is started in 32bit JVM. So if you do a "java -version" in console, the output might be "1.7.0 u45 32-bit", but as soon as you start the jar via double click it is started in an outdated 64bit JVM.
So if you ever run in an JavaFX issue (especially with UnsatisfiedLinkError) and you have a 64bit computer, just install the latest 64bit java and hope that it solves the problem.

Resources