JavaFX ChoiceBox ContextMenu Position - java

I am new to stackoverflow and also to Java programming, though I do have some small programming background.
I am building a little program using JavaFX 8.0.0-b132 and JavaSE 8...
The program has a GUI and this GUI has a ChoiceBox. The architecture for the layout is:
AnchorPane - VBox - TitledPane - GridPane - HBox - ChoiceBox
I have modified the ChoiceBox extensively using CSS.
Everything is working as it should except for one problem:
When I start the program and open the ChoiceBox (per mouse click or with show()) for the first time, it will display it's ContextMenu at the bottom edge as it should; however, when I close and open it again (with mouse or programmatically) it will display the ContextMenu on top of the ChoiceBox open-button (wrong y position), such that the bottom of the currently selected cell coincides with the bottom of the open-button (meaning it will change position after I select another cell and open it again).
How do I prevent this and make the ContextMenu appear always at the bottom as it does at first?
Here is a snippet of the GUI part of the program with the affected control:
EDIT: problem solved: apparently this behavior is the intended ChoiceBox behavior; I posted in the JavaFX forums that it would be better to make the popup behave like that from the start i.e. the first time it is opened so as not to seem buggy.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.input.MouseEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.*;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
import javafx.geometry.Insets;
import javafx.collections.*;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Side;
public class bugdemo extends Application {
// Elements needed in both threads
RadioButton radioBoxersOne = new RadioButton("One");
RadioButton radioBoxersTwo = new RadioButton("Two");
TextField warmupText = new TextField("skip warm up");
TextField noCyclesText = new TextField("3");
TextField cycleTimeText = new TextField("45");
TextField restingTimeText = new TextField("30");
String[] warmupTFtext = {"skip warm up", "\u00FCberspringen"};
public static void main(String... args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
// root container
AnchorPane anchor = new AnchorPane();
// Options TitledPane
GridPane trainingOptions = new GridPane();
ToggleGroup toggleGroup = new ToggleGroup();
radioBoxersOne.setToggleGroup(toggleGroup);
radioBoxersTwo.setToggleGroup(toggleGroup);
radioBoxersOne.setSelected(true);
HBox hbToggle = new HBox(15, radioBoxersOne, radioBoxersTwo);
hbToggle.setPadding(new Insets(5,0,0,0));
ObservableList<String> langList = FXCollections.observableArrayList("English", "Deutsch");
ChoiceBox<String> langBox = new ChoiceBox<String>(langList);
langBox.setValue("English");
HBox hbLangBox = new HBox(0, langBox);
hbLangBox.setPadding(new Insets(5,0,0,0));
Label warmupOptionsLabel = new Label("Warm up time (min): ");
Label noCyclesOptionsLabel = new Label("Number of cycles: ");
Label cycleOptionsLabel = new Label("Cycle time (sec): ");
Label restingOptionsLabel = new Label("Resting time (sec): ");
Label noBoxersOptionsLabel = new Label("Number of boxers: ");
Label langOptionsLabel = new Label("Language: ");
trainingOptions.add(warmupOptionsLabel, 0, 0);
trainingOptions.add(noCyclesOptionsLabel, 0, 1);
trainingOptions.add(cycleOptionsLabel, 0, 2);
trainingOptions.add(restingOptionsLabel, 0, 3);
trainingOptions.add(noBoxersOptionsLabel, 0, 4);
trainingOptions.add(langOptionsLabel, 0, 5);
trainingOptions.add(warmupText, 1, 0);
trainingOptions.add(noCyclesText, 1, 1);
trainingOptions.add(cycleTimeText, 1, 2);
trainingOptions.add(restingTimeText, 1, 3);
trainingOptions.add(hbToggle, 1, 4);
trainingOptions.add(hbLangBox, 1, 5);
TitledPane TPane_in = new TitledPane("Options", trainingOptions);
// Options TPane and Buttons together as UI (input)
VBox UI = new VBox(10, /* hbButtons ,*/ TPane_in);
anchor.getChildren().add(UI);
AnchorPane.setLeftAnchor(UI, 25.0);
AnchorPane.setTopAnchor(UI, 100.0);
// EventHandlers for the radio-buttons
radioBoxersOne.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
/* if (!singleBoxer){
trainingProgress.getChildren().remove(boxerLabel);
trainingProgress.getChildren().remove(boxerText);
}
changeTextFlow();
singleBoxer = true; */
}
});
radioBoxersTwo.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
/* singleBoxer = false;
trainingProgress.add(boxerLabel, 0, 3);
trainingProgress.add(boxerText, 1, 3);
changeTextFlow(); */
}
});
// "EventHandler" for the language ChoiceBox
langBox.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>() {
public void changed(ObservableValue ov, Number value, Number new_value) {
/* language = (int)new_value;
changeLanguage(); */
}
});
// initialize scene and show stage
Scene scene = new Scene(anchor, 800, 650);
primaryStage.setScene(scene);
primaryStage.setResizable(false); // resizeable on/off
// import CSS file
// scene.getStylesheets().add(Letsbox.class.getResource("Training.css").toExternalForm());
primaryStage.show();
langBox.show();
langBox.hide();
langBox.show();
}
}
In this example no CSS is used, but the problem persists...
I tried to fix it with:
/* langBox.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent e) {
ContextMenu cm = langBox.getContextMenu();
cm.show(cm.getOwnerNode(), Side.BOTTOM, 0.0, 0.0);
}
}); */
but it throws a NullPointerException...
Please tell me how I could fix this :)

