I have a Text Area swing element where I want to display some execution logs. messages should appear after each execution step. e.g. "Fetching has been started". But the problem is that all logs messages appear only once after the button action performed event is completed.Below is the way I used to display some text
getXmlButton = new JButton("Fetch Reports");
getXmlButton.addActionListener((new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
createDirectory();
stutusArea.append("Fetching has been started");
final String password = passwordTextField.getText();
final String username = loginTextField.getText();
OperatingSystemDriver os = new OperatingSystemDriver();
driver = os.getDriver();
stutusArea.append("getting some url");
driver.get(URL);
try {
LoginPage login = new LoginPage(driver);
login.loginAs(username, password);
stutusArea.append("successful login");
} catch (Exception e1) {
stutusArea.append("login error");
}
insertToDbButton.setEnabled(true);
}
}));
You have to use a different thread, otherwise your GUI blocks.
Please note that updating the GUI from an other thread is a bad idea, use SwingUtilities.invokeLater to avoid some strange errors/bugs.
public void actionPerformed(ActionEvent e) {
new Thread(new Runnable() {
public void run() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
stutusArea.append("Fetching has been started");
}
})
final String password = passwordTextField.getText();
final String username = loginTextField.getText();
// ...
}
}).start();
}
That's because you do all your ActionPerformed stuff in the GUI thread, so the GUI freezes, and waits for your ActionPerformed stuff to be done, a way to avoid this is using Threads, there is an example: Thread Example
Related
class class1{
public class1(){//here is my GUI commants}
#Override
public void actionPerformed(ActionEvent evt) //this is my action performed from a jframe window
{
worker = new SwingWorker<Void, Void>(){//ia m creating a worker
protected WaitWindow waitWindow;
#Override
protected Void doInBackground() throws Exception {
waitWindow= new WaitWindow();//i call waitWindow class to pop up my new window with the progressBar
return null;
}
#Override
protected void done(){
waitWindow.CloseWaitWindow();
}
};
try{
String option = (String)serversList.getSelectedItem();
if (evt.getSource().equals(Button1))//when client presses button1
{
if(option.equals("icsd Server"))
{//here is my connection
Registry registry = LocateRegistry.getRegistry("localhost",1080);
icsdserver = (ICSDinterface)registry.lookup("RmiCheckICSD");
worker.execute(); //i am calling execute until the server return 0 this might take a long time
if (icsdserver.RequestForEntry("icsd",0)==0)
{
worker.cancel(true); //when server tell its all ok (with 0) i call cancel(true)
AddGrade d = new AddGrade(icsdserver,"icsd");
}
}
}
}
catch (RemoteException ex) {System.out.println(ex);}
catch (NotBoundException ex) {System.out.println(ex);}
}}
The Wait Window class follows
class WaitWindow extends JFrame //my WaitWindow Class
{
private JProgressBar bar ;
public WaitWindow(){
super("Wait Until Connection Is ready");
setSize(100,200);
bar = new JProgressBar();
bar.setIndeterminate(true);
bar.setPreferredSize(new Dimension(300,330));
add(bar);
getContentPane();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public void CloseWaitWindow()
{
removeNotify();
}
}
What am I doing wrong here? I want the wait Window to shown until server's RequestForEntry method return 0 this might take some time. Also there is no error with RMI connection.
You're blocking the Event Dispathing Thread, with the call to RequestForEntry, which should be within the doInBackground method of the SwingWorker, for example
public void actionPerformed(ActionEvent ev) //this is my action performed from a jframe window
{
try {
final String option = (String) serversList.getSelectedItem();
if (evt.getSource().equals(Button1))//when client presses button1
{
final WaitWindow waitWindow = new WaitWindow();
worker = new SwingWorker<Void, Void>() {//ia m creating a worker
#Override
protected Void doInBackground() throws Exception {
if (option.equals("icsd Server")) {//here is my connection
Registry registry = LocateRegistry.getRegistry("localhost", 1080);
icsdserver = (ICSDinterface) registry.lookup("RmiCheckICSD");
worker.execute(); //i am calling execute until the server return 0 this might take a long time
if (icsdserver.RequestForEntry("icsd", 0) == 0) {
worker.cancel(true); //when server tell its all ok (with 0) i call cancel(true)
AddGrade d = new AddGrade(icsdserver, "icsd");
}
}
return null;
}
#Override
protected void done() {
waitWindow.CloseWaitWindow();
}
};
}
} catch (RemoteException ex) {
System.out.println(ex);
} catch (NotBoundException ex) {
System.out.println(ex);
}
}
Swing is a single threaded framework and isn't thread safe. This means that anything the blocks the Event Dispatching Thread will prevent it from processing new events, including paint requests.
Swing components should also only be updated from within the context of the EDT, which is where SwingWorker comes in.
See Concurrency in Swing and Worker Threads and SwingWorker for more details
Can't figure this one out. Using worker or invokeLater, the UI still freeze. After each file is downloaded, I want a JList to be updated. But the JList will only update after the tread returns.
Here is the code:
public class MyUi extends javax.swing.JFrame{
...
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt){
SwingUtilities.invokeLater(new Runnable() {
//To get out of the event tread
public void run() {
dl();
}
});
}
private void dl(){
...
//ini and run the download class
Download myDownload = new Download();
myDownload.doDownload(myDlList);
}
public void updateJlist(String myString){
myModel.addElement(myString);
jList1.repaint();
}
}
public class Download{
...
public void doDownload(String[] fileName){
for(int i=0; i<fileName.length; i++){
...//download action...
//for my jList1 to be updated after each file.
MyUi.updateJlist(fileName[i]);
}
}
}
Any example would help.
invokeLater does exactly the opposite of what you expect it to do - it runs operations on the EDT, which explains the behaviour.
Download the file on a background thread and wrap just updateJlist() in a Runnable.
SwingWorker would be more reliable.
Addendum: As #mre notes, SwingWorker also makes it easy to report interim results, as shown here.
I have create a WorkerThread class which take care of Threads and GUI current/main thread . i have put my GUI application in construct() method of WorkerThread when an event fire to start XXXServer then all threads are activate and GUI work smoothlly wihout freeze. have a look.
/** * Action Event * * #see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */
public void actionPerformed(ActionEvent ae) {
log.info("actionPerformed begin..." + ae.getActionCommand());
try {
if (ae.getActionCommand().equals(btnStart.getText())) {
final int portNumber = 9990;
try {
WorkerThread workerThread = new WorkerThread(){
public Object construct(){
log.info("Initializing the Server GUI...");
// initializing the Server
try {
xxxServer = new XXXServer(portNumber);
xxxServer.start();
btnStart.setEnabled(false);
} catch (IOException e) {
// TODO Auto-generated catch block
log.info("actionPerformed() Start button ERROR IOEXCEPTION..." + e.getMessage());
e.printStackTrace();
}
return null;
}
};workerThread.start();
} catch (Exception e) {
log.info("actionPerformed() Start button ERROR..." + e.getMessage());
e.printStackTrace();
}
} else if (ae.getActionCommand().equals(btnStop.getText())) {
log.info("Exit..." + btnStop.getText());
closeWindow();
}
} catch (Exception e) {
log
.info("Error in ServerGUI actionPerformed==="
+ e.getMessage());
}
}
I have a method like below.
ProgressWindow is a sub class of JFrame containing JProgressBar.
addProgress() increments a value in the JProgressBar.
If I call this method from a method in another class, a frame of ProgressWindow will show up but not JProgressBar and some JLabels inside the frame. They show up after the last line (System.out.println("finish")).
If I call this method in a main method in the class containing this method, then every component (Bar, labels...) instantly shows up.
What can I do for showing the window correctly?
static void search(){
ProgressWindow window = new ProgressWindow();
window.setVisible(true);
ExecutorService execs = Executors.newFixedThreadPool(Runtime
.getRuntime().availableProcessors());
Collection<Callable<Void>> processes = new LinkedList<>();
for (int i = 0; i < 100; i++) {
processes.add(new Callable<Void>() {
#Override
public Void call() throws Exception {
progressWindow.addProgress(); // increment progress value
return null;
}
});
}
try {
execs.invokeAll(processes);
} catch (Exception e) {
e.printStackTrace();
} finally {
execs.shutdown();
}
System.out.println("finish");
The main problem is you seem to be calling search from the context of the Event Dispatching Thread.
The problem occurs because you are using execs.invokeAll which blocks until all the callables have finished running.
This means that the EDT is unable to process new events in Event Queue, including repaint events, this is why your UI is coming to a stand still...
There are a number of issues you are now going to face...
You should never update/modify a UI component from any thread other than the EDT
You should block the EDT for any reason
You seem to want to know when the search is complete, so you know need some kind of event notification...
The first thing we need is some way to be notified that the search has completed, this means you can no longer rely on search returning when the search is complete...
public interface SearchListener {
public void searchCompleted();
}
Next we need an intermeditate search method that builds the UI and ensure that the search is launched within it's own Thread...
static void search(final SearchListener listener) {
final ProgressWindow window = new ProgressWindow();
window.setVisible(true);
Thread t = new Thread(new Runnable() {
#Override
public void run() {
search(listener, window);
}
});
t.start();
}
Then we need to modify the original search method to utilise the SearchListener interface to provide notification when the search is complete...
static void search(final SearchListener listener, final ProgressWindow window){
ExecutorService execs = Executors.newFixedThreadPool(Runtime
.getRuntime().availableProcessors());
Collection<Callable<Void>> processes = new LinkedList<>();
for (int i = 0; i < 100; i++) {
processes.add(new Callable<Void>() {
#Override
public Void call() throws Exception {
// This method needs to ensure that
// what ever it does to the UI, it is done from within
// the context of the EDT!!
progressWindow.addProgress();
return null;
}
});
}
try {
execs.invokeAll(processes);
} catch (Exception e) {
e.printStackTrace();
} finally {
execs.shutdown();
}
System.out.println("finish");
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
listener.searchCompleted();
}
});
}
Now, without the source code for addProgress, I might be tempted to use
processes.add(new Callable<Void>() {
#Override
public Void call() throws Exception {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
progressWindow.addProgress();
}
});
return null;
}
});
}
Instead...
Take a look at Concurrency in Swing for more details
Sounds like you what you're wanting to do is invoke the setVisible on the Swing UI thread, you can do this with invokeAndWait or invokeLater.
So something like:
final ProgressWindow window = new ProgressWindow();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
window.setVisible(true);
}
});
I'm trying to figure out why the text field isn't updating. I'm aware that using SwingWorker will probably fix this problem, but I can't understand why it doesn't work in the first place.
public class waitExample {
private JFrame frame;
private JTextField txtLeadingText;
private String one = "update string 1";
private String two = "update string 2";
private String three = "update string 3";
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
waitExample window = new waitExample();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public waitExample() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
txtLeadingText = new JTextField();
txtLeadingText.setHorizontalAlignment(SwingConstants.CENTER);
txtLeadingText.setText("leading text");
frame.getContentPane().add(txtLeadingText, BorderLayout.SOUTH);
txtLeadingText.setColumns(10);
JButton btnClickMeTo = new JButton("CLICK ME TO UPDATE TEXT");
btnClickMeTo.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
try {
updateOne();
Thread.sleep(1000);
updateTwo();
Thread.sleep(1000);
updateThree();
Thread.sleep(1000);
updateLast();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
frame.getContentPane().add(btnClickMeTo, BorderLayout.CENTER);
}
private void updateOne() {
txtLeadingText.setText(one);
}
private void updateTwo() {
txtLeadingText.setText(two);
}
private void updateThree() {
txtLeadingText.setText(three);
}
private void updateLast() {
txtLeadingText.setText("default text");
}
}
From what I understand, the default Thread will prevent any GUI updates. That shouldn't matter because I am setting the textField BEFORE the Thread.sleep.
Why doesn't the text field update? Shouldn't the text be set, then the Thread wait?
EDIT: As per the answers, the above code has been updated.
You are invoking Thread.sleep(1000); on EDT. This means that when your method will end - only then the repaint() will fire (at some point in time later).
Until then your GUI is freezed.
Consider that this is going on one thread (so processing is straightforward):
txtLeadingText.setText(one);
Thread.sleep(1000);
txtLeadingText.setText(two);
Thread.sleep(1000);
txtLeadingText.setText(three);
Thread.sleep(1000);
...
<returning from updateText()>
<processing other events on button click>
...
// some time later
<Swing finds out that GUI needs repaint: calls rapaint()>
This is what you should do (I didn't compile or test it):
public class MyRunnable implements Runnable {
private List<String> strsToSet;
public MyRunnable(List<String> strsToSet) {
this.strsToSet = strsToSet;
}
#Override
public void run() {
try {
if(strsToSet.size() > 0) {
final String str = strsToSet.get(0);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
txtLeadingText.setText(str);
}
});
Thread.sleep(1000);
List<String> newList = new LinkedList<String>(strsToSet);
newList.remove(0);
new Thread(new MyRunnable(newList)).start();
}
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
}
new Thread(new MyRunnable(Arrays.asList(one, two, three))).start();
It is hard to do in Swing but in contrast in dynamically languages (like Groovy) it would go as simple as that (you'll get a better grasp of what is going on):
edt {
textField.setText(one)
doOutside {
Thread.sleep(1000);
edt {
textField.setText(two)
doOutside {
Thread.sleep(1000);
edt {
textField.setText(three)
}
}
}
}
}
The GUI event loop updates the screen, but it can't update the screen until you return.
I suggest you avoid doing any blocking operations in the GUI event thread.
In my GUI I have a PDF file creation operation. The operation can take up to 10-15 seconds to complete. When I start the operation, I attach a listener to it. The listener changes the cursor and disables the GUI, until the operation completes.
I would also like to add a progressbar, so the users will have a idea when it is going to complete.
Created a method startProgressBar() and called it from the start of the operation method.
See Below:
private void startSavePdfOperation() {
startProgressBar();
saveOp = new AplotSaveOperation(appReg.getString("aplot.message.SAVETOPDF"), "PDF", session);
saveOp.addOperationListener(new MyOperationListener(this) {
startProgressBar Method - See Below:
public void startProgressBar() {
Shell shell = new Shell(getShell());
shell.setSize(260, 120);
final ProgressBar bar = new ProgressBar(shell, SWT.SMOOTH);
bar.setBounds (20, 20, 200, 20);
shell.open();
final int maximum = bar.getMaximum();
new Thread(new Runnable() {
public void run() {
for (final int[] i = new int[1]; i[0] <= maximum; i[0]++) {
try {Thread.sleep (100);} catch (Throwable th) {}
if (Display.getDefault().isDisposed()) return;
Display.getDefault().asyncExec(new Runnable() {
public void run() {
if (bar.isDisposed ()) return;
bar.setSelection(i[0]);
}
});
}
}
}).start();
The code above created the ProgressBar. The issue is that the operation would end well before the progressbar indicator was close to ending.
Question: Is this because in the method I am creating a new thread and the indicator is updating according to the new thread and not the operation thread?
Question: Is it possible to create a new thread that watches the GUI thread and updates the progressbar accordingly?
Read a article suggesting using ProgressMonitorDialog with IRunnableWithProgress.
Method startProgressBar using ProgressMonitorDialog - see below:
public void startProgressBar() {
ProgressMonitorDialog dialog = new ProgressMonitorDialog(getShell());
try {
dialog.run(true, true, new IRunnableWithProgress(){
public void run(IProgressMonitor monitor) {
monitor.beginTask("Some nice progress message here ...", 100);
** getThread(); **
monitor.done();
}
});
}
catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void getThread() {
new Thread etc.. etc...
}
It seems that it will have the same issues with threading and updating as the code above.
Question: So now I am thinking can I just add or update the ProgressBar to my existing Listener
OperationListener Code - see below:
public abstract class MyOperationListener implements InterfaceAIFOperationListener {
AplotCreatePDFDialog w = null;
public MyOperationListener(AplotCreatePDFDialog win) {
w = win;
}
public void startOperation(String startMessage) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_WAIT));
w.recursiveSetEnabled(getShell(), getShell().getEnabled());
w.getShell().setEnabled(!getShell().getEnabled());
}
});
}
public void endOperation() {
try {
endOperationImpl();
}
finally {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_ARROW));
w.recursiveSetEnabled(getShell(), true);
w.getShell().setEnabled(!getShell().getEnabled());
w.close();
}
});
}
}
abstract protected void endOperationImpl();
} // end class MyOperationListener
Thanks for any help you can give me with this.
EDIT
Baz, your answer below is exactly what the question asked, so thank you for answering.
But I am starting to think that what I am trying to do is not possible.
When my operation starts, I wanted the progress bar indicator to start and when my operation ended I wanted the indicator be at the end and the monitor would close.
I thought there might bee a way to use my listener to add the progressbar. Something like the following.
public void startOperation(String startMessage) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
->monitor.beginTask("Creating PDF File(s)", IProgressMonitor.UNKNOWN);<-
w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_WAIT));
w.recursiveSetEnabled(getShell(), getShell().getEnabled());
w.getShell().setEnabled(!getShell().getEnabled());
}
});
}
public void endOperation() {
try {
->monitor.worked(1);<-
endOperationImpl();
}
finally {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_ARROW));
w.recursiveSetEnabled(getShell(), true);
w.getShell().setEnabled(!getShell().getEnabled());
->monitor.done();<-
w.close();
}
});
}
}
abstract protected void endOperationImpl();
} // end class MyOperationListener
But I am starting to see that the ProgressBar has to have some sort of measurement to display the indicator correctly.
I would be happy if the indicator just went back and forth and the monitor would close at the end of the operation.
Why not use ProgressMonitorDialog?
Here is a related answer from me showing a simple example.
This is what it looks like:
If you are not sure about the workload, use this code:
monitor.beginTask("Copying files", IProgressMonitor.UNKNOWN);
It will show the idle bar while running.