How to keep a method running continuously in background? - java

I want that my pdf chek method runs in the background but I really have no idea how I can implement my method into an SwingBackgroupWorker or Thread...
public class PDFCheck extends JPanel {
private void testAllFontsAreEmbedded(PDFDocument pdf) throws PDFDocumentException {
for (PDFFont font : pdf.listFonts()) {
if (!font.isEmbedded()) {
this.problems.add(new ProblemDescription<PDFDocument>(pdf, "font not embedded: " + font.getName()));
}
}
}
}
Thank you very much...
I tried this code...but it doesn't seem to work..
public static class SwingBackgroupWorker extends SwingWorker<Object, Object> {
#Override
protected Object doInBackground() throws Exception {
private void testAllFontsAreEmbedded(PDFDocument pdf) throws PDFDocumentException {
for (PDFFont font : pdf.listFonts()) {
if (!font.isEmbedded()) {
this.problems.add(new ProblemDescription<PDFDocument>(pdf, "font not embedded: " + font.getName()));
}
}
}
}
I would then start the backgroundworker with new SwingBackgroupWorker().execute();
}
How can I run the Backgroundworker to test it?
public class MoveIcon extends JPanel {
public class MyTask extends SwingWorker<Void, Void> {
#Override
protected Void doInBackground() throws Exception {
int i = 0;
while (i < 10) {
System.out.print(i);
i++;
}
return null;
}
}
public static void main(String[] args) {
new MyTask();
}
}
That doesn't work :(

I usually create inner classes for SwingWorkers. So you could put your SwingWorker in a private inner class of PDFCheck and add the fields (in your case just the pdf) you need to access inside your worker. You then can set them through the constructor. You could do something like this:
public class PDFCheck extends JPanel {
/* ... */
private class MyTask extends SwingWorker<Void, Void> {
PDFDocument pdf;
MyTask(PDFDocument pdf)
{
this.pdf = pdf;
}
#Override
protected Void doInBackground() throws Exception
{
for (PDFFont font : pdf.listFonts())
{
if (!font.isEmbedded())
{
PDFCheck.this.problems.add(new ProblemDescription<PDFDocument>(pdf, "font not embedded: " + font.getName()));
}
}
}
}
/* ... */
// Call the Swing Worker from outside the class through this method
public void runWorker()
{
MyTask task = new MyTask(pdfFile);
task.execute()
}
}
Call it then from inside the PDFCheck class like this:
MyTask task = new MyTask(pdf);
task.execute();

Related

Android/Java: Is there a way to store a method?

So I have a loop class that is basically as follows:
public class Loop extends Thread {
private boolean running;
public Loop() {
running = false;
}
public void run() {
while(running) {
//Do stuff
}
}
public void setRunning(boolean b) {
running = b;
}
}
What I'd like to know is whether or not it is possible to store methods. For example the class could look like this instead.
public class Loop extends Thread {
private boolean running;
private Method method;
public Loop() {
running = false;
}
public void run() {
while(running) {
if(method != null)
method.callMethod();
}
}
public void setRunning(boolean b) {
running = b;
}
public void setMethod(Method m) {
method = m;
}
}
Is anything like this possible?
I assume you want this functionality in Java 6, so you can use interface and anonymous class.
Interface code:
public interface Listener {
void callMethod();
}
Your Thread:
public class Loop extends Thread {
private boolean running;
private Listener listener;
public Loop() {
running = false;
}
public void run() {
while(running) {
if(listener != null)
listener.callMethod();
}
}
public void setRunning(boolean b) {
running = b;
}
public void setListener(Listener listener) {
this.listener = listener;
}
}
Set Listener:
Loop loop = new Loop();
loop.setListener(new Listener() {
#Override
public void callMethod() {
// Do stuff
}
});
This will work for your usecase. If you want to save methods and pass methods as data, you have to either use Java 8 (not supported on all Android API levels) or Kotlin.

Run method not working inside ForkJoinTask

I have a sub class of RecursiveTask which contains a Runnable object and should execute it.The problem is that the code inside the run method never gets reached although I use ForkJoinPool.execute in order to not block the main thread.
public class test {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
Display.getDefault().syncExec(new Runnable() {
#Override
public void run() {
System.out.println("lo");
}
});
}
};
ATLockTask t = new ATLockTask();
t.runnable = r;
new ForkJoinPool().execute(t);
}
}
public class ATLockTask extends RecursiveTask<Object>{
public Runnable runnable;
#Override
protected Object compute() {
try {
runnable.run();
} catch (Exception e) {
logger.catching(e);
}
return null;
}
}

TinySound and multiple click in GUI (button)