public class Main extends Application{
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Group(), 450, 250);
Button notification = new Button();
notification.setPrefSize(80, 60);
notification.setAlignment(Pos.CENTER);
MenuItem item1 = new MenuItem("About");
item1.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
System.out.println("About");
}
});
MenuItem item2 = new MenuItem("Preferences");
item2.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
System.out.println("Preferences");
}
});
MenuItem item3 = new MenuItem("About");
item1.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
System.out.println("About");
}
});
MenuItem item4 = new MenuItem("Preferences");
item2.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
System.out.println("Preferences");
}
});
MenuItem item5 = new MenuItem("About");
item1.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
System.out.println("About");
}
});
MenuItem item6 = new MenuItem("Preferences");
item2.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
System.out.println("Preferences");
}
});
MenuItem item7 = new MenuItem("About");
item1.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
System.out.println("About");
}
});
MenuItem item8 = new MenuItem("Preferences");
item2.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
System.out.println("Preferences");
}
});
final ContextMenu contextMenu = new ContextMenu(item1, item2,item3, item4,item5, item6,item7, item8);
contextMenu.setMaxSize(50, 50);
contextMenu.setOnShowing(new EventHandler<WindowEvent>() {
public void handle(WindowEvent e) {
System.out.println("showing");
}
});
contextMenu.setOnShown(new EventHandler<WindowEvent>() {
public void handle(WindowEvent e) {
System.out.println("shown");
}
});
// contextMenu.hide();
notification.setContextMenu(contextMenu);
GridPane grid = new GridPane();
grid.setVgap(4);
grid.setHgap(10);
grid.setPadding(new Insets(5, 5, 5, 5));
grid.add(new Label("To: "), 0, 0);
grid.add(notification, 1, 0);
Group root = (Group) scene.getRoot();
root.getChildren().add(grid);
stage.setScene(scene);
stage.show();
notification.addEventHandler(MouseEvent.MOUSE_CLICKED, (MouseEvent me)->{
if(me.getButton()==MouseButton.PRIMARY ){
System.out.println("Mouse Left Pressed");
System.out.println(notification.getScaleX());
System.out.println(notification.getScaleY());
System.out.println(me.getScreenX());
System.out.println(me.getScreenY());
contextMenu.show(notification,Side.TOP,0,0);
//contextMenu.show(notification,me.getScreenX(),me.getScreenY());
}else{
contextMenu.hide();
}
});
}
}

Related

How to drag and drop button onto GridPane?

