JavaFX ImageView repaint stage in while - javafx

I can't redraw imageview in while. Without while is work with single image. May be it will be work if i try to use diffrent thread for image redraw, but i don't kno how to make it. Anybody can give me example for way where i can make it workable^)
package videostepone;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.ByteArrayInputStream;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.Scalar;
import org.opencv.highgui.Highgui;
import org.opencv.highgui.VideoCapture;
import org.opencv.objdetect.CascadeClassifier;
/**
*
* #author Анютка
*/
public class FXMLDocumentController implements Initializable {
#FXML
private Label label;
#FXML
private ImageView imageCam1;
#FXML
private void handleButtonAction(ActionEvent event) throws InterruptedException {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
//System.loadLibrary("opencv_java2410");
System.out.println("You clicked me!");
label.setText("Hello World!");
WebCamLive();
}
// Делает снимок с веб-камеры
private void WebCamShot() throws InterruptedException
{
VideoCapture camera = new VideoCapture(0);
Thread.sleep(1000);
camera.open(0); //Useless
if(!camera.isOpened()){
System.out.println("Camera Error");
}
else{
System.out.println("Camera OK?");
}
Mat frame = new Mat();
camera.read(frame);
System.out.println("Captured Frame Width " + frame.width());
Highgui.imwrite("camera.jpg", frame);
System.out.println("OK");
}
// Видео с веб-камеры
private void WebCamLive() throws InterruptedException
{
int i = 0;
VideoCapture camera = new VideoCapture(0);
Thread.sleep(1000);
camera.open(0); //Useless
if(!camera.isOpened()){
System.out.println("Camera Error");
}
else{
System.out.println("Camera OK?");
}
Mat frame = new Mat();
CascadeClassifier faceDetect = new CascadeClassifier("./res/haarcascade_frontalface_default.xml");
while (true)
{
camera.read(frame);
if (!frame.empty())
{
setImageOn(matToImage(frame));
// label.setText("1");
// Thread.sleep(6000);
// label.setText("-");
System.out.println(i++);
}
}
}
#FXML
private void setImageOn(Image img)
{
imageCam1.setImage(img);
}
private Image matToImage(Mat m){
MatOfByte memory = new MatOfByte();
try {
Highgui.imencode(".jpg", m, memory);
return (new Image(new ByteArrayInputStream(memory.toArray())));
} catch (Exception e) {
System.out.println(e);
}
return (new Image(new ByteArrayInputStream(memory.toArray())));
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}

As ItachiUchiha has pointed out your controller has some threading problems.
Like most other GUI toolkits, JavaFX is a single threaded GUI toolkit and thus all time consuming tasks which might block the GUI Thread should be performed elsewhere. Ohterwise nothings gets painted.
If I read your code correctly WebCamLive() takes a snapshot of the webcam every second?
Now you have two options on how to do this with JavaFX:
If the snapshot is taken rather fast, you can do this with a TimeLine, as shown here: Javafx Not on fx application thread when using timer
If the snapshot takes some time to capture, I would recommend writing a ScheduledService.
For further information on threading in JavaFX refer to the tutorial here: http://docs.oracle.com/javafx/2/threads/jfxpub-threads.htm

Related

Restarting and pausing and resuming clip hangs the gui of music player, while pressing pause and play resumes playing from stopping point

This program is a music player that allows user to pick a .wav file, play, pause, resume, and restart a the music file from a clip object and audioinput stream. The audio input stream loads a file that is determined by user via FileChooser. The program can play, pause, and resume by selecting a file, pressing play, pause, then play again, but does not play using the restart method or the resume method invoked via the respective buttons. Instead, the program hangs until the X button is clicked. I think it has something to do with the resetaudiostream method, but I am unsure what. Maybe something to do with ending the old clip and creating a new clip instance. Please review the logic and let me know what is making it hang and how that could be remedied.
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javax.sound.sampled.*;
import java.io.File;
import java.io.IOException;
public class Main extends Application {
static File musicfile;
static Long currentFrame;
static Clip clip;
static String status = "play";
static AudioInputStream audioInputStream;
static String filePath;
public void SimpleAudioPlayer()
throws UnsupportedAudioFileException,
IOException, LineUnavailableException
{
// create AudioInputStream object
audioInputStream =
AudioSystem.getAudioInputStream(new File(filePath).getAbsoluteFile());
// create clip reference
clip = AudioSystem.getClip();
// open audioInputStream to the clip
clip.open(audioInputStream);
clip.loop(Clip.LOOP_CONTINUOUSLY);
}
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Music Player");
GridPane gp = new GridPane();
Button selectFile = new Button("Select File");
GridPane.setConstraints(selectFile, 0,0);
selectFile.setOnAction(event->{
FileChooser filechooser = new FileChooser();
// create AudioInputStream object
try {
musicfile = filechooser.showOpenDialog(null);
audioInputStream = AudioSystem.getAudioInputStream(musicfile);
clip = AudioSystem.getClip();
// open audioInputStream to the clip
clip.open(audioInputStream);
}catch(IOException | UnsupportedAudioFileException | LineUnavailableException e){
e.printStackTrace();
}
});
Button play = new Button("Play");
GridPane.setConstraints(play, 1,0);
play.setOnAction(event->{
if(status == "play") {
clip.loop(Clip.LOOP_CONTINUOUSLY);
}
play();
});
Button pause = new Button("Pause");
GridPane.setConstraints(pause, 2,0);
pause.setOnAction(event -> pause());
Button restart = new Button("Restart");
GridPane.setConstraints(restart, 0,1);
restart.setOnAction(event -> {
try{
restart();
}
catch(IOException | UnsupportedAudioFileException | LineUnavailableException e){
e.printStackTrace();}
});
Button resume = new Button("Resume");
GridPane.setConstraints(resume, 1,1);
resume.setOnAction(event -> {
try {
resumeAudio();
}catch(IOException | LineUnavailableException | UnsupportedAudioFileException e){
e.printStackTrace();
}
});
gp.getChildren().addAll(play,selectFile, pause, restart, resume);
primaryStage.setScene(new Scene(gp, 300, 275));
primaryStage.show();
}
public void play()
{
//start the clip
clip.start();
status = "play";
}
// Method to pause the audio
public void pause()
{
if (status.equals("paused"))
{
System.out.println("audio is already paused");
return;
}
currentFrame =
clip.getMicrosecondPosition();
clip.stop();
status = "paused";
}
// Method to resume the audio
public void resumeAudio() throws UnsupportedAudioFileException,
IOException, LineUnavailableException
{
if (status.equals("play"))
{
System.out.println("Audio is already "+
"being played");
return;
}
clip.close();
resetAudioStream();
clip.setMicrosecondPosition(currentFrame);
status = "play";
play();
}
// Method to restart the audio
public void restart() throws IOException, LineUnavailableException,
UnsupportedAudioFileException
{
clip.stop();
clip.close();
resetAudioStream();
currentFrame = 0L;
clip.setMicrosecondPosition(0);
status = "play";
play();
}
// Method to stop the audio
public void stop() throws UnsupportedAudioFileException,
IOException, LineUnavailableException
{
currentFrame = 0L;
clip.stop();
clip.close();
}
// Method to jump over a specific part
public void jump(long c) throws UnsupportedAudioFileException, IOException,
LineUnavailableException
{
if (c > 0 && c < clip.getMicrosecondLength())
{
clip.stop();
clip.close();
resetAudioStream();
currentFrame = c;
clip.setMicrosecondPosition(c);
this.play();
}
}
// Method to reset audio stream
public void resetAudioStream() throws UnsupportedAudioFileException, IOException,
LineUnavailableException
{
audioInputStream = AudioSystem.getAudioInputStream(musicfile);
clip = AudioSystem.getClip();
clip.open(audioInputStream);
clip.loop(Clip.LOOP_CONTINUOUSLY);
}
public static void main(String[] args) {
launch(args);
}
}
It is quiet simple to get the required functionality with a MediaPlayer:
import java.net.URI;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaPlayer.Status;
import javafx.stage.Stage;
import javafx.util.Duration;
/*
* If you get "cannot access class com.sun.glass.utils.NativeLibLoader" exception you may need to
* add a VM argument: --add-modules javafx.controls,javafx.media as explained here:
* https://stackoverflow.com/questions/53237287/module-error-when-running-javafx-media-application
*/
public class Main extends Application {
private MediaPlayer player;
private static final long JUMP_BY = 5000;//millis
#Override
public void start(Stage primaryStage) throws Exception{
URI uri = new URI("https://www.soundhelix.com/examples/mp3/SoundHelix-Song-5.mp3");
Media media = new Media(uri.toString());
//OR Media media = new Media("https://www.soundhelix.com/examples/mp3/SoundHelix-Song-5.mp3");
player = new MediaPlayer(media);
player.setOnError(() -> System.out.println(media.getError().toString()));
GridPane gp = new GridPane();
gp.setHgap(10);
Button play = new Button("Play");
GridPane.setConstraints(play, 0,0);
play.setOnAction(event-> playAudio());
Button pause = new Button("Pause");
GridPane.setConstraints(pause, 1,0);
pause.setOnAction(event -> pauseAudio());
Button resume = new Button("Resume");
GridPane.setConstraints(resume, 2,0);
resume.setOnAction(event -> resumeAudio());
Button stop = new Button("Stop");
GridPane.setConstraints(stop, 3,0);
stop.setOnAction(event -> stopAudio());
Button restart = new Button("Restart");
GridPane.setConstraints(restart, 4,0);
restart.setOnAction(event -> restartAudio());
Button jump = new Button("Jump >");
GridPane.setConstraints(jump, 5,0);
jump.setOnAction(event -> jump(JUMP_BY));
Label time = new Label();
GridPane.setConstraints(time, 6,0);
time.textProperty().bind( player.currentTimeProperty().asString("%.4s") );
gp.getChildren().addAll(play, pause, resume, stop, restart, jump, time);
primaryStage.setScene(new Scene(gp, 400, 45));
primaryStage.show();
}
//play audio
public void playAudio()
{
player.play();
}
//pause audio
public void pauseAudio()
{
if (player.getStatus().equals(Status.PAUSED))
{
System.out.println("audio is already paused");
return;
}
player.pause();
}
//resume audio
public void resumeAudio()
{
if (player.getStatus().equals(Status.PLAYING))
{
System.out.println("Audio is already playing");
return;
}
playAudio();
}
//restart audio
public void restartAudio()
{
player.seek(Duration.ZERO);
playAudio();
}
// stop audio
public void stopAudio()
{
player.stop();
}
//jump by c millis
public void jump(long c)
{
player.seek(player.getCurrentTime().add(Duration.millis(c)));
}
public static void main(String[] args) {
launch(args);
}
}

