So I have this button. It can be pressed with the enter key, and can be selected through tabbing to it, but it cannot be clicked on, and doesn't appear to exist as far as the cursor is concerned. I don't believe anything is covering it, but it most be covered some how, as a button created with identical code is clickable.
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
primaryStage.setTitle("Mortgage Calculator");
GridPane pane = new GridPane();
pane.setAlignment(Pos.CENTER);
pane.setHgap(10);
pane.setVgap(10);
pane.setPadding(new Insets(25, 25, 25, 25));
Scene scene = new Scene(pane, 350, 325);
Text sceneTitle = new Text("Mortgage Calculator");
sceneTitle.setFont(Font.font("Arial", FontWeight.NORMAL, 20));
pane.add(sceneTitle, 0, 0, 2, 1);
Label total = new Label("Value of your Mortgage:");
pane.add(total, 0, 1);
final TextField totalField = new TextField();
pane.add(totalField, 1, 1);
Label percent = new Label("% Interest:");
pane.add(percent, 0, 2);
final TextField percentField = new TextField();
pane.add(percentField, 1, 2);
Label time = new Label("Length of mortgage:");
pane.add(time, 0, 3);
final TextField timeField = new TextField();
pane.add(timeField, 1, 3);
final Text amountOwed = new Text();
pane.add(amountOwed, 1, 7);
final Text payment = new Text();
pane.add(payment, 1, 8);
Button calculateButton = new Button("Calculate");
HBox hbox1 = new HBox(10);
hbox1.setAlignment(Pos.BOTTOM_RIGHT);
hbox1.getChildren().add(calculateButton);
calculateButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
double principal = Double.parseDouble(totalField.getText());
double interest = (Double.parseDouble(percentField.getText()) / 100) / 12;
int time = Integer.parseInt(timeField.getText());
int numPayment = time * 12;
double monthlyPayment = (principal * (interest * (Math.pow((interest + 1), numPayment)))) / (Math.pow((1 + interest), numPayment) - 1);
//double totalPayment = ;
//amountOwed.setText("Amount owed is: " + totalPayment);
payment.setText("Monthly payment is: $" + (int)Math.ceil(monthlyPayment));
}
});
pane.add(hbox1, 1, 4);
Button clearButton = new Button("Clear");
HBox hbox = new HBox(10);
hbox.setAlignment(Pos.BOTTOM_LEFT);
hbox.getChildren().add(clearButton);
pane.add(hbox, 1, 4);
EventHandler<ActionEvent> handler1 = new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
totalField.setText("");
percentField.setText("");
timeField.setText("");
payment.setText("");
}
};
clearButton.setOnAction(handler1);
primaryStage.setScene(scene);
primaryStage.show();
}
}
mouseTransparent Issue
You put the "Calculate" button in a HBox and then you call setMouseTransparent(true) on the HBox. Such a call will disable mouse input on the HBox and all it's children. This behavior is documented in the linked Javadoc:
If true, this node (together with all its children) is completely transparent to mouse events. When choosing target for mouse event, nodes with mouseTransparent set to true and their subtrees won't be taken into account.
You don't need the setMouseTransparent(true) call; just remove it, and the "Calculate" button will be clickable as you expect.
Overlapping Components Issue
You also need to ensure that you don't overlap some components with others otherwise only the top components will be clickable. In your case, the HBox containing the "Clear" button is overlapping the "Calculate" button.
So change:
pane.add(hbox, 1, 4);
To:
pane.add(clearButton, 1, 4);
Debugging Assistance
You can debug layouts either by calling layout.setStyle("-fx-background-color: green;") to show the extent of the layout, or by using ScenicView.
Related
I tried to just make a simple Gridpane that would ask the user to input two numbers. For some reason the elements just went all over the place. I'm pretty sure I got the constraints correct.
This is my Settings class.
public class Settings {
public static void display() {
GridPane layout = new GridPane();
layout.setPadding(new Insets(10));
layout.setVgap(8);
layout.setHgap(10);
Scene scene = new Scene(layout, 600, 400);
//Title label
Label label = new Label("Settings");
GridPane.setConstraints(label, 1, 0);
//Minutes label
Label minutesLabel = new Label("Minutes:");
GridPane.setConstraints(minutesLabel, 0, 1);
//Minutes input
TextField minutesInput = new TextField();
minutesInput.setPromptText("minutes");
GridPane.setConstraints(minutesInput, 1, 1);
//Seconds label
Label secondsLabel = new Label("Seconds:");
GridPane.setConstraints(secondsLabel, 0, 2);
//Seconds input
TextField secondsInput = new TextField();
secondsInput.setPromptText("seconds");
GridPane.setConstraints(secondsInput, 1, 2);
//Ok button
Button okButton = new Button("Ok");
okButton.setOnAction(e -> {
try {
int minutes = Integer.parseInt(minutesInput.getText());
int seconds = Integer.parseInt(secondsInput.getText());
if(minutes > 59) minutes = 59;
else if(minutes < 1) minutes = 1;
if(seconds > 59) seconds = 59;
else if(seconds < 1) seconds = 1;
Main.updateMinsAndSecs(minutes, seconds);
Main.setSceneMain();
}catch(NumberFormatException numberFormatException) {
label.setText("Please enter valid number(s)");
}catch(FileNotFoundException fileNotFoundException) {
fileNotFoundException.printStackTrace();
}
});
okButton.setStyle("-fx-background-radius: 0;");
GridPane.setConstraints(secondsInput, 0, 3);
//Cancel button
Button cancelButton = new Button("Cancel");
cancelButton.setOnAction(e -> {
Main.setSceneMain();
});
cancelButton.setStyle("-fx-background-radius: 0;");
GridPane.setConstraints(secondsInput, 1, 3);
//Apply button
Button applyButton = new Button("Apply");
applyButton.setOnAction(e -> {
try {
int minutes = Integer.parseInt(minutesInput.getText());
int seconds = Integer.parseInt(secondsInput.getText());
if(minutes > 59) minutes = 59;
else if(minutes < 1) minutes = 1;
if(seconds > 59) seconds = 59;
else if(seconds < 1) seconds = 1;
Main.updateMinsAndSecs(minutes, seconds);
}catch(NumberFormatException numberFormatException) {
label.setText("Please enter valid number(s)");
}catch(FileNotFoundException fileNotFoundException) {
fileNotFoundException.printStackTrace();
}
});
applyButton.setStyle("-fx-background-radius: 0;");
GridPane.setConstraints(secondsInput, 2, 3);
layout.getChildren().addAll(label, minutesLabel, minutesInput, secondsLabel, secondsInput, okButton, cancelButton, applyButton);
Main.window.setScene(scene);
Main.window.setTitle("Settings");
}
}
This is how it turned out.
screenshot
I would like the solution to not use fxml.
Stackoverflow says my post is mostly code and I need more details so I'm also going to say that I have used a Gridpane to create a simple login screen and that one was pretty good. The code was basically the same except the positioning and the content.
You are setting different constraints to secondsInput instead of okButton, cancelButton and applyButton:
GridPane.setConstraints(secondsInput, 1, 2);
GridPane.setConstraints(secondsInput, 0, 3);
GridPane.setConstraints(secondsInput, 1, 3);
GridPane.setConstraints(secondsInput, 2, 3);
Instead of:
GridPane.setConstraints(secondsInput, 1, 2);
GridPane.setConstraints(okButton, 0, 3);
GridPane.setConstraints(cancelButton, 1, 3);
GridPane.setConstraints(applyButton, 2, 3);
I am almost done with this here program. It is one of them work order forms with event handlers and an updated total. How may I return a total value updated after receiving user input? I am sure I need a return pane somewhere, just not sure where. Code below:
public class Working_order extends Application {
// Radio buttons
private RadioButton rbNext = new RadioButton("$20");
private RadioButton rbThis = new RadioButton("$12");
private RadioButton rbSome = new RadioButton("$5");
private Label lbDue = new Label("$0.00");
#Override
public void start(Stage primaryStage) {
// Create a pane and set its properties
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);
// Place nodes in the pane
pane.add(new Label("Item"), 0, 0);
pane.add(tfItem, 1, 0);
pane.add(new Label("Price"), 0, 1);
pane.add(tfPrice, 1, 1);
pane.add(new Label("Quantity"), 0, 2);
pane.add(tfQty, 1, 2);
CheckBox chTaxable = new CheckBox("Taxable?");
pane.add(chTaxable, 1, 3);
// More nodes in a pane
pane.add(new Label("Shipping"), 0, 4);
pane.add(rbNext, 1, 5);
pane.add(new Label("Next Day"), 0, 5);
pane.add(rbThis, 1, 6);
pane.add(new Label("This Week"), 0, 6);
pane.add(rbSome, 1, 7);
pane.add(new Label("Total Due"), 0, 8);
pane.add(lbDue, 1, 8);
pane.add(new Label("Some Day"), 0, 7);
Button btAdd = new Button("Process");
Button btAdd2 = new Button("Reset");
// Toggle group
ToggleGroup group = new ToggleGroup();
rbNext.setToggleGroup(group);
rbThis.setToggleGroup(group);
rbSome.setToggleGroup(group);
btAdd.setOnAction(e -> {
// read textboxes
String sPrice = tfPrice.getText();
double price = Double.parseDouble(sPrice);
int qty = Integer.parseInt(tfQty.getText());
double subTotal = price * qty;
double tax;
if (chTaxable.isSelected()) {
tax = subTotal * 0.07;
} else {
tax = 0;
}
});
pane.add(btAdd, 0, 9);
pane.add(btAdd2, 1, 9);
GridPane.setHalignment(btAdd, HPos.RIGHT);
GridPane.setHalignment(btAdd2, HPos.LEFT);
// Create a scene and place it in the stage
Scene scene = new Scene(pane);
primaryStage.setTitle("ShowGridPane"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display
}
public static void main(String[] args) {
launch(args);
}
}
First of all, you didn't construct the text fields (tfItem,tfPrice,tfQty).
to solve this add those lines
TextField tfItem = new TextField();
TextField tfPrice = new TextField();
TextField tfQty = new TextField();
your problem is simple, after calculating the result by applying your formula in the btAdd (process button) event handler just add this line at the end of the event handler
lbDue.setText( result + "" );
this shall solve your issue
For hours I'm trying to get this result: Design, GridDesign, FinalResult
My problem here is that I cant align properly the TotalPrice label, I want it to take 2 columns and align to the most right of the grid, when the label size gets bigger(More text is added to the label) I want it to grow only on the left side and still be aligned to the right of the grid!
But nothing seems to work properly!
In my case when I add a bigger price, it wont stay like I want to...
Here's my result with smaller label text, in this case it looks perfect, the price is aligned perfectly to the right:
result1
But here's the bad result when I put a bigger number, you can see the TotalPrice label is not aligned as it should:
result2
Here's my code with hardcoded strings just for testing:
GridPane grid = new GridPane();
//Delete Button
Button btn = new Button("X");
btn.setPrefWidth(40);
btn.setPrefHeight(40);
//Labels
Label productName = new Label("MaxiCheeseBurger Menu");
Label productPrice = new Label("120 den");
Label productQty = new Label("x1");
Label totalPrice = new Label("120 den");
totalPrice.setMaxWidth(Double.MAX_VALUE);
totalPrice.setAlignment(Pos.CENTER_RIGHT);
//Styling labels
productName.setStyle("-fx-font-size: 14;" +
"-fx-font-weight: bold;" +
"-fx-text-fill: #707070;");
totalPrice.setStyle("-fx-font-size: 14;" +
"-fx-font-weight: bold");
//Setting grid column constraints
for (int i = 0; i < 5; i++) {
ColumnConstraints col = new ColumnConstraints();
col.setPercentWidth(100.0 / 5);
col.setHgrow(Priority.ALWAYS);
col.setFillWidth(true);
grid.getColumnConstraints().add(col);
}
//Adding nodes to grid
grid.add(btn, 0, 0, 1, 2);
grid.add(productName, 1, 0, 4, 1);
grid.add(productPrice, 1, 1);
grid.add(productQty, 2, 1);
grid.add(totalPrice, 3, 1, 2, 1);
GridPane.setFillWidth(totalPrice, true);
GridPane.setHalignment(totalPrice, HPos.RIGHT);
grid.setGridLinesVisible(true);
grid.setHgap(3);
rows.getChildren().add(grid);
rows.setSpacing(5);
receipt_section.setContent(rows);
receipt_section.setPadding(new Insets(0, 0, 0, 5));
I create a box which I can rotate and what will do ~some action~ when clicked. The problem I'm having is display text on all the faces of this box, for example;
1 on the front, 2 on the top, 3 on the back, 4 on the bottom, 5 on the left and 6 on the right.
I understand that StackPane can be used to overlay a text box on-top of the cube but I don't think that'd really help in this scenario.
Since box is essentially a pre-constructed TriangleMesh, is this possible to do?
As far as seen, box doesn't have any in-built functionality to do this.
static double mousePosX;
static double mousePosY;
static double mouseOldX;
static double mouseOldY;
public static Scene testScene(Stage stage) {
Group root = new Group();
Scene scene = new Scene(root, stage.getWidth(), stage.getHeight(), true, SceneAntialiasing.BALANCED);
scene.setFill(Paint.valueOf("Blue"));
PerspectiveCamera camera = new PerspectiveCamera(true);
camera.setNearClip(0.1);
camera.setFarClip(10000.0);
camera.setTranslateZ(-10);
scene.setCamera(camera);
Box box = new Box(1,1,1);
box.setOnMouseClicked(e -> {
System.out.println("Test");
});
Rotate rotateX = new Rotate(10, 0, 0, 0, Rotate.X_AXIS);
Rotate rotateY = new Rotate(5, 0, 0, 0, Rotate.Y_AXIS);
box.getTransforms().addAll(rotateX, rotateY);
scene.setOnMousePressed(me -> {
mouseOldX = me.getSceneX();
mouseOldY = me.getSceneY();
});
scene.setOnMouseDragged(me -> {
mousePosX = me.getSceneX();
mousePosY = me.getSceneY();
rotateX.setAngle(rotateX.getAngle() - (mousePosY - mouseOldY));
rotateY.setAngle(rotateY.getAngle() + (mousePosX - mouseOldX));
mouseOldX = mousePosX;
mouseOldY = mousePosY;
});
root.getChildren().add(box);
return scene;
}
This is the code I've got so far and any assistance would be greatly appreciated.
This solution is based in the answer to this question, where the CuboidMesh from the FXyz library is used.
The main idea is to use an image as texture for the cube. The built-in JavaFX Box will apply this image to each of the 6 faces, so if we want to have different text in each face, we have to use the CuboidMesh, that makes use of the net image:
The cube can be generated as:
CuboidMesh cuboid = new CuboidMesh(100f, 100f, 100f);
cuboid.setTextureModeImage(getClass().getResource("net.png").toExternalForm());
The idea now is to write the text in each of the 6 faces and save the texture image that will be used later on.
This method will generate this net image:
private Image generateNet(String face1, String face2, String face3, String face4, String face5, String face6) {
GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
Label label1 = new Label(face1);
label1.setRotate(90);
GridPane.setHalignment(label1, HPos.CENTER);
Label label2 = new Label(face2);
GridPane.setHalignment(label2, HPos.CENTER);
Label label3 = new Label(face3);
GridPane.setHalignment(label3, HPos.CENTER);
Label label4 = new Label(face4);
GridPane.setHalignment(label4, HPos.CENTER);
Label label5 = new Label(face5);
GridPane.setHalignment(label5, HPos.CENTER);
Label label6 = new Label(face6);
label6.setRotate(90);
GridPane.setHalignment(label6, HPos.CENTER);
grid.add(label1, 1, 0);
grid.add(label2, 0, 1);
grid.add(label3, 1, 1);
grid.add(label4, 2, 1);
grid.add(label5, 3, 1);
grid.add(label6, 1, 2);
grid.setGridLinesVisible(true);
ColumnConstraints col1 = new ColumnConstraints();
col1.setPercentWidth(25);
ColumnConstraints col2 = new ColumnConstraints();
col2.setPercentWidth(25);
ColumnConstraints col3 = new ColumnConstraints();
col3.setPercentWidth(25);
ColumnConstraints col4 = new ColumnConstraints();
col4.setPercentWidth(25);
grid.getColumnConstraints().addAll(col1, col2, col3, col4);
RowConstraints row1 = new RowConstraints();
row1.setPercentHeight(33.33);
RowConstraints row2 = new RowConstraints();
row2.setPercentHeight(33.33);
RowConstraints row3 = new RowConstraints();
row3.setPercentHeight(33.33);
grid.getRowConstraints().addAll(row1, row2, row3);
grid.setPrefSize(600, 450);
Scene tmpScene = new Scene(grid);
tmpScene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
return grid.snapshot(null, null);
}
where style.css contains:
.root {
-fx-background-color: white;
}
.label {
-fx-font-size: 6em;
}
With it, the labels size and font can be adjusted properly.
Now you can generate a net image for any text:
Image net = generateNet("1", "2", "3", "4", "5", "6");
Finally, you can apply this texture to the cuboid:
PhongMaterial mat = new PhongMaterial();
mat.setDiffuseMap(net);
cuboid.setMaterial(mat);
And you will have your text applied:
I am currently working on a project, and I cannot find just any solution. I want a Gridpane row height to be dynamically counted from the width of one specific column inside that row. The whole Gridpane must be resizable and the rest of the available space should take another row below so the aspect ratio of that one cell is preserved according to the element inside that cell. Any ideas boys?
click for a pic
public class GridPaneControl extends GridPane {
private int index;
private Label startLabel;
private Label endLabel;
private HBox inputCellsContainer;
private HBox outputCellsContainer;
private Button inputOutputNextButton;
private Button inputOutputPreviousButton;
public GridPaneControl() {
setGridLinesVisible(true);
initialization();
ColumnConstraints cc0 = new ColumnConstraints();
cc0.setMaxWidth(Double.MAX_VALUE);
cc0.setHgrow(Priority.NEVER);
ColumnConstraints cc1 = new ColumnConstraints();
cc1.setMaxWidth(Double.MAX_VALUE);
ColumnConstraints cc2 = new ColumnConstraints();
cc2.setMaxWidth(Double.MAX_VALUE);
cc2.setHgrow(Priority.NEVER);
RowConstraints rc0 = new RowConstraints();
rc0.setVgrow(Priority.ALWAYS);
rc0.setFillHeight(false);
rc0.setMaxHeight(Double.MAX_VALUE);
RowConstraints rc1 = new RowConstraints();
rc1.setVgrow(Priority.ALWAYS);
rc1.setFillHeight(false);
rc1.setMaxHeight(Double.MAX_VALUE);
RowConstraints rc2 = new RowConstraints();
rc2.setVgrow(Priority.NEVER);
RowConstraints rc3 = new RowConstraints();
rc3.setVgrow(Priority.ALWAYS);
getColumnConstraints().addAll(cc0, cc1, cc2);
getRowConstraints().addAll(rc0, rc1, rc2, rc3);
}
private void initialization() {
inputCellsContainer = new HBox(0);
outputCellsContainer = new HBox(0);
GridPane.setValignment(inputCellsContainer, VPos.BOTTOM);
GridPane.setValignment(outputCellsContainer, VPos.TOP);
inputOutputPreviousButton = new Button("<<");
inputOutputPreviousButton.maxWidth(Double.MAX_VALUE);
GridPane.setHgrow(inputOutputPreviousButton, Priority.NEVER);
GridPane.setVgrow(inputOutputPreviousButton, Priority.NEVER);
GridPane.setMargin(inputOutputPreviousButton, new Insets(5));
inputOutputNextButton = new Button(">>");
inputOutputNextButton.maxWidth(Double.MAX_VALUE);
GridPane.setHgrow(inputOutputNextButton, Priority.NEVER);
GridPane.setVgrow(inputOutputNextButton, Priority.NEVER);
GridPane.setMargin(inputOutputNextButton, new Insets(5));
for (int i = 0; i < 32; i++) {
InputOutputCell cellIn = new InputOutputCell(String.format("%02X", i), Color.AQUA, 0);
InputOutputCell cellOut = new InputOutputCell(String.format("%02X", i), Color.BEIGE, 1);
HBox.setHgrow(cellIn, Priority.ALWAYS);
HBox.setHgrow(cellOut, Priority.ALWAYS);
inputCellsContainer.getChildren().add(cellIn);
outputCellsContainer.getChildren().add(cellOut);
}
GridPane.setHgrow(inputCellsContainer, Priority.ALWAYS);
GridPane.setHgrow(outputCellsContainer, Priority.ALWAYS);
GridPane.setVgrow(inputCellsContainer, Priority.ALWAYS);
GridPane.setVgrow(outputCellsContainer, Priority.ALWAYS);
startLabel = new Label("0");
endLabel = new Label("31");
GridPane.setHalignment(startLabel, HPos.LEFT);
GridPane.setHalignment(endLabel, HPos.RIGHT);
this.add(inputOutputPreviousButton, 0, 0, 1, 2);
this.add(inputCellsContainer, 1, 0);
this.add(outputCellsContainer, 1, 1);
this.add(inputOutputNextButton, 2, 0, 1, 2);
this.add(startLabel, 1, 2);
this.add(endLabel, 1, 2);
}
public int getIndex() {
return index;
}
private class InputOutputCell extends StackPane {
#FXML
Text text;
#FXML
Rectangle rectangle;
public InputOutputCell(String text, Color color, int type) {
setMinSize(0, 0);
this.text = new Text(text);
rectangle = new Rectangle();
if (type == 0) {
rectangle.widthProperty().bind(inputCellsContainer.widthProperty().divide(32));
rectangle.heightProperty().bind(inputCellsContainer.widthProperty().divide(32));
} else {
rectangle.widthProperty().bind(outputCellsContainer.widthProperty().divide(32));
rectangle.heightProperty().bind(outputCellsContainer.widthProperty().divide(32));
}
rectangle.maxWidth(Double.MAX_VALUE);
rectangle.maxHeight(Double.MAX_VALUE);
rectangle.setArcHeight(10);
rectangle.setArcWidth(10);
rectangle.setFill(color);
rectangle.setStroke(Color.BLACK);
getChildren().addAll(rectangle, this.text);
}
public void setText(String text) {
this.text.setText(text);
}
public String getText() {
return this.text.getText();
}
}
}
I want cells 1,0 and 1,1 to be resizable and clearly by increasing their width the height of row 0 and 1 should not be increasing equally. If there should be any height left I want the row 3 to take it because row 2 should not grow to height at all.
You did a fair bit of explanation (which is good) but it is complex enough to make me read 10 times, and I think I understood 70% of it. The most puzzling part is this line:
the rest of the available space should take another row below so the aspect ratio of that one cell is preserved according to the element inside that cell.
Not sure which "cell" you are referrring to, and what you mean by keeping aspect ratio.
Now for the actual answer, I think the most obvious one that I can see is that you have given rows 0 and 1 ALWAYS priority for VGrow.
You have 3 rows that has ALWAYS VGrow, and what the GridPane will do is to give all children to whatever space that they preferred to have, then distribute all the "leftover" spaces to rows with ALWAYS. That is why the 3 gaps in your image has the same height.