I'm working on a school project creating a simple battleship game and i want to use the Drag And Drop function to drag buttons from HBox on the bottom of the screen to the GridPane that the player uses to place ships on. But i can't get it to work properly. Here's a picture of my board per now.
I have tried to use the button.setOnMouseDragged(e -> {CODE HERE}); but it doesnt work.
Here is the code i used for my window
public class GridOrganizer {
private BorderPane borderPane;
public GridOrganizer() {
borderPane = new BorderPane();
borderPane.setStyle("-fx-background-color: grey;");
borderPane.setPrefHeight(600);
borderPane.setPrefWidth(600);
createGrid();
}
public void createGrid() {
//Creates the grids where the game is played and buttons/ships to place on grid
GridPane playerGrid = new GridPane();
GridPane enemyGrid = new GridPane();
Insets padding = new Insets(10);
//Create playergrid
for (int i = 0; i < 10; i++) {
playerGrid.getColumnConstraints().add(new ColumnConstraints(50)); //50 wide
playerGrid.getRowConstraints().add(new RowConstraints(50));
}
//Create enemygrid
for (int i = 0; i < 10; i++) {
enemyGrid.getColumnConstraints().add(new ColumnConstraints(50)); //50 wide
enemyGrid.getRowConstraints().add(new RowConstraints(50));
}
//looping through row and columns and adds buttons
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
Button button = new Button();
button.setPrefHeight(50);
button.setPrefWidth(50);
GridPane.setConstraints(button, j, i); //(button, column, row)
playerGrid.getChildren().add(button); //add button on each index
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
//HIT or MISS
System.out.println("Row: " + GridPane.getRowIndex(button) + ", Column: " + GridPane.getColumnIndex(button));
button.setStyle("-fx-background-color: grey;");
}
});
}
}
//..same with enemy grid
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
Button button = new Button();
button.setPrefHeight(50);
button.setPrefWidth(50);
GridPane.setConstraints(button, j, i); //(button, column, row)
enemyGrid.getChildren().add(button); //add button on each index
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
System.out.println("Row: " + GridPane.getRowIndex(button) + ", Column: " + GridPane.getColumnIndex(button));
button.setStyle("-fx-background-color: grey;");
}
});
}
}
//Make buttons for the ships
Button rowboat = new Button("Rowboat");
Button sailboat = new Button("Sailboat");
Button submarine = new Button("Submarine");
Button destroyer = new Button("Destroyer");
Button battleship = new Button("Battleship");
//Size the ship buttons to match game description
battleship.setPrefHeight(50);
battleship.setPrefWidth(250); //size 5
destroyer.setPrefHeight(50);
destroyer.setPrefWidth(200); //size 4
submarine.setPrefHeight(50);
submarine.setPrefWidth(150); //size 3
sailboat.setPrefHeight(50);
sailboat.setPrefWidth(150); //size 3
rowboat.setPrefHeight(50);
rowboat.setPrefWidth(100); //size 2
//Drags button
rowboat.setOnMouseDragged(e -> {
//CODE HERE
});
//Drops button on grid
//CODE HERE
sailboat.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
//PLACE SHIP
}
});
submarine.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
//PLACE SHIP
}
});
destroyer.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
//PLACE SHIP
}
});
battleship.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
//PLACE SHIP
}
});
HBox ships = new HBox(); //Horizontal box
ships.getChildren().addAll(rowboat, sailboat, submarine, destroyer, battleship); //Add buttons to horizontal box
//Add grids and ship buttons to pane with padding
borderPane.setLeft(enemyGrid);
BorderPane.setMargin(enemyGrid, padding);
borderPane.setRight(playerGrid);
BorderPane.setMargin(playerGrid, padding);
borderPane.setBottom(ships);
BorderPane.setMargin(ships, padding);
}
public Pane getGrid() {
return borderPane;
}
}
The plan here is to start a drag event with the data needed to create your button when the drag event finished. In your code, it looks like you have added the Buttons into the Grid already. That means you need to only transfer a String to change the Button's text. In my code, I am using a StackPane when creating the Grid. I then create and add the Buttons later. You approach may be better. I have looked that far. I have added an MCVE (Altered code from here):
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.input.*;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
* Demonstrates a drag-and-drop feature.
*/
public class HelloDragAndDrop extends Application
{
#Override
public void start(Stage stage)
{
//Source Buttons.
final Button boat1 = new Button("boat1");
final Button boat2 = new Button("boat2");
final Button boat3 = new Button("boat3");
final Button boat4 = new Button("boat4");
//Adding OnDragDetected to source Buttons.
setOnDragDetected(boat1);
setOnDragDetected(boat2);
setOnDragDetected(boat3);
setOnDragDetected(boat4);
//Adding onDragDone to source Buttons.
setOnDragDone(boat1);
setOnDragDone(boat2);
setOnDragDone(boat3);
setOnDragDone(boat4);
//Creating GridPane
GridPane gridPane = new GridPane();
gridPane.setVgap(5);
gridPane.setHgap(5);
gridPane.setPadding(new Insets(5, 5, 5, 5));
gridPane.setStyle("-fx-background-color: black;");
//Adding StackPane to every Cell in the GridPane and Adding the Target Events to each StackPane.
for (int i = 0; i < 6; i++) {
StackPane stackPane = new StackPane();
stackPane.setPrefSize(150, 50);
stackPane.setStyle("-fx-background-color: yellow;");
setOnDragOver(stackPane);
setOnDragEntered(stackPane);
setOnDragExited(stackPane);
setOnDragDropped(stackPane);
gridPane.add(stackPane, i / 3, i % 3);
}
HBox root = new HBox(new VBox(boat1, boat2, boat3, boat4), gridPane);
stage.setTitle("Hello Drag And Drop");
Scene scene = new Scene(root, 400, 200);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args)
{
Application.launch(args);
}
//source events handlers
public void setOnDragDetected(Button source)
{
source.setOnDragDetected((MouseEvent event) -> {
/* drag was detected, start drag-and-drop gesture*/
System.out.println("onDragDetected");
/* allow any transfer mode */
Dragboard db = source.startDragAndDrop(TransferMode.ANY);
/* put a string on dragboard */
ClipboardContent content = new ClipboardContent();
content.putString(source.getText());
db.setContent(content);
event.consume();
});
}
public void setOnDragDone(Button source)
{
source.setOnDragDone((DragEvent event) -> {
/* the drag-and-drop gesture ended */
System.out.println("onDragDone");
/* if the data was successfully moved, clear it */
// if (event.getTransferMode() == TransferMode.MOVE) {
// source.setText("");
// }
event.consume();
});
}
//target event handlers
public void setOnDragOver(StackPane target)
{
target.setOnDragOver((DragEvent event) -> {
/* data is dragged over the target */
System.out.println("onDragOver");
/* accept it only if it is not dragged from the same node
* and if it has a string data */
if (event.getGestureSource() != target
&& event.getDragboard().hasString()) {
/* allow for both copying and moving, whatever user chooses */
event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
}
event.consume();
});
}
public void setOnDragEntered(StackPane target)
{
target.setOnDragEntered((DragEvent event) -> {
/* the drag-and-drop gesture entered the target */
System.out.println("onDragEntered");
/* show to the user that it is an actual gesture target */
if (event.getGestureSource() != target
&& event.getDragboard().hasString()) {
target.setStyle("-fx-background-color: green;");
}
event.consume();
});
}
public void setOnDragExited(StackPane target)
{
target.setOnDragExited((DragEvent event) -> {
/* mouse moved away, remove the graphical cues */
target.setStyle("-fx-background-color: transparent;");
event.consume();
});
}
public void setOnDragDropped(StackPane target)
{
target.setOnDragDropped((DragEvent event) -> {
/* data dropped */
System.out.println("onDragDropped");
/* if there is a string data on dragboard, read it and use it */
Dragboard db = event.getDragboard();
boolean success = false;
if (db.hasString()) {
//target.setText(db.getString());
Button tempBoat = new Button(db.getString());
tempBoat.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
target.getChildren().clear();
target.getChildren().add(tempBoat);
success = true;
}
/* let the source know whether the string was successfully
* transferred and used */
event.setDropCompleted(success);
event.consume();
});
}
}
In this code, the Buttons that represent the Boats all have onDragDetected and onDragDone event handlers attached. They are considered Source/start of a Drag event. For every cell in the GridPane, a StackPane is added. These StackPanes are considered the Target/areas to drop drag events. Each StackPane has onDragOver, onDragEntered, onDragDropped, and onDragExited attached. Once a drag event is complete, the StackPane/Target that receives the event gets a new Button as a child with the same name as the Source Button.