What's a good observable appendable base for a TextArea?

I have a StringBuffer that is occasionally appended with new information.
In a separate module, I have a JavaFX TextArea that displays that StringBuffer.
Right now, I have to manually update the TextArea every time the underlying data is modified.
Is there something like an ObservableList (which I use for TableViews) that I can use as the back-end data for the TextArea instead, so I don't have to manually manage pushing the changes to the display?
I am not attached to using a StringBuffer. I'm glad to use any appendable data structure to hold text.
You can consider something simple like this:
import javafx.beans.binding.StringBinding;
public class ObservableStringBuffer extends StringBinding {
private final StringBuffer buffer = new StringBuffer() ;
#Override
protected String computeValue() {
return buffer.toString();
}
public void set(String content) {
buffer.replace(0, buffer.length(), content);
invalidate();
}
public void append(String text) {
buffer.append(text);
invalidate();
}
// wrap other StringBuffer methods as needed...
}
This enables easy coding for binding to a text area. You can simply do
TextArea textArea = new TextArea();
ObservableStringBuffer buffer = new ObservableStringBuffer();
textArea.textProperty().bind(buffer);
// ...
buffer.append("Hello world");
However, it's important to note here that you don't transfer the efficiency of the buffer API to the text area: the text area simply has a textProperty() representing its text, which can still only really be modified by set(...) and setValue(...). In other words, when you append to the buffer, you essentially end up with textArea.setText(textArea.getText() + "Hello world") (not textArea.appendText("Hello world"). If you're just looking for a clean API, then this should work for you; if you're looking for something efficient, you would have to "wire" the calls to appendText yourself, since that is simply not supported by the text area's textProperty().
Here's a SSCCE using the above class:
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class ObservableStringBufferTest extends Application {
private int counter ;
#Override
public void start(Stage primaryStage) {
ObservableStringBuffer buffer = new ObservableStringBuffer();
TextArea textArea = new TextArea();
textArea.setEditable(false);
textArea.textProperty().bind(buffer);
buffer.set("Item 0");
Timeline timeline = new Timeline(new KeyFrame(
Duration.seconds(1),
e -> buffer.append("\nItem "+(++counter))));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
primaryStage.setScene(new Scene(new StackPane(textArea)));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Alert in JAVA FX

I want to display an alert when a file already exists when trying to create the file with same name . I have not completed the code fully. I want to retrieve the button value Yes/No from the UI .
Code:
This is how the controller is coded.
package application;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.TreeMap;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;
public class WarningController implements Initializable {
#FXML
public Button yes;
#FXML
public Button no;
public static String type;
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
// TODO Auto-generated method stub
}
public String confirmSelection(ActionEvent event)throws IOException{
Button button = (Button) event.getSource();
type = button.getText();
if(type.equals("Yes")){
Stage stage = (Stage) yes.getScene().getWindow();
stage.close();
//System.out.println("Yes");
return type;
}
else{
//System.out.println("No");
Stage stage1 = (Stage) no.getScene().getWindow();
stage1.close();
return type;
}
}
/********************************************************************************/
public void writesheet(String[][] result,String ComboValue,String[] heading) throws IOException{
//Create blank workbook
XSSFWorkbook workbook = new XSSFWorkbook();
//Create a blank sheet
XSSFSheet spreadsheet = workbook.createSheet( " Employee Info ");
//Create row object
XSSFRow row;
String[][] towrite=result;
int rows=towrite.length;
//int cols=towrite[0].length;
// System.out.println(rows +" "+ cols);
Map < String, Object[] > empinfo = new TreeMap < String, Object[] >();
empinfo.put("0", heading);
for(int i=1;i<=rows;i++){
empinfo.put( Integer.toString(i),towrite[i-1]);
}
//Iterate over data and write to sheet
Set < String > keyid = empinfo.keySet();
int rowid = 0;
for (String key : keyid)
{
row = spreadsheet.createRow(rowid++);
Object [] objectArr = empinfo.get(key);
int cellid = 0;
for (Object obj : objectArr)
{
Cell cell = row.createCell(cellid++);
//cell.setCellValue((String)obj);
cell.setCellValue(obj.toString());
}
}
//Write the workbook in file system
File f=new File(("C:\\"+ComboValue+".xlsx"));
if(f.exists()){
Stage primaryStage=new Stage();
Parent root=FXMLLoader.load(getClass().getResource("/application/Warning.fxml"));
Scene scene = new Scene(root,350,150);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
System.out.println(type);
}
FileOutputStream out = new FileOutputStream(f);
workbook.write(out);
out.close();
System.out.println(ComboValue+" "+"Excel document written successfully" );
workbook.close();
}
}
I want to use button value(stored in String type) in writesheet function. Now it is returning NULL.
Please suggest if there is any other way to show warning.I am using two fxml files and this is the second excel file.
[1]: http://i.stack.imgur.com/ZK6UC.jpg
Simply use the Alert class. It provides functionality for most yes/no dialogs that you ever need.
Alert alert = new Alert(AlertType.WARNING,
"File already exists. Do you want to override?",
ButtonType.YES, ButtonType.NO);
Optional<ButtonType> result = alert.showAndWait();
if (result.get() == ButtonType.YES){
// ... user chose YES
} else {
// ... user chose NO or closed the dialog
}
Also here is a good tutorial.
I usually make a method, and call it if certain conditions are not met.
Ex:
if(condition)
alert();
public void alert(){ //alert box
Alert alert = new Alert(AlertType.WARNING,"", ButtonType.YES, ButtonType.NO); //new alert object
alert.setTitle("Warning!"); //warning box title
alert.setHeaderText("WARNING!!!");// Header
alert.setContentText("File already exists. Overwrite?"); //Discription of warning
alert.getDialogPane().setPrefSize(200, 100); //sets size of alert box
Optional<ButtonType> result = alert.showAndWait();
if (result.get() == ButtonType.YES){
// ... user chose YES
} else {
// ... user chose NO or closed the dialog
}
}
I grabbed some code from Jhonny007, credit to him.

JavaFX file listview with icon and file name

In a JavaFX dialog, I would like to show a list of files with their icons and file names.
It was easy to find how to get an icon for a file extension:
File file = File.createTempFile("icon", ".doc");
FileSystemView view = FileSystemView.getFileSystemView();
java.swing.Icon icon = view.getSystemIcon(file);
file.delete();
But, how can I draw that Swing Icon in a JavaFX ListView?
private static class AttachmentListCell extends ListCell<String> {
#Override
public void updateItem(String fileName, boolean empty) {
if (item != null) {
// Get file Icon for fileName as shown above.
java.swing.Icon icon =
// Transform Icon to something that can be
// added to the box, maybe an ImageView.
javafx.scene.image.ImageView image = ???
// Label for file name
Label label = new Label(item);
HBox box = new HBox();
box.getChildren().addAll(image, label);
setGraphic(box);
}
}
}
Here is an example for a list view with file icons:
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;
import javax.swing.filechooser.FileSystemView;
public class ListViewCellFactory2 extends Application {
ListView<String> list = new ListView<String>();
ObservableList<String> data = FXCollections.observableArrayList(
"a.msg", "a1.msg", "b.txt", "c.pdf",
"d.html", "e.png", "f.zip",
"g.docx", "h.xlsx", "i.pptx");
#Override
public void start(Stage stage) {
VBox box = new VBox();
Scene scene = new Scene(box, 200, 200);
stage.setScene(scene);
stage.setTitle("ListViewSample");
box.getChildren().addAll(list);
VBox.setVgrow(list, Priority.ALWAYS);
list.setItems(data);
list.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
#Override
public ListCell<String> call(ListView<String> list) {
return new AttachmentListCell();
}
});
stage.show();
}
private static class AttachmentListCell extends ListCell<String> {
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
setText(null);
} else {
Image fxImage = getFileIcon(item);
ImageView imageView = new ImageView(fxImage);
setGraphic(imageView);
setText(item);
}
}
}
public static void main(String[] args) {
launch(args);
}
static HashMap<String, Image> mapOfFileExtToSmallIcon = new HashMap<String, Image>();
private static String getFileExt(String fname) {
String ext = ".";
int p = fname.lastIndexOf('.');
if (p >= 0) {
ext = fname.substring(p);
}
return ext.toLowerCase();
}
private static javax.swing.Icon getJSwingIconFromFileSystem(File file) {
// Windows {
FileSystemView view = FileSystemView.getFileSystemView();
javax.swing.Icon icon = view.getSystemIcon(file);
// }
// OS X {
//final javax.swing.JFileChooser fc = new javax.swing.JFileChooser();
//javax.swing.Icon icon = fc.getUI().getFileView(fc).getIcon(file);
// }
return icon;
}
private static Image getFileIcon(String fname) {
final String ext = getFileExt(fname);
Image fileIcon = mapOfFileExtToSmallIcon.get(ext);
if (fileIcon == null) {
javax.swing.Icon jswingIcon = null;
File file = new File(fname);
if (file.exists()) {
jswingIcon = getJSwingIconFromFileSystem(file);
}
else {
File tempFile = null;
try {
tempFile = File.createTempFile("icon", ext);
jswingIcon = getJSwingIconFromFileSystem(tempFile);
}
catch (IOException ignored) {
// Cannot create temporary file.
}
finally {
if (tempFile != null) tempFile.delete();
}
}
if (jswingIcon != null) {
fileIcon = jswingIconToImage(jswingIcon);
mapOfFileExtToSmallIcon.put(ext, fileIcon);
}
}
return fileIcon;
}
private static Image jswingIconToImage(javax.swing.Icon jswingIcon) {
BufferedImage bufferedImage = new BufferedImage(jswingIcon.getIconWidth(), jswingIcon.getIconHeight(),
BufferedImage.TYPE_INT_ARGB);
jswingIcon.paintIcon(null, bufferedImage.getGraphics(), 0, 0);
return SwingFXUtils.toFXImage(bufferedImage, null);
}
}
EDIT: On a HDPI monitor, the file icons are clipped.
What has to be done to have the icons entirely displayed in the row?
How can I retrieve the scale factor from Java?
I came up with this code, which seems to work for converting the icon returned by getSystemIcon to a format which JavaFX can understand. It does this by using a combo of SwingUtilities.invokeLater with Platform.runLater to try to mitigate any potential threading issues between the two projects. The javax.swing.Icon is painted to java.awt.BufferedImage which is converted by SwingFXUtils to a JavaFX Image.
So the Swing Icon => JavaFX image portion of the code you were asking about seems to work. The only thing is, when I tested the application on OS X 10.7 running Oracle Java8u20, every file extension type I tried gave the exact same icon. So it would seem that your method for getting an icon from the system via the swing FileSystemView isn't really supported on OS X (as far as I can tell). I guess you could try it on another OS and see if it works for you there (presuming that supporting this icon lookup feature on OS X is not necessary for your task).
So googling around brought up the following question:
Access file type icons Mac OSX
And in that, Sam Barnum recommends a FileView works much better than a FileSystemView - and so it did for me. I switched your code to use a FileView and after that started getting different icons for different file types on OS X. The icons were still really small 16x16 icons (I wouldn't know how to retrieve the hi-res retina icons for instance), but at least the icons which were retrieved appeared correct and file type specific.
import javafx.application.Application;
import javafx.application.Platform;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class FileIconViewer extends Application {
#Override
public void start(Stage stage) throws IOException {
Runnable fetchIcon = () -> {
File file = null;
try {
file = File.createTempFile("icon", ".png");
// commented code always returns the same icon on OS X...
// FileSystemView view = FileSystemView.getFileSystemView();
// javax.swing.Icon icon = view.getSystemIcon(file);
// following code returns different icons for different types on OS X...
final javax.swing.JFileChooser fc = new javax.swing.JFileChooser();
javax.swing.Icon icon = fc.getUI().getFileView(fc).getIcon(file);
BufferedImage bufferedImage = new BufferedImage(
icon.getIconWidth(),
icon.getIconHeight(),
BufferedImage.TYPE_INT_ARGB
);
icon.paintIcon(null, bufferedImage.getGraphics(), 0, 0);
Platform.runLater(() -> {
Image fxImage = SwingFXUtils.toFXImage(
bufferedImage, null
);
ImageView imageView = new ImageView(fxImage);
stage.setScene(
new Scene(
new StackPane(imageView),
200, 200
)
);
stage.show();
});
} catch (IOException e) {
e.printStackTrace();
Platform.exit();
} finally {
if (file != null) {
file.delete();
}
}
};
javax.swing.SwingUtilities.invokeLater(fetchIcon);
}
public static void main(String[] args) { launch(args); }
}
Note: there is an existing request in the JavaFX issue tracker to add this functionality to JavaFX (it is currently not scheduled for implementation, though you could log into the issue tracker and vote for the issue, comment on it, link it back to this StackOverflow question, etc):
RT-19583 Possibility to get native icons, on different sizes.

Make JavaFX wait and continue with code

Basically I am trying to make a short effect using JavaFX. I have the shape of a heart (added together from two circles and a polygon) that I can vary in size using the double value p. "Standart Size" would be p = 1.0;.
I am trying to add a pumping effect to the heart. I have the method pumpOnce():
public void pumpOnce(){
p = p + 1;
initHeart();
//Here goes what ever it takes to make stuff working!!
p = p - 1;
initHeart();
}
initHeart() draws the heart based on p.
I have found out that Thread.sleep(); or similar methods will not work due to the thread philosophy in JavaFX.
But what can I use instead?
The JavaFX animations are probably the way to go, but the "thread philosophy" in JavaFX isn't hard to work with if you want to roll your own, or do other, more complicated things in background threads.
The following code will pause and change the value in a label (full disclosure, I'm reusing code I wrote for another question):
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javax.xml.datatype.Duration;
public class DelayWithTask extends Application {
private static Label label;
public static void main(String[] args) { launch(args); }
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World!");
label = new Label();
label.setText("Waiting...");
StackPane root = new StackPane();
root.getChildren().add(label);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
delay(5000, () -> label.setText("Hello World"));
}
public static void delay(long millis, Runnable continuation) {
Task<Void> sleeper = new Task<Void>() {
#Override
protected Void call() throws Exception {
try { Thread.sleep(millis); }
catch (InterruptedException e) { }
return null;
}
};
sleeper.setOnSucceeded(event -> continuation.run());
new Thread(sleeper).start();
}
}
The basic JavaFX background tool is the Task, any JavaFX application that actually does anything will probably be littered with these all over. Learn how to use them.
Dave's solution is great for general purpose off thread based work in JavaFX.
If you wish to use the animation facilities of JavaFX, the solutions below demonstrate this using a Timeline or a ScaleTransition. The timeline implements a discrete scale of the UI element, so every quarter of a second the UI element is scaled larger or back to it's original size. The scale transition implements a smooth scale of the UI element, so the UI element gradually gets larger then smaller using an interpolated scale factor with the default easing interpolator.
import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class BeatingHeart extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(Stage stage) {
ImageView heart = new ImageView(HEART_IMAGE_LOC);
animateUsingTimeline(heart);
// animateUsingScaleTransition(heart);
StackPane layout = new StackPane(heart);
layout.setPrefWidth(heart.getImage().getWidth() * 2);
layout.setPrefHeight(heart.getImage().getHeight() * 2);
Scene scene = new Scene(layout);
stage.setScene(scene);
stage.show();
}
private void animateUsingTimeline(ImageView heart) {
DoubleProperty scale = new SimpleDoubleProperty(1);
heart.scaleXProperty().bind(scale);
heart.scaleYProperty().bind(scale);
Timeline beat = new Timeline(
new KeyFrame(Duration.ZERO, event -> scale.setValue(1)),
new KeyFrame(Duration.seconds(0.5), event -> scale.setValue(1.1))
);
beat.setAutoReverse(true);
beat.setCycleCount(Timeline.INDEFINITE);
beat.play();
}
private void animateUsingScaleTransition(ImageView heart) {
ScaleTransition scaleTransition = new ScaleTransition(
Duration.seconds(1), heart
);
scaleTransition.setFromX(1);
scaleTransition.setFromY(1);
scaleTransition.setFromZ(1);
scaleTransition.setToX(1.1);
scaleTransition.setToY(1.1);
scaleTransition.setToZ(1.1);
scaleTransition.setAutoReverse(true);
scaleTransition.setCycleCount(Animation.INDEFINITE);
scaleTransition.play();
}
private static final String HEART_IMAGE_LOC =
"http://icons.iconarchive.com/icons/mirella-gabriele/valentine/128/Heart-red-icon.png";
// icon obtained from: http://www.iconarchive.com/show/valentine-icons-by-mirella-gabriele/Heart-red-icon.html
// icon license: Free for non-commercial use, commercial use not allowed.
}

Resources