Whenever I click refresh in my program here, it will generate 5 random numbers from between 1 to 13 and display it in the form of cards on screen. I'm using JavaFx for that. I cannot figure out the second thing, which is when I click the Sort button then the program should take the current set of random numbers and show the cards from lowest to highest.
public class Cards extends Application {
public static void main(String[] args) {
Application.launch(args);
}
public static int mycard() {
Random rand = new Random();
int n = rand.nextInt(13) + 1;
return n;
}
public void start(Stage primaryStage) {
primaryStage.setTitle("Cards Layout");
GridPane pane = new GridPane();
pane.setAlignment(Pos.CENTER);
pane.setHgap(10);
pane.setVgap(5);
// creates button
Button refresh = new Button("Refresh");
HBox button = new HBox(10);
button.setAlignment(Pos.BOTTOM_LEFT);
button.getChildren().add(refresh);
pane.getChildren().add(refresh);
//Create sort button
Button sort = new Button("Sort");
HBox button1 = new HBox(10);
button1.setAlignment(Pos.BOTTOM_RIGHT);
button1.getChildren().add(sort);
pane.getChildren().add(sort);
// creates random card images and adds them to pane
Image img = new Image("image/card/"+mycard()+".png");
ImageView imgView = new ImageView(img);
pane.add(imgView, 1, 0);
Image img2 = new Image("image/card/"+mycard() +".png");
ImageView imgView2 = new ImageView(img2);
pane.add(imgView2, 2, 0);
Image img3 = new Image("image/card/" +mycard()+ ".png");
ImageView imgView3 = new ImageView(img3);
pane.add(imgView3, 3, 0);
Image img4 = new Image("image/card/" +mycard()+".png");
ImageView imgView4 = new ImageView(img4);
pane.add(imgView4, 4, 0);
Image img5 = new Image("image/card/" +mycard()+".png");
ImageView imgView5 = new ImageView(img5);
pane.add(imgView5, 5, 0);
Scene scene = new Scene(pane, 600, 200);
primaryStage.setScene(scene);
primaryStage.show();
refresh.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
imgView.setImage(new Image("image/card/" +mycard()+".png"));
imgView2.setImage(new Image("image/card/" +mycard()+".png"));
imgView3.setImage(new Image("image/card/" +mycard()+".png"));
imgView4.setImage(new Image("image/card/" +mycard()+".png"));
imgView5.setImage(new Image("image/card/" +mycard()+".png"));
}
});
sort.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
imgView.setImage(new Image("image/card/" + "1.png"));
imgView2.setImage(new Image("image/card/" + "2.png"));
imgView3.setImage(new Image("image/card/" + "3.png"));
imgView4.setImage(new Image("image/card/" + "4.png"));
imgView5.setImage(new Image("image/card/" + "5.png"));
//Cannot figure out what to do here ^
}
});
}
}
When you call myCard() you need to add the randomly generated number to a List. When you click on refresh you need to clear that list (myList.clear()). When you click on sort you need to first sort that list and then access the items in the list by index from 0 to myList.size().
If you add your images to a List, too, you can use the same index to match image with number / imageResource.
Since you have a fixed number of cards you could also use an Array (but if you plan on reusing code for implementations with more cards I'd use a List)
Related
This is my main class. I'm trying to get the string that is being selected from the combobox and "get the wall color" from that string. The problem is that when I run the application, after hitting the playbutton I get an error saying that in line 75 - if (stringWallColor.equals("Default - Black")), stringWallColor is null.
Does that I mean that it uses the public static String stringWallColor which is null as default? And how can I fix this?
public static String stringWallColor;
public static void main(String[] args) {
launch(args);
System.out.println("Done!");
}
public void start(Stage primaryStage) throws Exception {
Main.primaryStage = primaryStage;
MenuBar MENU = new MenuBar();
MenuGenerator.menuCreator(MENU);
Button playButton = new Button("Play Game");
ComboBox<String> wallColorCombo = new ComboBox<>();
wallColorCombo.setPromptText("Choose wall color");
wallColorCombo.getItems().addAll(
"Default - Black",
"Dark Green",
"Dark Red",
"Dark Gray",
"Saddle Brown",
"Midnight Blue",
"Dark Magenta",
"Crimson",
"Navy");
stringWallColor = wallColorCombo.getSelectionModel().getSelectedItem();
gameGrid = new GridPane();
GridPane root = new GridPane();
root.add(MENU,0,0);
root.add(gameGrid, 0, 1);
gameScene = new Scene(root,600,625);
GridPane startGrid = new GridPane();
startGrid.setHgap(20);
startGrid.setVgap(20);
playButton.setLineSpacing(10);
startGrid.add(playButton,8,12);
startGrid.add(wallColorCombo,7,12);
GridPane root0= new GridPane();
root0.add(startGrid,0,1);
Scene startScene = new Scene(root0, 400, 400);
primaryStage.setScene(startScene);
primaryStage.setTitle(GameEngine.GAME_NAME);
primaryStage.show();
System.out.println("Default save file not loaded yet");
playButton.setOnAction(e -> {
MenuGenerator.loadDefaultSaveFile(primaryStage);
System.out.println("Default save file loaded");
primaryStage.setScene(gameScene); });
}
public static Color getWallColor() {
Color wallColor = Color.BLACK;
if (stringWallColor.equals("Default - Black"))
wallColor = Color.BLACK;
if (stringWallColor.equals("Dark Green"))
wallColor = Color.DARKGREEN;
if (stringWallColor.equals("Dark Red"))
wallColor = Color.DARKRED;
if (stringWallColor.equals("Dark Gray"))
wallColor = Color.DARKGRAY;
if (stringWallColor.equals("Saddle Brown"))
wallColor = Color.SADDLEBROWN;
if (stringWallColor.equals("Midnight Blue"))
wallColor = Color.MIDNIGHTBLUE;
if (stringWallColor.equals("Dark Magenta"))
wallColor = Color.DARKMAGENTA;
if (stringWallColor.equals("Crimson"))
wallColor = Color.CRIMSON;
if (stringWallColor.equals("Navy"))
wallColor = Color.NAVY;
return wallColor;
}
}
Solved by setting stringWallColor = wallColorCombo.getSelectionModel().getSelectedItem(); as an action for the playbutton.
Each stack pane is supposed to have two nodes. However the bottom node disappears outside the for loop for the first 2 indices in the stack pane array.
public class Main extends Application {
GridPane images;
StackPane[] stackPane;
ImageView cardBack;
ImageView[] cardImages;
#Override
public void start(Stage stage) throws FileNotFoundException {
images = new GridPane(); images.setAlignment(Pos.CENTER);
images.setVgap(5); images.setHgap(5);
cardBack = new ImageView(new Image(new FileInputStream("images/b1fv.gif")));
cardImages = new ImageView[]{
new ImageView(new Image(new FileInputStream("images/c1.gif"))),
new ImageView(new Image(new FileInputStream("images/c2.gif"))),
new ImageView(new Image(new FileInputStream("images/c3.gif")))
};
final Button[] flip = new Button[cardImages.length];
stackPane = new StackPane[cardImages.length];
for (int i = 0; i < cardImages.length; i++) {
stackPane[i] = new StackPane();
stackPane[i].getChildren().addAll(cardBack, cardImages[i]);
images.add(stackPane[i], i, 0, 1, 1);
flip[i] = new Button("Flip");
GridPane.setHalignment(flip[i], HPos.CENTER);
images.add(flip[i], i, 1, 1, 1);
// Debug
System.out.println(stackPane[i].getChildren().toString());
final int j = i;
flip[j].setOnAction(event -> doFlip(j));
}
// Debug
System.out.println("");
for (StackPane pane : stackPane)
System.out.println(pane.getChildren().toString());
stage.setTitle("Assignment 11");
stage.setScene(new Scene(images, 500,200));
stage.show();
}
void doFlip(int loc) {
// Debug
System.out.println("");
for (StackPane pane : stackPane)
System.out.println(pane.getChildren().toString());
ObservableList<Node> children = stackPane[loc].getChildren();
Node topNode = children.get(children.size()-1);
topNode.toBack();
}
public static void main(String[] args) {
launch(args);
}
}
[ImageView#5e1bc54a[styleClass=image-view], ImageView#25389181[styleClass=image-view]]
[ImageView#5e1bc54a[styleClass=image-view], ImageView#ff7cf97[styleClass=image-view]]
[ImageView#5e1bc54a[styleClass=image-view], ImageView#18b8669d[styleClass=image-view]]
[ImageView#25389181[styleClass=image-view]]
[ImageView#ff7cf97[styleClass=image-view]]
[ImageView#5e1bc54a[styleClass=image-view], ImageView#18b8669d[styleClass=image-view]]
[ImageView#25389181[styleClass=image-view]]
[ImageView#ff7cf97[styleClass=image-view]]
[ImageView#5e1bc54a[styleClass=image-view], ImageView#18b8669d[styleClass=image-view]]
Inside the for loop it displays all objects. However, outside the loop in does not display the bottom nodes except for the last element of array.
You cannot add the same Node instance to multiple parents!
In the top of your loop you have the following line:
stackPane[i].getChildren().addAll(cardBack, cardImages[i]);
The cardBack Node would be added to all StackPanes, but since it can only have one parent, it will be removed from the previous. Javafx has provided a way to reuse Image resources though (which is I imagine the thing you want to achieve). Instead of creating one ImageView, you can cache the Image instance passes in the ImageView constructor. E.g:
cardBack = new Image(new FileInputStream("images/b1fv.gif"));
// some stuff
for (int i = 0; i < cardImages.length; i++) {
stackPane[i] = new StackPane();
stackPane[i].getChildren().addAll(new ImageView(cardBack) , cardImages[i]);
// rest of the loop
}
If you use the Image and ImageView as described above, things will work correctly.
I have a GUI that takes the input of an image name, and once the refresh button is pressed, its displayed in a fixed position. I want to be able to input a character 'A-G' which will change the X position of the image, and a character '0-6' that will change the Y position of the image. The name of the images are just "A1", "A2"..."A5". So, if the user inputs "A1B3", it will display the image A1 in X-Position 'B' and Y-Position '3'. So B could be 200, and 3 could be 300, which makes the (X,Y) coordinates (200,300).
This is my code that gets the users input for the image.
private void getImage(){
Image img = new Image("comp1110/ass2/gui/assets/" + textField.getText() + ".png", 100, 100, false, false);
ImageView image = new ImageView();
image.setImage(img);
image.setX(100);
image.setY(100);
pane.getChildren().add(image);
}
I think you should do something along the lines of this yes there is some cosmetic issues that you will need to fix. But its only to give you an idea of what to do. It uses a gridpane so you don't have to worry about getting exact coordinates I choose a vbox so I didn't have to worry about layout you can keep the Pane that you have it shouldn't make a difference.
public class Main extends Application {
private GridPane gridPane;
private TextField imageTextField = new TextField();
private HashMap<String,String> hashMap = new HashMap<>();
#Override
public void start(Stage primaryStage) {
fillHashMapValues();
gridPane = new GridPane();
gridPane.setGridLinesVisible(true);
for (int i = 0; i < 7; i++) {
RowConstraints rowConstraints = new RowConstraints();
rowConstraints.setPercentHeight(14);
gridPane.getRowConstraints().add(rowConstraints);
ColumnConstraints columnConstraints = new ColumnConstraints();
columnConstraints.setPercentWidth(14);
gridPane.getColumnConstraints().add(columnConstraints);
gridPane.addColumn(i);
gridPane.addRow(i);
}
imageTextField.setPromptText("Enter Image Letters?");
TextField textField = new TextField();
textField.setPromptText("Enter Coordinates");
Button button = new Button("Go!");
button.setOnAction(event -> {
addToGridPane(textField.getText());
});
VBox vBox = new VBox();
vBox.setPrefSize(300, 300);
vBox.setAlignment(Pos.TOP_CENTER);
vBox.getChildren().addAll(imageTextField, textField, button, gridPane);
primaryStage.setScene(new Scene(vBox));
primaryStage.show();
button.requestFocus();//This is only so you can see the prompt text its irrelevant
}
private void fillHashMapValues(){
hashMap.put("A", "1");
hashMap.put("B", "2");
hashMap.put("C", "3");
hashMap.put("D", "4");
hashMap.put("E", "5");
hashMap.put("F", "6");
hashMap.put("G", "7");
}
private void addToGridPane(String string){
char[] chars = string.toCharArray();
if(chars.length==2){//Do more data validation here
if(hashMap.containsKey(String.valueOf(chars[0]))) {
int xValue = Integer.parseInt(hashMap.get(String.valueOf(chars[0])));
int yValue = Integer.parseInt(String.valueOf(chars[1]));
ImageView image = getImage();
gridPane.add(image, xValue, yValue);
}
}
}
private ImageView getImage(){
Image image = new Image("comp1110/ass2/gui/assets/" + imageTextField.getText() + ".png", 100, 100, false, false);
ImageView imageView = new ImageView();
imageView.setImage(image);
//imageView.setX(100);
//imageView.setY(100);
//pane.getChildren().add(image);
return imageView;
}
public static void main(String[] args) { launch(args); }
}
I'm trying to make TreeView with CheckBoxTreeItems. When I collapse/expand a CheckBoxTreeItems the image I set up does not display correctly. I googled but I couldn't find correct answer. On Stack Overflow, I found a similar problem, but I didn't get a valid answer.
E.g
JavaFX CheckBoxTreeItem graphic disappear when siblings collapse
JavaFX CheckBoxTreeItem: Graphic disappears if graph is extended
Any ideas?
public class ClientApplication extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(final Stage stage) {
ImageView folderIcon = new ImageView();
Image folderImage = new Image("image/folder.png");
folderIcon.setImage(folderImage);
folderIcon.setFitWidth(16);
folderIcon.setFitHeight(16);
CheckBoxTreeItem<String> rootItem = new CheckBoxTreeItem<String>("folder", folderIcon);
rootItem.setExpanded(true);
for (int i = 0; i < 4; i++) {
CheckBoxTreeItem<String> checkBoxTreeItem = new CheckBoxTreeItem<String>("Sample" + (i + 1), folderIcon);
rootItem.getChildren().add(checkBoxTreeItem);
}
final TreeView<String> tree = new TreeView<String>(rootItem);
tree.setCellFactory(CheckBoxTreeCell.<String>forTreeView());
tree.setRoot(rootItem);
tree.setShowRoot(true);
StackPane root = new StackPane();
root.getChildren().add(tree);
stage.setScene(new Scene(root, 300, 250));
stage.show();
}
}
enter image description here
I tried to use the ideas provided by #Jai,But when I click the expand/collapse icon, there is still a problem.Attachment is a screenshot.Thanks in advance.
enter image description here
ImageView is a JavaFX control. This means that each instance represents a unique control you see on your screen. You should never use the same instance for multiple locations in your GUI.
On the other hand, Image represents an image (i.e. an array of pixel data), so it is reusable.
This should work:
#Override
public void start(final Stage stage) {
final Image folderImage = new Image("image/folder.png");
CheckBoxTreeItem<String> rootItem = new CheckBoxTreeItem<String>("folder", createImageView(folderImage));
rootItem.setExpanded(true);
for (int i = 0; i < 4; i++) {
CheckBoxTreeItem<String> checkBoxTreeItem = new CheckBoxTreeItem<String>("Sample" + (i + 1), createImageView(folderImage));
rootItem.getChildren().add(checkBoxTreeItem);
}
final TreeView<String> tree = new TreeView<String>(rootItem);
tree.setCellFactory(CheckBoxTreeCell.<String>forTreeView());
tree.setRoot(rootItem);
tree.setShowRoot(true);
StackPane root = new StackPane();
root.getChildren().add(tree);
stage.setScene(new Scene(root, 300, 250));
stage.show();
}
private ImageView createImageView(Image folderImage) {
ImageView folderIcon = new ImageView();
folderIcon.setImage(folderImage);
folderIcon.setFitWidth(16);
folderIcon.setFitHeight(16);
return folderIcon;
}
I have a program in which it displays 3 random hieroglyphic images on the screen. I have added a "Refresh" button in order to refresh the hieroglyphic images. When I click the button, the images refresh and randomize properly. After the button has been clicked for the first time however, it disappears. I am almost certain it has something to do with my pane.getChildren().clear(); line, but I cant seem to figure it out. Any tips or advice?
If I have posted incorrectly or without using proper guidelines, I apologize. This is one of my first posts.
Here is my code:
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.control.Button;
import javafx.geometry.Pos;
import javafx.scene.layout.HBox;
public class Lab6a extends Application {
#Override
public void start(Stage myStage) {
//Create an HBox layout.
HBox hBox1 = new HBox();
//Set alignment.
hBox1.setAlignment(Pos.CENTER);
getRandomHieroglyphic(hBox1);
//Create a Refresh button.
Button refresh = new Button("Refresh");
refresh.setOnAction(e -> getRandomHieroglyphic(hBox1));
hBox1.getChildren().add(refresh);
//Set the title for the second window.
myStage.setTitle("Random Hieroglyphics with Refresh");
//Create a scene for the window.
Scene myScene = new Scene(hBox1, 400, 400);
//Place the scene in the second window.
myStage.setScene(myScene);
//Show the stage.
myStage.show();
}
public void getRandomHieroglyphic(HBox pane) {
pane.getChildren().clear();
//Create random generators to get a random image
int randomInt1 = (int) (Math.random() * 9) + 1;
int randomInt2 = (int) (Math.random() * 9) + 1;
int randomInt3 = (int) (Math.random() * 9) + 1;
//Create paths for the images to be called
String path1 = "Image/Hieroglyphics/h" + randomInt1 + ".png";
String path2 = "Image/Hieroglyphics/h" + randomInt2 + ".png";
String path3 = "Image/Hieroglyphics/h" + randomInt3 + ".png";
//Add the images into the pane
pane.getChildren().add(new ImageView (path1));
pane.getChildren().add(new ImageView (path2));
pane.getChildren().add(new ImageView (path3));
}
public static void main(String[] args) {
launch(args);
}
}
clear() removes all children from the HBox including the Button.
You've got 3 ImageViews and want to keep the number of ImageViews constant. This means you should not replace them, but replace the images they contain instead. Furthermore you should avoid reloading the images and load all 9 images at the start:
public class Lab6a extends Application {
private Image[] images;
private final Random random = new Random();
#Override
public void start(Stage myStage) {
// load all hieroglyphs
images = new Image[9];
for (int i = 0; i < images.length; i++) {
images[i] = new Image("Image/Hieroglyphics/h" + (i+1) + ".png");
}
// store all imageviews in array
final ImageView[] imageViews = Stream.generate(ImageView::new).limit(3).toArray(ImageView[]::new);
// set initial images
getRandomHieroglyphic(imageViews);
...
hBox1.getChildren().add(refresh);
for (ImageView iv : imageViews) {
hBox1.getChildren().add(iv);
}
...
refresh.setOnAction(e -> getRandomHieroglyphic(imageViews));
...
}
public void getRandomHieroglyphic(ImageView[] imageViews) {
for (ImageView iv : imageViews) {
iv.setImage(images[random.nextInt(images.length)]);
}
}
You're right. You Hbox has 4 cildren initially, 3 images and the button. you should add the button too in the getRandomHieroglyphic() method.
But the better way was separate the button from the images. Best is this done by Adding a BorderPane to the Scene, and put the HBox with the images only in the center and the button in the bottom area.
#Override
public void start(Stage myStage) {
HBox hBox1 = new HBox();
hBox1.setAlignment(Pos.CENTER);
getRandomHieroglyphic(hBox1);
Button refresh = new Button("Refresh");
refresh.setOnAction(e -> getRandomHieroglyphic(hBox1));
BorderPane borderPane = new BorderPane();
borderPane.getBottom().add(refresh);
myStage.setTitle("Random Hieroglyphics with Refresh");
Scene myScene = new Scene(borderPane, 400, 400);