JavaFX Grid Pane button "taking" 2 cells - javafx

I'm trying to make a calculator like GUI with JavaFX.
The problem is that I don't know the way to add button to "take" two cells. See the photo bellow.
In that empty space i want to add a button
I tried adding it to the position 0, 3 but it spaces all the buttons
Here's my code
Main:
public class Test extends Application {
#Override
public void start(Stage primaryStage) {
BorderPane borderPane = new BorderPane();
borderPane.setPadding(new Insets(5, 35, 5, 35));
TextField txf = new TextField("6.333");
txf.setAlignment(Pos.TOP_RIGHT);
txf.setPrefHeight(35);
GridPane grid = new GridPane();
grid.setHgap(5);
grid.setVgap(5);
grid.setPadding(new Insets(10, 5, 10, 5));
String[] signs = new String[]{"7", "8", "9", "+",
"4", "5", "6", "-",
"3", "2", "1", "*"};
int signIndex = 0;
for(int i = 0; i<3; i++) {
for(int j = 0; j<4; j++) {
CustomButton btnTemp = new CustomButton(signs[signIndex]);
grid.add(btnTemp, j, i);
signIndex++;
}
}
CustomButton btnZero = new CustomButton("0", 100, 20);
//grid.add(btnZero, 0, 3);
CustomButton btnDot = new CustomButton(".");
grid.add(btnDot, 2, 3);
CustomButton btnSlash = new CustomButton("/");
grid.add(btnSlash, 3, 3);
CustomButton btnC = new CustomButton("C", 100, 20);
grid.add(btnC, 4, 0);
CustomButton btnSqrt = new CustomButton("√", 100, 20);
grid.add(btnSqrt, 4, 1);
CustomButton btnPlusMinus = new CustomButton("+/-", 100, 20);
grid.add(btnPlusMinus, 4, 2);
CustomButton btnEqu = new CustomButton("=", 100, 20);
grid.add(btnEqu, 4, 3);
borderPane.setTop(txf);
borderPane.setCenter(grid);
Scene scene = new Scene(borderPane, 400, 200);
primaryStage.setTitle("Calculator");
primaryStage.setScene(scene);
primaryStage.setResizable(false);
primaryStage.show();
}
}

