missed tap gestures from leap motion in java - java

I wrote a test code to see if my tap gestures are accepted from leap motion.
After running the code I noticed that I have to tap really aggressively and even then, I only get a tap received once in every few taps.
How can I change my code to prevent this ?
(Please notice, I am very new to coding so plz be elaborate, thanks)
FILE #1
package com.leaptoarduino;
import com.leapmotion.leap.Controller;
import com.leapmotion.leap.Gesture;
public class Leapd
{
//Main
public static final void main(String args[])
{
//Initialize serial communications
RS232Protocol serial = new RS232Protocol();
serial.connect("COM3");
//Initialize the Leapd listener
LeapdListener leap = new LeapdListener(serial);
Controller controller = new Controller();
controller.addListener(leap);
controller.enableGesture(Gesture.Type.TYPE_KEY_TAP);
//Set up controller for gestures
controller.config().setFloat("Gesture.KeyTap.MinDownVelocity", 5.0f);
controller.config().setFloat("Gesture.KeyTap.HistorySeconds", .8f);
controller.config().setFloat("Gesture.KeyTap.MinDistance", 20.0f);
controller.config().save();
}
}
FILE #2
package com.leaptoarduino;
import com.leapmotion.leap.*;
import com.leapmotion.leap.Gesture.Type;
import com.leapmotion.leap.KeyTapGesture;
public class LeapdListener extends Listener
{
//Serial port that will be used to communicate with the Arduino
private RS232Protocol serial;
//Constructor
public LeapdListener(RS232Protocol serial)
{
this.serial = serial;
}
//Member function: onInit
public void onInit(Controller controller)
{
System.out.println("Initialized");
}
//Member function: onConncect
public void onConnect(Controller controller)
{
System.out.println("Connected");
}
//Member Function: onDisconnect
public void onDisconnect(Controller controller)
{
System.out.println("Disconnected");
}
//Member Function: onExit
public void onExit(Controller controller)
{
System.out.println("Exited");
}
//Member Function: onFrame
public void onFrame(Controller controller)
{
//Get the most recent frame
Frame frame = controller.frame();
//Verify a hand is in view
if (frame.hands().count() > 0)
{
GestureList gestures = frame.gestures();
for (Gesture gesture: gestures)
{
if (gesture.type() == Type.TYPE_KEY_TAP)
{
KeyTapGesture keytap = new KeyTapGesture (gesture);
System.out.println("KEYTAPPED");
}
}
//Send the tap data to the Arduino
// TBD
//Give the Arduino some time to process our data
try { Thread.sleep(30); }
catch (InterruptedException e) { e.printStackTrace(); }
}
}
}

When you sleep the thread in the OnFrame handler, you are going to miss frames from the Leap Motion service. Part of your problem is probably that the tap gestures are recognized in those missed frames. Frame.gestures() takes a "sinceFrame" parameter to avoid this problem: frame.gestures(sinceFrame) gives you all the gestures that occurred between sinceFrame and the current frame and thus you don't miss any when frames are dropped or skipped. What you do is save the current frame to a lastFrameProcessed variable every time your onFrame handler runs. You pass this lastFrameProcessed variable to gestures() to get the complete gesture list. Something like:
Frame lastFrameProcessed = Frame.invalid();
public void onFrame(Controller controller)
{
//Get the most recent frame
Frame frame = controller.frame();
//Verify a hand is in view
if (frame.hands().count() > 0)
{
GestureList gestures = frame.gestures(lastFrameProcessed);
for (Gesture gesture: gestures)
{
if (gesture.type() == Type.TYPE_KEY_TAP)
{
KeyTapGesture keytap = new KeyTapGesture (gesture);
System.out.println("KEYTAPPED");
}
}
//Send the tap data to the Arduino
// TBD
//Give the Arduino some time to process our data
try { Thread.sleep(30); }
catch (InterruptedException e) { e.printStackTrace(); }
}
lastFrameProcessed = frame;
}

Related

MouseHook Deletes Text on Mac OS X

