I have a command to run the list of audio files as follows
public static void main(String[] args) {
File[] listFiles = new File(folder).listFiles();
ObservableList<Media> mediaList = FXCollections.observableArrayList();
for (File listFile : listFiles) {
mediaList.add(new Media(new File(listFile.getAbsolutePath()).toURI().toString()));
}
playMediaTracks(mediaList);
}
private static void playMediaTracks(ObservableList<Media> mediaList) {
if (!mediaList.isEmpty()) {
MediaPlayer mediaplayer = new MediaPlayer(mediaList.remove(0));
mediaplayer.play();
mediaplayer.setOnEndOfMedia(() -> {
playMediaTracks(mediaList);
});
}
}
Operation code is not stable,I have 10 audio files but sometimes only 2 or 3 files are stopped.But the program does not report bugs,I do not know how to fix. Please help me
Related
I have a problem how to correctly update Java FX UI. I'm moving from Swing to FX for the first time and also ExecutorService. Problem is I need to show gif file and update progress bar during code execution but instead I get white screen with mouse loading icon. The gif and progressbar are eventually showed but after finishing this for cycle: for (int i = 0; i < futures.size(); i++)
I thought that running tasks in ExecutorService is in separate thread and using Platform.runLater for progressbar will separate UI from long running code in ExecutorService. Can you give me some explanation what is going on please?
Controller.java:
public void initialize() {
ivGif.setImage(new Image(Main.class.getResourceAsStream("/test/loading.gif")));
}
public void synchronizeFiles() {
Platform.runLater(() -> pbDownloading.setVisible(true));
ExecutorService pool = Executors.newFixedThreadPool(1);
ArrayList<Future<Boolean>> futures = new ArrayList<>();
File localFile = new File(simplified code here);
Future<Boolean> f = pool.submit(new DownloadTask(new URL(simplified code here), localFile));
futures.add(f);
for (int i = 0; i < futures.size(); i++) {
final int position = i;
Platform.runLater(() -> {
pbDownloading.setProgress(position / (double) futures.size());
});
if (!futures.get(i).get(600, TimeUnit.SECONDS)) {
System.out.println("ShutdownNow");
pool.shutdownNow();
}
}
}
DownloadTask.java:
public class DownloadTask implements Callable<Boolean> {
protected Category cat = Category.getInstance(DownloadTask.class.getName());
private URL fileURL;
private File toPath;
public DownloadTask(URL fileURL, File toPath) {
this.fileURL = fileURL;
this.toPath = toPath;
}
private void downloadFile(URL fileURL, File toPath) throws IOException {
ReadableByteChannel readableByteChannel = Channels.newChannel(fileURL.openStream());
if (!toPath.getParentFile().exists()) {
if (!toPath.getParentFile().mkdirs()) throw new IOException("Unable to create parent dirs for file: "+toPath.getAbsolutePath());
}
FileOutputStream fileOutputStream = new FileOutputStream(toPath);
fileOutputStream.getChannel().transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
URLConnection urlConnection = fileURL.openConnection();
if (!toPath.setLastModified(urlConnection.getLastModified())) cat.error("Unable to write modified time stamp for file: "+toPath.getAbsolutePath());
}
#Override
public Boolean call() {
try {
downloadFile(fileURL, toPath);
} catch (IOException e){
System.out.println(e);
cat.error(e, e);
return false;
}
return true;
}
}
Thank you
EDIT: I didn't realize that the main class is running from FX Application Thread. So I had reverse threads and just applied the new thread (() -> {...}).Start(); in the main class in the start method and it's ok.
So I'm trying to play indefinitly a song on a background thread, but when the music ends it does not loop as it was supose to.
Tried the offered solution but yet no joy! Here is the code for the main class, hope this helps in the resolution of the issue.
Even tried to loop the thread, but no joy...
Not sure why it's ending after playing the full file once, but not sure how to solve it!
Here is the code I have. Any help is welcome
public class Main extends Application {
Media sugar = new Media(this.getClass().getResource("sounds/t1coSugar.wav").toExternalForm());
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
Application.launch(Main.class, args);
}
#Override
public void start(Stage primaryStage)
{
primaryStage.setTitle("pacman");
primaryStage.setWidth(MazeData.calcGridX(MazeData.GRID_SIZE_X + 2)); //stage size x
primaryStage.setHeight(MazeData.calcGridY(MazeData.GRID_SIZE_Y + 5)); //stage size y
//splash screen
//end of splash screen
final Group root = new Group();
final Scene scene = new Scene(root);
root.getChildren().add(new Maze());
primaryStage.setScene(scene);
primaryStage.show();
int playbackgroundmusic = playbackgroundmusic();
}
private int playbackgroundmusic()
{
Runnable task = new Runnable() {
#Override
public void run() {
playSugar(); //method of the music
}
};
// Run the task in a background thread
Thread backgroundThread = new Thread(task);
// Terminate the running thread if the application exits
backgroundThread.setDaemon(true);
// Start the thread
backgroundThread.start();
return 0;
}
public void playSugar()
{
MediaPlayer mediaplayer = new MediaPlayer(sugar);
mediaplayer.volumeProperty().setValue(0.4);
mediaplayer.setStartTime(Duration.seconds(0));
mediaplayer.setStopTime(Duration.seconds(67));
mediaplayer.setAutoPlay(true);
mediaplayer.setCycleCount(MediaPlayer.INDEFINITE);
mediaplayer.play();
}
I have a small javafx application using scene builder which on a button click should read a string from COM port at regular intervals and update in a text field.
But now it only shows the last string if I use a for loop, and nothing if i put the code in infinite loop (That's my temporary requirement).
Can anyone help me so that at each read from COM port the new string is updated in the text field.
Here is the code I used for both the cases :
Note : In both cases in controller class, I'm getting perfect output on console.
public class Main extends Application
{
#Override
public void start(Stage primaryStage)
{
try
{
Parent root = FXMLLoader.load(getClass().getResource("test.fxml"));
Scene scene = new Scene(root);
//scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setTitle("test");
primaryStage.setScene(scene);
primaryStage.show();
}
catch(Exception e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
launch(args);
}
}
Here is the Controller class :
// In this case it shows only the last string in the text field.
public class Controller implements Initializable
{
#FXML
private Button sayHelloButton;
#FXML
private TextField helloField;
#Override
public void initialize(URL arg0, ResourceBundle arg1)
{
}
#FXML
public void printHello(ActionEvent event)
{
if(event.getSource() == sayHelloButton)
{
SerialPort serialPort = new SerialPort("COM22");
for(int i=0;i<5;i++)
{
try
{
if(!serialPort.isOpened())
{
serialPort.openPort();
serialPort.setParams(9600, 8, 1, 0);
}
String str = serialPort.readString(10,3000);
System.out.println(str);
helloField.clear();
helloField.setText(str);
}
catch(Exception e)
{
helloField.setText(e.toString());
}
}
}
}
}
Here is the method with infinite loop :
//this shows nothing in the text field
#FXML
public void printHello(ActionEvent event)
{
if(event.getSource() == sayHelloButton)
{
SerialPort serialPort = new SerialPort("COM22");
while(true)
{
try
{
if(!serialPort.isOpened())
{
serialPort.openPort();
serialPort.setParams(9600, 8, 1, 0);
}
String str = serialPort.readString(10,3000);
System.out.println(str);
helloField.clear();
helloField.setText(str);
}
catch(Exception e)
{
helloField.setText(e.toString());
}
}
}
}
There are a couple things happening here. In your first example, you state that the console output is correct but the TextField only shows the last result.
This is expected if the loop executes quickly. The TextField is being updated, but it happens so quickly that you can't see it until the loop ends and the last result is still being displayed. Even if you have a delay built into the loop, this could still block the UI from being updated until the loop is completed.
With your infinite loop, the issue is that the loop is being run on the JavaFX Application Thread (JFXAT). This blocks any updates to the GUI until the loop is finished, which is never is.
You will need to move the infinite loop to a new background thread. From there, you can update the GUI using the Platform.runLater() method.
SerialPort serialPort = new SerialPort("COM22");
new Thread(() -> {
while(true)
{
try
{
if(!serialPort.isOpened())
{
serialPort.openPort();
serialPort.setParams(9600, 8, 1, 0);
}
String str = serialPort.readString(10,3000);
System.out.println(str);
// Update the UI on the JavaFX Application Thread
Platform.runLater(() -> {
helloField.clear();
helloField.setText(str);
});
}
catch(Exception e)
{
Platform.runLater(() -> helloField.setText(e.toString()));
}
}
}).start();
This allows your UI to continually update as the background thread sends it new information.
How can we add jogl to native java library so that we can run a jogl program like any other java program using notepad without any ide like netbeans, eclipse.
I have downloaded jogl. To test it i have run the following example program given in the documentation.
But i get an error saying the package javax.media.opengl doesnot exist.
i read the installation guide in tutorialspoint.But it is given for an ide.
can't we run the jogl program using notepad.
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
import javax.swing.JFrame;
public class BasicFrame implements GLEventListener
{
#Override
public void display(GLAutoDrawable arg0)
{
// method body
}
#Override
public void dispose(GLAutoDrawable arg0)
{ //method body
}
#Override
public void init(GLAutoDrawable arg0)
{
// method body
}
#Override
public void reshape(GLAutoDrawable arg0, int arg1, int arg2, int arg3, int arg4) {
// method body
}
public static void main(String[] args)
{
//getting the capabilities object of GL2 profile
final GLProfile profile = GLProfile.get(GLProfile.GL2);
GLCapabilities capabilities = new GLCapabilities(profile);
// The canvas
final GLCanvas glcanvas = new GLCanvas(capabilities);
BasicFrame b = new BasicFrame();
glcanvas.addGLEventListener(b);
glcanvas.setSize(400, 400);
//creating frame
final Frame frame = new Frame (" Basic Frame");
//adding canvas to frame
frame.add(glcanvas);
frame.setSize( 640, 480 );
frame.setVisible(true);
}
}
My code currently reads my Gmail inbox via IMAP (imaps) and javamail, and once it finds an email with zip/xap attachment, it displays a stage (window) asking whether to download the file, yes or no.
I want the stage to close once I make a selection, and then return to the place within the loop from which the call came. My problem arises because you cannot launch an application more than once, so I read here that I should write Platform.setImplicitExit(false); in the start method, and then use primartyStage.hide() (?) and then something like Platform.runLater(() -> primaryStage.show()); when I need to display the stage again later.
The problem occuring now is that the flow of command begins in Mail.java's doit() method which loops through my inbox, and launch(args) occurs within a for loop within the method. This means launch(args) then calls start to set the scene, and show the stage. Since there is a Controller.java and fxml associated, the Controller class has an event handler for the stage's buttons which "intercept" the flow once start has shown the stage. Therefore when I click Yes or No it hides the stage but then just hangs there. As if it can't return to the start method to continue the loop from where launch(args) occurred. How do I properly hide/show the stage whenever necessary, allowing the loop to continue whether yes or no was clicked.
Here is the code for Mail.java and Controller.java. Thanks a lot!
Mail.java
[Other variables set here]
public static int launchCount = 0;#FXML public Text subjectHolder;
public static ReceiveMailImap obj = new ReceiveMailImap();
public static void main(String[] args) throws IOException, MessagingException {
ReceiveMailImap.doit();
}
#Override
public void start(Stage primaryStage) throws Exception {
loader = new FXMLLoader(getClass().getResource("prompts.fxml"));
root = loader.load();
controller = loader.getController();
controller.setPrimaryStage(primaryStage);
scene = new Scene(root, 450, 250);
controller.setPrimaryScene(scene);
scene.getStylesheets().add("styleMain.css");
Platform.setImplicitExit(false);
primaryStage.setTitle("Download this file?");
primaryStage.initStyle(StageStyle.UNDECORATED);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void doit() throws MessagingException, IOException {
Folder inbox = null;
Store store = null;
try {
Properties props = System.getProperties();
Session session = Session.getDefaultInstance(props, null);
store = session.getStore("imaps");
store.connect("imap.gmail.com", "myAccount#gmail.com", "Password");
inbox = store.getFolder("Inbox");
inbox.open(Folder.READ_WRITE);
Message[] messages = inbox.getMessages();
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.ENVELOPE);
fp.add(UIDFolder.FetchProfileItem.FLAGS);
fp.add(UIDFolder.FetchProfileItem.CONTENT_INFO);
fp.add("X-mailer");
inbox.fetch(messages, fp);
int doc = 0;
int maxDocs = 400;
for (int i = messages.length - 1; i >= 0; i--) {
Message message = messages[i];
if (doc < maxDocs) {
doc++;
message.getSubject();
if (!hasAttachments(message)) {
continue;
}
String from = "Sender Unknown";
if (message.getReplyTo().length >= 1) {
from = message.getReplyTo()[0].toString();
} else if (message.getFrom().length >= 1) {
from = message.getFrom()[0].toString();
}
subject = message.getSubject();
if (from.contains("myAccount#gmail.com")) {
saveAttachment(message.getContent());
message.setFlag(Flags.Flag.SEEN, true);
}
}
}
} finally {
if (inbox != null) {
inbox.close(true);
}
if (store != null) {
store.close();
}
}
}
public static boolean hasAttachments(Message msg) throws MessagingException, IOException {
if (msg.isMimeType("multipart/mixed")) {
Multipart mp = (Multipart) msg.getContent();
if (mp.getCount() > 1) return true;
}
return false;
}
public static void saveAttachment(Object content)
throws IOException, MessagingException {
out = null; in = null;
try {
if (content instanceof Multipart) {
Multipart multi = ((Multipart) content);
parts = multi.getCount();
for (int j = 0; j < parts; ++j) {
part = (MimeBodyPart) multi.getBodyPart(j);
if (part.getContent() instanceof Multipart) {
// part-within-a-part, do some recursion...
saveAttachment(part.getContent());
} else {
int allow = 0;
if (part.isMimeType("application/x-silverlight-app")) {
extension = "xap";
allow = 1;
} else {
extension = "zip";
allow = 1;
}
if (allow == 1) {
if (launchCount == 0) {
launch(args);
launchCount++;
} else {
Platform.runLater(() -> primaryStage.show());
}
} else {
continue;
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if ( in != null) { in .close();
}
if (out != null) {
out.flush();
out.close();
}
}
}
public static File createFolder(String subject) {
JFileChooser fr = new JFileChooser();
FileSystemView myDocs = fr.getFileSystemView();
String myDocuments = myDocs.getDefaultDirectory().toString();
dir = new File(myDocuments + "\\" + subject);
savePathNoExtension = dir.toString();
dir.mkdir();
System.out.println("Just created: " + dir);
return dir;
}
}
Controller.java
public class Controller implements Initializable {
#FXML
private Text subjectHolder;
public Button yesButton, noButton;
public ReceiveMailImap subject;
#Override
public void initialize(URL url, ResourceBundle rb) {
subject= new ReceiveMailImap();
subjectHolder.setText(subject.returnSubject());
}
public Stage primaryStage;
public Scene scene;
#FXML
ComboBox<String> fieldCombo;
public void setPrimaryStage(Stage stage) {
this.primaryStage = stage;
}
public void setPrimaryScene(Scene scene) {
this.scene = scene;
}
public String buttonPressed(ActionEvent e) throws IOException, MessagingException {
Object source = e.getSource();
if(source==yesButton){
System.out.println("How to tell Mail.java that user clicked Yes?");
return "POSITIVE";}
else{subject.dlOrNot("no");
System.out.println("How to tell Mail.java that user clicked No?");
primaryStage.hide();
return "NEGATIVE";}
}
}
There are a lot of issues with the code you have posted, but let me just try to address the ones you ask about.
The reason the code hangs is that Application.launch(...)
does not return until the application has exited
In general, you've kind of misunderstood the entire lifecycle of a JavaFX application here. You should think of the start(...) method as the equivalent of the main(...) method in a "traditional" Java application. The only thing to be aware of is that start(...) is executed on the FX Application Thread, so if you need to execute any blocking code, you need to put it in a background thread.
The start(...) method is passed a Stage instance for convenience, as the most common thing to do is to create a scene graph and display it in a stage. You are under no obligation to use this stage though, you can ignore it and just create your own stages as and when you need.
I think you can basically structure your code as follows (though, to be honest, I have quite a lot of trouble understanding what you're doing):
public class Mail extends Application {
#Override
public void start(Stage ignored) throws Exception {
Platform.setImplicitExit(false);
Message[] messages = /* retrieve messages */ ;
for (Message message : messages) {
if ( /* need to display window */) {
showMessage(message);
}
}
}
private void showMessage(Message message) {
FXMLLoader loader = new FXMLLoader(getClass().getResource("prompts.fxml"));
Parent root = loader.load();
Controller controller = loader.getController();
Scene scene = new Scene(root, 450, 250);
stage.setScene(scene);
stage.initStyle(StageStyle.UNDECORATED);
stage.setTitle(...);
// showAndWait will block execution until the window is hidden, so
// you can query which button was pressed afterwards:
stage.showAndWait();
if (controller.wasYesPressed()) {
// ...
}
}
// for IDEs that don't support directly launching a JavaFX Application:
public static void main(String[] args) {
launch(args);
}
}
Obviously your logic for decided whether to show a window is more complex, but this will give you the basic structure.
To check which button was pressed, use showAndWait as above and then in your controller do
public class Controller {
#FXML
private Button yesButton ;
private boolean yesButtonPressed = false ;
public boolean wasYesPressed() {
return yesButtonPressed ;
}
// use different handlers for different buttons:
#FXML
private void yesButtonPressed() {
yesButtonPressed = true ;
closeWindow();
}
#FXML
private void noButtonPressed() {
yesButtonPressed = false ; // not really needed, but makes things clearer
closeWindow();
}
private void closeWindow() {
// can use any #FXML-injected node here:
yesButton.getScene().getWindow().hide();
}
}