JavaFx Transition Animation with multiple nodes

I am trying to implement a Transition effect on a node, below is SSCE,
public class GridPaneExperiments extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Experiment");
Button button2 = new Button("Expand");
Button button3 = new Button("Button 3");
Button button4 = new Button("Button 4");
GridPane gridPane = new GridPane();
ToolBar bar = new ToolBar();
bar.getItems().addAll(button3, button4);
gridPane.add(button2, 0, 0, 1, 1);
gridPane.add(bar, 1, 0, 1, 1);
//Handle Mouse on Button
button2.setOnMouseEntered((MouseEvent event) -> {
TranslateTransition openNav = new TranslateTransition(new Duration(350), bar);
openNav.setToX(0);
if (bar.getTranslateX() != 0) {
openNav.play();
}
});
button2.setOnMouseExited((MouseEvent event) -> {
TranslateTransition closeNav = new TranslateTransition(new Duration(350), bar);
closeNav.setToX(-(((GridPane) gridPane).getWidth()));
closeNav.play();
});
//Handle Mouse on ToolBar
bar.setOnMouseExited((MouseEvent event) -> {
TranslateTransition closeNav = new TranslateTransition(new Duration(350), bar);
closeNav.setToX(-(((GridPane) gridPane).getWidth()));
closeNav.play();
});
bar.setOnMouseEntered((MouseEvent event) -> {
TranslateTransition openNav = new TranslateTransition(new Duration(350), bar);
openNav.setToX(0);
if (bar.getTranslateX() != 0) {
openNav.play();
}
});
Scene scene = new Scene(gridPane, 240, 100);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
What I am trying to achieve is:
When mouse entered the Button "Expand" a Node will be opened to its right, after which if mouse entered the opened node it should not get close .
When mouse entered the Button "Expand" a Node will be opened and mouse exited from Button "Expand" (but not entered the opened node) , then the opened node should be closed.
Currently I am playing the Transition animation in Mouse events of both Button and Node.
How can I achieve this?
Just use a single animation for closing and opening. This way you can reverse the animation easily, don't run the risk of starting multiple animations in parallel and starting a closing animation is not an issue, since you change the animation to a opening animation when entering one of the nodes:
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Experiment");
Button button2 = new Button("Expand");
Button button3 = new Button("Button 3");
Button button4 = new Button("Button 4");
GridPane gridPane = new GridPane();
ToolBar bar = new ToolBar();
bar.getItems().addAll(button3, button4);
bar.setTranslateX(-10000); // somewhere outside view
gridPane.add(button2, 0, 0, 1, 1);
gridPane.add(bar, 1, 0, 1, 1);
TranslateTransition transition = new TranslateTransition(Duration.millis(300), bar);
transition.setToX(0);
EventHandler<MouseEvent> enterHandler = (MouseEvent event) -> {
transition.setFromX(-gridPane.getWidth());
Duration time = transition.getCurrentTime();
transition.setRate(1);
transition.playFrom(time);
};
EventHandler<MouseEvent> exitHandler = (MouseEvent event) -> {
if (!(button2.isHover() || bar.isHover())) {
Duration time = transition.getCurrentTime();
transition.setRate(-1);
transition.playFrom(time);
}
};
//Handle Mouse on Button
button2.setOnMouseEntered(enterHandler);
bar.setOnMouseEntered(enterHandler);
button2.setOnMouseExited(exitHandler);
bar.setOnMouseExited(exitHandler);
Scene scene = new Scene(gridPane, 240, 100);
primaryStage.setScene(scene);
primaryStage.show();
}
you can simply achive your task using a helper HBox and setting setOnMouseExited to only that:
public class GridPaneExperiments extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Experiment");
Button button2 = new Button("Expand");
Button button3 = new Button("Button 3");
Button button4 = new Button("Button 4");
ToolBar bar = new ToolBar();
bar.getItems().addAll(button3, button4);
GridPane gridPane = new GridPane();
HBox hbox = new HBox(button2, bar);
hbox.setStyle("-fx-border-color: red");
gridPane.add(hbox, 0, 0);
//Handle Mouse on Button
button2.setOnMouseEntered((MouseEvent event) -> {
TranslateTransition openNav = new TranslateTransition(new Duration(350), bar);
openNav.setToX(0);
if (bar.getTranslateX() != 0) {
openNav.play();
}
});
// button2.setOnMouseExited((MouseEvent event) -> {
// TranslateTransition closeNav = new TranslateTransition(new Duration(350), bar);
// closeNav.setToX(-(((GridPane) gridPane).getWidth()));
// closeNav.play();
// });
//Handle Mouse on ToolBar
hbox.setOnMouseExited((MouseEvent event) -> {
TranslateTransition closeNav = new TranslateTransition(new Duration(350), bar);
closeNav.setToX(-(((GridPane) gridPane).getWidth()));
closeNav.play();
});
// bar.setOnMouseEntered((MouseEvent event) -> {
// TranslateTransition openNav = new TranslateTransition(new Duration(350), bar);
// openNav.setToX(0);
// if (bar.getTranslateX() != 0) {
// openNav.play();
// }
// });
Scene scene = new Scene(gridPane, 240, 100);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}

