JavaFX Exception in Application start method file upload - image

High I've been trying for two days to create a link to a card folder, I'm currently trying to gain add a random card to the interface but I keep on getting an exception I don't understand how my class path is wrong I tried everything any help would be hugely appreciated. I'm at a bit of dead end and I can't find anything that will help with the issue online
my code is as follows
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
//Imports for components in this application.
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.control.RadioButton;
import javafx.scene.control.ToggleGroup;
//Imports for images.
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class HighLowJavafx extends Application {
// Declare labels
Label lblFirst, lblSecond, lblNext;
// Declare Radio Buttons
// radio button 1 with an empty string for its label
RadioButton rb1 = new RadioButton();
// radio button 2 with an empty string for its label
RadioButton rb2 = new RadioButton();
Button btnFirst, btnSecond;
// Declare controls at class scope.
Label lblStatus;
MenuBar mBar;
Image imgRight2;
ImageView imgViewRight;
public HighLowJavafx() {
// TODO Auto-generated constructor stub
}
#Override
public void init() {
// Instantiate components.
lblFirst = new Label("First Card Dealt:");
lblSecond = new Label("Second Card dealt:");
lblNext = new Label("Next Card Will Be:");
mBar = new MenuBar();
// ------------------------------------------------------------------
// File menu
Menu mnuFile = new Menu("File");
// add new game to file menu
MenuItem newGame = new MenuItem("New Game");
mnuFile.getItems().add(newGame);
// add shuffle to file menu
MenuItem shuffle = new MenuItem("Shuffle");
mnuFile.getItems().add(shuffle);
// add exit to file menu
MenuItem exit = new MenuItem("Exit");
mnuFile.getItems().add(exit);
// Add the menu to the menu bar.
mBar.getMenus().add(mnuFile);
// -------------------------------------------------------------------
// Create a help menu.
Menu mnuHelp = new Menu("Help");
// Add menu items to the help menu.
MenuItem aboutItem = new MenuItem("About");
mnuHelp.getItems().add(aboutItem);
aboutItem.setOnAction(ae -> showAboutDialog());
// Add the help menu to the menu bar.
mBar.getMenus().add(mnuHelp);
// ------------------------------------------------------------------
// Add image view
imgViewRight = new ImageView();
// Handle menu events.
newGame.setOnAction(ae -> {
});
}// init()
private void showAboutDialog() {
// Create a new stage and set sizes and title.
Stage dialog = new Stage();
dialog.setWidth(250);
dialog.setHeight(180);
dialog.setTitle("About");
// A label for the dialog.
Label lblAbout = new Label(" Luke Gallagher 2933229 ");
// An OK button for the dialog.
Button btnOK = new Button("OK");
// Handle events (clicks) on the dialog button.
btnOK.setOnAction(ae -> dialog.close());
btnOK.setMinWidth(120);
// Layout for the about dialog.
VBox vbAbout = new VBox();
BorderPane dlgBP = new BorderPane();
dlgBP.setCenter(btnOK);
// The button.
BorderPane bpLbl = new BorderPane();
bpLbl.setCenter(lblAbout);
// Set the padding.
vbAbout.setPadding(new Insets(40));
vbAbout.setSpacing(20);
// Add components.
vbAbout.getChildren().add(bpLbl);
vbAbout.getChildren().add(dlgBP);
// Create a scene.
Scene dlgScene = new Scene(vbAbout);
// Set the scene.
dialog.setScene(dlgScene);
// Show the stage.
dialog.show();
}// showAboutDialog()
public int cardNum() {
int Num = (int) Math.ceil(Math.random() * 52);
return Num;
}
#Override
public void start(Stage pStage) throws Exception {
// Set the title.
pStage.setTitle("Hi-Lo Card Game");
// Set the width and height.
// Width and height.
pStage.setWidth(600);
pStage.setHeight(400);
// images
// fileR = new File("cards/" + cardRight.toString(cardRight)+/".png")
// imgRight2= new Image("cards/2_of_clubs.png");
// imgViewRight.setImage(imgRight2);
// imgRight2= new Image(fileR.toURI().toString());
// imgViewRight.setImage(imgRight2);
// Instantiate components.
lblFirst = new Label("First Card Dealt:");
lblSecond = new Label("Second Card Dealt:");
lblNext = new Label("Next Card Will Be:");
// Start and stop buttons.
btnFirst = new Button("<- Deal First Card");
btnSecond = new Button("Deal Second Card ->");
// Manage button sizes.
btnFirst.setMaxWidth(130);
btnSecond.setMaxWidth(130);
// rb button functionality only one can be selected at once
ToggleGroup group = new ToggleGroup();
RadioButton rb1 = new RadioButton("Higher");
rb1.setToggleGroup(group);
rb1.setSelected(true);
RadioButton rb2 = new RadioButton("Lower");
rb2.setToggleGroup(group);
// Create a layout.
BorderPane bpMain = new BorderPane();
// Add components to the layout.
bpMain.setTop(mBar);
BorderPane.setAlignment(lblSecond, Pos.TOP_RIGHT);
BorderPane.setMargin(lblSecond, new Insets(12, 80, 12, 12));
bpMain.setRight(lblSecond);
VBox pane1 = new VBox();
pane1.getChildren().add(lblNext);
pane1.getChildren().add(rb1);
pane1.getChildren().add(rb2);
pane1.getChildren().add(btnFirst);
pane1.getChildren().add(btnSecond);
pane1.setSpacing(10);
BorderPane.setAlignment(pane1, Pos.CENTER);
BorderPane.setMargin(pane1, new Insets(40, 12, 12, 120));
bpMain.setCenter(pane1);
// images
// final Image img = new Image("cards/"+cardNum()+".png");
final ImageView imgView = new ImageView(".cards");
// vbox2
VBox pane2 = new VBox();
pane2.getChildren().add(lblFirst);
BorderPane.setAlignment(pane2, Pos.TOP_LEFT);
BorderPane.setMargin(pane2, new Insets(12, 12, 12, 12));
bpMain.setLeft(pane2);
// disables max button to keep everything in-line
pStage.resizableProperty().setValue(Boolean.FALSE);
// Create a scene.
Scene s = new Scene(bpMain);
// Set the scene.
pStage.setScene(s);
btnFirst.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
imgView.setImage(new Image("cards/2_of_clubs.png"));
pane2.getChildren().add(imgView);
pane2.getChildren().add(lblFirst);
BorderPane.setAlignment(pane2, Pos.TOP_LEFT);
BorderPane.setMargin(pane2, new Insets(12, 12, 12, 12));
bpMain.setLeft(pane2);
}
});
// Show the stage.
pStage.show();
}// start()
public static void main(String[] args) {
// Launch the application.
launch();
}// main()
}// class
the exceptions and errors I'm getting is as follows
Exception in Application start method
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.launcher.LauncherHelper$FXHelper.main(Unknown Source)
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$155(LauncherImpl.java:182)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.IllegalArgumentException: Invalid URL: Invalid URL or resource not found
at javafx.scene.image.Image.validateUrl(Image.java:1118)
at javafx.scene.image.Image.<init>(Image.java:620)
at javafx.scene.image.ImageView.<init>(ImageView.java:166)
at HighLowJavafx.start(HighLowJavafx.java:267)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
... 1 more
Caused by: java.lang.IllegalArgumentException: Invalid URL or resource not found
at javafx.scene.image.Image.validateUrl(Image.java:1110)
... 12 more
Exception running application HighLowJavafx
Picked up _JAVA_OPTIONS: -Xmx512M

