Running logic in separate thread still locks UI - Java - java

I have developed a simple MIDI application that allows me to play MIDI notes, in order for the user to be able to interact with the UI whilst the MIDI sounds are playing I have put the logic necessary in an anonymous subclass like so:
public static void Play()
{
new Thread(new Runnable()
{
public void run()
{
if (!_sequencer.isRunning())
{
try
{
_sequencer.setSequence(_sequence);
_sequencer.start();
}
catch (Exception e)
{
Logger.Add(e.getMessage());
}
}
}
}).start();
}
Although the music begins to play the UI still fails to respond when I click on a ComboBox for example, I have something similar working fine in C#.
Is there some sort of caveat to thread in Java that would explain the behaviour i'm seeing?
(The Java API I'm using if it helps - javax.sound.midi)
Thanks for your time.
Edit:
Click around the UI a little more and noticed something interesting; everything seems to work fine with exception to two ComboBoxes in the top left most corner, I've tried deleting them and replacing them but makes no difference. The boxes change to blue when clicked (as it would normally) but the drop down box does not appear below it and the colour does not return to it's default when focus is on another UI component. Could it be a bug introduced by NetBeans perhaps?
Example:
Edit 2:
Well after much trial and error I have finally found the cause of the problem, the threading works great. The problem was that NetBeans has somehow realigned my UI components which causes the Window to fill the screen, manually resizing and testing the ComboBoxes showed that they actually worked fine.
Thanks for everybodys feedback!

What does the combo box do when it's clicked? Does it interact with the _sequencer? Furthermore, was your sequencer created on the UI thread? I would suspect that while you're invoking the start method on a separate thread, the sequencer still runs on the context where it was created (i.e. UI thread).
Try creating the sequencer on the playing thread (i.e. NOT the UI thread) and see if that frees up your UI.

Well after much trial and error I have finally found the cause of the problem, the threading works great. The problem was that NetBeans has somehow realigned my UI components which causes the Window to fill the screen, manually resizing and testing the ComboBoxes showed that they actually worked fine.

Related

JavaFX stage *sometimes* appears blank on Win10

My class extends a JavaFX Stage. In a development environment it never fails to load and process, but my users regularly report that sometimes it doesn't properly show which looks like this on Windows 10.
The class itself is a fairly standard affair, I trigger it with Platform.runLater() and the thread processes as expected. Every log output is written out and it is possible to interact with the screen as programmed, or close it, which does not trigger any error or exception.
The stage constructor is pretty basic:
log.debug("Constructing the screen.");
setTitle("Screen");
setAlwaysOnTop(true);
initStyle(StageStyle.UNDECORATED);
try {
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass().getResource("....fxml"));
Pane panel = fxmlLoader.load();
controller = fxmlLoader.getController();
controller.postInit(currentIdle); // some elements processed
Scene scene = new Scene(panel);
setScene(scene);
scene.setOnKeyPressed(controller::handleKeyEvent);
setOnHiding((WindowEvent e) -> processor::leaveScreen);
log.debug("Showing the screen.");
show();
log.debug("Screen shown.");
requestFocus();
log.debug("Finished constructing the screen.");
} catch (IOException e) {
// ...doesn't go here
}
From the logs everything seems to work as intended, including the controls, keyboard shortcuts and the leaveScreen() hook, and there are no exceptions thrown, except that the user sometimes cannot see the content and controls on the screen.
What am I looking at? Is this a problem with my code, or a JavaFX bug? A problem with graphics on the user laptop? Can you think of a way to prevent or at least detect this state and force a refresh somehow?
Alternatively, under what circumstances is it possible that a JavaFX stage passes its show() method without an error, but does not actually show its contents?
Environments affected: All combinations of latest JDK 14 GA, Corretto 11, (custom jlink-created image) and JavaFX 11.0.2 or 14.0.1 - it does not make a difference. It also happens regardless of whether the application is installed with a jlinked JRE using jpackage or Advanced Installer.
Warm thanks, guys, for your honorable attempts to help. It is now a bit cold at nine months later, but I believe that it deserves a close in case anyone stumbles upon the problem later. My conclusions:
The problem is not caused by my application, and
that I have found a workaround.
We gradually managed to confidently isolate the problem to hardware, i.e. we noticed it would happen more frequently if plugging/unplugging display peripherals and docking stations was involved. It was also sometimes triggered by sleeping / running out of battery oddly.
This led us to believe that the problem was somewhere between Prism's hardware acceleration and the graphic cards. In the end we managed to avoid this kind of rendering freeze by changing the application's GraphicsPipeline from com.sun.prism.d3d.D3DPipeline to com.sun.prism.sw.SWPipeline. For us this is not a problem, because the application doesn't render complex 3D graphics, and after switching to software rendering the problem disappeared.
This can be achieved by setting -Dprism.order=sw to the JVM parameters at startup. You can confirm the pipeline in use by logging your com.sun.prism.GraphicsPipeline.getPipeline().getClass().getName().
Hard to help without more info, but 2 things I've had to use in the past for windows issues were
Thread.currentThread().setContextClassLoader(App.class.getClassLoader());
placed at the begin of the start(Stage stage) method where App is obviously replaced with the name of your class extending Application
The other 'fix' I've used is
System.setProperty("glass.accessible.force", "false");
as a workaround for issues with clicking on out of focus Nodes