When trying to add items to a JavaFX TableView through an ObservableList, the TableView items won't show

I'm making a grocery list app, and it has the feature to add items to the list(a tableview) along with the # of items and price. THe thing is, it works(because the tableview doesnt say "No content in table") But the table is blank. Any suggestions?
Code:
package listproject;
public class Main extends Application{
public Node getNodeByRowColumnIndex(final int row,final int column,GridPane gridPane) {
Node result = null;
ObservableList<Node> childrens = gridPane.getChildren();
for(Node node : childrens) {
if(gridPane.getRowIndex(node) == row && gridPane.getColumnIndex(node) == column) {
result = node;
break;
}
}
return result;
}
ObservableList<Product> data =
FXCollections.observableArrayList(
);
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Grocery List");
primaryStage.setWidth(450);
primaryStage.setHeight(800);
//menu buttons
Button addLinkMain = new Button("Add an Item");
Button addLinkTitle = new Button("Add an Item");
Button mainLinkAdd = new Button("Back");
Button mainLinkTitle = new Button("Back");
Button addItem = new Button("Add");
Button setTitleMenu = new Button("Set Title");
Button setTitleAdd = new Button("Set Title");
Button clear = new Button("Clear");
//items for the item addition screen
TextField title = new TextField("Name");
TextField quantity = new TextField("#");
TextField price = new TextField("$");
HBox addBox = new HBox();
BorderPane addBorder = new BorderPane();
HBox addMenu = new HBox();
//mainScene items
BorderPane pane = new BorderPane();
HBox mainscenemenu=new HBox();
TableView<Product> tableview = new TableView<Product>();
//tableview items
TableColumn itemTitle=new TableColumn("Product");
TableColumn itemQuantity=new TableColumn("Quantity");
TableColumn itemPrice=new TableColumn("Price");
//settitle items
TextField listTitle= new TextField("Rename the List");
Button setTittle = new Button("Set List Title");
BorderPane setTitlePane=new BorderPane();
StackPane setTitleFieldContainer=new StackPane();
HBox setTitleOwnMenu = new HBox();
//Scene declaration
Scene mainScene = new Scene(pane);
primaryStage.setScene(mainScene);
Scene addScene = new Scene(addBorder);
Scene setTitleScene = new Scene(setTitlePane);
//Main Scene
pane.setCenter(tableview);
pane.setBottom(mainscenemenu);
tableview.getColumns().addAll(itemTitle,itemQuantity,itemPrice);
mainscenemenu.getChildren().addAll(setTitleMenu,clear,addLinkMain);
tableview.setItems(data);
//Item Addition Scene
addBox.getChildren().addAll(title,quantity,price);
addMenu.getChildren().addAll(mainLinkAdd,addItem,setTitleAdd);
addBorder.setCenter(addBox);
addBorder.setBottom(addMenu);
//Set Title Scene
setTitleFieldContainer.getChildren().addAll(listTitle);
setTitleOwnMenu.getChildren().addAll(addLinkTitle,setTittle,mainLinkTitle);
setTitlePane.setCenter(setTitleFieldContainer);
setTitlePane.setBottom(setTitleOwnMenu);
//Menu Button Event Handlers
addLinkMain.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
primaryStage.setScene(addScene);
}
});
addLinkTitle.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
primaryStage.setScene(addScene);
}
});
mainLinkAdd.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
primaryStage.setScene(mainScene);
}
});
mainLinkTitle.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
primaryStage.setScene(mainScene);
}
});
setTitleMenu.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
primaryStage.setScene(setTitleScene);
}
});
setTitleAdd.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
primaryStage.setScene(setTitleScene);
}
});
//Adding an Item to the List *unfinished
addItem.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent event) {
data.add(new Product(title.getText(),quantity.getText(),price.getText()));
}
});
//Changing the Title of The List
setTittle.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
primaryStage.setTitle(listTitle.getText());
}
});
//Clearing the List
clear.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
tableview.getItems().clear();
}
});
//Show the Stage
primaryStage.show();
}
public static void main(String[] args){
launch(args);
}
}
You never set the cellValueFactorys for the table's columns. You need to do this to specify the part of the items that should be displayed in the column.
An example with anonymus classes as cellValueFactorys can be found here.
Using PropertyValueFactory could reduce the amount of code needed. More about this here.
A tutorial can be found here: https://docs.oracle.com/javase/8/javafx/user-interface-tutorial/table-view.htm

