Issue
Hi all so i am attempting to create a gui where one can drag and drop images of components into a stackpane, then take this finished layout / image (of multiple uploaded images) and put it into an excel file, i figured it would be better to save a local version of that snapshoted node first on the users computer and then send it to excel but when i attempt to save a test png it does not work. Not in the sense that it doesnt work at all but once the .showSaveDialog window opens i choose .PNG as an extension then give the file a name like "test" for example and hit save no file is created.i dont know what else would be needed or if its some silly mistake(of course i dont know im fairly new to javafx so please be patient). PS i attempted to make a minimal reproducible example im sorry if it is not perfect. My controller class:
public class Main {
@FXML private AnchorPane layoutPane;
@FXML private Canvas layoutCanvas;
@FXML private StackPane stackPane;
Window mainStage;
String filePath;
String imageFilePath;
// just to test saving a snapshot it just sets a single imageview as a child of the
// stack pane when button clicked otherwise this deals with drag and drop
public void dragAndDropImageView(ImageView image)
{
image.setOnMousePressed(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent mouseEvent) {
x = image.getLayoutX() - mouseEvent.getSceneX();
y = image.getLayoutY() - mouseEvent.getSceneY();
}
});
image.setOnMouseDragged(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent mouseEvent) {
image.setLayoutX(mouseEvent.getSceneX() + x);
image.setLayoutY(mouseEvent.getSceneY() + y);
}
});
stackPane.getChildren().addAll(image);
}
// is supposed to handle the creation of new image views on each button click
public void handleImage() throws IOException
{
final double startingXPosition = 14;
final double startingYPosition = 146;
File chosenFile = fileChooser.showOpenDialog(mainStage);
String imageFilePath = chosenFile.getAbsolutePath();
Image componentImage = new Image(imageFilePath);
ImageView imageView = new ImageView();
imageView.setImage(componentImage);
imageView.setLayoutX(startingXPosition);
imageView.setLayoutY(startingYPosition);
imageView.setFitWidth(154);
imageView.setFitHeight(135);
layoutPane.getChildren().addAll(imageView);
imageView.setVisible(true);
dragAndDropImageView(imageView);
}
//handles saving image as png and sending to excel
public void exportImage() throws IOException
{
FileInputStream fis = new FileInputStream(filePath);
//String imageFilePath = imageFile.getAbsolutePath();
XSSFWorkbook workBook = new XSSFWorkbook(fis);
XSSFSheet sheet = workBook.getSheet("Tooling Layout");
WritableImage wi = new WritableImage(1080,790);
stackPane.snapshot(null, wi);
BufferedImage bImage = SwingFXUtils.fromFXImage(wi, null);
FileChooser saveFile = new FileChooser();
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("PNG files", "*.PNG");
saveFile.getExtensionFilters().add(extFilter);
File imageFile = saveFile.showSaveDialog(mainStage);
ImageIO.write(bImage, ".png", imageFile);
InputStream is = new FileInputStream(imageFile);
byte[] bytes = IOUtils.toByteArray(is);
int pictureId = workBook.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
is.close();
CreationHelper helper = workBook.getCreationHelper();
Drawing drawing = sheet.createDrawingPatriarch();
ClientAnchor anchor = helper.createClientAnchor();
anchor.setCol1(1);
anchor.setRow1(2);
Picture pict = drawing.createPicture(anchor, pictureId);
FileOutputStream fos = new FileOutputStream(filePath);
workBook.write(fos);
fis.close();
fos.close();
workBook.close();
}
}
my FXML
<VBox prefHeight="400.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Main">
<children>
<MenuBar prefHeight="67.0" prefWidth="640.0" style="-fx-background-color: white;" VBox.vgrow="NEVER" />
<AnchorPane maxHeight="-1.0" maxWidth="-1.0" prefHeight="-1.0" prefWidth="-1.0" style="-fx-background-color: #00A5AD;" VBox.vgrow="ALWAYS">
<children>
<TabPane layoutY="-1.0" prefHeight="375.0" prefWidth="640.0" style="-fx-background-color: white;" tabClosingPolicy="UNAVAILABLE">
<tabs>
<Tab text="Tooling layout">
<content>
<AnchorPane fx:id="layoutPane" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<Label layoutX="16.0" layoutY="115.0" text="Selected component Image:" />
<Button layoutX="4.0" layoutY="26.0" mnemonicParsing="false" onAction="#handleImage" style="-fx-background-color: black;" text="Upload Image of Component" textFill="WHITE" />
<Rectangle arcHeight="5.0" arcWidth="5.0" fill="WHITE" height="319.0" layoutX="207.0" layoutY="17.0" scaleZ="0.0" stroke="BLACK" strokeType="INSIDE" width="426.0" />
<Button layoutX="3.0" layoutY="72.0" mnemonicParsing="false" onAction="#exportImage" style="-fx-background-color: black;" text="Export Layout to SpreadSheet" textFill="WHITE" />
<StackPane fx:id="stackPane" layoutX="217.0" layoutY="26.0" prefHeight="301.0" prefWidth="409.0" />
</children>
</AnchorPane>
</content>
</Tab>
</tabs>
</TabPane>
</children>
</AnchorPane>
</children>
</VBox>
my App class:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class App extends Application{
public void start(Stage primaryStage) throws Exception {
try{
FXMLLoader loader = new FXMLLoader(getClass().getResource("mainframe.fxml"));
Parent root = (Parent) loader.load();
Scene scene = new Scene(root);
primaryStage.setTitle("Excel Populator");
primaryStage.setScene(scene);
primaryStage.show();
}
catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception
{
launch(args);
}
}
Solution
So I actually was able to get my code working by removing a few things and realizing that I was never actually creating a file that ImageIO would write to in essence I was able to do all the Buffered Image code and FXutils code in a single line and create a new file each time the snapshot was to be saved so that ImageIO could write my taken snapshot to that Png file.
Those were my mistakes below is what I changed:
Image finalImage = stackPane.snapshot(null, null);
FileChooser saveFile = new FileChooser();
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("PNG files", "*.PNG");
saveFile.getExtensionFilters().add(extFilter);
File imageFile = saveFile.showSaveDialog(mainStage);
ImageIO.write(SwingFXUtils.fromFXImage(finalImage, null), "png", imageFile);
Answered By - Aaron Perel
Answer Checked By - Pedro (JavaFixing Volunteer)