I am struggling with a problem using TinySound (http://finnkuusisto.github.io/TinySound/). I've made a method to play a sound (i've implemented the Music class, since it allows to be played without a thread sleep limiter). My problem is that the "Play" button in my GUI can be spammed, resulting in the sound or music being played in a stack. I've checked out the setMultiClickThreshold in the Java API, but this do not solve my problem (You never know how long the sound or music-file is going to be).
Has anyone used TinySound, or know a workaround this challenge?
Here is the code for the method (I will provide more if necessary):
public void playSound(String filePath) {
soundFile = new File(filePath);
TinySound.init();
Music sound = TinySound.loadMusic(soundFile);
sound.play(false);
while(sound.done()) {
TinySound.shutdown();
}
}
Consider using a SwingWorker, disabling the JButton on button press, and re-enabling it when the SwingWorker has completed its actions. The re-enabling could be done within a PropertyChangeListener that has been added to your Swingworker and that responds to a PropertyChangeEvent.newValue() of SwingWorker.StateValue.DONE.
For example, your code could look something like,....
public class SwingworkerEg {
// .....
public void playSound(String filePath) {
soundFile = new File(filePath);
TinySound.init();
Music sound = TinySound.loadMusic(soundFile);
sound.play(false);
while (sound.done()) {
TinySound.shutdown();
}
}
// The JButton or menu item's Action or ActionListener class
private class PlayAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
// disable the button or menu item
setEnabled(false);
// create worker to play music in a background thread
// pass in the file path
PlayWorker playWorker = new PlayWorker(filePath);
// listen for when the worker thread is done
playWorker.addPropertyChangeListener(new PlayWorkerListener(this));
// execute the worker (in a background thread)
playWorker.execute();
}
}
// To listen for when the worker is done
class PlayWorkerListener implements PropertyChangeListener {
private PlayAction playAction;
// pass in the Action so we can re-enable it when done
public PlayWorkerListener(PlayAction playAction) {
this.playAction = playAction;
}
#Override
public void propertyChange(PropertyChangeEvent evt) {
// if the worker is done
if (evt.getNewValue().equals(SwingWorker.StateValue.DONE)) {
// re-enable the button
playAction.setEnabled(true);
}
}
}
// this is to call playSound in a background thread
class PlayWorker extends SwingWorker<Void, Void> {
private String filePath;
// pass in the file path String
public PlayWorker(String filePath) {
this.filePath = filePath;
}
#Override
protected Void doInBackground() throws Exception {
// this is called in a background thread
playSound(filePath);
return null;
}
}
}
Here's a trivial working example:
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
#SuppressWarnings("serial")
public class SwingWorkerEg2 extends JPanel {
private JSpinner spinner = new JSpinner(new SpinnerNumberModel(3, 3, 10, 1));
public SwingWorkerEg2() {
add(new JLabel("Seconds to wait:"));
add(spinner);
add(new JButton(new FooAction("Please Press Me!")));
}
// The JButton or menu item's Action or ActionListener class
private class FooAction extends AbstractAction {
public FooAction(String name) {
super(name); // set button name
int mnemonic = (int) name.charAt(0); // get first letter as int
putValue(MNEMONIC_KEY, mnemonic); // set button mnemonic for first letter
}
#Override
public void actionPerformed(ActionEvent e) {
// disable the button or menu item
setEnabled(false);
int spinnerValue = ((Integer) spinner.getValue()).intValue();
// create worker to play music in a background thread
FooWorker playWorker = new FooWorker(spinnerValue);
// listen for when the worker thread is done
playWorker.addPropertyChangeListener(new FooWorkerListener(this));
// execute the worker (in a background thread)
playWorker.execute();
}
}
// To listen for when the worker is done
class FooWorkerListener implements PropertyChangeListener {
private FooAction fooAction;
// pass in the Action so we can re-enable it when done
public FooWorkerListener(FooAction fooAction) {
this.fooAction = fooAction;
}
#Override
public void propertyChange(PropertyChangeEvent evt) {
// if the worker is done
if (evt.getNewValue().equals(SwingWorker.StateValue.DONE)) {
// re-enable the button
fooAction.setEnabled(true);
}
}
}
// this is to call count down in a background thread
class FooWorker extends SwingWorker<Void, Void> {
private int spinnerValue;
// pass in the file path String
public FooWorker(int spinnerValue) {
this.spinnerValue = spinnerValue;
}
#Override
protected Void doInBackground() throws Exception {
for (int i = 0; i < spinnerValue; i++) {
System.out.println("count is: " + i);
Thread.sleep(1000);
}
System.out.println("count is: " + spinnerValue);
return null;
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("SwingWorker Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new SwingWorkerEg2());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Make sure to read Concurrency in Swing for more on how to use SwingWorkers
Got it to work! Thank you very much! I will try to implement it in my ActionController class, it is a bit messy keeping everything in the same method in the SoundHandler ;)
here is the final working SoundHandler:
import java.io.File;
import javax.swing.SwingWorker;
import kuusisto.tinysound.Music;
import kuusisto.tinysound.TinySound;
import imports.ActionController;
import imports.GUI;
/**
* This class handles the playing of the sound and extends SwingWorker so that
* the JFrame do not freeze when the sound is played.
*
* #author Gaute Gjerlow Remen
* #version 1.0
*/
public class SoundHandler extends SwingWorker<Void, Void> {
private GUI gui;
private ActionController actionController;
private File soundFile;
public SoundHandler() {
actionController = new ActionController(this);
gui = new GUI(actionController);
}
/**
* Plays the sound file in another thread
* #param filePath
* #throws Exception if the thread is interrupted
* #return null when doInBackground is finished
*/
public void playSound(String filePath) {
soundFile = new File(filePath);
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
TinySound.init();
Music sound = TinySound.loadMusic(soundFile);
sound.play(false);
while (!sound.done()) {
gui.unablePlayButton();
}
gui.enablePlayButton();
TinySound.shutdown();
return null;
}
};
worker.execute();
}
/**
* #return file opened in the GUI
*/
public String openFile() {
return gui.openFile();
}
/**
* Calls the about window in GUI
*/
public void showAbout() {
gui.showAbout();
}
/**
* Calls the showNoSong window in GUI
*/
public void showNoSong() {
gui.showNoSong();
}
/**
* Calls the changeSongLabel window in GUI
*/
public void changeSongLabel() {
gui.changeSongLabel();
}
/**
* A empty method made only for the extending of the class
*/
#Override
protected Void doInBackground() throws Exception {
// TODO Auto-generated method stub
return null;
}
}

JavaFX update textArea

I have a simple JavaFX application which has a TextArea. I can update the content of the textArea with the code below inside the start() method:
new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 2000; i++) {
Platform.runLater(new Runnable() {
public void run() {
txtarea.appendText("text\n");
}
});
}
}
}).start();
The code just write the text string into the TextArea 2000 times. I want to update this textArea from a function which is implemented outside of the start() method.
public void appendText(String p){
txtarea.appendText(p);
}
This function can be called from arbitrary programs which use the JavaFX application to update the TextArea. How can I do this inside the appendText function?
You could give the class which needs to write to the javafx.scene.control.TextArea an reference to your class which holds the public void appendText(String p) method and then just call it. I would suggest you also pass an indication from which class the method was called, e.g.:
public class MainClass implements Initializable {
#FXML
private TextArea txtLoggingWindow;
[...more code here...]
public void appendText(String string, String string2) {
txtLoggingWindow.appendText("[" + string + "] - " + string2 + "\n");
}
}
public class SecondClass {
private MainClass main;
public SecondClass(MainClass mClass) {
this.main = mClass;
}
public void callMainAndWriteToArea() {
this.main.appendText(this.getClass().getCanonicalName(), "This Text Goes To TextArea");
}
}