Properly to loading a large Java Swing UI without freezing it

I am developing a big Swing application with a lot of components that are loaded at the launch of the application. The process of loading the components, setting their attributes and adding them to panels takes a few seconds.
The applications UI freezes during the loading of the application. I would like to show a splash loading screen for the time of loading the whole UI, but the splash also freezes.
If I move the UI construction to another Thread, this would be the EDT Threading violation.
What is the correct way to load such Swing interface without freezing the UI?
I have seen existing answers on this topic but they cover the case where external tasks not related to Swing are blocking the UI, but here, the construction of the complex UI itself is blocking the UI refreshing (splash screen progress bar).
There is two possibilities to solve this problem.
You split your UI initialization in small chunks and call each chunk using SwingUtilities.invokeLater. Each invokeLater triggers repainting, so your GUI can be refreshed. This should be the preferred way.
When you have problems on splitting your appllication into small independent chunks, you can "misaply" the Foxtrot lib to provide synchron breaks for UI repainting
public static void sleepNonBlocking(long millis) {
Worker.post(new Job() {
#Override
public Object run() {
try {
Thread.sleep(millis);
} catch (Exception e) {
// nothing
}
return null;
}
});
}
You need to call this method on some places in your application to force repainitng.

SwingWorker locks GUI on (unsuccessful) JLabel Icon updating

Ok im really struggling with unlocking my GUI which is locked due to separate SwingWorker thread. Basically what my program does: Initializes webcam, and then grabs single frame and displays it as JLabel icon (doing single grab+display on Button click is ease, however i have immense difficulties in doing such operation consecutively in order to do some image processing). I am aiming to obtain such result:
Grab frame -> process it -> display as ImageIcon of Jlabel > ... repeat Grab frame >...
I need results while webcam is streaming, therefore i used SwingWorker publish and process. In my code "processing part" is not included as it is not necessary since i cant even obtain proper continuous frame grabbing. Generally my background thread will never finish unless cancelled (well thats the assumption as i want to process images as fast as possible with maximum frames per second - unless i should do it other way? - i guess separate thread for single frame grab&process would be bad idea due to fact that im aiming to get 10+ FPS). I know my SwingWorker thread works, since i made tests of saving consecutive images to C:\, and it did work, but my GUI is locked anyway, but at least i know that thread is running and grabbing frames.
Generally i have 2 problems:
no JLabel icon update
Locked GUI
My SwingWorker code:
private class FrameStream extends SwingWorker<Void, BufferedImage> {
#Override
protected Void doInBackground() throws InterruptedException{
BufferedImage processedImage = null;
while (!isCancelled()) {
processedImage = getPIC_COLOR(player);
publish(processedImage);
Thread.sleep(5000); // i made such delay to check whether program is not "choking" with data, but its not the case, without this delay everthing is the same
}
return null;
}
#Override
protected void process(List<BufferedImage> mystuff) {
Iterator it = mystuff.iterator();
while (it.hasNext()) {
img_field.setIcon(new ImageIcon(mystuff.get(mystuff.size()-1)));
}
}
#Override
protected void done() {
infoBAR.setText("FINISHED");
}
}
I am so desperate that i rewritten my code completely basing on tutorials example: Flipper as you can see it is ridiculously similar. All my previous efforts also locked gui so tried the 'tutorial way', nonetheless it did not work, which is a pity. Im in a dead end because i have no clue how to fix that. Im desperate for help since as you can see it seems exactly the same as the tutorial one, maybe something other causes issues: MY FULL CODE
Please help, i'm unable to solve it by myself.
One thing that looks a little different to me is your process method. Rather than specifying the last image, you might wish to iterate through all images like so:
#Override
protected void process(List<BufferedImage> mystuff) {
for (BufferedImage bImage : mystuff) {
img_field.setIcon(new ImageIcon(bImage));
}
}
I'm not sure if this will make a significant difference, but I believe that this is how process should be written. Another thought -- if the BufferedImages are large you may wish to create the ImageIcon in the background thread and publish the ImageIcon rather than the BufferedImage.
Nothing stands out as an issue. Steps I would suggest to further debug.
Instead of using a loop and the process method, just pull one frame and set the Icon once. You need to get that working before you try to make it loop. Your application should be able to set the icon that fact that it doesn't highlights a problem.
Second, because your GUI is locking up, there is something still happening on the EDT. Try, running a profiler or adding System.out.println in your code to find what is running while the GUI is locked.
Last, make sure you don't need to be repainting, revalidating the Label's container to make the image visible.
hmmmm, if I read your last post about this issue, there are maybe lots of possible mistakes (and I see your code), that's nothing to do with SwingWorker, another example just replace change Color for JButton#setBackground() with your Icon or ImageIcon
Have you tried to set the label to observe the image icon?
icon.setImageObserver(label);