Related

Is it possible to consume the event from a JavaFX FileChooser window?

I have a JavaFX Button that triggers when the user presses enter. This causes a FileChooser to open up. Some people (like myself) may hit enter inside the FileChooser to save the file. However, this causes the save button to trigger itself again and open the FileChooser again to save a new file. Clicking the button (in the FileChooser) with the mouse does not have this issue.
I thought consuming the event from the button would do something about this issue, but it only consumes the button on the GUI's event, rather than the FileChooser button. I've tried looking for ways to modify the FileChooser's EventHandler to consume an enter keypress, but with no success.
I've also tried taking the focus off the button and moving it to the parent (a Pane) so it can't be clicked again. However, there are buttons that benefit being clicked multiple times without having to regain focus on them again.
A example of my code looks like this (obviously this would be part of a bigger class that extends Application):
EventHandler<KeyEvent> enter = event -> {
if (event.getCode() == KeyCode.ENTER && event.getSource() instanceof Button) {
Button src = (Button) event.getSource();
src.fire();
}
event.consume();
};
Button b1 = new Button("Save");
b1.setOnKeyReleased(enter);
/* Called by .fire method */
b1.setOnAction(event -> {
/* Create the save dialog box */
FileChooser saveDialog = new FileChooser();
saveDialog.setTitle("Save");
/* Get file */
File f = saveDialog.showSaveDialog(stage);
/*
* ... do stuff with file ...
*/
});
Note: This example isn't my exact code. Instead the key released event is a variable used for multiple buttons, rather than just the save button (i.e. b2.setOnKeyReleased(enter);
b2.setOnAction(event -> {/* Do something */});).
How could I go about preventing the button from triggering when the user presses enter in the FileChooser? I don't want the user to be stuck in a loop if they don't have a mouse. I'm aware that pressing Alt+S also saves it, but I can't expect all users to be aware of that.
EDIT: As requested in a comment which appears to be deleted now, here's a runnable version of the code:
import java.io.File;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.HBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
public class ButtonTest extends Application {
#Override
public void start(Stage stage) throws Exception {
/* EventHandler to be used with multiple buttons */
EventHandler<KeyEvent> enter = event -> {
if (event.getCode() == KeyCode.ENTER && event.getSource() instanceof Button) {
Button src = (Button) event.getSource();
src.fire();
}
event.consume();
};
/* Create a new button */
Button b1 = new Button("Save");
Button b2 = new Button("Print");
/* Add event handlers */
b1.setOnKeyReleased(enter);
b2.setOnKeyReleased(enter);
/* Called by .fire method of save button */
b1.setOnAction(event -> {
/* Create the save dialog box */
FileChooser saveDialog = new FileChooser();
saveDialog.setTitle("Save");
/* Get file */
File f = saveDialog.showSaveDialog(stage);
/* ... do stuff with file ... */
});
/* Called by .fire method of print button */
b2.setOnAction(event -> System.out.println("Pressed"));
Scene scene = new Scene(new HBox(b1, b2));
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
The problem is firing the Button from the onKeyReleased handler. By the time you release the ENTER key the FileChooser has been hidden and the Stage has regained focus, meaning the key-release event is given to your Stage/Button. Obviously this will cause a cycle.
One possible solution is to fire the Button from inside a onKeyPressed handler. This will give slightly different behavior relative to other applications, however, which your users might not expect/appreciate.
Another possible solution is to track if the FileChooser had been open before firing the Button, like what Matt does in his answer.
What you seem to be trying to do is allow users to use the ENTER key to fire the Button; this should be default behavior on platforms like Windows.
Not for me. Space is the only key that triggers a button. I think the reason for that is because enter is used to trigger the default button which is set using btn.setDefaultButton(true);
For me, pressing ENTER while the Button has focus fires the action event when using JavaFX 11.0.2 but not JavaFX 8u202, both on Windows 10. It appears the behavior of Button changed since JavaFX 8. Below is the different implementations of com.sun.javafx.scene.control.behavior.ButtonBehavior showing the registered key bindings.
JavaFX 8u202
protected static final List<KeyBinding> BUTTON_BINDINGS = new ArrayList<KeyBinding>();
static {
BUTTON_BINDINGS.add(new KeyBinding(SPACE, KEY_PRESSED, PRESS_ACTION));
BUTTON_BINDINGS.add(new KeyBinding(SPACE, KEY_RELEASED, RELEASE_ACTION));
}
JavaFX 11.0.2
public ButtonBehavior(C control) {
super(control);
/* SOME CODE OMITTED FOR BREVITY */
// then button-specific mappings for key and mouse input
addDefaultMapping(buttonInputMap,
new KeyMapping(SPACE, KeyEvent.KEY_PRESSED, this::keyPressed),
new KeyMapping(SPACE, KeyEvent.KEY_RELEASED, this::keyReleased),
new MouseMapping(MouseEvent.MOUSE_PRESSED, this::mousePressed),
new MouseMapping(MouseEvent.MOUSE_RELEASED, this::mouseReleased),
new MouseMapping(MouseEvent.MOUSE_ENTERED, this::mouseEntered),
new MouseMapping(MouseEvent.MOUSE_EXITED, this::mouseExited),
// on non-Mac OS platforms, we support pressing the ENTER key to activate the button
new KeyMapping(new KeyBinding(ENTER, KeyEvent.KEY_PRESSED), this::keyPressed, event -> PlatformUtil.isMac()),
new KeyMapping(new KeyBinding(ENTER, KeyEvent.KEY_RELEASED), this::keyReleased, event -> PlatformUtil.isMac())
);
/* SOME CODE OMITTED FOR BREVITY */
}
As you can see, both register SPACE to fire the Button when it has focus. However, the JavaFX 11.0.2 implementation also registers ENTER for the same—but only for non-Mac OS platforms. I couldn't find any documentation about this change in behavior.
If you want the same behavior in JavaFX 8, and you don't mind hacking into the internals of JavaFX, then you can use reflection to alter the behavior of all button-like controls in your application. Here's a utility method example:
import com.sun.javafx.PlatformUtil;
import com.sun.javafx.scene.control.behavior.ButtonBehavior;
import com.sun.javafx.scene.control.behavior.KeyBinding;
import java.lang.reflect.Field;
import java.util.List;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
public final class ButtonUtils {
public static void installEnterFiresButtonFix() throws ReflectiveOperationException {
if (PlatformUtil.isMac()) {
return;
}
Field bindingsField = ButtonBehavior.class.getDeclaredField("BUTTON_BINDINGS");
Field pressedActionField = ButtonBehavior.class.getDeclaredField("PRESS_ACTION");
Field releasedActionField = ButtonBehavior.class.getDeclaredField("RELEASE_ACTION");
bindingsField.setAccessible(true);
pressedActionField.setAccessible(true);
releasedActionField.setAccessible(true);
#SuppressWarnings("unchecked")
List<KeyBinding> bindings = (List<KeyBinding>) bindingsField.get(null);
String pressedAction = (String) pressedActionField.get(null);
String releasedAction = (String) releasedActionField.get(null);
bindings.add(new KeyBinding(KeyCode.ENTER, KeyEvent.KEY_PRESSED, pressedAction));
bindings.add(new KeyBinding(KeyCode.ENTER, KeyEvent.KEY_RELEASED, releasedAction));
}
private ButtonUtils() {}
}
You would call this utility method early in the startup of your application, before any Buttons are created. Here's an example using it:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
ButtonUtils.installEnterFiresButtonFix();
} catch (ReflectiveOperationException ex) {
ex.printStackTrace();
}
Button button = new Button("Save");
button.setOnAction(event -> {
event.consume();
System.out.println(new FileChooser().showSaveDialog(primaryStage));
});
Scene scene = new Scene(new StackPane(button), 300, 150);
primaryStage.setScene(scene);
primaryStage.setTitle("Workshop");
primaryStage.show();
}
}
Reminder: This fix is implementation dependent.
I added a boolean for the fileChooser being open and it seems to be working for me but I had to split the events up otherwise it will only fire the print button every other
public class Main extends Application {
private boolean fileChooserOpen = false;
#Override
public void start(Stage stage) throws Exception{
/* EventHandler to be used with multiple buttons */
EventHandler<KeyEvent> enterWithFileChooser = event -> {
if (!fileChooserOpen && event.getCode() == KeyCode.ENTER && event.getSource() instanceof Button) {
Button src = (Button) event.getSource();
src.fire();
fileChooserOpen = true;
}else {
fileChooserOpen = false;
}
event.consume();
};
EventHandler<KeyEvent> enter = event -> {
if (event.getCode() == KeyCode.ENTER && event.getSource() instanceof Button) {
Button src = (Button) event.getSource();
src.fire();
}
event.consume();
};
/* Create a new button */
Button b1 = new Button("Save");
Button b2 = new Button("Print");
/* Add event handlers */
b1.setOnKeyReleased(enterWithFileChooser);
b2.setOnKeyReleased(enter);
/* Called by .fire method of save button */
b1.setOnAction(event -> {
/* Create the save dialog box */
FileChooser saveDialog = new FileChooser();
saveDialog.setTitle("Save");
/* Get file */
File f = saveDialog.showSaveDialog(stage);
/* ... do stuff with file ... */
});
/* Called by .fire method of print button */
b2.setOnAction(event -> System.out.println("Pressed"));
Scene scene = new Scene(new HBox(b1, b2));
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) { launch(args); }
}