How to see communicate between 2 runnable with progression

I have 2 classes .java
The main :
public class Controller extends javax.swing.JFrame
{
public static void updateProgressBar(int i) {
jProgressBar1.setValue(i);
jProgressBar1.repaint();
}
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
Controller app = new Controller();
app.setVisible(true);
app.setResizable(false);
}
});
}
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
ChildModel model = new ChildModel();
Thread t1 = new Thread(model);
t1.start();
}
private javax.swing.JProgressBar jProgressBar1; //Initialized with Netbeans builder
}
My ChildModel (ChildModel.java) computes some code (that takes around 10-20 sec) and I want to show the progress on the father class (Controller.java).
Here is my ChildModel :
public class ChildModel implements Runnable
{
public ChildModel(){ /* Something */ }
public void complexMath()
{
//Lots of logic here
Controller.updateProgression(purcent);
}
#Override
public void run() {
complexMath();
}
}
The problem is obviously my static void updateProgressBar that cannot modify a non-static variable. How can I accomplish this ?
The jProgressBar1 variable is an instance variable, so you can't access it from a static method. And the method shouldn't be static: you want to update the progress in the controller, and not in all the Controller instances.
Pass a reference to the controller to the ChildModel, and use this reference from the ChildModel in order to update the progress bar. Also remember that all Swing interactions must be done in the EDT, and not in a background thread. SO the code should look like this:
public class Controller extends javax.swing.JFrame
{
public void updateProgressBar(int i) {
jProgressBar1.setValue(i);
// no need for repaint. The progress bar knows it must be repainted
// when its value changes
}
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
Controller app = new Controller();
app.setVisible(true);
app.setResizable(false);
}
});
}
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
ChildModel model = new ChildModel(this);
Thread t1 = new Thread(model);
t1.start();
}
private javax.swing.JProgressBar jProgressBar1; //Initialized with Netbeans builder
}
public class ChildModel implements Runnable
{
private Controller controller;
public ChildModel(Controller controller){
this.controller = controller;
}
public void complexMath()
{
//Lots of logic here
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
controller.updateProgression(percent);
}
});
}
#Override
public void run() {
complexMath();
}
}
Swing has its own concurrency mechanisms to deal with updating components. Here you could use
a Swing Timer and update the JProgressBar. Rather than have ChildModel implement Runnable, you could use a Timer as a class member variable and pass in your instance jProgressBar1, enabling you to call setValue when required.

Categories