I'm working on a Java FX application that involves using a moushook to capture text selected with the mouse. This was worked without problems when compiled and run with Java 8, but I'm currently required to use Java 10, which has caused an issue to arise on Mac OS X (there is no problem when run on Windows 10).
The problem is that when text is selected from a document (e.g. text in TexEdit) the selected text is deleted and replaced with 'c', rather than being copied. This doesn't happen every time, but does happen very frequently.
I've stripped the mouseHook class down to a very basic test case that shows the problem:
MouseHook class ---------------------------------------------------------
package problem;
import org.jnativehook.GlobalScreen;
import org.jnativehook.mouse.NativeMouseEvent;
import org.jnativehook.mouse.NativeMouseInputListener;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.KeyEvent;
import java.util.Timer;
import java.util.TimerTask;
public class MouseHook implements NativeMouseInputListener
{
private static MouseHook mouseHook = null;
private Robot mouseRobot = null;
private boolean mouseLeftButtonDown = false;
private boolean dragged = false;
private MouseHook()
{
//disable console output from JNativeHook's internal logger (mouse-tracking, etc)
java.util.logging.Logger logger = java.util.logging.Logger.getLogger(GlobalScreen.class.getPackage().getName());
logger.setLevel(java.util.logging.Level.OFF);
}
public static synchronized MouseHook getInstance()
{
if(mouseHook == null)
{
mouseHook = new MouseHook();
GlobalScreen.addNativeMouseListener(mouseHook);
GlobalScreen.addNativeMouseMotionListener(mouseHook);
}
return mouseHook;
}
#Override
public void nativeMousePressed(NativeMouseEvent e)
{
//If left button pressed, set mouseLeftButtonDown and look-out for dragging
if(e.getButton() == NativeMouseEvent.BUTTON1)
{
mouseLeftButtonDown = true;
}
}
#Override
public void nativeMouseDragged(NativeMouseEvent e)
{
//only record a drag if left mouse button is held down.
//NativeMouseEvent doesn't say which button was the source, hence test the variable.
if(mouseLeftButtonDown)
{
dragged = true;
}
}
#Override
public void nativeMouseReleased(NativeMouseEvent e)
{
//copy text if the mouse was dragged while the left mouse button was held down.
if(e.getButton() == NativeMouseEvent.BUTTON1)
{
final Timer timer = new Timer("ReleaseDetect");
timer.schedule(new TimerTask()
{
#Override
public void run()
{
if(dragged)
{
copy();
dragged = false;
}
mouseLeftButtonDown = false;
timer.cancel();
}
}, 500);
}
}
#Override
public void nativeMouseClicked(NativeMouseEvent e)
{}
#Override
public void nativeMouseMoved(NativeMouseEvent e)
{}
private synchronized void copy()
{
try
{
if(mouseRobot == null)
{
mouseRobot = new Robot();
mouseRobot.setAutoDelay(100);
mouseRobot.setAutoWaitForIdle(true);
}
if(System.getProperty("os.name").toLowerCase().contains("mac"))
{
mouseRobot.keyPress(KeyEvent.VK_META);
mouseRobot.keyPress(KeyEvent.VK_C);
mouseRobot.keyRelease(KeyEvent.VK_C);
mouseRobot.keyRelease(KeyEvent.VK_META);
}
else
{
mouseRobot.keyPress(KeyEvent.VK_CONTROL);
mouseRobot.keyPress(KeyEvent.VK_C);
mouseRobot.keyRelease(KeyEvent.VK_C);
mouseRobot.keyRelease(KeyEvent.VK_CONTROL);
}
Thread.sleep(250);
Transferable t=Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
if(t != null && t.isDataFlavorSupported(DataFlavor.stringFlavor))
{
String activeContent = (String) t.getTransferData(DataFlavor.stringFlavor);
System.out.println(activeContent);
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
Class to run the example--------------------------------------------------------
package problem;
import org.jnativehook.GlobalScreen;
import org.jnativehook.NativeHookException;
public class Runnit
{
private static MouseHook mouseHook;
public static void main(String[] args)
{
try
{
GlobalScreen.registerNativeHook();
}
catch(NativeHookException e)
{
System.out.println("Cannot set up the NativeHook listener on the GlobalScreen");
}
mouseHook = MouseHook.getInstance();
}
}
I'm using Oracle's Java 10.0.2 and jNativeHook 2.1.0, with Mac OS High Sierra (10.13.6) on a Mac mini.
The problem seems to be to do this java.awt.Robot, rather than jNativeHook.
e.g. If I replace the VK_C keyPress/Release with VK_B the mousehook deletes selected text and replaces it with 'b'.
My gut feeling was that the VK_META keypress was being ignored. I tried putting in a delay before that keypress, but it makes no difference.
I've also tried using a different mouse, and someone else's Macintosh, but the problem still happens. As I said, it only happens on Mac OS X, not Windows 10, when the code is compiled and run with Java 10.
I would be grateful if anyone has any ideas as to whether this is a lost cause, or if there is a work-around. It may be that I've missed something obvious, as I normally work on Windows and have lsss familiarity with Mac OS X.

Using multi-threading to pause my application does not behave as expected

I am designing a matching memory game, I am almost done with it and everything is working as it should be, however, when the user has opened two different cards the program won't pause(wait) few seconds so the user can see what the second card was.
I have tried using a long for loop operation but encountered the same problem. I have tried Thread.sleep, TimeUnit.SECONDS.sleep, Task and Platform.runLater.
The program opens the card and closes it instantly THEN it waits for the specified duration, keeping in mind that I am calling pauseThread after open and before close functions.
I have tried the above suggestions but they are leading me no where and I can't seem to find where the problem is with my code or where should I place the pauseThread. Thanks in advance.
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class MemoryMatchingGame extends Application{
private static Card selectedCard=null; // This is to save a reference for the first card to use in comparison
private static int numOfCorrectPairs = 0; // Keeping track of how many cards the user got correct
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
String[] images = {"C:\\Users\\userName\\Desktop\\Project#4\\1.png", // This is a string array to store images locations
"C:\\Users\\userName\\Desktop\\Project#4\\2.png",
"C:\\Users\\userName\\Desktop\\Project#4\\3.jpg",
"C:\\Users\\userName\\Desktop\\Project#4\\4.jpg",
"C:\\Users\\userName\\Desktop\\Project#4\\5.jpg",
"C:\\Users\\userName\\Desktop\\Project#4\\6.png",
"C:\\Users\\userName\\Desktop\\Project#4\\7.jpg",
"C:\\Users\\userName\\Desktop\\Project#4\\8.jpg"};
ArrayList<Card> listOfCards = new ArrayList<Card>();
for(int i=0; i<images.length; i++) { // This for loop will add each image twice to the array list
listOfCards.add(new Card(images[i]));
listOfCards.add(new Card(images[i]));
}
Collections.shuffle(listOfCards); // Shuffling the deck of cards
primaryStage.setTitle("Memory Matching Game");
HBox hb = new HBox();
VBox firstColoumn = new VBox();
for(int i=0; i<4; i++)
firstColoumn.getChildren().add(listOfCards.get(i));
VBox secondColoumn = new VBox();
for(int i=4; i<8; i++)
secondColoumn.getChildren().add(listOfCards.get(i));
VBox thirdColoumn = new VBox();
for(int i=8; i<12; i++)
thirdColoumn.getChildren().add(listOfCards.get(i));
VBox fourthColoumn = new VBox();
for(int i=12; i<16; i++)
fourthColoumn.getChildren().add(listOfCards.get(i));
hb.getChildren().addAll(firstColoumn, secondColoumn, thirdColoumn, fourthColoumn);
Scene scene = new Scene(hb, 460, 450);
primaryStage.setScene(scene);
primaryStage.show();
}
private class Card extends Button {
private String imageLocation; // To store the destination of the image
private Image img; // To store a reference of the image to be used when setting graphic on a button
public Card(String imageLocation) throws FileNotFoundException {
this.imageLocation = imageLocation;
FileInputStream fis = new FileInputStream(imageLocation);
img = new Image(fis);
setPrefSize(150, 150);
setOnMouseClicked(e -> {
if(isCardOpen()==true)
return; // To ensure no action is made once an image is already opened and the user clicked on it again
if(selectedCard==null) {// This will test if the user has a card open already for comparison or not, if not it will store a reference to the card to use to compare once another card is opened
selectedCard = this;
open();
}
else { // If we enter this statement, this means the user has a card open already and we are ready to perform comparison
open(); // First action taken is to reveal the second card then perform comparison
if(this.isEqual(selectedCard)) {
numOfCorrectPairs++;
System.out.println("Got one");
}
else {
//Get program to pause here
Hold pauseThread = new Hold();
pauseThread.run();
System.out.println("After pausing");
this.close();
selectedCard.close();
}
selectedCard=null; // This will nullify the variable so that we are able to perform comparison again for two other cards
} // End of else statement
}); // End of actionHandler
close(); // This will ensure whenever a card is created it is set face-down
}
private void close() {
setGraphic(null);
}
public void open() {
setGraphic(new ImageView(img));
System.out.println("Open");
}
private boolean isCardOpen() {
return this.getGraphic()!=null;
}
private boolean isEqual(Card selectedCard) {
return this.imageLocation.equals(selectedCard.imageLocation);
}
}
private class Hold extends Thread{
public void run() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Everything in your code is running in the JavaFX Application Thread. You don't want to pause this thread because it will lock your GUI. As has already been mentioned, you are starting another thread and putting it to sleep, but this doesn't add delay to your GUI that is running in the JavaFX Thread.
An alternative approach would be to use Platform.runLater(). The Hold thread can invoke a method in the JavaFX thread that implements a Platform.runLater() runnable. The runnable is a short lambda that holds the code to close the selected card. The timing may vary slightly from 3000 ms, but you don't have much going on in the JavaFX thread and it doesn't seem critical for this application.
Here are the modifications to try.
First modify the Hold class to include a constructor to pass in the Card object. Then call the closeAfterPause() method on card.
private class Hold extends Thread {
private Card card;
public Hold(Card card) {
this.card = card;
}
public void run() {
try {
TimeUnit.SECONDS.sleep(3);
card.closeAfterPause();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Then create the closeAfterPause() method in the MemoryMatchingGame class.
private void closeAfterPause() {
Platform.runLater(() -> {
System.out.println("After Pausing");
close();
selectedCard.close();
});
}
Then modify the else part of your if-else statement as follows
else {
//Get program to pause here
Hold pauseThread = new Hold(this);
new Thread(pauseThread).start();
}
FX comes with a rich set of Animation/Timeline support - there's no need for falling back onto bare Threads. The most simple form of getting wait-for-xx is to use a Timeline configured with xx and an actionHandler that does something when ready:
Timeline holdTimer = new Timeline(new KeyFrame(
Duration.seconds(2), e -> closeCards()));
Also it's a good idea to centralize all logic outside of a Control. Actually, you should never-ever extend a view for the purpose to include view-unrelated logic. So your long-time goal should be to
extract all single card logic from Card into a CardModel which exposes properties like f.i. image, id, open, disposed
use a plain Button, configure and bind its properties to model properties as appropriate
centralize all game logic like timing, selecting, when opening is allowed, when succeed into a game controller
As I don't want to spoil your fun in doing that - I'll just post a little outline in the direction of the last bullet. Its responsibilities so far
provide api to open a single card
provide api to end a turn: either match or close cards
internals to keep track of opened cards and timing
The snippets just re-mixes your code a bit, moving game logic from the button into the controller (aka: here simply the outer class) and setting the button's action handler to access the controller.
private Card firstCard;
private Card secondCard;
private Timeline holdTimer = new Timeline(new KeyFrame(
Duration.millis(2000), e -> closeCards()));
public void closeCards() {
if (firstCard == null || secondCard == null) {
System.out.println("error!!");
return;
}
if (firstCard.isEqual(secondCard)) {
System.out.println("success");
firstCard.setDisable(true);
secondCard.setDisable(true);
firstCard = null;
secondCard = null;
} else {
firstCard.close();
secondCard.close();
firstCard = null;
secondCard = null;
}
}
public void openCard(Card card) {
if (card.isCardOpen()) return;
if (holdTimer.getStatus() == Status.RUNNING) return;
if (firstCard == null) {
firstCard = card;
firstCard.open();
} else if (secondCard == null) {
secondCard = card;
secondCard.open();
holdTimer.playFromStart();
}
}
// Dont! dont, dont!!! ever extend a Control
//**TBD**: Move open/close state logic into a CardModel
// then configure a plain Button with the properies of that model
private class Card extends Button {
private String imageLocation; // To store the destination of the image
// private Image img; // To store a reference of the image to be used when setting graphic on a button
public Card(String imageLocation) throws FileNotFoundException {
this.imageLocation = imageLocation;
setPrefSize(150, 150);
setOnAction(e -> openCard(this));
}
public void close() {
setText("");
}
public void open() {
setText(imageLocation);
System.out.println("Open");
}
public boolean isCardOpen() {
return getText() != null && getText().length() > 0;//this.getGraphic()!=null;
}
private boolean isEqual(Card selectedCard) {
if (selectedCard == null) return false;
return this.imageLocation.equals(selectedCard.imageLocation);
}
}

Java swing timer- timer.stop() with actionListeners & interface

I obviously am having problems with my understanding of interfaces/ listeners in Java. (Java newbie alert at red).
Using https://docs.oracle.com/javase/7/docs/api/javax/swing/Timer.html and interface examples, I am getting behaviour I do not understand from timer.stop, and/ or removing actionlisteners from the timer (I.e. firing the 'tick').
Whatever I do, I cannot stop the timer when using an interface etc- I can only get it to work in local classes = spaghetti code.
public void actionPerformed(ActionEvent e) {
SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");
JButton clicked= (JButton) e.getSource();
ClockLabel mainsClockList= new ClockLabel(mainsLab);
if (clicked==clock1But) {
///////// Clock not started
if (mainsRunning==false) {
//mainsClockList = new ClockLabel(mainsLab); // that starts
// it, wait for FB in listnr
mainsClockList.setStopWatchListener(new StopWatchListener() {
public void clockCount(long count) {
System.out.println("Clock fired"); // fired every
//click- should only be on attach
// multiple calls button or EL?
mainsLab.setText(sdf.format(count));
}
});
clock1But.setText("Stop");
mainsRunning=true;
}
//// clock already started
else if (mainsRunning== true) {
System.out.println("in butt pressed already run");
mainsClockList.stopClock();
mainsClockList.setEnabled(false);
mainsRunning=false;
}
}
else if (clicked==clock2But) {
System.out.println("Got 2nd but"); }
else if (clicked==clock3But) {
System.out.println("Got 3rd but"); }
}
the Clock Lab class stuff:-
public ClockLabel(JLabel labIn) {
sdf = new SimpleDateFormat("mm:ss");
t= new Timer(500, this );
t.start();
}
public void actionPerformed(ActionEvent e) {
// this is listener for t....
Date d= new Date();
long diff= d.getTime() -cStarted.getTime();
swListener.clockCount(diff);
}
public void stopClock() {
System.out.println("In CL, called stopclock");
t.stop(); // no effect
swListener= null; // no effect
System.out.println("swListener := null");
// swListener.wait(5000); null pointer on try catch so
//has killed sw....!
}
public void setStopWatchListener(StopWatchListener listener) {
this.swListener= listener;
}
}
Interface
public interface StopWatchListener {
public void clockCount(long count);
}
I have tried to minimise code but keep comments in to help. Thanks for any pointers, much appreciated.
System out is as follows with only 1 click on button to start, and one to stop:
Clock fired
Clock fired
Clock fired
Clock fired
in butt pressed already run
In CL, called stopclock
swListener := null
Clock fired
Clock fired
Clock fired
Clock fired

Dispose frame after start frame Java Swing

I'm new to Stackoverflow. I have a problem in java/swing with project to school.
The project is a testing service. I want to run an additional window before running the main program that checks the connection to the server. After checking the connection it should start the main window of the program and disappear. If I manually click startProgramButton it's all right. However, if the program is connected to the server at startup, the main window of the program is started, but this window does not disappear.
public class PreForm extends javax.swing.JFrame {
/**
* Creates new form PreForm
*/
MainForm form1;
Settings form2;
public PreForm() {
initComponents();
checkConnection();
}
private void settingsButtonActionPerformed(java.awt.event.ActionEvent evt) {
errorLabel.setText("");
form2 = new Settings();
form2.setVisible(true);
}
private void runProgramButtonActionPerformed(java.awt.event.ActionEvent evt) {
checkConnection();
}
private void checkConnection() {
if (hostAvailabilityCheck()) {
runMainProgram();
} else
errorLabel.setText("<html>Error connect to server!<br>"
+ "Check connect settings and try again!</html>");
}
private boolean hostAvailabilityCheck() {
try (Socket s = new Socket(SettingsFile.getAddress(), Integer.parseInt(SettingsFile.getPort()))) {
return true;
} catch (IOException ex) {
/* ignore */
}
return false;
}
private void runMainProgram() {
this.setVisible(false);
form1 = new MainForm();
form1.setVisible(true);
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new PreForm().setVisible(true);
}
});
}
So, after running the program, the checkConnection method is executed. Then the runMainProgram method is executed. And that's where this.setVisible (false) code comes in, which should hide the window, but it stays. But only if the checkConnection method is started in the constructor. If you run it manually through the startProgramButton, this window is hidden.

How force the program wait a Task and show Progress Bar to user?

I use Swing Application Framework in my program. And I have some long-time work. I use org.jdesktop.application.Task for it. Another programmer wrote two Tasks before I took this project (I can not ask him about the programm). When Tasks are executing user sees progress bar without showing percent complete, but what shows "Wait" message and user can not click to a main window while Task does not ended. It is fine! But I could not find place where ProgressBars was created. May be it is described in some xml-file or property-file?
Also I wrote another Tasks and when they run, progress bar which I created is not displayed or displayed incorrectly. I read about ProgressBar and ProgressMonitor, but it does not help me.
Programm continue to run after someTask.execute(), but I want to it displays ProgressBar, ProgressMonitor or something else and user can not click the main window and window will display correctly. Now window has black "blocks" when user change it.
May be I need use org.jdesktop.application.TaskMonitor. I try to use it as here https://kenai.com/projects/bsaf/sources/main/content/other/bsaf_nb/src/examples/StatusBar.java?rev=235 , but my main window is displayed incorrectly and my ProgressBar is not displayed.
I need to when Task is running program waits it, but user can see ProgressBar, can cancel the operation and can not click to the main window. How can I do it?
Here my code:
public class A{
#Action(name = "ActionName", block = Task.BlockingScope.APPLICATION)
public RequestInfoTask requestInfo() {
RequestInfoTask task = new RequestInfoTask(Application.getInstance());
isSuccessedGetInfo=false;
task.addTaskListener(new TaskListener.Adapter<List<InfoDTO>, Void>() {
#Override
public void succeeded(TaskEvent<List<InfoDTO>> listTaskEvent) {
isSuccessedGetResources=true;
}
});
//Here I want to the program shows ProgressMonitor and user can not click to the main window.
//But small window with message "Progress..." is displayed for several seconds and disappear.
ProgressMonitor monitor = new ProgressMonitor(getMainView(), "Wait! Wait!", "I am working!", 0, 100);
int progress = 0;
monitor.setProgress(progress);
while(!task.isDone()){
monitor.setProgress(progress+=5);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
monitor.setProgress(100);
//This code must run after "task" finishes.
if(isSuccessedGetInfo){
MyTask2 task2 = new MyTask2(Application.getInstance());
isSuccessedTask2=false;
task2.addTaskListener(new TaskListener.Adapter<Map<?,?>, Void>(){
#Override
public void succeeded(TaskEvent<Map<String, ICredential>> arg0) {
isSuccessedTask2=true;
}
});
//Do something with results of task2.
}
return task;
}
}
public class RequestInfoTask extends Task<List<InfoDTO>, Void> {
public RequestInfoTask(Application application) {
super(application);
}
#Override
protected List<InfoDTO> doInBackground() throws Exception {
List<InfoDTO> result = someLongerLastingMethod();
return result;
}
}
Part of your problem sounds like it comes from not using the EDT correctly. Any long running task needs to be started in it's own thread to keep the GUI responsive and repainting.
Ideally you'd be following a MVC pattern. In that case you place your Progress Bar in the view, your flag (that indicates whether the task should be running still) in the control, and your long running task in in the Model.
From that point, if your model checks periodically if it should stop (Probably at good stopping points), you can reset everything.
Here's an example with MVC:
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
public class ProgressBarDemo{
public static class View extends JPanel{
Controller control;
public JProgressBar progressBar = new JProgressBar(0, 100);
JButton button = new JButton("Start Long Running Task");
public View(Controller controlIn){
super();
this.control = controlIn;
setLayout(new BorderLayout());
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
//Toggle between running or not
if(control.isRunning){
control.isRunning = false;
button.setText("Canceling...");
button.setEnabled(false);
} else{
control.isRunning = true;
button.setText("Cancel Long Running Task");
control.startTask();
}
}});
progressBar.setStringPainted(true);
add(progressBar);
add(button, BorderLayout.SOUTH);
}
}
//Communications gateway
public static class Controller{
View view = new View(this);
boolean isRunning = false;
public void updateProgress(final int progress){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
view.progressBar.setValue(progress);
}});
}
public void reset(){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
isRunning = false;
view.button.setText("Start Long Running Task");
view.progressBar.setValue(0);
view.button.setEnabled(true);
}});
}
public void startTask(){
LongRunningClass task = new LongRunningClass(this);
new Thread(task).start();
}
}
public static class LongRunningClass implements Runnable{
Controller control;
public LongRunningClass(Controller reference){
this.control = reference;
}
#Override
public void run() {
try {
for(int i = 0; i < 11; i++){
//Monitor the is running flag to see if it should still run
if(control.isRunning == false){
control.reset();
break;
}
control.updateProgress(i * 10);
Thread.sleep(3000);
}
control.reset();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
// Create and set up the window.
JFrame frame = new JFrame("LabelDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Add content to the window.
frame.add(new Controller().view);
// Display the window.
frame.pack();
frame.setVisible(true);
}
}

Categories

Resources