JavaFX "quickfixes" with tooltips and hyperlinks

does JavaFX provide something like Eclipse Quickfixes? Meaning that you hover over a thing that is broken and got some solutions for it that you can apply immediately.
I know that there are tooltips but they can only contain text, I would need something clickable. Another solution would be something like Dialogs, but I don't want to open another window. I want it to appear on the current stage.
Any suggestions?
Edit: to make it clear, I want to adopt the concept of eclipse quickfixes onto a JavaFX based application, maybe showing a "quickfix" when hovering over a circle instance. I don't want to check any (java/javafx) source code.
Edit2: I've got a hyperlink on a tooltip now:
HBox box = new HBox();
Tooltip tooltip = new Tooltip();
tooltip.setText("Select an option:");
tooltip.setGraphic(new Hyperlink("Option 1"));
Tooltip.install(box, tooltip);
I've got three new problems now:
How to make the tooltip not disappear when leaving the HBox and staying there when entering the mouse into the tooltip?
How to add mulitple graphics / hyperlinks? Is it even possible?
How to first show the text and then, in a new line, display the graphics?
Thanks in advance!
You can add any node to a tooltip using the setGraphic() method. Here is a simple example demonstrating using a tooltip for "quick fix" functionality:
import java.util.Random;
import javafx.application.Application;
import javafx.css.PseudoClass;
import javafx.scene.Scene;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TooltipWithQuickfix extends Application {
#Override
public void start(Stage primaryStage) {
TextField textField = new TextField();
textField.pseudoClassStateChanged(PseudoClass.getPseudoClass("invalid"), true);
textField.setTextFormatter(new TextFormatter<Integer>(c -> {
if (c.getText().matches("\\d*")) {
return c ;
}
return null ;
}));
textField.textProperty().isEmpty().addListener((obs, wasEmpty, isNowEmpty) ->
textField.pseudoClassStateChanged(PseudoClass.getPseudoClass("invalid"), isNowEmpty));
Tooltip quickFix = new Tooltip();
Hyperlink setToDefault = new Hyperlink("Set to default");
Hyperlink setToRandom = new Hyperlink("Set to random");
setToDefault.setOnAction(e -> {
textField.setText("42");
quickFix.hide();
});
Random rng = new Random();
setToRandom.setOnAction(e -> {
textField.setText(Integer.toString(rng.nextInt(100)));
quickFix.hide();
});
VBox quickFixContent = new VBox(new Label("Field cannot be empty"), setToDefault, setToRandom);
quickFixContent.setOnMouseExited(e -> quickFix.hide());
quickFix.setGraphic(quickFixContent);
textField.setOnMouseEntered(e -> {
if (textField.getText().isEmpty()) {
quickFix.show(textField, e.getScreenX(), e.getScreenY());
}
});
VBox root = new VBox(textField);
root.getStylesheets().add("style.css");
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
with the stylesheet (style.css):
.root {
-fx-alignment: center ;
-fx-padding: 24 10 ;
}
.text-field:invalid {
-fx-control-inner-background: #ff7979 ;
-fx-focus-color: red ;
}

JavaFX button background image

I have problem with setting backgroundImage on button in JavaFX.
Image newGame = new Image("File:/CSS/nova_hra.png");
BackgroundImage newGameBgr = new BackgroundImage(newGame, null, null, null, null);
Button buttonNewGame = new Button("Nová Hra");
Button buttonLoadGame = new Button("Načíst Hru");
Button buttonStatistics = new Button("Statistiky");
Button buttonExit = new Button("Konec");
buttonNewGame.setGraphic(new ImageView(newGame));
//buttonNewGame.setBackground(new Background(newGameBgr));
buttonExit.setMinHeight(40);
buttonLoadGame.setMinHeight(40);
buttonNewGame.setMinHeight(40);
buttonStatistics.setMinHeight(40);
buttonExit.setMinWidth(120);
buttonLoadGame.setMinWidth(120);
buttonNewGame.setMinWidth(120);
buttonStatistics.setMinWidth(120);
This does nothing with the buttonNewGame. Every time I tryed to load image with this
Image image = new Image(getClass().getResourceAsStream("a.png"));
I got runTime exception. When I used
Image image = new Image(getClass().getResourceAsStream("a.png"));
the whole image disapeard.
You can do it via css. If your background.jpg is in a package testing, simply do this:
package testing;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
Pane root = new Pane();
Button button = new Button( "Click me!");
button.setStyle("-fx-background-image: url('/testing/background.jpg')");
root.getChildren().add(button);
Scene scene = new Scene(root, 800, 400);
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
If you don't want to use css, you could do it like this:
BackgroundImage backgroundImage = new BackgroundImage( new Image( getClass().getResource("/testing/background.jpg").toExternalForm()), BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.DEFAULT, BackgroundSize.DEFAULT);
Background background = new Background(backgroundImage);
Button button = new Button( "Click me!");
button.setBackground(background);

Why am I getting an "exception while running" error? [duplicate]

This question already has an answer here:
Java - NullPointerException in Array [duplicate]
(1 answer)
Closed 7 years ago.
I made an array of Images to be set with a lesser number of image views. I want 10 images to randomly assign themselves to 4 Image views and then be displayed through the gridpane. Every time I run the code I get an error, "exception while running application". Is it the path of the images? I don't see any obvious errors.
package Flag;
import java.util.Random;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class Flag extends Application {
#Override public void start(Stage primaryStage) {
// Initialize Variables
GridPane pane = new GridPane();
pane.setAlignment(Pos.CENTER);
ImageView [] imv = new ImageView [4];
Image [] images = new Image[10];
//Fill Images array
images[0] = new Image(Flag.class.getResourceAsStream("images/flag0.gif"));
images[1] = new Image(Flag.class.getResourceAsStream("images/flag1.gif"));
images[2] = new Image(Flag.class.getResourceAsStream("images/flag2.gif"));
images[3] = new Image(Flag.class.getResourceAsStream("images/flag3.gif"));
images[4] = new Image(Flag.class.getResourceAsStream("images/flag4.gif"));
images[5] = new Image(Flags.class.getResourceAsStream("images/flag5.gif"));
images[6] = new Image(Flag.class.getResourceAsStream("images/flag6.gif"));
images[7] = new Image(Flag.class.getResourceAsStream("images/flag7.gif"));
images[8] = new Image(Flags.class.getResourceAsStream("images/flag8.gif"));
images[9] = new Image(Flags.class.getResourceAsStream("images/flag9.gif"));
//Random number
Random rand = new Random();
//Give Each Image an Image View
for (ImageView imv1 : imv) {
/*This is line 38*/ imv1.setImage(images[rand.nextInt(9)]);
}
// Add nodes to pane
pane.add(imv[0], 0, 0);
pane.add(imv[1], 0, 1);
pane.add(imv[2], 1, 0);
pane.add(imv[3], 1, 1);
//Create a scene and place it in the stage
Scene scene = new Scene(pane);
primaryStage.setTitle("ShowGridPane");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
Here's the log
Exception in Application start method
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.javafx.main.Main.launchApp(Main.java:642)
at com.javafx.main.Main.main(Main.java:805)
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:403)
at com.sun.javafx.application.LauncherImpl.access$000(LauncherImpl.java:47)
at com.sun.javafx.application.LauncherImpl$1.run(LauncherImpl.java:115)
at java.lang.Thread.run(Thread.java:724)
Caused by: java.lang.NullPointerException
at Flag.Flag.start(FlagsHwB.java:38)
at com.sun.javafx.application.LauncherImpl$5.run(LauncherImpl.java:319)
at com.sun.javafx.application.PlatformImpl$5.run(PlatformImpl.java:215)
at com.sun.javafx.application.PlatformImpl$4$1.run(PlatformImpl.java:179)
at com.sun.javafx.application.PlatformImpl$4$1.run(PlatformImpl.java:176)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl$4.run(PlatformImpl.java:176)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:29)
at com.sun.glass.ui.win.WinApplication$3$1.run(WinApplication.java:73)
... 1 more
Java Result: 1
images[9] - this does not exist. The array only has nine elements. The error message says this: Caused by: java.lang.ArrayIndexOutOfBoundsException: 9
The problem is because of
Image [] images = new Image[9];
You are initializing an array of 9 elements and trying to insert 10 elements into it.
images[9] = new Image(Flags.class.getResourceAsStream("images/flag9.gif"));
represents the 9th index and the 10th element. Just increase the array size to 10 i.e.
Image [] images = new Image[10];
A better option is to use an ArrayList if you are not sure of the size of the array. ArrayList resizes itself on element adding.
Edit - as per user comments
The NullPointerException is because you haven't initialized any of you ImageView's. Initialize the ImageView's before using them.
for (ImageView imv1 : imv) {
imv1 = new ImageView(); // Initialization
imv1.setImage(images[rand.nextInt(9)]);
}
or you can directly use
for (ImageView imv1 : imv) {
imv1 = new ImageView(images[rand.nextInt(9)]));
}

