I want to add Multiple images in Scollpane by clicking button i try below code but it will not display image any idea about that?
#FXML private void OnClick(ActionEvent ae)
{
getGalleryView();
}
public void getGalleryView()
{
ScrolPane sp=new ScroPane();
Hbox hb=new Hbox();
Image [] images=new Image[5];
ImageView []pics=new ImageView[5];
final String [] imageNames = new String [] {"fw1.jpg", "fw2.jpg",
"fw3.jpg", "fw4.jpg", "fw5.jpg"};
for (int i = 0; i < 5; i++) {
images[i] = new Image(getClass().getResourceAsStream(imageNames[i]));
pics[i] = new ImageView(images[i]);
pics[i].setFitWidth(100);
pics[i].setPreserveRatio(true);
hb.getChildren().add(pics[i]);
sp.setContent(hb);
}
}
You need to add the scrollpane to the scene:
#FXML private void OnClick(ActionEvent ae)
{
getGalleryView(ae);
}
public void getGalleryView(ActionEvent ae)
{
ScrolPane sp=new ScroPane();
Hbox hb=new Hbox();
Image [] images=new Image[5];
ImageView []pics=new ImageView[5];
final String [] imageNames = new String [] {"fw1.jpg", "fw2.jpg",
"fw3.jpg", "fw4.jpg", "fw5.jpg"};
for (int i = 0; i < 5; i++) {
images[i] = new Image(getClass().getResourceAsStream(imageNames[i]));
pics[i] = new ImageView(images[i]);
pics[i].setFitWidth(100);
pics[i].setPreserveRatio(true);
hb.getChildren().add(pics[i]);
sp.setContent(hb);
}
Scene scene = ((Node) ae.getSource()).getScene();
((Pane) scene.getRoot()).getChildren().add(sp);
}
I assumed here that your root node is a Pane or one of its subclasses.
ScrolPane sp=new ScroPane(); error?
EDIT:
I was developing similar method. Mine works fine. You can check if you want to.
private List<String> listFileNames(File folder) throws NullPointerException{
List<String> list = new ArrayList<>();
for (File file : folder.listFiles()) {
if (file.isDirectory())
listFileNames(file);
else {
System.out.println(file.getName());
list.add(file.getName());
}
}
return list;
}
private void insertImages(List<String> list, Hero thisHero) {
int column = 0;
int row = 0;
for (String path:list) {
String fullPath = "file:"+thisHero.getHeroClass().getFile()+"\\"+path;
ToggleButton button = new ToggleButton();
button.setBackground(Background.EMPTY);
button.setGraphic(new ImageView(new Image(fullPath)));
grid.add(button,column,row);
column++;
if (column == 5) {
row++;
column = 0;
}
}
}
I can write more if you want. I use Lists because of it's ease of adding items.
You can use first method to just get all file names to list, from your folder filled with image files.
Second method does the job of making new ImageViews filled with ToggleButtons with graphic. I just changed the concept to buttons, so sorry about my laziness of not changing code to exactly fit your needs.
Path is the exact file name, thisHero.getHeroClass().getFile() returns path to the directory which contains this image.
grid.add(button, column, row) adds this button to the grid pane which i made before. It's my app, so sorry for not sharing all the code, but i thought that this snippet could be usefull.
EDIT2: You could also provide us with error information if there is any.
Related
Im using scenebuilder and I have come up with 3 choiceboxes. The second choicebox depends on the input of the first choicebox and the third depends on the 2nd. How can I achieve this?
I've tried this
#FXML
private ChoiceBox course;
course.getSelectionModel().selectedIndexProperty().addListener(
(ObservableValue<? extends Number> ov,
Number old_val, Number new_val) -> {
//some code here
}
);
But this event only occurs if i switch value, the first selection would not trigger this event, which is not what I want.
How can I achieve this, thanks in advance.
You can do something like this where everytime an action is done it will set the values of the next one. Make note of the .getItems().clear(); this will ensure the list is emptied everytime so that you don't have old values in the list. The for loop however is not important only there to add some variety to the text values I added
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
ChoiceBox<String> choiceBoxOne = new ChoiceBox<>();
choiceBoxOne.setPrefWidth(100);
choiceBoxOne.getItems().addAll("Choice1", "Choice2", "Choice3");
ChoiceBox<String> choiceBoxTwo = new ChoiceBox<>();
choiceBoxTwo.setPrefWidth(100);
ChoiceBox<String> choiceBoxThree = new ChoiceBox<>();
choiceBoxThree.setPrefWidth(100);
choiceBoxOne.setOnAction(event -> {
choiceBoxTwo.getItems().clear();
//The above line is important otherwise everytime there is an action it will just keep adding more
if(choiceBoxOne.getValue()!=null) {//This cannot be null but I added because idk what yours will look like
for (int i = 3; i < 6; i++) {
choiceBoxTwo.getItems().add(choiceBoxOne.getValue() + i);
}
}
});
choiceBoxTwo.setOnAction(event -> {
choiceBoxThree.getItems().clear();
//The above line is important otherwise everytime there is an action it will just keep adding more
if(choiceBoxTwo.getValue()!=null) {//This can be null if ChoiceBoxOne is changed
for (int i = 6; i < 9; i++) {
choiceBoxThree.getItems().add(choiceBoxTwo.getValue() + i);
}
}
});
VBox vBox = new VBox();
vBox.setPrefSize(300, 300);
vBox.setAlignment(Pos.TOP_CENTER);
vBox.getChildren().addAll(choiceBoxOne, choiceBoxTwo, choiceBoxThree);
primaryStage.setScene(new Scene(vBox));
primaryStage.show();
}
public static void main(String[] args) { launch(args); }
}
An ObservableList obList has a listener, upon addition it updates the TreeView. As new string "music" is added to obList, new item is created and put in the tree view. The item renders as "{ [music] added at 0 }" instead of expected "music".
TreeItem<String> root = new TreeItem();
root.setExpanded(true);
TreeView<String> treeView = new TreeView(root);
treeView.getChildren().add(new TreeItem<String>("cat")); // normal behaviour
obList = FXCollections.observableArrayList();
obList.addListener(new ListChangeListener<String>() {
#Override
public void onChanged(ListChangeListener.Change<? extends String> c) {
while (c.next()) {
if (c.wasAdded()) {
TreeItem<String> temp = new TreeItem(c);
tree.getRoot().getChildren().add(temp);
}
}
});
obList.add("music");
It seems that variable c contains string and extra information. What is going on and what should I do?
If you didn't use the raw type, the compiler would have complained about the issue.
You set the value to the ListChangeListener.Change object instead of a String in the following line. Using the raw type on the right hand side removes the type check that would have resulted in a compile time error.
TreeItem<String> temp = new TreeItem(c);
Instead iterate through the list of added items and add a TreeItem for all of them:
while (c.next()) {
if (c.wasAdded()) {
for (String element : c.getAddedSubList()) {
TreeItem<String> temp = new TreeItem<>(element);
tree.getRoot().getChildren().add(temp);
}
}
}
Ok, I fixed it with:
obList.getAddedSubList().forEach(l ->
TreeItem<String> temp = new TreeItem(l);
tree.getRoot().getChildren().add(temp);
});
apologies for the length of my code. I realized last night that I was on the wrong path and now have gotten stuck on an issue that I think relates to JavaFX event handling. Initially I had the logic functioning outside a GUI in a basic loop that depended on interaction through the console. Everything was working great. I've now tried to get this to work in a GUI with interaction from the user.
I have two main problems with the code below.
The first is that the text in textArea is not updating with additional text after the startButton executes the start of my main logic sequence. The first append starts right under the first while loop. I was hoping to have this show up in the GUI as the logic executes. I'm not sure if I need to tell the GUI to update at certain intervals or if there's something else wrong.
Second, I'm not sure how to get the program to wait for the user to type in something into textField before hitting the textButton I created to continue on. I used to have a scanner created which caused the program to wait in the console for input. I realize I need some way of telling it to wait for a button press when it's running inside JavaFX.
I chose not to include the rest of the code to make things easier to read, but I can add it on if it will help resolve this issue.
Thank you everyone for your help!
public class FxApp extends Application {
//Creates FileParser object with methods that alter the incoming Array of Strings into the format we need
FileParser fileParser = new FileParser();
Configure configure = new Configure();
private String text;
private String initialState;
private ArrayList<Machine> machines = new ArrayList<Machine>();
private Map<String, String> initialStates = new HashMap<String, String>();
private Map<String, String> states = new HashMap<String, String>();
private Map<String, ArrayDeque<String>> queues = new HashMap<String, ArrayDeque<String>>();
private Map<Integer, ArrayList<String>> parsedData = new HashMap<Integer, ArrayList<String>>();
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("File Chooser");
FileChooser fileChooser = new FileChooser();
fileChooser.getExtensionFilters().addAll(new ExtensionFilter("Text Files", "*.txt"));
Button startButton = new Button("Start");
Button openButton = new Button("Click to open a file...");
openButton.setPrefSize(200, 80);
Button textButton = new Button("Enter");
TextArea textArea = new TextArea();
textArea.setWrapText(true);
TextField textField = new TextField();
Label lbl = new Label();
VBox vbox = new VBox(lbl, openButton, startButton, textArea, textField, textButton);
vbox.setSpacing(10);
vbox.setPadding(new Insets(15));
lbl.setText("This tool creates virtual automata based \ron the file.");
Scene scene = new Scene(vbox, 640, 480);
primaryStage.setScene(scene);
primaryStage.show();
openButton.setOnAction(
new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
File file = fileChooser.showOpenDialog(primaryStage);
if (file != null) {
//Execute the method to convert to string array before sending to file parser
try {
fileParser.convertFile(file);
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
});
textButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
text = textField.getText();
}
});
startButton.setOnAction(new EventHandler <ActionEvent>()
{
public void handle(ActionEvent event)
{
machineCreation();
String exit = "no";
String nextLine = null;
ArrayList<String> listOfCurrentTransitions = new ArrayList<String>();
int nextInt = 0;
states = initialStates;
while(!(exit.toLowerCase().equals("yes"))) {
textArea.appendText("Choose a state to load");
//Print out the states possible for each machine
ArrayList<String> tempTrans = machines.get(nextInt).getTransitions();
//This loops through the list of transitions of the machine and pulls possible transitions from its current state
for(int i = 0; i < tempTrans.size(); i++) {
String pull = tempTrans.get(i);
String[] apart = pull.split(" ");
pull = apart[0];
if(states.get(Integer.toString(nextInt)).equals(pull)) {
listOfCurrentTransitions.add(tempTrans.get(i));
}
}
if(!(listOfCurrentTransitions.isEmpty())) {
textArea.appendText("The following transitions are possible. Choose one: " + listOfCurrentTransitions);
}
else {
textArea.appendText("No transitions for this machine exist from its current state");
}
//Tell GUI to wait for user input in textField and execute textButton which assigns to String text. Resume on button click.
The while loop blocks the JavaFX application thread which prevents updates of the GUI and handling of events.
You need to execute the logic of a single iteration of the loop on each "text commit" instead:
private TextArea textArea;
private void activateState(int nextInt) {
ArrayList<String> listOfCurrentTransitions = new ArrayList<String>();
textArea.appendText("Choose a state to load");
//Print out the states possible for each machine
ArrayList<String> tempTrans = machines.get(nextInt).getTransitions();
//This loops through the list of transitions of the machine and pulls possible transitions from its current state
for(int i = 0; i < tempTrans.size(); i++) {
String pull = tempTrans.get(i);
String[] apart = pull.split(" ");
pull = apart[0];
if(states.get(Integer.toString(nextInt)).equals(pull)) {
listOfCurrentTransitions.add(tempTrans.get(i));
}
}
if(listOfCurrentTransitions.isEmpty()) {
textArea.appendText("No transitions for this machine exist from its current state");
} else {
textArea.appendText("The following transitions are possible. Choose one: " + listOfCurrentTransitions);
}
}
#Override
public void start(Stage primaryStage) throws Exception {
...
textArea = new TextArea();
...
startButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
machineCreation();
activateState(0);
}
});
textButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
// read input and ask for more input...
int nextState = Integer.parseInt(textField.getText()); // TODO: deal with invalid input
activateState(nextState);
}
});
You probably need to fix the logic a bit to verify a transition is valid, change the values of some fields ect...
I'm trying to make a program that will display a random set of 4 cards, then when I click the button again it will clear the old set and display a new random set.
Right now my program will display 4 random images of cards when I click the button; however, when I try to click it again nothing happens. I'm assuming it has something to do with the EventHandler no longer being registered to the button after I clear the root children. However, I don't know how to go about fixing this. Any help is greatly appreciated! I haven't been able to find an answer to this yet, and have only been learning JavaFX for about a week. Thank you.
The code I have so far:
public class CardShuffle extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
StackPane root = new StackPane();
Scanner input = new Scanner(System.in);
File cardsFolder = new File("C:\\Users\\timsp\\Pictures\\JPEG");
ArrayList<File> cardsFilePaths = new ArrayList<File> (Arrays.asList(cardsFolder.listFiles()));
Button deal = new Button("DEAL");
Pane hb = new HBox(10);
hb.setPadding(new Insets(5, 5, 5, 5));
root.getChildren().add(deal);
deal.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
root.getChildren().clear();
ArrayList<ImageView> cards = getRandomCards(cardsFilePaths);
for (int i = 0; i < 4; i++) {
cards.get(i).setFitWidth(150);
cards.get(i).setFitHeight(100);
hb.getChildren().add(cards.get(i));
}
root.getChildren().addAll(deal, hb);
}
});
Scene scene = new Scene(root, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
public ArrayList<ImageView> getRandomCards(ArrayList<File> cardsFilePaths) {
ArrayList<ImageView> cards = new ArrayList<ImageView>();
try {
for (int i = 0; i < 4; i++) {
Image card = new Image((new FileInputStream(cardsFilePaths.get((int) (Math.random() * 52)).getPath())));
ImageView temp = new ImageView();
temp.setImage(card);
cards.add(temp);
}
} catch (FileNotFoundException e) {
e.getMessage();
}
return cards;
}
}
Many problems here :
the first one, and the most important (because it hides your further error) is the root layout : you use a StackPane, the first thing you should do is to replace it by a VBox for example and rerun your program, it will be easier to see what really happens. (you will not have 4 cards, but 8, 12, 16 and so on).
the first one generates the second one. By doing this root.getChildren().addAll(deal, hb); you put the HBox layout above the button, and the click is first consumed by the HBox. Here is an example to see it more easily :
// Add the HBox as soon as the initialization
root.getChildren().add(deal);
hb.setOnMouseClicked(e -> System.out.println("HBox clicked"));
deal.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
root.getChildren().clear();
ArrayList<ImageView> cards = getRandomCards(cardsFilePaths);
for(int i = 0; i < 4; i++) {
cards.get(i).setFitWidth(150);
cards.get(i).setFitHeight(100);
hb.getChildren().add(cards.get(i));
}
hb.setStyle("-fx-background-color:CORNFLOWERBLUE;-fx-opacity:0.8;");
root.getChildren().addAll(deal, hb);
}
});
And the last one, you don't really want to remove all root's children, what you want is to replace your cards by another 4 ones. Thus it is not necessary to remove the button, only the HBox can be manipulated as shown by the following example :
// Add the HBox as soon as the initialization
root.getChildren().addAll(hb, deal);
deal.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
// root.getChildren().clear();
// Replace the previous line by the following :
hb.getChildren().clear();
ArrayList<ImageView> cards = getRandomCards(cardsFilePaths);
for(int i = 0; i < 4; i++) {
cards.get(i).setFitWidth(150);
cards.get(i).setFitHeight(100);
hb.getChildren().add(cards.get(i));
}
// The following is useless now.
// root.getChildren().addAll(hb, deal);
}
});
In my JavaFX TableView, I am trying to retrieve TableCells from a selected row to mark them
with custom colors.
Simply changing the colors of the entire row does not work in this case, as I use different color shadings in each cell depending
on the value of each cell
The example below shows two approaches I tried I to solve the problem
1) Use a listener to retrieve cells in the selected row. Printing the row index and content already works
However, I could not find how to retrieve a TableCell from table.getSelectionModel().
2) Try a dirty workaround to add the TableCells to a global data structure in the columnCellFactory.
However, the TableCells do not get added to the tableCells ArrayList for some reason.
To obtain a short example, the imports and the Classes defining the EditingCell (custom TableCell) and CellEditEvent were omitted.
package TableViewColExample;
public class TableViewExample extends Application {
private Callback<TableColumn, TableCell> columnCellFactory ;
final TableView<String[]> table = new TableView<String[]>();
ObservableSet<Integer> selectedRowIndexes = FXCollections.observableSet();
ObservableSet<String> selectedRows = FXCollections.observableSet();
ArrayList<ArrayList<EditingCell>> tableColumns = new ArrayList<ArrayList<EditingCell>>();
#Override
public void start(Stage stage) {
String[][] dat = new String[][]{
{"C1","C2","C3"},{"a","b","c"},{"d","e","f"},{"g","i","h"}};
ObservableList<String []> data = FXCollections.observableArrayList();
data.addAll(Arrays.asList(dat));
data.remove(0);
table.setItems(data);
for (int i = 0; i < dat[0].length; i++) {
TableColumn tc = new TableColumn(dat[0][i]);
final int colNo = i;
tc.setCellValueFactory(new Callback<CellDataFeatures<String[], String>, ObservableValue<String>>() {
public ObservableValue<String> call(CellDataFeatures<String[], String> p) {
return new SimpleStringProperty((p.getValue()[colNo]));
}
});
ArrayList<EditingCell> tableCells = new ArrayList<EditingCell>();
columnCellFactory =
new Callback<TableColumn, TableCell>() {
public TableCell call(TableColumn p) {
EditingCell tcell = new EditingCell();
//For some reason, the EditingCell is never added to the list
tableCells.add(tcell);
return tcell;
}
};
tc.setCellFactory(columnCellFactory);
tableColumns.add(tableCells);
//The printed value here is 0, which means that the Factory does not add the Editing Cell to the List
System.out.println(" Column rows "+tableCells.size());
table.getColumns().add(tc);
}
//Output: TableColumns 3, TableRows 0
System.out.println("TableColumns "+ tableColumns.size() + " Table rows "+tableColumns.get(0).size());
table.setItems(data);
table.getSelectionModel().getSelectedCells().addListener((Change<? extends TablePosition> change) -> {
selectedRows.clear();
table.getSelectionModel().getSelectedCells().stream().map(TablePosition::getRow).f orEach(row -> {
selectedRowIndexes.add(row);
System.out.println(selectedRowIndexes.toString());
});
table.getSelectionModel().getSelectedItems().forEach(row -> {
selectedRows.add(Arrays.toString(row));
System.out.println(selectedRows.toString());
});
});
stage.setScene(new Scene(table));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}