JavaFx Program throws java.lang.reflect.InvocationTargetException

This is my first question here so donĀ“t be to mad at me if something is wrong. I am currently programming an idle like game for java with help of JavaFx.
The code here under was written with eclipse mars and JavaFx. Eclipse shows to me that the code is right but when I want to start the program it throws this block of error messages:
public class Main extends Application{
private static final Color color = Color.web("#464646");
Button button3 = new Button("D");
DropShadow shadow = new DropShadow();
Label label = new Label();
public static void main(String[] args) throws Exception {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception{
Scene scene = new Scene(new Group());
primaryStage.setTitle("Button Sample");
primaryStage.setWidth(300);
primaryStage.setHeight(190);
label.setFont(Font.font("Times New Roman", 22));
label.setTextFill(color);
Image imageDecline = new Image(getClass().getResourceAsStream("../not.png"));
Image imageAccept = new Image(getClass().getResourceAsStream("../ok.png"));
VBox vbox = new VBox();
vbox.setLayoutX(20);
vbox.setLayoutY(20);
HBox hbox1 = new HBox();
HBox hbox2 = new HBox();
Button button1 = new Button("Accept");
button1.setStyle("-fx-font: 22 arial; -fx-base: #b6e7c9;");
button1.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
label.setText("Accepted");
}
});
Button button2 = new Button("Accept");
button2.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
label.setText("Accepted");
}
});
button3.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
label.setText("Declined");
}
});
button3.addEventHandler(MouseEvent.MOUSE_ENTERED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent e) {
button3.setEffect(shadow);
}
});
button3.addEventHandler(MouseEvent.MOUSE_EXITED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent e) {
button3.setEffect(null);
}
});
hbox1.getChildren().add(button2);
hbox1.getChildren().add(button3);
hbox1.getChildren().add(label);
hbox1.setSpacing(10);
hbox1.setAlignment(Pos.BOTTOM_CENTER);
Button button4 = new Button();
button4.setGraphic(new ImageView(imageAccept));
button4.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
label.setText("Accepted");
}
});
Button button5 = new Button();
button5.setGraphic(new ImageView(imageDecline));
button5.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
label.setText("Declined");
}
});
hbox2.getChildren().add(button4);
hbox2.getChildren().add(button5);
hbox2.setSpacing(25);
vbox.getChildren().add(button1);
vbox.getChildren().add(hbox1);
vbox.getChildren().add(hbox2);
vbox.setSpacing(10);
((Group) scene.getRoot()).getChildren().add(vbox);
primaryStage.setScene(scene);
primaryStage.show();
}}
I hope anyone here has a hint or a solution for this problem :) Would be very nice from you.
Best Greetings,
Mike
I think your problem has to do with the input streams you use for creating your Image objects:
... = new Image(getClass().getResourceAsStream("../not.png"));
When I start your application in Eclipse, I get an InvocationTargetException as well. It is caused by a NullPointerException because the PNG files cannot be found.
Try to start your application without creating the Image objects and see if you still get any exceptions.

