JavaFx thin lines color distortion - javafx

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
public class LinesTest extends Application {
#Override
public void start(Stage stage) throws Exception {
final AnchorPane root = new AnchorPane();
final Line line1 = new Line(20, 10, 300, 10);
final Line line2 = new Line(250, 10, 400, 10);
root.getChildren().addAll(line1, line2);
stage.setTitle("Lines Test");
stage.setScene(new Scene(root, 500, 500));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
If you run the code above you could mention that two lines overlapping create another color. Is it possible to prevent this behavior?

You can prevent it in 2 ways:
1) Use setSnapToPixel
final AnchorPane root = new AnchorPane();
root.setSnapToPixel(true);
2) Or, define lines' startY and endY values as half:
final Line line1 = new Line(20, 10.5, 300, 10.5);
final Line line2 = new Line(250, 10.5, 400, 10.5);
For the technical details of these I will leave to jewelsea's great answers:
What are a line's exact dimensions in JavaFX 2?
How to draw a crisp, opaque hairline in JavaFX 2.2?

Related

I want to move the text so that when I display the image it is to the bottom right of the pane. I'm not exactly sure how to set the position

When I run the program, the text appears in the center of the image. I want to move it to the bottom right corner, but nothing happens when I try to change the position. I'm not sure how to set the position of the text.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.scene.paint.Color;
import javafx.scene.shape.Ellipse;
import javafx.scene.text.Text;
import javafx.scene.text.Font;
public class Art extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
//this will create a canvas with a width of 400px and height of 200px
StackPane pane = new StackPane();
Scene scene = new Scene(pane, 400, 250);
primaryStage.setScene(scene);
primaryStage.show();
//draw three ellipses with different colors
Ellipse e1 = new Ellipse(150, 0, 100, 25);
e1.setFill(Color.PINK);
Ellipse e2 = new Ellipse(75, 25, 75, 25);
e2.setFill(Color.DARKGRAY);
Ellipse e3 = new Ellipse(0, 50, 40, 25);
e3.setFill(Color.GRAY);
/*this will set the color, font and size of the text and place it at the
lower right corner*/
Text t1 = new Text(150, 300, "text");
t1.setFont(Font.font("Century Gothic", 14));
t1.setStroke(Color.BLACK);
//display the stage
pane.getChildren().addAll(e1, e2, e3, t1);
primaryStage.setScene(scene);
primaryStage.show();
}
}
As #Slaw suggested in his comment to your question, the below code uses several different layouts to achieve what you want. I suggest you refer to the javadoc for details on how they work.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.NodeOrientation;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Ellipse;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class Art extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
StackPane pane = new StackPane();
// draw three ellipses with different colors
Ellipse e1 = new Ellipse(150, 0, 100, 25);
e1.setFill(Color.PINK);
Ellipse e2 = new Ellipse(75, 25, 75, 25);
e2.setFill(Color.DARKGRAY);
Ellipse e3 = new Ellipse(0, 50, 40, 25);
e3.setFill(Color.GRAY);
/*
* this will set the color, font and size of the text and place it at the lower
* right corner
*/
Text t1 = new Text(150, 300, "text");
t1.setFont(Font.font("Century Gothic", 14));
t1.setStroke(Color.BLACK);
FlowPane flow = new FlowPane(t1);
flow.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT);
flow.setPadding(new Insets(0.0d, 0.0d, 20.0d, 20.0d));
// display the stage
pane.getChildren().addAll(e1, e2, e3);
BorderPane root = new BorderPane(pane);
root.setBottom(flow);
Scene scene = new Scene(root, 400, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Set a shape drawn on another shape as Invisible

I want to draw a line passing through a circle. However, I do not want the line to be shown while its inside the circle. How can I accomplish this? Note that I'm drawing the circle first and then the line.
I used a couple of things like:
Circle.setOpacity to 1, which didn't help!
Used line.toBack() after adding the circle and line in the same group. This didnt help either
line.toBack()
line.toFront()
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;
public class LineUnderCircle extends Application {
#Override
public void start(Stage stage) throws Exception {
Line line = new Line(10, 10, 50, 50);
line.setStrokeWidth(3);
Circle left = new Circle(10, 10, 8, Color.FORESTGREEN);
Circle right = new Circle(50, 50, 8, Color.FIREBRICK);
Button lineToBack = new Button("Line to back");
lineToBack.setOnAction(e -> line.toBack());
Button lineToFront = new Button("Line to front");
lineToFront.setOnAction(e -> line.toFront());
Pane shapePane = new Pane(line, left, right);
HBox controlPane = new HBox(10, lineToBack, lineToFront);
VBox layout = new VBox( 10, controlPane, shapePane);
layout.setPadding(new Insets(10));
stage.setScene(new Scene(layout));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}

How do I use a button in JavaFX to change the size of a line

I want to change the size of a line using a button so later I can make the line look like it is rotating... Here is the code I have so far:
package JavaFXApplication14;
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
public class JavaFXApplication14 extends Application
{
public static void main(String[] args)
{
launch(args);
}
int x = 200;
#Override public void start(Stage primaryStage) throws Exception
{
final GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
grid.setHgap(100);
grid.setVgap(100);
grid.setPadding(new Insets(10, 10, 10, 10));
Scene scene = new Scene(grid, 600, 400); //Color.BLACK ?
primaryStage.setScene(scene);
primaryStage.setTitle("4D");
primaryStage.show();
Line ln = new Line(100, 200, x, 200);
ln.setStroke(Color.BLUE);
ln.setStrokeWidth(5);
grid.add(ln, 0, 0);
Button btn = new Button("X-Y");
grid.setHalignment(btn, HPos.CENTER);
btn.setOnAction(e -> btn_Click());
grid.add(btn, 0, 1);
}
public void btn_Click()
{
x = x + 50;
}
}
Also, sometimes when I use the following line of code the color of the background does not change.
Scene scene = new Scene(grid, 600, 400, Color.BLACK);
What is the reason for that?
The button works very well you can test it, but here you only set a new value to x and nothing else, in other words you don't update the position x2 of your Line.You can dot that by making your variable ln accessible and updating its value EndX:
//before the method start
Line ln;
//Inside your btn_click() method add
ln.setEndX(x);
But it will only increase the size of your line (Horizontally) and not rotate it. with a little research explained here and following what I told you in the comment you can do this easily based on the axis of rotation (startX & startY) and the points to be rotated (endX & endY):
public class Launcher extends Application{
private Pane root = new Pane();
private Scene scene;
private Button btn = new Button("Test");
private Line line;
#Override
public void start(Stage stage) throws Exception {
line = new Line(200,200,200,100);
line.setStroke(Color.BLACK);
line.setStrokeWidth(5);
btn.setOnAction(e -> rotate());
root.getChildren().addAll(btn,line);
scene = new Scene(root,500,500);
stage.setScene(scene);
stage.show();
}
private void rotate(){
double x1 = line.getEndX() - line.getStartX();
double y1 = line.getEndY() - line.getStartY();
//The more you reduce the angle the longer the rotation
double x2 = x1 * Math.cos(0.1) - y1 * Math.sin(0.1);
double y2 = x1 * Math.sin(0.1) + y1 * Math.cos(0.1);
line.setEndX(x2+ line.getStartX());
line.setEndY(y2+ line.getStartY());
}
public static void main(String[] args) {
launch(args);
}
}
Note: In your example you use a GridPane, so you will be restricted to its functioning, Good luck !

Binding a Shape class to the StackPane height

Scenario : A Stage contains a Scene.The Scene contains a StackPane. The height and width of the StackPane and Scene are bind together. The StackPane contains a Shape which is a union of Rectangle and Shape.
Issue - I am facing issue while binding a Shape class to the height of StackPane. How to bind a particular part of Shape class or the complete Shape class in my example?
Requirement - I have 2 requirements.
When I maximize the stage, the StackPane gets increased since the
height and width are bind to Scene but the Shape doesnt increase. I
need both the Shape's(smallShape and bigRectangle) to increase
in terms of height only.
When I maximize the stage the StackPane should increase as well as only the bigger rectangle height should increase but not the other small rectangle i.e bigRectangle height should increase only.
Below is my code snippet
package application;
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.Rectangle;
import javafx.scene.shape.RectangleBuilder;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;
public class BindingShape extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
StackPane stackPane = new StackPane();
stackPane.setPrefHeight(200);
stackPane.setPrefWidth(200);
stackPane.setStyle("-fx-background-color: BEIGE");
Shape smallShape = RectangleBuilder.create()
.x(0)
.y(3)
.arcWidth(6)
.arcHeight(6)
.width(50) // allow overlap for union of tab and content rectangle
.height(50)
.build();
Rectangle bigRectangle = RectangleBuilder.create()
.x(25)
.y(0)
.arcWidth(10)
.arcHeight(10)
.width(100)
.height(100)
.build();
Shape unionShape = Shape.union(smallShape, bigRectangle);
unionShape.setFill(Color.rgb(0, 0, 0, .50));
unionShape.setStroke(Color.BLUE);
Group shapeGroup = new Group();
shapeGroup.getChildren().add(unionShape);
stackPane.getChildren().add(shapeGroup);
Group paneGroup = new Group();
paneGroup.getChildren().add(stackPane);
Scene scene = new Scene(paneGroup, 400, 400,Color.LIGHTSKYBLUE);
stackPane.prefHeightProperty().bind(scene.heightProperty().divide(2));
stackPane.prefWidthProperty().bind(scene.widthProperty().divide(2));
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Please let me know the solution. Thanks in advance.
As the union cannot be resized in parts, I would rebuild the union if the container has been resized like in:
public class BindStackPaneToScene extends Application {
Shape union;
Shape makeShape(double w, double h) {
Rectangle smallShape = new Rectangle(0, 3, 50, 50);
smallShape.setArcHeight(6);
smallShape.setArcWidth(6);
Rectangle bigRectangle = new Rectangle(25, 3, w/2, h/2);
bigRectangle.setArcHeight(10);
bigRectangle.setArcWidth(10);
Shape unionShape = Shape.union(smallShape, bigRectangle);
unionShape.setFill(Color.rgb(0, 0, 0, .50));
unionShape.setStroke(Color.BLUE);
return unionShape;
}
#Override
public void start(Stage primaryStage) throws Exception {
StackPane stackPane = new StackPane();
stackPane.setPrefHeight(200);
stackPane.setPrefWidth(200);
stackPane.setStyle("-fx-background-color: BEIGE");
union = makeShape(200,200);
Group shapeGroup = new Group();
shapeGroup.getChildren().add(union);
stackPane.getChildren().add(shapeGroup);
stackPane.heightProperty().addListener((p, o, n) -> {
if (union != null) shapeGroup.getChildren().remove(union);
union = makeShape(stackPane.getWidth(), n.doubleValue());
shapeGroup.getChildren().add(union);
});
Group paneGroup = new Group();
paneGroup.getChildren().add(stackPane);
Scene scene = new Scene(paneGroup, 400, 400,Color.LIGHTSKYBLUE);
stackPane.prefHeightProperty().bind(scene.heightProperty().divide(1));
stackPane.prefWidthProperty().bind(scene.widthProperty().divide(1));
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

TextArea setScrollTop

I created this simple example of TextArea
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class MainApp extends Application
{
#Override
public void start(Stage stage) throws Exception
{
HBox hbox = new HBox();
// Text Area
TextArea dataPane = new TextArea();
dataPane.setScrollTop(0);
dataPane.setEditable(false);
dataPane.prefWidthProperty().bind(hbox.widthProperty());
dataPane.setWrapText(true); // New line of the text exceeds the text area
dataPane.setPrefRowCount(10);
dataPane.appendText("Computer software, or simply software, also known as computer programs");
dataPane.appendText("\nis the non-tangible component of computers.");
dataPane.appendText("\nComputer software contrasts with computer hardware, which");
dataPane.appendText("\nis the physical component of computers.");
dataPane.appendText("Computer hardware and software require each");
dataPane.appendText("\nother and neither can be");
dataPane.appendText("\nrealistically used without the other.");
dataPane.appendText("\nComputer software");
hbox.setAlignment(Pos.CENTER);
hbox.setSpacing(1);
hbox.setPadding(new Insets(10, 0, 10, 0));
hbox.getChildren().add(dataPane);
Scene scene = new Scene(hbox, 800, 90);
stage.setTitle("JavaFX and Maven");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
I want to set by default the the position of the slider to be at the top of the TextArea.
Can you help me to fix this?
If you set dataPane.setScrollTop(0); after your stage is shown, it will work :)
So like this:
#Override
public void start(Stage stage) {
HBox hbox = new HBox();
// Text Area
TextArea dataPane = new TextArea();
dataPane.setEditable(false);
dataPane.prefWidthProperty().bind(hbox.widthProperty());
dataPane.setWrapText(true); // New line of the text exceeds the text area
dataPane.setPrefRowCount(10);
dataPane.appendText("Computer software, or simply software, also known as computer programs");
dataPane.appendText("\nis the non-tangible component of computers.");
dataPane.appendText("\nComputer software contrasts with computer hardware, which");
dataPane.appendText("\nis the physical component of computers.");
dataPane.appendText("Computer hardware and software require each");
dataPane.appendText("\nother and neither can be");
dataPane.appendText("\nrealistically used without the other.");
dataPane.appendText("\nComputer software");
hbox.setAlignment(Pos.CENTER);
hbox.setSpacing(1);
hbox.setPadding(new Insets(10, 0, 10, 0));
hbox.getChildren().add(dataPane);
Scene scene = new Scene(hbox, 800, 90);
stage.setTitle("JavaFX and Maven");
stage.setScene(scene);
stage.show();
dataPane.setScrollTop(0.0);
}

Resources