Use setColumnSpan:
GridPane.setColumnSpan(btnC, 2);
(Assuming you meant btnC, I can't understand which button you want to span 2 columns... )

Related

Span selected Nodes after have declared the number of comumns and rows in javafx

I would like to know the way to span the next node in the second column after the node containing the label "Info" to the rest of the remaining columns and on 3 rows below.
Below is my present output with the associated code.
public class Test extends Application {
#Override
public void start(Stage primaryStage) {
GridPane root = new GridPane();
root.setGridLinesVisible(true);
final int numCols = 5 ;
final int numRows = 12 ;
for (int i = 0; i < numCols; i++) {
ColumnConstraints colConst = new ColumnConstraints();
colConst.setPercentWidth(100.0 / numCols);
root.getColumnConstraints().add(colConst);
}
for (int i = 0; i < numRows; i++) {
RowConstraints rowConst = new RowConstraints();
rowConst.setPercentHeight(100.0 / numRows);
root.getRowConstraints().add(rowConst);
}
Label nameLbl = new Label("Name");
Label nameFld = new Label();
Label infoLbl = new Label("Info : ");
Label infoFld = new Label();
infoFld.setStyle("-fx-background-color: lavender;-fx-font-size: 7pt;-fx-padding: 10 0 0 0;");
Button okBtn = new Button("OK");
Button cancelBtn = new Button("Cancel");
Label commentBar = new Label("Status: Ready");
commentBar.setStyle("-fx-background-color: lavender;-fx-font-size: 7pt;-fx-padding: 10 0 0 0;");
root.add(nameLbl, 0, 0, 1, 1);
root.add(nameFld, 1, 0, 1, 1);
root.add(infoLbl, 0, 1, 1, 1);
root.add(infoFld, 1, 1, 4, 4);
root.add(okBtn, 3, 9, 1, 1);
root.add(cancelBtn, 2, 9, 1, 1);
root.add(commentBar, 0, 11, GridPane.REMAINING, 1);
primaryStage.setScene(new Scene(root, 900, 500));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
If you want the label to span four rows, as well as four columns, set its column span as well as its row span to 4:
// root.add(infoFld, 1, 1, 4, 1);
root.add(infoFld, 1, 1, 4, 4);
By default a label will not grow beyond its preferred size (which in this case is zero, because it has no text). Allow it to grow indefinitely:
infoFld.setMaxWidth(Double.MAX_VALUE);
infoFld.setMaxHeight(Double.MAX_VALUE);

Is it possible to add a LinearGradient fill to an SVGPath that already has an ImagePattern Fill?

In my main application I have some SVGPaths that I add to an XYChart. Sometimes they have an ImagePattern fill which now needs to have a LinearGradient fill. The ImagePattern fill is a crosshatch and this needs to be colored with the LinearGradient the same as if it was a solid Rectangle with a LinearGradient applied. The SVGPath also has a dotted outline and the LinearGradient should fill the dotted outline and the ImagePattern fill as it they were part of the same shape.
I've written some sample code to show where I'm at. This colors the crosshatch as it's created and looks ok but isn't the effect I describe above as each cross in the ImagePattern has the LinearGradient applied individually. Ideally the LinearGradient would just be applied to the final SVGPath once the ImagePattern fill has been applied.
I've also tried some effects using Blend and ColorInput but haven't managed to get any closer to the solution.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.image.Image;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.ImagePattern;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Paint;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Line;
import javafx.scene.shape.SVGPath;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
List<Color> colors = Arrays.asList(Color.RED, Color.YELLOW, Color.GREEN);
ArrayList<Stop> stops = new ArrayList<>(colors.size() * 2);
for (int i = 0; i < colors.size(); i++) {
stops.add(new Stop(getOffset(i, colors.size()), colors.get(i)));
stops.add(new Stop(getOffset(i + 1, colors.size()), colors.get(i)));
}
LinearGradient lg = new LinearGradient(0, 0, 20, 20, false, CycleMethod.REPEAT, stops);
SVGPath svgPath = new SVGPath();
svgPath.setContent("M-84.1487,-15.8513 a22.4171,22.4171 0 1 0 0,31.7026 h168.2974 a22.4171,22.4171 0 1 0 0,-31.7026 Z");
Image hatch = createCrossHatch(lg);
ImagePattern pattern = new ImagePattern(hatch, 0, 0, 10, 10, false);
svgPath.setFill(pattern);
svgPath.setStroke(lg);
BorderPane root = new BorderPane();
root.setCenter(svgPath);
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
catch (Exception e) {
e.printStackTrace();
}
}
protected static Image createCrossHatch(Paint paint) {
Pane pane = new Pane();
pane.setPrefSize(20, 20);
pane.setStyle("-fx-background-color: transparent;");
Line fw = new Line(-5, -5, 25, 25);
Line bw = new Line(-5, 25, 25, -5);
fw.setStroke(paint);
bw.setStroke(paint);
fw.setStrokeWidth(3);
bw.setStrokeWidth(3);
pane.getChildren().addAll(fw, bw);
new Scene(pane);
SnapshotParameters sp = new SnapshotParameters();
sp.setFill(Color.TRANSPARENT);
return pane.snapshot(sp, null);
}
private double getOffset(double i, int count) {
return (((double) 1) / (double) count * (double) i);
}
public static void main(String[] args) {
launch(args);
}
}
If you run the supplied code you will see it draws a dog bone. The lineargradient colors of the dashed outline should continue through the cross hatch ImagePattern fill. I'm aware of why the hatched ImagePattern is colored like it is but this is the best compromise I have at present. As mentioned I'd like to be able to applied the LinearGradient fill to the whole shape once the ImagePattern fill has been applied so the LinearGradient affects the whole shape the same.
Thanks
There is no direct way to apply and combine two paints over one single node. We can overlay many different paints (like solid, linear gradients or even image patterns) using background color via css, but that won't combine.
So in order to combine two different paints, on one side a linear gradient, on the other a pattern fill, we need to apply them to two nodes, and use a blending effect between both paints.
According to the code posted, this is the SVGPath with the linear gradient:
#Override
public void start(Stage primaryStage) {
Node base = getNodeWithGradient();
BorderPane root = new BorderPane();
Group group = new Group(base);
root.setCenter(group);
Scene scene = new Scene(root, 400, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
private SVGPath getNodeWithGradient() {
List<Color> colors = Arrays.asList(Color.RED, Color.YELLOW, Color.GREEN);
ArrayList<Stop> stops = new ArrayList<>(colors.size() * 2);
for (int i = 0; i < colors.size(); i++) {
stops.add(new Stop(getOffset(i, colors.size()), colors.get(i)));
stops.add(new Stop(getOffset(i + 1, colors.size()), colors.get(i)));
}
LinearGradient lg = new LinearGradient(0, 0, 20, 20, false, CycleMethod.REPEAT, stops);
SVGPath svgPath = getSVGPath();
svgPath.setFill(lg);
svgPath.setStroke(lg);
return svgPath;
}
private SVGPath getSVGPath() {
SVGPath svgPath = new SVGPath();
svgPath.setContent("M-84.1487,-15.8513 a22.4171,22.4171 0 1 0 0,31.7026 h168.2974 a22.4171,22.4171 0 1 0 0,-31.7026 Z");
return svgPath;
}
private double getOffset(double i, int count) {
return (((double) 1) / (double) count * (double) i);
}
While this is the SVGPath with the image pattern fill:
#Override
public void start(Stage primaryStage) {
Node overlay = getNodeWithPattern();
BorderPane root = new BorderPane();
Group group = new Group(overlay);
root.setCenter(group);
Scene scene = new Scene(root, 400, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
private SVGPath getNodeWithPattern() {
Image hatch = createCrossHatch();
ImagePattern pattern = new ImagePattern(hatch, 0, 0, 10, 10, false);
SVGPath svgPath = getSVGPath();
svgPath.setFill(pattern);
return svgPath;
}
private SVGPath getSVGPath() {
SVGPath svgPath = new SVGPath();
svgPath.setContent("M-84.1487,-15.8513 a22.4171,22.4171 0 1 0 0,31.7026 h168.2974 a22.4171,22.4171 0 1 0 0,-31.7026 Z");
return svgPath;
}
private static Image createCrossHatch() {
Pane pane = new Pane();
pane.setPrefSize(20, 20);
Line fw = new Line(-5, -5, 25, 25);
Line bw = new Line(-5, 25, 25, -5);
fw.setStroke(Color.BLACK);
bw.setStroke(Color.BLACK);
fw.setStrokeWidth(3);
bw.setStrokeWidth(3);
pane.getChildren().addAll(fw, bw);
new Scene(pane);
SnapshotParameters sp = new SnapshotParameters();
return pane.snapshot(sp, null);
}
Now the trick is to combine both SVGPath nodes, adding a blending mode to the one on top.
According to JavaDoc for BlendMode.ADD:
The color and alpha components from the top input are added to those from the bottom input.
#Override
public void start(Stage primaryStage) {
Node base = getNodeWithGradient();
Node overlay = getNodeWithPattern();
overlay.setBlendMode(BlendMode.ADD);
BorderPane root = new BorderPane();
Group group = new Group(base, overlay);
root.setCenter(group);
Scene scene = new Scene(root, 400, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
private SVGPath getNodeWithGradient() {
List<Color> colors = Arrays.asList(Color.RED, Color.YELLOW, Color.GREEN);
ArrayList<Stop> stops = new ArrayList<>(colors.size() * 2);
for (int i = 0; i < colors.size(); i++) {
stops.add(new Stop(getOffset(i, colors.size()), colors.get(i)));
stops.add(new Stop(getOffset(i + 1, colors.size()), colors.get(i)));
}
LinearGradient lg = new LinearGradient(0, 0, 20, 20, false, CycleMethod.REPEAT, stops);
SVGPath svgPath = getSVGPath();
svgPath.setFill(lg);
svgPath.setStroke(lg);
return svgPath;
}
private SVGPath getNodeWithPattern() {
Image hatch = createCrossHatch();
ImagePattern pattern = new ImagePattern(hatch, 0, 0, 10, 10, false);
SVGPath svgPath = getSVGPath();
svgPath.setFill(pattern);
return svgPath;
}
private SVGPath getSVGPath() {
SVGPath svgPath = new SVGPath();
svgPath.setContent("M-84.1487,-15.8513 a22.4171,22.4171 0 1 0 0,31.7026 h168.2974 a22.4171,22.4171 0 1 0 0,-31.7026 Z");
return svgPath;
}
private static Image createCrossHatch() {
Pane pane = new Pane();
pane.setPrefSize(20, 20);
Line fw = new Line(-5, -5, 25, 25);
Line bw = new Line(-5, 25, 25, -5);
fw.setStroke(Color.BLACK);
bw.setStroke(Color.BLACK);
fw.setStrokeWidth(3);
bw.setStrokeWidth(3);
pane.getChildren().addAll(fw, bw);
new Scene(pane);
SnapshotParameters sp = new SnapshotParameters();
return pane.snapshot(sp, null);
}
private double getOffset(double i, int count) {
return (((double) 1) / (double) count * (double) i);
}
And we get the desired result:

How to add label to top of stage

I am trying to place the "Registration form" text at the top but when I do pane.add it separates the spacing between the labels and textfield boxes. How do I add it to the top without it affecting everything below it?
public class RegistrationForm extends Application {
public void start(Stage primaryStage) {
GridPane pane = new GridPane();
pane.setAlignment(Pos.CENTER);
pane.setPadding(new Insets(11.5, 12.5, 13.5, 14.5));
pane.setHgap(5.5);
pane.setVgap(5.5);
Text text = new Text ("Registration Form");
text.setFont(Font.font("Times New Roman", FontWeight.BOLD,
FontPosture.ITALIC, 20));
pane.getChildren().add(text);
pane.add(new Label("User Name: "), 0, 1);
pane.add(new TextField(), 1, 1);
pane.add(new Label("Password: "), 0, 2);
pane.add(new TextField(), 1, 2);
pane.add(new Label("Email: "), 0, 3);
pane.add(new TextField(), 1, 3);
pane.add(new Label("Phone: "), 0, 4);
pane.add(new TextField(), 1, 4);
Button btReg = new Button("Register");
pane.add(btReg, 0, 5);
GridPane.setHalignment(btReg, HPos.LEFT);
Button btCan = new Button("Cancel");
pane.add(btCan, 1, 5);
GridPane.setHalignment(btCan, HPos.LEFT);
Scene scene = new Scene(pane);
primaryStage.setTitle("Registration Form");
primaryStage.setScene(scene);
primaryStage.show();
}
}
In the Docs
add(Node child, int columnIndex, int rowIndex, int colspan, int
rowspan) Adds a child to the gridpane at the specified column,row
position and spans.
You should use:
pane.add(label, 0, 0, 2, 1);

junit test for javafx sample login form

please help to test this code using junit
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("JavaFX Welcome");
GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(25, 25, 25, 25));
Text scenetitle = new Text("Welcome");
scenetitle.setFont(Font.font("Tahoma", FontWeight.NORMAL, 20));
grid.add(scenetitle, 0, 0, 2, 1);
Label userName = new Label("User Name:");
grid.add(userName, 0, 1);
TextField userTextField = new TextField();
grid.add(userTextField, 1, 1);
Label pw = new Label("Password:");
grid.add(pw, 0, 2);
PasswordField pwBox = new PasswordField();
grid.add(pwBox, 1, 2);
Label status = new Label();
status.setId( "status-label" );
Button btn = new Button("Sign in");
btn.setId("btn");
HBox hbBtn = new HBox(10);
hbBtn.setAlignment(Pos.BOTTOM_RIGHT);
hbBtn.getChildren().add(btn);
grid.add(hbBtn, 1, 4);
grid.add(status, 1, 8);
final Text actiontarget = new Text();
grid.add(actiontarget, 1, 6);
// ImageView imageView = new ImageView(new Image(getClass().getResourceAsStream("person.png"), 0, 65, true, true));
//grid.add(imageView, 0, 0,2,2);
//btn.setOnAction( ( e ) -> status.setText( computeStatus() ) );
//private String computeStatus() {
// return "Name: " + userTextField.getText() + ", Password: " + pwBox.getText();
//}
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
actiontarget.setFill(Color.CORNFLOWERBLUE);
actiontarget.setText("Name: " + userTextField.getText() + ", Password: " + pwBox.getText());
}
});
Scene scene = new Scene(grid, 300, 275);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}

how to fit a gridpane in javafx2 accross the whole scene

I would like to fit the gridbox accross the whole scene as per attached picture and code below, however i cannot whatever I do!!
I have tried generating empty rows and columns but still does not fill, unless i add a lot.
I would like to specify a number of rows and columns and then let the program divide these equally along the screen, please help
how can I also locate the text inside the table the the right of the cell?
#Override public void start(Stage stage) {
timer.start();
buildData_timer.start();
Group root = new Group();
Scene scene = new Scene(root, 1180, 650);
stage.setScene(scene);
stage.setTitle("Separator Sample");
scene.getStylesheets().addAll(this.getClass().getResource("style.css").toExternalForm());
GridPane Mainpane = new GridPane();
scene.setRoot(Mainpane);
Mainpane.setGridLinesVisible(true);
Mainpane.setId("Mainpane");
GridPane prayertime_pane = new GridPane();
prayertime_pane.setId("prayertime_pane");
prayertime_pane.setGridLinesVisible(true);
prayertime_pane.setPadding(new Insets(20, 20, 20, 20));
prayertime_pane.setVgap(20);
prayertime_pane.setHgap(35);
HBox clock1Box = new HBox();
clock1Box.setSpacing(0);
clock1Box.getChildren().addAll(clock);
HBox fajrBox = new HBox();
fajrBox.setSpacing(0);
fajrBox.setMaxSize(155, 54);
fajrBox.getChildren().addAll(fajr_hourLeft, fajr_hourRight, time_Separator1, fajr_minLeft, fajr_minRight);
prayertime_pane.setConstraints(fajrBox, 0, 1);
prayertime_pane.getChildren().add(fajrBox);
HBox zuhrBox = new HBox();
zuhrBox.setSpacing(0);
zuhrBox.setMaxSize(155, 54);
zuhrBox.getChildren().addAll(zuhr_hourLeft, zuhr_hourRight, time_Separator2, zuhr_minLeft, zuhr_minRight);
prayertime_pane.setConstraints(zuhrBox, 0, 2);
prayertime_pane.getChildren().add(zuhrBox);
HBox asrBox = new HBox();
asrBox.setSpacing(0);
asrBox.setMaxSize(155, 54);
asrBox.getChildren().addAll(asr_hourLeft, asr_hourRight, time_Separator3, asr_minLeft, asr_minRight);
prayertime_pane.setConstraints(asrBox, 0, 3);
prayertime_pane.getChildren().add(asrBox);
HBox maghribBox = new HBox();
maghribBox.setSpacing(0);
maghribBox.setMaxSize(155, 54);
maghribBox.getChildren().addAll(maghrib_hourLeft, maghrib_hourRight, time_Separator4, maghrib_minLeft, maghrib_minRight);
prayertime_pane.setConstraints(maghribBox, 0, 4);
prayertime_pane.getChildren().add(maghribBox);
HBox ishaBox = new HBox();
ishaBox.setSpacing(0);
ishaBox.setMaxSize(155, 54);
ishaBox.getChildren().addAll(isha_hourLeft, isha_hourRight, time_Separator5, isha_minLeft, isha_minRight);
prayertime_pane.setConstraints(ishaBox, 0, 5);
prayertime_pane.getChildren().add(ishaBox);
TextFlow fajrtextFlow = new TextFlow();
Text text1 = new Text("الفجر\n");
text1.setId("prayer-text-arabic");
Text text10 = new Text("Fajr");
text10.setId("prayer-text-english");
fajrtextFlow.getChildren().addAll(text1, text10);
prayertime_pane.setConstraints(fajrtextFlow, 1, 1);
prayertime_pane.getChildren().add(fajrtextFlow);
TextFlow duhrtextFlow = new TextFlow();
Text text2 = new Text("الظهر\n");
text2.setId("prayer-text-arabic");
Text text20 = new Text("Duhr");
text20.setId("prayer-text-english");
duhrtextFlow.getChildren().addAll(text2,text20);
prayertime_pane.setConstraints(duhrtextFlow, 1, 2);
prayertime_pane.getChildren().add(duhrtextFlow);
TextFlow asrFlow = new TextFlow();
Text text3 = new Text("العصر\n");
text3.setId("prayer-text-arabic");
Text text30 = new Text("Asr");
text30.setId("prayer-text-english");
asrFlow.getChildren().addAll(text3,text30);
prayertime_pane.setConstraints(asrFlow, 1, 3);
prayertime_pane.getChildren().add(asrFlow);
TextFlow maghribFlow = new TextFlow();
Text text4 = new Text("المغرب\n");
text4.setId("prayer-text-arabic");
Text text40 = new Text("Maghrib");
text40.setId("prayer-text-english");
maghribFlow.getChildren().addAll(text4,text40);
prayertime_pane.setConstraints(maghribFlow, 1, 4);
prayertime_pane.getChildren().add(maghribFlow);
TextFlow ishaFlow = new TextFlow();
Text text5 = new Text("العشاء\n");
text5.setId("prayer-text-arabic");
Text text50 = new Text("Isha");
text50.setId("prayer-text-english");
ishaFlow.getChildren().addAll(text5,text50);
prayertime_pane.setConstraints(ishaFlow, 1, 5);
prayertime_pane.getChildren().add(ishaFlow);
final Separator sepHor = new Separator();
// sepHor.setAlignment(Pos.CENTER_LEFT);
// sepHor.setOrientation(Orientation.HORIZONTAL);
prayertime_pane.setConstraints(sepHor, 0, 1);
prayertime_pane.setColumnSpan(sepHor, 2);
prayertime_pane.getChildren().add(sepHor);
Mainpane.setConstraints(prayertime_pane, 2, 3);
Mainpane.getChildren().add(prayertime_pane);
Mainpane.setConstraints(clock1Box, 7, 1);
Mainpane.getChildren().add(clock1Box);
stage.show();
// stage.setFullScreen(true);
}
Try
ColumnConstraints c1 = new ColumnConstraints();
c1.setHgrow(Priority.ALWAYS);
ColumnConstraints c2 = new ColumnConstraints();
c2.setHgrow(Priority.NEVER);
Mainpane.getColumnConstraints().addAll(c1, c2);
RowConstraints r1 = new RowConstraints();
r1.setVgrow(Priority.NEVER);
RowConstraints r2 = new RowConstraints();
r2.setVgrow(Priority.ALWAYS);
Mainpane.getRowConstraints().addAll(r1, r2);
For more row/column/cell settings investigate GridPane, RowConstraints and ColumnConstraints.
However I suggest you to use AnchorPane or BorderPane here.

Resources