How do you call graphics class from main class in JavaFX?

I'm a really new programmer so idk if this question sounds really stupid but..
This is my main:
package culminating;
import javafx.application.Application;
& all other necessary imports...
public class CulminatingMAIN extends Application {
//Set Global variables
int count = 0;
String name;
String gender = "Boy";
Label testLabel = new Label(gender + " has been selected");
#Override
public void start(Stage primaryStage) throws Exception {
/**
* ************************ SCENE 1 WORK *************************
*/
TextField nameTextField = new TextField();
nameTextField.setMaxWidth(100);
Label nameLabel = new Label("Please enter your name.");
Label genderLabel = new Label();
Label titleLabel = new Label("Math Adventure!");
titleLabel.setFont(Font.font("Arial", FontWeight.BOLD, 30));
Rectangle titleRectangle = new Rectangle();
titleRectangle.setFill(Color.TOMATO);
titleRectangle.setWidth(280);
titleRectangle.setHeight(60);
titleRectangle.setStroke(Color.BLACK);
titleRectangle.setStrokeWidth(2.0);
StackPane root = new StackPane(titleRectangle, titleLabel);
//Set VBox properties
VBox vbox1 = new VBox(25);
vbox1.setAlignment(Pos.TOP_CENTER);
vbox1.setPadding(new Insets(60, 0, 0, 0));
vbox1.setStyle("-fx-background-color: lightskyblue");
HBox genderBtnBox = new HBox(25);
genderBtnBox.setAlignment(Pos.CENTER);
//Set Scene 1 buttons
Button enterNameBtn = new Button("Enter");
Button goToScene2Btn = new Button("Continue");
//Set Radio Button functionality here
final ToggleGroup genderGroup = new ToggleGroup();
RadioButton rb1 = new RadioButton("Boy");
rb1.setToggleGroup(genderGroup);
rb1.setUserData("Boy");
rb1.setSelected(true);
RadioButton rb2 = new RadioButton("Girl");
rb2.setToggleGroup(genderGroup);
rb2.setUserData("Girl");
//Add panes, labels and buttons to the VBox
vbox1.getChildren().addAll(root, nameLabel, nameTextField, enterNameBtn, genderLabel, genderBtnBox);
Scene scene = new Scene(vbox1, 500, 500);
primaryStage.setScene(scene);
primaryStage.setTitle("Culminating Project");
primaryStage.show();
/**
* ************************ SCENE 2 WORK *************************
*/
//THIS IS ROUGH WORK SO FAR
//Here, testing out new scene to see that it loads properly (and it does)
Circle testCircle = new Circle();
testCircle.setRadius(30);
testCircle.setFill(Color.YELLOW);
StackPane testPane = new StackPane(testCircle, testLabel);
Scene scene2 = new Scene(testPane, 500, 500);
/**
* ************************ EVENTS *************************
*/
//Stores user-entered name and prompts for user gender. Adds Continue button
enterNameBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
if ((count < 1) && (!nameTextField.getText().isEmpty())) {
name = nameTextField.getText();
genderLabel.setText("Hi " + name + "! Please select whether you are a boy or girl.");
genderBtnBox.getChildren().addAll(rb1, rb2);
vbox1.getChildren().add(goToScene2Btn);
count++;
}
}
});
//When pressed, changes the scene so that scene 2 is set instead
goToScene2Btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
primaryStage.setScene(scene2);
}
});
//Radio button selection is stored in gender variable
genderGroup.selectedToggleProperty().addListener(new ChangeListener<Toggle>() {
#Override
public void changed(ObservableValue<? extends Toggle> ov,
Toggle old_toggle, Toggle new_toggle) {
if (genderGroup.getSelectedToggle() != null) {
gender = genderGroup.getSelectedToggle().getUserData().toString();
testLabel.setText(gender + " has been selected");
}
}
});
if (gender.equals("boy")){
{
}
}
else if (gender.equals("girl")){
{
}
}
}
public static void main(String[] args) {
launch(args);
}
}
Now I have another class called CharacterGraphic, which I want to call and make the graphic I created in it appear.
package culminating;
& all the other imports
public class CharacterGraphic extends Culminating_JavaFX {
public void start(Stage primaryStage) throws Exception {
String gender = "boy";
Pane pane = new Pane();
pane.setStyle("-fx-background-color: LIGHTBLUE");
pane.setPrefSize(200, 200);
Circle head = new Circle();
head.setRadius(50);
head.setCenterX(240);
head.setCenterY(120);
head.setFill(Color.BURLYWOOD);
etc etc (all other graphics i made)
How do I do this???? And where would I do this?? Any answers really, really appreciated!

Categories