How to get position of an item in ListView in JavaFX?

If I create a ListView in JavaFX like this:
ObservableList<String> elements = FXCollections.observableArrayList("John", "Doe");
ListView<String> lView = new ListView<String>(elements);
What I want to do is draw a line starting from the end of a row in the ListView, say from "John"
To do this, I need the location(x,y) of the row "John". Is it possible to get the location?
Update
This is a sample interface that I got using Swing and Piccolo2D. However, using that library is painful. I am wondering if I can do the same in JavaFX
It is possible, but it may not be as straight forward as you hoped. In order to determine the layout coordinates for a particular Cell within a ListView (or TableView/TreeView) you need to have access to that particular Cell object. The best way (and maybe only way in JavaFX 2.2) is to provide the container with a custom Cell and CellFactory that exposes each Cell. How you expose the Cell depends on what your triggers are for drawing the line.
Bases on your illustration, you'll need access to each cell once the ListViews are populated. You can do this with a List<ListCell<String>> field in the CellFactory. I'll mention one caveat here about ListCells. The ListViewSkin will reuse Cells whenever possible. That means that if you are going to try to populate and connect a list that ends up scrolling, then keeping your lines in the right place will be much more difficult. I'd recommend trying to ensure that all your list items fit on screen.
Below is an example with some notes in the comments. Take note that getting the correct coordinates for drawing your Line will probably require calculating the offset of your SceneGraph which I didn't do in this example.
package listviewcellposition;
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
import javafx.util.Callback;
public class ListViewCellPosition extends Application {
// CustomCellFactory for creating CustomCells
public class CustomCellFactory implements
Callback<ListView<String>, ListCell<String>> {
List<ListCell<String>> allCells = new ArrayList<>();
#Override
public ListCell<String> call(final ListView<String> p) {
final CustomCell cell = new CustomCell();
allCells.add(cell);
return cell;
}
public List<ListCell<String>> getAllCells() {
return allCells;
}
}
// CustomCell is where the exposure occurs. Here, it's based on the
// Cell being selected in the ListView. You could choose a different
// trigger here but you'll need to explore.
public class CustomCell extends ListCell<String> {
// General display stuff
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
setText(item == null ? "" : item);
setGraphic(null);
}
}
}
#Override
public void start(Stage primaryStage) {
// This pane will contain the lines after they are created.
// I set it into an AnchorPane to avoid having to deal with
// resizing.
Pane linePane = new Pane();
AnchorPane pane = new AnchorPane();
pane.setPrefSize(100, 250);
AnchorPane.setBottomAnchor(linePane, 0.0);
AnchorPane.setLeftAnchor(linePane, 0.0);
AnchorPane.setRightAnchor(linePane, 0.0);
AnchorPane.setTopAnchor(linePane, 0.0);
pane.getChildren().add(linePane);
ListView<String> lView = new ListView<>();
lView.setPrefSize(100, 250);
CustomCellFactory lCellFactory = new CustomCellFactory();
lView.setCellFactory(lCellFactory);
ListView<String> rView = new ListView<>();
rView.setPrefSize(100, 250);
CustomCellFactory rCellFactory = new CustomCellFactory();
rView.setCellFactory(rCellFactory);
lView.getItems().addAll("Bill", "Doctor", "Steve", "Joanne");
rView.getItems().addAll("Seuss", "Rowling", "King", "Shakespeare");
HBox root = new HBox();
root.getChildren().addAll(lView, pane, rView);
Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
connectCells(lCellFactory, "Bill", rCellFactory, "Shakespeare", linePane);
connectCells(lCellFactory, "Doctor", rCellFactory, "Seuss", linePane);
connectCells(lCellFactory, "Steve", rCellFactory, "King", linePane);
connectCells(lCellFactory, "Joanne", rCellFactory, "Rowling", linePane);
}
// Looks up the ListCell<> for each String and creates a Line
// with the coordinates from each Cell. The calculation is very
// contrived because I know that all the components have the same
// x-coordinate. You'll need more complicated calculations if your
// containers are not aligned this way.
private void connectCells(CustomCellFactory lCellFactory, String lVal,
CustomCellFactory rCellFactory, String rVal, Pane linePane) {
List<ListCell<String>> lList = lCellFactory.getAllCells();
ListCell<String> lCell = null;
for (ListCell<String> lc : lList) {
if (lc.getItem() != null && lc.getItem().equals(lVal)) {
lCell = lc;
break;
}
}
List<ListCell<String>> rList = rCellFactory.getAllCells();
ListCell<String> rCell = null;
for (ListCell<String> rc : rList) {
if (rc.getItem() != null && rc.getItem().equals(rVal)) {
rCell = rc;
break;
}
}
if (lCell != null && rCell != null) {
double startY = lCell.getLayoutY() +
(lCell.getBoundsInLocal().getHeight() / 2);
double endY = rCell.getLayoutY() +
(rCell.getBoundsInLocal().getHeight() / 2);
Line line = new Line(0, startY,
linePane.getBoundsInParent().getWidth(), endY);
line.setStrokeWidth(2);
line.setStroke(Color.BLACK);
linePane.getChildren().add(line);
}
}
public static void main(String[] args) {
launch(args);
}
}

Resources