we know jasper viewer need much time to process report according to the data that will display.
I want to handle it, with give the user loading information.
this my step :
Check ,is the viewer in process or done.
If in process, create JLabel and set text to "Loading report..."
If done, set text to "" or null
And the point 1 , i don't know How to check viewer is in generating process?
Please help me. Thank you :)
Make the call to viewReport() in a separate thread. Store an instance level AtomicBoolean, and set it to false once the report is done. In you client checking method, check this instance variable periodically to check if the report is done.
Example pseudocode:
public void YourClass {
private AtomicBoolean reportRunning;
...
private void getReport() {
new Thread() {
reportRunning = new AtomicBoolean(true);
JRViewer.viewReport();
reportRunning.set(false);
}.start();
}
// Call periodically and update UI
private boolean clientCheck() {
return reportRunning != null && reportRunning.get();
}
Related
I have a jframe i want to display while my main frame is running. i want to pause my main code, until the user does the necessary actions on the other frame. I've read a lot of solutions but i need to see it done for my code to understand and grasp it fully. i do not want to use jdialog like I've seen listed as an answer before. My main goal is to understand better threading so that i can use what i learn in different cases.
With the code I've created, when running the thread, only just the frame loads, none of the other features are there on the frame. (the frame is simple it has a label, a list the user selects from, and a button to basically return the chosen list value.) its like the thread is cut off from completing or something.
here is my class calling the screen:
public class myThread implements Runnable {
String result = null;
public void run() {
MessageScreen ms = new MessageScreen();
ms.setVisible(true);
}
public String getResult() {
return result;
}
public void setResult(String AS) {
result = AS;
}
}
in my main code, a method is called that is returning a String[] value, with this method at some point i have the following code calling the new thread to get the value necessary to return in the original main method:
myThread mt = new myThread();
Thread t = new Thread(mt);
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
myreturn = new String[] {"true", mt.getResult()};
without listing the whole code for the second frame, when the user presses the button, and at the end of the listener tied to the button press the i want to close the frame and return a string that was selected from the list:
jf.dispose();
myt.setResult(AdminSelection);
in the frame class, i have the following instance variables declared:
String AdminSelection = null;
myThread myt;
i hope this is enough information for someone to help me out and understand whats gone wrong here.
The function join() waits until the end of the run() method, when you do t.join(), your thread is already or almost ended. This is because in your run() method there is nothing that blocks the thread until the user has clicked the confirm button. And is better like this!
There is no sense to create a thread here, you should use a callback, or more generally in Java, a listener. You can take a look at Creating Custom Listeners.
But, especially if you want to pause your main code, you should use a (modal) JDialog which is made for this! Don't try to block the UI by yourself, you could block the UI thread (handled by Swing/AWT) by mistake. Creating a JDialog is better because everything is already made for this usage on the UI thread.
Also, you must know that create a Thread is really long, use a Thread when you really need it.
I'm implementing a GUI for a JUnit test and I currently have a SwingWorker performing a set of JUnit tests.
I'm using a 3rd party program to get access to a USB device and perform the JUnit tests on that device. However I have a problem of how to stop the SwingWorker in case of no connection to the device or if the connection fails for some reason.
One simple solution would be to create a cancel button, but that is not very user friendly to just let the user wait until they get impatient and cancel the tests themselves.
Here's a sample code:
public void startButtonPresset(){
class Worker extends SwingWorker<Result, Void>{
Class<?> curtest;
#Override
public Result doInBackground() {
Class<?> curtest = 3rdPartyTest.class;
cl = com.firm.test.acp.commands.3rdPartyTest.class;
oi = new com.firm.test.acp.commands.3rdPartyTest();
JUnitCore junit = new JUnitCore();
result = junit.run(curtest);
return result;
}
#Override
public void done() {
serialNo = cl.getField("serial").get(oi).toString().trim();
softwareVer = cl.getField("swvers").get(oi).toString();
testVer = cl.getField("testver").get(oi).toString();
result = get();
if (getOutputType().equalsIgnoreCase("console")) {
OutputGenerator.outputConsole(result, testVer, serialNo, softwareVer);
} else if (getOutputType().equalsIgnoreCase("csv")) {
OutputGenerator.outputCSV(result, testVer, serialNo, softwareVer);
}
3rdPartyTest.setTestNamesArrayToNull();
curtest = null;
cl = null;
oi = null;
result = null;
}
}
}
worker.execute();
}
I hope it is pretty clear that if doInBackground never returns a result the program will just hang and so goes with the interface. What I want is some way to either make a "timer" or a "partial test result" and check if some of the tests have been performed. The 3rd party tool is currently creating an array holding all the test names and I though of maybe using this, but I have no idea of how to do this together with some sort of timer.
The tests usually takes between 1 and 20 seconds at tops whether or not a link to the device has been established.
Any suggestions?
I have implemented a programm in javafx which dynamically generates an input mask and generates a Word-document after a button click on that mask.
I define in an db-table which input fields are available in this mask.
Now I'm adding support for custom procedures which are executed on specific states of my program (onFocusLost of an field,onChange,...)
Wich works perfect.
Now I'm stuck at the onGenerate execution.
When I render the mask, I hold a List of Runnables to store my actions which should be executed on generation (At the render time i know which action should be executed. At Generation time i would have to read all the data in again. So I thought I save the action with FunctionalInterface. And I need no inputParameter and no ReturnValue ... so i ended up with Runnable)
TextField tf = ...;
String s = ...;
actionsBeforeGenerate.add(() -> {
tf.setText(s);
});
So now, if I press the generate button, I do the following:
private void startGenerate(){
//main.getActionsBeforeGenerate() == List<Runnable>
main.getActionsBeforeGenerate().forEach(action -> action.run());
generateWordDocument();
}
The text is set to the node correctly, BUT after the document is generated.
How can I change the textField BEFORE my generationLogic starts?
If you need more information, don't hesitate to ask for it.
EDIT:
I think I've found the solution for my problem:
private void startGenerate(){
Task<Boolean> task = new Task<Boolean>() {
#Override
public Boolean call() throws Exception {
main.getActionsBeforeGenerate().forEach(action -> action.run());
....
generateWordDocument();
....
return Boolean.TRUE;
}
};
Thread thread = new Thread(task);
thread.setDaemon(true);
thread.start();
}
Now I have the new values textField values available in generateWordDocument()
The following code run inside a new thread.
private class SaveUserTask extends AsyncTask<User, Void, Void> {
#Override
protected Void doInBackground(User... users) {
DatabaseHandler dbHandler = new DatabaseHandler(LoginActivity.this);
dbHandler.createUser(users[0]);
return null;
}
}
The code that construct it and run it is inside a callback method.
private class GraphCallbackHandler implements Request.GraphUserCallback {
#Override
public void onCompleted(GraphUser gUser, Response response) {
if (gUser != null) {
id = gUser.getId().trim();
DatabaseHandler dbHandler = new DatabaseHandler(
LoginActivity.this);
if (!dbHandler.isFacebookIdAlreadyStored(id)) {
SaveUserTask suTask = new SaveUserTask();
User user = new User();
user.setUsername(gUser.getUsername().trim());
user.setFacebookId(id);
if (email != null)
user.setEmail(emailStr.trim());
suTask.execute(user);
}
}
It looks as if that callback method is being called twice causing two identical rows to be inserted into the table. Is there any way to prevent this either by preventing the callback method from being called twice (which to me seems quite unlikely to achieve) or stopping the background task from running twice?
Simply do this steps:
Move your user existance check code to your doInBackground method.
set doInBackground method code synchronized by an Object LOCK.
or you can store your saved users to an object like HashSet inside memory and check existance before inserting to db.
Note that some where of working with database in cases like that must be thread safe or synchronized. Otherwise, you may have such problems like this.
I think you just have a typical race condition if onCompleted called twice in short period of time:
Happy path:
Check user doesn't exist (thread1)
Launch insert in another thread (thread1)
Do insert (thread2)
Check user doesn't exist (thread1) -> do nothing
and it could work in another order, as threads work in parallel:
Check user doesn't exist (thread1)
Launch insert in another thread (thread1)
Check user doesn't exist (thread1)
Launch insert in another thread (thread1)
Do insert (thread2)
Do insert (thread3)
I think the best solution is to move (or copy) the check so that the async operation should do the check to make the operation idempotent.
We have a ViewerFilter for a TableViewer that is a little slow, so to try to give the impression of awesomeness, we wanted to have the viewer wait 500 milliseconds before refreshing the window (otherwise, it was blocking after every key stroke).
Not having any clue what I was doing, I tried creating a class that would check if System.currentTimeMillis() was greater then the time of the last key stroke + 500 from a different thread. This just caused an Invalid thread access exception to be thrown, so I'm lost.
Edit: I was able to use TableViewer.getTable().getDisplay().asyncExec() to sidestep the invalid thread problem, but I don't like my solution, and would love to hear other suggestions.
You might want to try to turn off redraw while updating the viewer.
Viewer.getControl().setRedraw(false);
// update
Viewer.getControl().setRedraw(true);
It can sometimes give a better user experience. You can also schedule a ui-job that you cancel when the user hits a new key or modifies the text. E.g.
class RefreshJob extends WorkbenchJob
{
public RefreshJob()
{
super("Refresh Job");
setSystem(true); // set to false to show progress to user
}
public IStatus runInUIThread(IProgressMonitor monitor)
{
monitor.beginTask("Refreshing", ProgressMonitor.UNKNOWN);
m_viewer.refresh();
monitor.done();
return Status.OK_STATUS;
};
}
and then reschedule the refresh in a separate job.
private RefreshJob m_refreshJob = new RefreshJob();
private Text m_filterText;
void hookModifyListener()
{
m_filterText.addModifyListener(new ModifyListener()
{
public void modifyText(ModifyEvent e)
{
m_refreshJob.cancel();
m_refreshJob.schedule(500);
}
});
}
If the user hits the Enter key you can schedule a refresh job without the delay,
Just wrap your code in display.syncExec, something like this:
Display.getDefault().asyncExec(new Runnable() {
public void run() {
// check refresh time
// refresh.
}
});
You may want to look in to asyncExec too, if syncExec does not meet your needs.