Can anyone tell me why some items from a dropdown list are not visible when running the jar application? It seems to happen randomly. I create an ObservableList, then recursively create a Line, assign it a stroke type from the observable list through a String as line.setStyle("-fx-stroke-dash-array:" + dashString + ";"). Finally, everything works fine and the ComboBox gets the whole list of line and a certain selection. But it sometimes fail to display lines in the dropdown list. The code is:
package test;
import java.util.ArrayList;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
public class ComboLines extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
ComboBox<Line> dashCombo = new ComboBox<>();
initDashLineCombo(dashCombo, dashUnit, 2);
dashCombo.getStylesheets().add("test/style.css");
dashCombo.setStyle("-fx-min-width: 100; -fx-max-width: 100; -fx-pref-width: 100; -fx-min-height: 15; -fx-pref-height: 15; -fx-max-height: 15;");
StackPane root = new StackPane();
root.getChildren().add(dashCombo);
primaryStage.setScene(new Scene(root, 150, 300));
primaryStage.show();
}
public static void initDashLineCombo(ComboBox<Line> cb, ObservableList<int[]> list, int i)
{
ArrayList<Line> LinesList = new ArrayList<>(); // to store lines
// cycle over the list and generate a line with dashing defined by list
for(int j = 0; j < list.size(); j++)
{
int sum = 0;
int[] dash = list.get(j);
String dashString = " ";
for(int k : dash) // cycle over an int array which defines the dashing
{ dashString += k + " ";
sum += k; }
System.out.println("sum = " + sum);
Line line = new Line(15, 0, 1*(15+sum), 0);
System.out.print("\ndashString :" + dashString);
// apply style
line.setStrokeWidth(2);// line width
line.setStroke(Color.BLACK);
line.setStyle("-fx-stroke-dash-array:" + dashString + ";"); // line dashing
LinesList.add(line); // collect the line
}
// create the observable list
final ObservableList<Line> LinesObs = FXCollections.observableArrayList(LinesList);
// set all line items in the combo box
cb.setItems(LinesObs);
// select an item ion the combo box
cb.setValue(LinesObs.get(i-1));
}
// ... dashing ...
int[] s10 = {1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3,};
int[] s9 = {1,3,1,3,1,4,5,4,5,4, 1,3,1,3,1,4,5,4,5,4};
int[] s8 = {6,3,6,3,6,5,1,5, 6,3,6,3,6,5,1,5};
int[] s7 = {1,3,1,3,1,6,6,6, 1,3,1,3,1,6,6,6};
int[] s6 = {5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3};
int[] s5 = {5, 4, 5, 4, 1, 3, 1, 4, 5, 4, 5, 4, 1, 3, 1, 4};
int[] s4 = {5, 4, 1, 3, 1, 4, 5, 4, 1, 3, 1, 4, 5, 4, 1, 3, 1, 4};
int[] s3 = {5, 3, 1, 3, 5, 3, 1, 3, 5, 3, 1, 3, 5, 3, 1, 3};
int[] s2 = {15, 3, 15, 3, 15, 3};
int[] s1 = {60};
final ObservableList<int[]> dashUnit = FXCollections.observableArrayList(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10);
}
/* style.css */
.combo-box {
-fx-min-width: 35;
-fx-pref-width: 35;
-fx-max-width: 35;
-fx-min-height: 20;
-fx-pref-height: 20;
-fx-max-height: 20;
-fx-padding: -2 -8 -2 -5;
}
.combo-box-base > .arrow-button {
-fx-background-radius: 0 3 3 0, 0 2 2 0, 0 1 1 0;
-fx-background-color: transparent;
-fx-alignment: center-left;
}
.combo-box .cell {
-fx-font-size: 8.75pt;
-fx-font-family: "Arial";
-fx-text-fill: BLACK;
-fx-alignment: BASELINE_RIGHT;
-fx-padding: 0 3 0 -5;
}
invisible lines
UPDATE: Using cell factory a simplified version (no CSS and no dashing applied) is like this. The same problem persists and further I cannot get the initial selection applied.
package test;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
import javafx.util.Callback;
public class ComboLines extends Application
{
public static void main(String[] args) { launch(args); }
ComboBox<Line> dashCombo = new ComboBox<>();
#Override
public void start(Stage primaryStage)
{
StackPane root = new StackPane();
root.getChildren().add(dashCombo);
dashCombo.setItems(FXCollections.observableList(DASHUNIT));
dashCombo.getSelectionModel().selectFirst();
dashCombo.setCellFactory(new Callback<ListView<Line>, ListCell<Line>>()
{
#Override
public ListCell<Line> call(ListView<Line> newLine)
{
return new ListCell<Line>()
{
#Override
protected void updateItem(Line item, boolean y)
{
super.updateItem(item, false);
setGraphic(item);
} // end updateItem
} ; // end new ListCell
} // end call()
}); // end setCellFactory
primaryStage.setScene(new Scene(root, 150, 300));
primaryStage.show();
}
Line line1 = new Line(15, 0, 50, 0), line2 = new Line(15, 0, 50, 0), line3 = new Line(15, 0, 50, 0);
final ObservableList<Line> DASHUNIT = FXCollections.observableArrayList(line1, line2, line3);
}
Finally, I got it working with the code below. Following kleopatra's comments, the insipartion came from the official Oracle page https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/ComboBox.html
ComboBox<Line> dashCombo = new ComboBox<>();
dashCombo.getStylesheets().add("style.css");
dashCombo.setStyle("-fx-min-width: 100; -fx-max-width: 100; -fx-pref-width: 100; "
+ "-fx-min-height: 15; -fx-pref-height: 15; -fx-max-height: 15;");
initDashLineCombo(dashCombo, common.General.DASHUNIT, (numberCoils - i), colCombo);
public static void initDashLineCombo(ComboBox<Line> cb, ObservableList<int[]> list, int i, ColorPicker cp)
{
for(int j = 0; j < list.size(); j++) // cycle over the list and generate a line with dashing defined by list
{
int[] dash = list.get(j);
String dashString = " ";
for(int k : dash)
dashString += k + " ";
Line line = new Line(25, 0, 95, 0);
line.setStrokeWidth(2); line.strokeProperty().bind(cp.valueProperty());
line.setStyle("-fx-stroke-dash-array:" + dashString + ";");
cb.getItems().add(line);
}
cb.getSelectionModel().clearAndSelect(i-1);
cb.setCellFactory(new Callback<ListView<Line>, ListCell<Line>>()
{
#Override public ListCell<Line> call(ListView<Line> p)
{
return new ListCell<Line>() {
private final Line line;
{
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
line = new Line(0, 0, 70, 0);
line.setStrokeWidth(2);
line.strokeProperty().bind(cp.valueProperty());
} // end Line
#Override protected void updateItem(Line item, boolean empty)
{
super.updateItem(item, empty);
if (item == null || empty) {
setGraphic(null);
}
else {
line.setStyle(item.getStyle());
setGraphic(line);
setItem(line);
}
} // end updateItem()
}; // end ListCell
} // end call()
}); // end setCellFactory
}
enter image description here
enter image description here
Related
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);
Note: 25 years with Java, 2.5 hours (almost) with JavaFX.
I want to be able to highlight all cells of a GridPane that the mouse is dragged across - i.e. everything that intersects with the rectangle cornered by the click point and the current drag point. I can do that if all children are 1x1, but with mixed sizes I'm having no joy.
For example, if the top row has 1 1 column cell (A) and 1 2 column cell (B) and the bottom has 1 2 column cell (C) and 1 1 column cell (D), if I click in A and drag down into C I can highlight both. However, I cannot figure out when I drag into the right half of C so that B should be highlighted.
Sample Board:
Apologies for the HSCE - it's a bit long but I felt stripping it down would reduce readability.
import java.util.*;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.*;
import javafx.scene.Node;
import javafx.stage.Stage;
import javafx.geometry.*;
public class AddTestSSCE extends Application
{
ArrayList<StackPane> sPanes = new ArrayList<StackPane>(); // selected panes
GridPane theGrid;
Node startNode = null;
int col0, col1;
int row0, row1;
#Override
public void start(Stage stage) {
theGrid = new GridPane();
ColumnConstraints col = new ColumnConstraints(300);
theGrid.getColumnConstraints().addAll(col, col, col);
RowConstraints row = new RowConstraints(200);
theGrid.getRowConstraints().addAll(row, row, row);
addGridPane();
theGrid.getStyleClass().add("bg-grid");
Scene scene = new Scene(theGrid, 1024, 768);
scene.getStylesheets().add("addtestssce.css");
stage.setScene(scene);
stage.show();
}
public void addGridPane() {
theGrid.setHgap(10);
theGrid.setVgap(10);
theGrid.setPadding(new Insets(0, 10, 0, 10));
StackPane theSP = sPAdd(new Label("A"));
theGrid.add(theSP, 0, 0, 1, 1);
theSP = sPAdd(new Label("B"));
theGrid.add(theSP, 1, 0, 2, 1);
theSP = sPAdd(new Label("C"));
theGrid.add(theSP, 0, 1, 2, 1);
theSP = sPAdd(new Label("D"));
theGrid.add(theSP, 2, 1, 1, 1);
theGrid.addEventFilter(MouseEvent.MOUSE_PRESSED, //Creating the mouse event handler
new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent e) {
System.out.println("We're Moving!!");
startNode = (Node)e.getTarget();
sPanes.add((StackPane)startNode);
col0 = GridPane.getColumnIndex(startNode).intValue();
row0 = GridPane.getRowIndex(startNode).intValue();
System.out.printf("Starting at %d %d\n", col0, row0);
}
});
theGrid.addEventFilter(MouseEvent.MOUSE_DRAGGED, //Creating the mouse event handler
new EventHandler<MouseEvent>() {
Node lastNode = null;
#Override
public void handle(MouseEvent e) {
Node target = (Node)e.getTarget();
double xLoc = e.getX();
double yLoc = e.getY();
Bounds bs = target.localToScene(target.getBoundsInLocal());
Node moveTarget;
if( bs.contains(xLoc, yLoc) )
{
moveTarget = target;
}
else
{
moveTarget = getContainingNode((int)xLoc, (int)yLoc);
}
if( moveTarget != null && lastNode != moveTarget )
{
col1 = GridPane.getColumnIndex(moveTarget).intValue();
row1 = GridPane.getRowIndex(moveTarget).intValue();
doHighlighting();
lastNode = moveTarget;
}
}
});
}
void doHighlighting()
{
int c0, c1, r0, r1;
c0 = col0 > col1 ? col1 : col0;
c1 = !(col0 > col1) ? col1 : col0;
r0 = row0 > row1 ? row1 : row0;
r1 = !(row0 > row1) ? row1 : row0;
Rectangle2D rec1 = new Rectangle2D(c0, r0, c1-c0+1, r1-r0+1);
System.out.printf("Box: %d %d %d %d\n", c0, c1, r0, r1);
List<Node> nodes = theGrid.getChildren();
for( Node node : nodes )
{
StackPane sp = (StackPane)node;
unhighlight(sp);
int col = GridPane.getColumnIndex(sp).intValue();
int row = GridPane.getRowIndex(sp).intValue();
if( occupiesCell(sp, rec1) )
{
highlight(sp);
}
}
}
boolean occupiesCell(Node node, Rectangle2D r1)
{
boolean result = false;
int col = GridPane.getColumnIndex(node).intValue();
int row = GridPane.getRowIndex(node).intValue();
int wid = GridPane.getColumnSpan(node).intValue();
int hei = GridPane.getRowSpan(node).intValue();
Rectangle2D r2 = new Rectangle2D( col, row, wid, hei);
return r2.intersects(r1);
}
void unhighlight(Node node)
{
if( !(node instanceof StackPane) )
{
return;
}
StackPane label = (StackPane)node;
List<String> cList = label.getStyleClass();
cList.remove("b2");
cList.add("b1");
}
void highlight(Node node)
{
if( !(node instanceof StackPane) )
{
return;
}
StackPane label = (StackPane)node;
List<String> cList = label.getStyleClass();
cList.remove("b1");
cList.add("b2");
}
private Node getContainingNode(int xLoc, int yLoc)
{
Node tgt = null;
for( Node node : theGrid.getChildren() )
{
Bounds boundsInScene = node.localToScene(node.getBoundsInLocal());
if( boundsInScene.contains(xLoc, yLoc) )
{
return node;
}
}
return tgt;
}
private StackPane sPAdd(Label label)
{
StackPane gPPane = new StackPane();
gPPane.getChildren().add(label);
gPPane.getStyleClass().addAll("b1", "grid-element");
GridPane.setFillHeight(gPPane, true);
GridPane.setFillWidth(gPPane, true);
return gPPane;
}
public static void main(String[] args)
{
launch();
}
}
.bg-grid {
-fx-background-color: slategrey;
}
.grid-element {
-fx-border-width: 10;
-fx-border-color: rgb(225, 128, 217);
-fx-background-color: rgb(247, 146, 146);
-fx-font: 36 arial;
}
.b1 {
-fx-text-base-color: white;
-fx-border-color: rgb(225, 128, 217);
}
.b2 {
-fx-text-base-color: lightgray;
-fx-border-color: rgb(233, 228, 86);
}
After a bit of back and forth with #james_d and #slaw, finally came up with a working solution.
import java.util.*;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.*;
import javafx.scene.Node;
import javafx.stage.Stage;
import javafx.geometry.*;
import javafx.css.PseudoClass;
public class AddTestSSCE extends Application
{
private static final PseudoClass highlight = PseudoClass.getPseudoClass("highlight");
ArrayList<StackPane> sPanes = new ArrayList<StackPane>(); // selected panes
GridPane theGrid;
Node startNode = null;
int x0, y0, x1, y1;
#Override
public void start(Stage stage) {
theGrid = new GridPane();
ColumnConstraints col = new ColumnConstraints(300);
theGrid.getColumnConstraints().addAll(col, col, col);
RowConstraints row = new RowConstraints(200);
theGrid.getRowConstraints().addAll(row, row, row);
addGridPane();
theGrid.getStyleClass().add("bg-grid");
Scene scene = new Scene(theGrid, 1024, 768);
scene.getStylesheets().add("addtestssce.css");
stage.setScene(scene);
stage.show();
}
public void addGridPane() {
theGrid.setHgap(10);
theGrid.setVgap(10);
theGrid.setPadding(new Insets(0, 10, 0, 10));
StackPane theSP = sPAdd(new Label("A"));
theGrid.add(theSP, 0, 0, 1, 1);
theSP = sPAdd(new Label("B"));
theGrid.add(theSP, 1, 0, 2, 1);
theSP = sPAdd(new Label("C"));
theGrid.add(theSP, 0, 1, 2, 1);
theSP = sPAdd(new Label("D"));
theGrid.add(theSP, 2, 1, 1, 1);
theGrid.addEventFilter(MouseEvent.MOUSE_PRESSED, //Creating the mouse event handler
new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent e) {
System.out.println("We're Moving!!");
startNode = (Node)e.getTarget();
sPanes.add((StackPane)startNode);
x0 = x1 = (int)e.getX();
y0 = y1 = (int)e.getY();
doHighlighting();
System.out.printf("Starting at %d %d\n", x0, y0);
}
});
theGrid.addEventFilter(MouseEvent.MOUSE_DRAGGED, //Creating the mouse event handler
new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent e) {
Node target = (Node)e.getTarget();
x1 = (int)e.getX();
y1 = (int)e.getY();
Bounds bs = target.localToScene(target.getBoundsInLocal());
Node moveTarget;
if( bs.contains(x1, y1) )
{
moveTarget = target;
}
else
{
moveTarget = getContainingNode( x1, y1);
}
if( moveTarget != null )
{
doHighlighting();
}
}
});
}
void doHighlighting()
{
int c0, c1, r0, r1;
c0 = x0 > x1 ? x1 : x0;
c1 = !(x0 > x1) ? x1 : x0;
r0 = y0 > y1 ? y1 : y0;
r1 = !(y0 > y1) ? y1 : y0;
Bounds dragged = new BoundingBox(c0, r0, c1-c0+1, r1-r0+1);
for (Node child : theGrid.getChildren())
{
child.pseudoClassStateChanged(highlight, dragged.intersects(child.getBoundsInParent()));
}
}
private Node getContainingNode(int xLoc, int yLoc)
{
Node tgt = null;
for( Node node : theGrid.getChildren() )
{
Bounds boundsInScene = node.localToScene(node.getBoundsInLocal());
if( boundsInScene.contains(xLoc, yLoc) )
{
return node;
}
}
return tgt;
}
private StackPane sPAdd(Label label)
{
StackPane gPPane = new StackPane();
gPPane.getChildren().add(label);
gPPane.getStyleClass().addAll("b1", "grid-element");
GridPane.setFillHeight(gPPane, true);
GridPane.setFillWidth(gPPane, true);
return gPPane;
}
public static void main(String[] args)
{
launch();
}
}
and the CSS:
.bg-grid {
-fx-background-color: slategrey;
}
.grid-element {
-fx-border-width: 10;
-fx-border-color: rgb(225, 128, 217);
-fx-background-color: rgb(247, 146, 146);
-fx-font: 36 arial;
}
.grid-element:highlight {
-fx-text-base-color: lightgray;
-fx-border-color: rgb(233, 228, 86);
}
I've created a calculator in JavaFX but one thing frustrates me - it seems like the scene or the primary stage has slightly rounded corners, and these are visible behind the square corners of the buttons.
Screenshot of the problem
I've played around with the background radius of the scene but can't work it out. Any ideas where this radius (if that's what it is) is set?
Here is my code and CSS:
.root
{
-fx-font-size: 12pt;
}
.label
{
-fx-background-color: #999999;
-fx-text-fill: #f9f9f9;
-fx-font-weight: 500;
}
.label-main
{
-fx-background-color: #999999;
-fx-text-fill: #f9f9f9;
-fx-font-size: 35pt;
-fx-font-weight: 500;
}
.button
{
-fx-font-weight: lighter;
-fx-border-style: solid;
-fx-border-color: gray;
-fx-background-color: #E0E0E0;
-fx-border-width: 0 1 1 0;
-fx-background-insets: 0,1,1;
-fx-background-radius: 0;
}
.del-clear
{
-fx-font-weight: lighter;
-fx-font-size: 9pt;
-fx-border-style: solid;
-fx-border-color: gray;
-fx-background-color: #E0E0E0;
-fx-border-width: 0 1 1 0;
-fx-background-insets: 0,1,1;
-fx-background-radius: 0;
}
.button-bigger
{
-fx-font-size: 14pt;
}
.button:pressed
{
-fx-background-color: #B2B2B2;
}
.button-special
{
-fx-background-color: #EA9747;
-fx-text-fill: white;
-fx-border-width: 0 0 1 0;
}
.zero-point
{
-fx-border-width: 0 1 0 0;
}
.button-equals
{
-fx-border-width: 0 0 0 0;
}
package calculator;
import java.util.ArrayList;
import java.util.List;
import javafx.application.*;
import static javafx.application.Application.launch;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.effect.DropShadow;
import javafx.scene.layout.*;
import javafx.stage.*;
public class UserInterface extends Application {
private static int appWidth = 215; //230;
private static int appHeight = 295; //300;
private static int numRows = 7;
private static int numCols = 8;
private List<Button> numButList = new ArrayList();
private List<Button> functButtons = new ArrayList();
private List<Button> compButtons = new ArrayList();
private Calculator calc;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
//Screen s
Label screen2 = new Label("0");
screen2.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
screen2.setAlignment(Pos.CENTER_RIGHT);
screen2.getStyleClass().add("label-main");
Label screen1 = new Label("");
screen1.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
screen1.setAlignment(Pos.CENTER_RIGHT);
GridPane screenBox = new GridPane();
screenBox.getStyleClass().add("innerGrid");
screenBox.setPrefSize(UserInterface.appWidth, (UserInterface.appHeight / UserInterface.numRows) * 2);
//Set the row constraints
for (int i = 0; i < 4; i++) {
RowConstraints r = new RowConstraints();
r.setVgrow(Priority.ALWAYS);
r.setFillHeight(true);
r.setPercentHeight(25);
screenBox.getRowConstraints().add(r);
}
//Set the column constraints
ColumnConstraints c = new ColumnConstraints();
c.setHgrow(Priority.ALWAYS);
c.setPercentWidth(100);
screenBox.getColumnConstraints().add(c);
//screenBox.setGridLinesVisible(true);
screenBox.add(screen1, 0, 0, 1, 1);
screenBox.add(screen2, 0, 1, 1, 3);
//Create calc and pass the screen1 to it
this.calc = new Calculator(screen1, screen2);
//Create 0-9 buttons
for (int i = 0; i < 10; i++) {
Button tempButton = new Button(Integer.toString(i));
if (i == 0) {
tempButton.getStyleClass().add("zero-point");
}
final String tempVar = Integer.toString(i);
tempButton.setOnAction(e -> this.calc.setUserInput(tempVar));
tempButton.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
HBox.setHgrow(tempButton, Priority.ALWAYS);
VBox.setVgrow(tempButton, Priority.ALWAYS);
numButList.add(tempButton);
}
//Point button
//point button
Button point = new Button(".");
String tepointVarmpVar = ".";
point.setOnAction(e -> this.calc.setUserInput(tepointVarmpVar));
point.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
HBox.setHgrow(point, Priority.ALWAYS);
VBox.setVgrow(point, Priority.ALWAYS);
point.getStyleClass().add("button-bigger");
point.getStyleClass().add("zero-point");
//Equals, plus, minus, multiply, and divide buttons
Button equals = new Button("=");
this.compButtons.add(equals);
equals.setOnAction(e -> this.calc.calculate());
Button plus = new Button("+");
this.compButtons.add(plus);
String plusVar = "+";
plus.setOnAction(e -> this.calc.setUserInput(plusVar));
Button minus = new Button("-");
String minusVar = "-";
minus.setOnAction(e -> this.calc.setUserInput(minusVar));
this.compButtons.add(minus);
minus.setStyle("fx-font-size: 16");
Button multiply = new Button("x");
String xVar = "*";
multiply.setOnAction(e -> this.calc.setUserInput(xVar));
this.compButtons.add(multiply);
Button divide = new Button("/");
this.compButtons.add(divide);
String divideVar = "/";
divide.setOnAction(e -> this.calc.setUserInput(divideVar));
//Add button configs
for (int i = 0; i < 5; i++) {
this.compButtons.get(i).setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
this.compButtons.get(i).getStyleClass().add("button-special");
HBox.setHgrow(this.compButtons.get(i), Priority.ALWAYS);
VBox.setVgrow(this.compButtons.get(i), Priority.ALWAYS);
}
equals.getStyleClass().add("button-equals");
for (int i = 0; i < 4; i++) {
this.compButtons.get(i).getStyleClass().add("button-bigger");
}
//Clear and delete buttons
Button clear = new Button("CLR");
clear.setOnAction(e -> this.calc.clearUserInput());
clear.getStyleClass().add("del-clear");
this.functButtons.add(clear);
Button del = new Button("DEL");
del.setOnAction(e -> this.calc.backSpace());
del.getStyleClass().add("del-clear");
this.functButtons.add(del);
for (int i = 0; i < 2; i++) {
this.functButtons.get(i).setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
HBox.setHgrow(this.functButtons.get(i), Priority.ALWAYS);
VBox.setVgrow(this.functButtons.get(i), Priority.ALWAYS);
}
//Create GridPane
GridPane grid = new GridPane();
//Add nodes to grid pane
grid.add(numButList.get(0), 0, 6, 4, 1);
grid.add(point, 4, 6, 2, 1);
grid.add(numButList.get(1), 0, 5, 2, 1);
grid.add(numButList.get(2), 2, 5, 2, 1);
grid.add(numButList.get(3), 4, 5, 2, 1);
grid.add(numButList.get(4), 0, 4, 2, 1);
grid.add(numButList.get(5), 2, 4, 2, 1);
grid.add(numButList.get(6), 4, 4, 2, 1);
grid.add(numButList.get(7), 0, 3, 2, 1);
grid.add(numButList.get(8), 2, 3, 2, 1);
grid.add(numButList.get(9), 4, 3, 2, 1);
grid.add(equals, 6, 6, 2, 1);
grid.add(plus, 6, 5, 2, 1);
grid.add(minus, 6, 4, 2, 1);
grid.add(multiply, 6, 3, 2, 1);
grid.add(divide, 6, 2, 2, 1);
grid.add(clear, 0, 2, 3, 1);
grid.add(del, 3, 2, 3, 1);
grid.add(screenBox, 0, 0, 8, 2);
// Set row and column constraints
for (int rowIndex = 0; rowIndex < UserInterface.numRows; rowIndex++) {
RowConstraints rc = new RowConstraints();
rc.setVgrow(Priority.ALWAYS);
rc.setFillHeight(true);
rc.setPercentHeight(UserInterface.appHeight / UserInterface.numRows);
grid.getRowConstraints().add(rc);
}
for (int colIndex = 0; colIndex < UserInterface.numCols; colIndex++) {
ColumnConstraints cc = new ColumnConstraints();
cc.setHgrow(Priority.ALWAYS);
cc.setFillWidth(true);
cc.setPercentWidth(UserInterface.appWidth / UserInterface.numCols);
grid.getColumnConstraints().add(cc);
}
// Create the scene and the stage
Scene scene = new Scene(grid, appWidth, appHeight);
scene.getStylesheets().add("Simple.css");
primaryStage.setScene(scene);
//primaryStage.setTitle("Calculator");
primaryStage.setResizable(false);
primaryStage.show();
}
}
package calculator;
import java.util.ArrayList;
import java.util.List;
public class StringCalculator {
public StringCalculator() {
}
public static double calcString(final String str2) {
return new Object() {
int pos = -1, ch;
void nextChar() {
ch = (++pos < str2.length()) ? str2.charAt(pos) : -1;
}
boolean eat(int charToEat) {
while (ch == ' ') {
nextChar();
}
if (ch == charToEat) {
nextChar();
return true;
}
return false;
}
double parse() {
nextChar();
double x = parseExpression();
if (pos < str2.length()) {
throw new RuntimeException("Unexpected: " + (char) ch);
}
return x;
}
// Grammar:
// expression = term | expression `+` term | expression `-` term
// term = factor | term `*` factor | term `/` factor
// factor = `+` factor | `-` factor | `(` expression `)`
// | number | functionName factor | factor `^` factor
double parseExpression() {
double x = parseTerm();
for (;;) {
if (eat('+')) {
x += parseTerm(); // addition
} else if (eat('-')) {
x -= parseTerm(); // subtraction
} else {
return x;
}
}
}
double parseTerm() {
double x = parseFactor();
for (;;) {
if (eat('*')) {
x *= parseFactor(); // multiplication
} else if (eat('/')) {
x /= parseFactor(); // division
} else {
return x;
}
}
}
double parseFactor() {
if (eat('+')) {
return parseFactor(); // unary plus
}
if (eat('-')) {
return -parseFactor(); // unary minus
}
double x;
int startPos = this.pos;
if (eat('(')) { // parentheses
x = parseExpression();
eat(')');
} else if ((ch >= '0' && ch <= '9') || ch == '.') { // numbers
while ((ch >= '0' && ch <= '9') || ch == '.') {
nextChar();
}
x = Double.parseDouble(str2.substring(startPos, this.pos));
} else if (ch >= 'a' && ch <= 'z') { // functions
while (ch >= 'a' && ch <= 'z') {
nextChar();
}
String func = str2.substring(startPos, this.pos);
x = parseFactor();
if (func.equals("sqrt")) {
x = Math.sqrt(x);
} else if (func.equals("sin")) {
x = Math.sin(Math.toRadians(x));
} else if (func.equals("cos")) {
x = Math.cos(Math.toRadians(x));
} else if (func.equals("tan")) {
x = Math.tan(Math.toRadians(x));
} else {
throw new RuntimeException("Unknown function: " + func);
}
} else {
throw new RuntimeException("Unexpected: " + (char) ch);
}
if (eat('^')) {
x = Math.pow(x, parseFactor()); // exponentiation
}
return x;
}
}.parse();
}
}
I'm having trouble getting the Hit button to work in my BlackJack program. I tried programming the action for the hit button in the setOnAction block as well as lambda, but I get an error about the variables not being final. So, I tried it this way, but I don't think my variables are carrying over. It's probably something very simple. Please help if you can. Thanks!
import java.util.Arrays;
import java.util.ArrayList;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.scene.layout.GridPane;
import javafx.scene.control.Label;
import javafx.scene.control.Labeled;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
public class BlackJackGame extends Application {
public String btHitY;
public int NumberPlayerCards;
public int NumberDealerCards;
public int NUMBER_OF_CARDS;
public int PlayerCards[];
public int DealerCards[];
public Image imagesP[];
public Image imagesD[];
public int deck[];
public String URLBase;
public GridPane pane;
public BlackJackGame() {
this.btHitY = " ";
this.btHitY = new String();
}
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
//Create array deck, suit string, and rank string
int[] deck = new int[52];
String[] suits = {"Spades", "Hearts", "Diamonds", "Clubs"};
String[] ranks = {"Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"};
int NUMBER_OF_CARDS = 4;
String URLBase = "http://www.cs.armstrong.edu/liang/common/image/card/";
//Initialize the cards
for (int i = 0; i < deck.length; i++)
deck[i] = i;
//Shuffle the cards
for (int i = 0; i < deck.length; i++) {
//Generate an index randomly
int index = (int)(Math.random() * deck.length);
int temp = deck[i];
deck[i] = deck[index];
deck[index] = temp;
}
int NumberPlayerCards = 2;
int NumberDealerCards = 2;
int[] PlayerCards = new int[50];
int[] DealerCards = new int[50];
//Display the first cards
for (int i = 0; i < 8; i++) {
String suit = suits[deck[i] / 13];
String rank = ranks[deck[i] % 13];
System.out.println("Card number " + deck[i] + ": " + rank + " of " + suit);
}
for (int i = 0; i < NumberPlayerCards; i++)
PlayerCards[i] = deck[i * 2];
for (int i = 0; i < NumberDealerCards; i++)
DealerCards[i] = deck[i * 2 + 1];
// Create a pane to hold the image views
GridPane pane = new GridPane();
pane.setAlignment(Pos.CENTER);
pane.setPadding(new Insets(5, 5, 5, 5));
pane.setHgap(5);
pane.setVgap(5);
Image[] imagesP = new Image[50];
Image[] imagesD = new Image[50];
for (int i = 0; i < NumberPlayerCards; i++) {
int cardForPrint = PlayerCards[i] + 1;
System.out.println(URLBase + cardForPrint + ".png");
imagesP[i] = new Image(URLBase + cardForPrint + ".png");
}
for (int i = 0; i < NumberDealerCards; i++) {
int cardForPrint = DealerCards[i] + 1;
System.out.println(URLBase + cardForPrint + ".png");
imagesD[i] = new Image(URLBase + cardForPrint + ".png");
}
//rotate flag image to cover dealer card
Image flag = new Image("http://www.cs.armstrong.edu/liang/common/image/us.gif");
ImageView imageFlag = new ImageView(flag);
imageFlag.setRotate(90);
imageFlag.setFitHeight(75);
imageFlag.setFitWidth(95);
pane.add(new Label("Player Cards"), 0, 0);
pane.add(new ImageView(imagesP[0]), 1, 0);
pane.add((imageFlag), 1, 1);
pane.add(new Label("Dealer Cards"), 0, 1);
pane.add(new ImageView(imagesP[1]), 2, 0);
pane.add(new ImageView(imagesD[1]), 2, 1);
Button btHit = new Button("Hit");
Button btStay = new Button("Stay");
pane.add(btHit, 1, 2);
pane.add(btStay, 2, 2);
// Create a scene and place it in the stage
Scene scene = new Scene(pane, 1200, 700);
primaryStage.setTitle("Black Jack"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
HitHandlerClass handlerHit = new HitHandlerClass();
btHitY = " ";
btHit.setOnAction(handlerHit);
/* if (btHitY.equals("Hit")); {
NumberPlayerCards = NumberPlayerCards + 1;
NUMBER_OF_CARDS = NUMBER_OF_CARDS + 1;
PlayerCards[NumberPlayerCards - 1] = deck[NUMBER_OF_CARDS - 1];
for (int j = 0; j < NumberPlayerCards; j++){
System.out.println(PlayerCards[j]);
}
System.out.println(NumberPlayerCards);
int CardForPrint2 = PlayerCards[NumberPlayerCards - 1] + 1;
imagesP[NumberPlayerCards - 1] = new Image(URLBase + CardForPrint2 + ".png");
pane.add(new ImageView(imagesP[NumberPlayerCards - 1]), NumberPlayerCards, 0);
btHitY = " ";
primaryStage.show();
} */
}
/**
* The main method is only needed for the IDE with limited
* JavaFX support. Not needed for running from the command line.
* #param args
*/
public static void main(String[] args) {
launch(args);
}
class HitHandlerClass implements EventHandler<ActionEvent> {
#Override
public void handle(ActionEvent e) {
NumberPlayerCards = NumberPlayerCards + 1;
NUMBER_OF_CARDS = NUMBER_OF_CARDS + 1;
PlayerCards[NumberPlayerCards - 1] = deck[NUMBER_OF_CARDS - 1];
for (int j = 0; j < NumberPlayerCards; j++){
System.out.println(PlayerCards[j]);
}
System.out.println(NumberPlayerCards);
int CardForPrint2 = PlayerCards[NumberPlayerCards - 1] + 1;
imagesP[NumberPlayerCards - 1] = new Image(URLBase + CardForPrint2 + ".png");
pane.add(new ImageView(imagesP[NumberPlayerCards - 1]), NumberPlayerCards, 0);
btHitY = " ";
}
}
}
You declare this global
public int deck[];
and then local
int[] deck = new int[52];
So the global never gets initialized and gives you a Nullpointer Exception.
Solution:
deck = new int[52];
Same for the other variables.
public class BlackJackGame extends Application {
//snip
public int NUMBER_OF_CARDS;
public int deck[];
//snip
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
//Create array deck, suit string, and rank string
int[] deck = new int[52];
int NUMBER_OF_CARDS = 4;
//snip
You've declared deck[] and NUMBER_OF_CARDS at a higher scope, then redeclared them later, at a lower scope.
To fix these issues, simply remove the type declaration in the start method.
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
//Create array deck, suit string, and rank string
deck = new int[52];
NUMBER_OF_CARDS = 4;
//snip
As a side note, I would like to recommend you read up a little bit on Code conventions for Java/Javafx, as they help other programmers read your code by providing a standard style.
I want to create a table-like structure and stroke the borders and just some of the inner lines to help guide the viewer's eye. This is just a snippet of a much larger structure to help illustrate the goal:
click to view sample here
I am currently using GridPane rather than TableView because this structure is both input/output. The user will need to view the information and update some of the numbers on the screen.
The trouble is that turning gridlines on for the entire structure becomes very noisy visually. So instead I want to use CSS to only put lines around certain elements within the GridPane.
But then with CSS I run into a complex mess. For example the ward1 cell needs to be stroked on the left, top and bottom. The ward2 cell needs to be stroked on just the top and bottom, same for ward3 ... the ward7 cell needs top, right and bottom and so on.
Is there a better way to do this - either with CSS, or with a better layout, that would make it easier to stroke just the parts of the grid that I want stroked?
(currently using Java 1.7.0_40-b43 and Scene Builder 1.1)
A GridPane doesn't generate cells like a TableView or ListView. It is basically just a Pane with special constraints for the nodes you add to it. Unfortunately, this means creating your own cells and applying styles to them which can get very messy.
With some planning and some helper methods, it is possible to keep things somewhat tidy. The following generates a GridPane with styles similar to the example image provided using StackPanes as cells. I only used labels, so you would have to replace with TextFields or whatever controls you are using for input. This code is just to demonstrate one way to keep things orderly.
Note that rotating labels will not rotate their bounds and therefore will not behave as expected within GridPane constraints, so in this case, it is best to put them in a Group first:
public static void main(final String... a) {
Application.launch(a);
}
#Override
public void start(final Stage primaryStage) throws Exception {
GridPane grid = new GridPane();
grid.setPadding(Insets.EMPTY);
grid.setVgap(0);
grid.setHgap(0);
grid.setAlignment(Pos.TOP_LEFT);
ColumnConstraints column = new ColumnConstraints();
column.setHgrow(Priority.ALWAYS);
column.setHalignment(HPos.LEFT);
column.setFillWidth(true);
grid.getColumnConstraints().add(column);
for (int i = 0; i < 12; i++) {
column = new ColumnConstraints();
column.setHgrow(Priority.SOMETIMES);
column.setHalignment(HPos.CENTER);
grid.getColumnConstraints().add(column);
}
// row 0
addCell(grid, 1, 0, 7, 1, "Ward/Branch Actual", Pos.CENTER, true, false, false, false);
addCell(grid, 8, 0, 3, 1, "Current Qtr", Pos.CENTER, true, false, false, false);
addCell(grid, 11, 0, 2, 1, "Stake Totals", Pos.CENTER, true, false, false, false);
// row 1
addCell(grid, 0, 1, 1, 1, "Members/Families", Pos.BOTTOM_LEFT, true, true, false, false);
for (int i = 1; i < 8; i++) {
addVerticalCell(grid, i, 1, "Ward " + i, (i == 7));
}
addVerticalCell(grid, 8, 1, "Actual", false);
addVerticalCell(grid, 9, 1, "Potential", false);
addVerticalCell(grid, 10, 1, "%", true);
addVerticalCell(grid, 11, 1, "% 1 year ago", false);
addVerticalCell(grid, 12, 1, "% 5 years ago", true);
// row 2
addDividerRow(grid, 2);
// row 3
addCell(grid, 0, 3, 1, 1, "Total Members", Pos.CENTER_LEFT, false, true, true, true);
for (int i = 1; i < 13; i++) {
addCell(grid, i, 3, 1, 1, "78%", Pos.CENTER, false, (i == 7 || i == 10 || i == 12), true, true);
}
// row 4
addCell(grid, 0, 4, 1, 1, "Total Families", Pos.CENTER_LEFT, false, true, false, false);
for (int i = 1; i < 13; i++) {
addCell(grid, i, 4, 1, 1, "83%", Pos.CENTER, false, (i == 7 || i == 10 || i == 12), false, false);
}
// row 5
addDividerRow(grid, 5);
final Scene scene = new Scene(grid, 1000, 700);
scene.getStylesheets().add("styles/style.css"); // or wherever you put it
primaryStage.setScene(scene);
primaryStage.setTitle("Styled GridPane Test");
primaryStage.show();
}
private void addCell(GridPane grid, int col, int row, int cspan, int rspan, String text, Pos pos, boolean isBold, boolean hasRightBorder, boolean hasBottomBorder, boolean isShaded) {
Label label = new Label(text);
if (isBold) {
label.getStyleClass().add("h1");
}
StackPane spane = new StackPane(label);
spane.setAlignment(pos);
if (hasBottomBorder && hasRightBorder) {
spane.getStyleClass().addAll("bd", "bdrb");
} else if (hasBottomBorder && !hasRightBorder) {
spane.getStyleClass().addAll("bd", "bdb");
} else if (!hasBottomBorder && hasRightBorder) {
spane.getStyleClass().addAll("bd", "bdr");
}
if (isShaded) {
spane.getStyleClass().addAll("shaded");
}
grid.add(spane, col, row, cspan, rspan);
}
private void addVerticalCell(GridPane grid, int col, int row, String text, boolean hasRightBorder){
Label label = new Label(text);
Group group = new Group(label);
StackPane spane = new StackPane(group);
spane.getStyleClass().addAll("vert", "bd");
if (hasRightBorder) {
spane.getStyleClass().add("bdtr");
} else {
spane.getStyleClass().add("bdt");
}
grid.add(spane, col, row, 1, 1);
}
private void addDividerRow(GridPane grid, int row) {
StackPane stack_0_2 = new StackPane();
stack_0_2.getStyleClass().addAll("bd", "divider");
grid.add(stack_0_2, 0, row, 1, 1);
StackPane stack_1_2 = new StackPane();
stack_1_2.getStyleClass().addAll("bd", "divider");
grid.add(stack_1_2, 1, row, 7, 1);
StackPane stack_1_8 = new StackPane();
stack_1_8.getStyleClass().addAll("bd", "divider");
grid.add(stack_1_8, 8, row, 3, 1);
StackPane stack_1_11 = new StackPane();
stack_1_11.getStyleClass().addAll("bd", "divider");
grid.add(stack_1_11, 11, row, 2, 1);
}
/*
style.css
*/
.root {
-fx-background-color: rgb(255, 255, 255);
-fx-padding: 4px;
}
.label {
-fx-font-size: 12px;
-fx-padding: 2px 4px 2px 4px;
}
.h1 {
-fx-font-size: 14px;
-fx-font-weight: bold;
}
.vert {
-fx-alignment: BOTTOM_CENTER;
}
.vert .label {
-fx-rotate: -90;
}
.bd {
-fx-border-color: rgb(180, 180, 180);
-fx-border-width: 1;
}
.bdt {
-fx-border-width: 1px 0 0 0;
}
.bdtr {
-fx-border-width: 1px 1px 0 0;
}
.bdr {
-fx-border-width: 0 1px 0 0;
}
.bdrb {
-fx-border-width: 0 1px 1px 0;
}
.bdb {
-fx-border-width: 0 0 1px 0;
}
.divider {
-fx-border-width: 1px 1px 1px 0;
-fx-padding: 2px;
}
.shaded {
-fx-background-color: rgb(230, 230, 230);
}