Pause execution in Java GUI

I am writing a quiz program for the Android (written in Java). When the user answers a question (by clicking a button), I want to flash a message on the screen saying whether they were correct or not, followed by a 5 second pause before moving on to the next question.
However, when an answer button is clicked, the program pauses, but does not display the message of correct/incorrect. The message only comes up once the sleep method has finished.
if (correct)
Answer.setText("CORRECT!");
else
Answer.setText("WRONG!");
try { Thread.sleep(5000); }
catch(InterruptedException e) {}
As a bonus, I'd like the answer buttons to be disabled during the pause.
You'll need an AsyncTask for that. Google gives you an intro to it here.
When you Thread.sleep() on the main Activity, you are putting the application to sleep. The AsyncTask will allow you to pause for the 5 seconds, maybe show a little In Progress bar and then pick up from there, without freezing the screen.
Imo AsyncTask is too much for this usecase.
Don't use sleep.
Instead set your correct/incorrect message and than do this:
new Handler().postDelayed(new Runnable(){
public void run()
{
goToNextScreen();
}
}
, 5000);
Use a Handler: you can send a message with a 5000 millisecond delay, disable the buttons and when the message arrives you can re-enable the buttons. See http://www.tutorialforandroid.com/2009/01/using-handler-in-android.html for more info.
You should look into using timers for this. I don't think using threads are sensible for this. Using a timer to move onto the next question would work.
Look at timers here
Hope this helps.
Disclaimer: I have only used timers in Java to do something similar but i'm sure it would work in Android.

How to use a delay in a swing application

I am building a swing application. At some point, I have to start an "animation":
...
jpanel1.setBackground(Color.Black);
Delay(milli)
jpanel1.setBackground(Color.White);
...
and so on.
The gui itself and all the logic behind it work.It is just this time depended color-changing that does not. I have read, that swing is not thread safe, but all the examples I found showed me how to start another thread (for example in the background) but never how to stop the current swing-gui thread.
Edit:
The application should work as following:
configuration files are read, jframe is set up.
some simple questions are beeing asked
a dialogue is opened, which explains the animation.
after the user clicked "ok" the animation - some color flashing - is started. the color and the delay between the color-changing is depended on the configuration
another dialogue is opened and the programm continues -> new jpanel inside the jframe, buttons and so on.
the online thing that does not work are the delays between the color-changing. I understand now why it does not work and I am trying to build a timer, which activates a actionlister, which then changes the color and stops the timer... it just seems so much work for a simple delay... and I have to reorganize the entire animation in the application.
Take a look at: https://timingframework.dev.java.net/
and the samples that come in http://filthyrichclients.org/
They provide some very good information on how animation work and using the Timer framework. You'll have a good understanding of how it works.
I did a sample animation here with Swing after reading those:
count down demo app http://img580.imageshack.us/img580/742/capturadepantalla201004wd.png
Java application featuring blog.stackoverflow.com page ( click on image to see the demo video )
But I'm not even sure what is what you want to achieve.
EDIT
I read about the timing framework to understand better what is all about, but I actually didn't use it ( it is useful to create animations with no linear times - ie no every second as mine, but things like 1, 5, 3, 2 seconds )
The code I'm using in the demo above is exactly this:
final Timer imageTimer = new Timer();
imageTimer.schedule( new TimerTask() {
public void run() {
changeImage();
}
}, 0, 10000 ); //<-- every 10 seconds.
The animation for the "stackoverflowing" and the count down use a similar approach.
You do not want to stop the GUI thread, even if you want to have a flashing effect. This is because other basic actions, like repainting when the GUI is hidden by other windows, will be stalled. Take a look at Timer. It will allow you to have an event fired on an interval and you can handle that, in the GUI thread, in your actionPerformed method.
You will want to use the javax.swing.Timer class and not the java.util.Timer class.
The later is preferred when you need general timing the former is preferred for UI updating/changes.
See http://java.sun.com/docs/books/tutorial/uiswing/misc/timer.html
You may also want to look at https://timingframework.dev.java.net/.
Do the timer on another thread and when the timer goes off it can send an update message for the animation to draw the next frame.
Another consideration is the delay itself. Don't pick a fixed delay-interval. Old games used to do that and they become unplayable on faster computers. Instead what the newer games do is use the speed of the current CPU to figure out how many update events they need a second at runtime, call it a 'delay-factor', and is set when the program starts up. . The timer uses the delay factor so the animation displays correctly even on machines of different clock-speed.

Categories