Results 1 to 20 of 21
- 07-26-2011, 11:58 PM #1
Member
- Join Date
- Jun 2011
- Posts
- 23
- Rep Power
- 0
Concurrently writing to a JComponent
Greetings. I'll get right to it. I'm writing a program where several threads (each thread is one instance of a data processing procedure, and there are an undetermined number that need to execute, though a maximum of 2 will ever be executing simultaneously) need to write to a shared console (JTextArea) indicating something has happened in that thread's execution. Along with this, indicators such as JLabels and JProgressBars also need to update with information showing how far along the overall process is (how many procedures are waiting to execute, the current status of the overall execution, and the overall percentage complete). However, I'm having issues with the concurrency of the threads and getting these components to update. What happens is that each component waits until the overall completion has ended before it updates, so the indicators are basically useless.
To this end, I have constructed an example with just the console. This code is displayed below. It is meant to provide an idea of what I'm doing, as well as show my logic as to what I believe it's doing. What I believe it should do, it is not doing, and that is where I need help. Basically, I create 3 threads that I want to print a simple message to the console in intervals of 2 seconds. However, what happens is that each thread waits for the execution of the other threads to complete, and they all print at the same time.
My question is, what is flawed about this? Is it my logic or is concurrency defeating me? Any insight into this would be greatly apprciated. Thanks in advance.
Java Code:import java.awt.BorderLayout; import java.awt.Container; import java.awt.FlowLayout; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; public class ConTesting { static JTextArea console = new JTextArea(); public static void main(String[] args) { ConTesting test = new ConTesting(); test.setup(); } public void setup() { JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.setSize(500, 400); frame.setTitle("Activity Console - UL/DL Execution Progress"); frame.setResizable(false); frame.setLocation(1700, 200); Container pane = frame.getContentPane(); JPanel progPanel = new JPanel(); progPanel.setLayout(new FlowLayout()); final JButton exButton = new JButton("Start"); exButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { execute(); } }); final JButton clButton = new JButton("Clear"); clButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { console.setText(""); } }); progPanel.add(exButton); progPanel.add(clButton); console = new JTextArea(); console.setEditable(false); console.setFont(new Font("Courier", Font.PLAIN, 11)); JScrollPane consolePane = new JScrollPane(console); pane.add(consolePane, "Center"); pane.add(progPanel, "South"); frame.setVisible(true); } public static void writeToConsole(String message) { if (!message.equals("")) console.append(message); } public void execute() { for (int i = 0; i < 3; i++) { Worker w = new Worker(); Thread t = new Thread(w); t.start(); try { Thread.sleep(2000); } catch (Exception e){} } } private class Worker implements Runnable { @Override public void run() { try { long time = System.nanoTime(); Thread t = Thread.currentThread(); writeToConsole("This is " + t.getName() + " being printed; Time: " + time + "\n"); } catch (Exception e) { } } } }
-
You're calling Thread.sleep(...) in Swing's event thread, the EDT, so it's not surprising that the GUI will become unresponsive. Solution: don't do that. Consider doing that in a background thread such as with a SwingWorker, or using a Swing Timer if all you need to do is to delay the action of something.
- 07-27-2011, 12:29 AM #3
Member
- Join Date
- Jun 2011
- Posts
- 23
- Rep Power
- 0
Well, this is just an example, and I'm not necessarily talking about having a problem with it becoming unresponsive (though I would like to fix that as well). My logic was that the Sleep call would wait 2 seconds before proceeding to executing the next thread, effectively creating a 2 second interval between console prints. But like I said, they all wait until all are done executing before they print.
-
But that's entirely the problem -- your gui is not displaying anything because you are not doing threading properly and you are putting your GUI to sleep.
Please see this link for more: Lesson: Concurrency in Swing (The Java™ Tutorials > Creating a GUI With JFC/Swing)
-
For example (quick and dirty):
Java Code:import java.awt.*; import java.awt.event.*; import java.util.List; import javax.swing.*; @SuppressWarnings("serial") public class ConTesting2 extends JPanel { private JTextArea textArea = new JTextArea(25, 50); public ConTesting2() { JPanel buttonPanel = new JPanel(); buttonPanel.add(new JButton(new StartAction1())); buttonPanel.add(new JButton(new StartAction2())); buttonPanel.add(new JButton(new ClearAction())); setLayout(new BorderLayout()); add(new JScrollPane(textArea), BorderLayout.CENTER); add(buttonPanel, BorderLayout.SOUTH); } public void appendText(String text) { textArea.append(text); } private class StartAction1 extends AbstractAction { protected static final int MAX_COUNT = 3; public StartAction1() { super("Start 1: Timer"); } public void actionPerformed(ActionEvent e) { int timerDelay = 2000; new Timer(timerDelay, new ActionListener() { private int count = 0; @Override public void actionPerformed(ActionEvent e) { if (count < MAX_COUNT) { new Thread(new Runnable() { public void run() { long time = System.nanoTime(); Thread t = Thread.currentThread(); final String text = "This is " + t.getName() + " being printed; Time: " + time + "\n"; SwingUtilities.invokeLater(new Runnable() { public void run() { appendText(text); } }); } }).start(); count++; } else { ((Timer) e.getSource()).stop(); } } }).start(); } } private class StartAction2 extends AbstractAction { protected static final long SLEEP_TIME = 2000; public StartAction2() { super("Start 2: SwingWorker"); } public void actionPerformed(ActionEvent e) { new SwingWorker<Void, String>() { @Override protected Void doInBackground() throws Exception { for (int i = 0; i < 3; i++) { Thread.sleep(SLEEP_TIME); long time = System.nanoTime(); Thread t = Thread.currentThread(); String text = "This is " + t.getName() + " being printed; Time: " + time + "\n"; publish(text); } return null; } @Override protected void process(List<String> chunks) { for (String chunk : chunks) { appendText(chunk); } } }.execute(); } } private class ClearAction extends AbstractAction { public ClearAction() { super("Clear"); } public void actionPerformed(ActionEvent e) { textArea.setText(""); } } private static void createAndShowGui() { JFrame frame = new JFrame("ConTesting 2"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new ConTesting2()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGui(); } }); } }
- 07-27-2011, 12:36 AM #6
Member
- Join Date
- Jun 2011
- Posts
- 23
- Rep Power
- 0
- 07-27-2011, 03:40 PM #7
Member
- Join Date
- Jun 2011
- Posts
- 23
- Rep Power
- 0
- 07-27-2011, 04:24 PM #8
Member
- Join Date
- Apr 2011
- Posts
- 69
- Rep Power
- 0
Take note of the SwingUtilities.invokeLater() call. Anytime you update a component, always do it this way. This will have the main thread process it instead of whatever thread you are calling from.
- 07-28-2011, 05:54 PM #9
Member
- Join Date
- Jun 2011
- Posts
- 23
- Rep Power
- 0
Ok, doing what has been suggested I have fixed the lockup of the UI. However, I still cannot get the progress indicators to update (updateProgressIndicators()) with every 'activity' that occurs (I've inserted several calls to this just for testing purposes). It updates the first time through the loop, but never again after that. The progress indicators include a JTextArea that is the 'console', a JLabel showing how many items are left in the queue, and a JProgressBar showing percent complete.
In addition, it also still completely executes one activity before moving to the next, which is not how I want it to work. I want a maximum of 2 instances of SCPActivity to be executing at a given time. An SCPActivity is just a file download or upload automated through WinSCP's command-line interface. To do this, I create a process using a Runtime.exec() call to the cmd.exe program. I also pull off this process's stdout stream so that I can print it to the console when it has completed.
Basically, I want to go thorugh the loop and create a new thread for a new activity if less than 2 instances of winscp.com are currently executing, and wait if there are 2 or more, with each thread updating the progress indicators whenever it finishes. Also, it continues to loop even after the while loop ends and I don't really understand why. Does it have something to do with being in a run() call?
Any ideas?
The code I have for a 'StartAction' inner class is as follows (sorry for the mess, it's deep):
Java Code:private class StartAction extends AbstractAction { public StartAction() { super("Execute"); } @Override public void actionPerformed(ActionEvent e) { if (queue.size() > 0) { new SwingWorker<Void, String>() { public Void doInBackground() { while (true) { if (queue.size() <= 0) break; new Thread(new Runnable() { @Override public void run() { updateProgressIndicators(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { int instances = Utilities.getNumberOfProcesses("winscp.com"); System.out.println("WinSCP instances: " + instances); System.out.println("Remaining: " + remaining); if (instances < 2 && queue.size() > 0) { SCPActivity act = queue.pop(); act.execute(); InputStream stream = act.getStream(); console.append("File '" + act.getFilename() + "' " + act.getType() + " initiated..." + newline); String line; BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); try { line = reader.readLine(); while (!line.contains("Active session:")) { line = reader.readLine(); } line = reader.readLine(); console.append(line + newline + newline); remaining--; updateProgressIndicators(); } catch (IOException e1) { e1.printStackTrace(); } } } }); } }).start(); updateProgressIndicators(); } return null; } }.execute(); } else { writeToConsole("There are no activities in the queue. Please select modules to " + "execute or wait for" + newline + "the queue to populate." + newline); } } }Last edited by unaligned; 07-28-2011 at 07:02 PM. Reason: clarifications
-
I highly doubt that anyone will be able to make heads or tails out of the code you've posted, and I strongly urge you to put in the effort to create and post an SSCCE that demonstrates your problem (see the link). I don't think that it's asking too much, as I've already put in a similar effort to try to help you (see my code above for example).
- 07-28-2011, 11:06 PM #11
Member
- Join Date
- Jun 2011
- Posts
- 23
- Rep Power
- 0
I was afraid this might be the case. I tried hard to explain it fully so that it was at least slightly understandable without the rest of the code, but I understand that there's no way anyone can truly know what I'm trying to do until they see it.
As such, I will try to make one and post it on here, though it will not be for a few days as this is for work and I am off until Monday. I hope you're still still around when I post it next week. Thanks for the help, I greatly appreciate it.
- 08-03-2011, 09:25 PM #12
Member
- Join Date
- Jun 2011
- Posts
- 23
- Rep Power
- 0
Ok, here is an SSCCE for this project. I have changed the WinSCP portion of the original project to use ping instead, as it is conceptually the same idea as WinSCP in this context (executing a new process via command line to perform a procedure). This is why some of the files contain SCP in the classname.
What I want it to do is update the console (JTextArea), which is the main window of the program, with the text resulting from the ping command, a JLabel showing status, and a JProgressBar showing progress. Currently they don't update at all, even when all tasks are complete.
Additionally, I want each of these tasks to create a new thread so a maximum of 2 are executing simultaneously, though right now it completely goes through the loop for one task before moving on the the next. Also, I've noticed that after all tasks are completed, the program continues to loop even though queue.size() is 0, which is the loop break condition. I don't fully understand how this is all happening.
*EDIT: this program will not run on a non-windows system because it utilizes several Windows-specific calls to execute the procedures (cmd.exe, tasklist.exe, ping.exe).Last edited by unaligned; 08-03-2011 at 09:42 PM.
- 08-03-2011, 10:32 PM #13
Its interesting that you have documented here what you want your code to do, but when I look in the code there are NO comments saying what the code is supposed to do.
Why is that?
Do you expect us to copy your comments from this thread into your code so that we know what the code is supposed to do?
- 08-04-2011, 04:16 PM #14
Member
- Join Date
- Jun 2011
- Posts
- 23
- Rep Power
- 0
Updated code with some changes and comments.
EDIT: I missed an initialization,at line 185 of ActivityQueue needs to beJava Code:String line
Apologies... I figured this would be better than reposting the entire code.Java Code:String line = "";
Last edited by unaligned; 08-04-2011 at 04:24 PM.
- 08-04-2011, 04:32 PM #15
Member
- Join Date
- Jun 2011
- Posts
- 23
- Rep Power
- 0
-
I've looked some at your code, and it's a bit much to digest during the work week, but one thing that strikes me as odd is that you seem to be trying to call code that takes a long time to run in the SwingWorker but on the event dispatch thread:
e.g.,
I may look at it more over the weekend, but would appreciate it if you could shrink it and simplify it greatly. Do that -- and then post the finished product here -- and you'll have a much greater chance of me or someone else looking at it in greater depth. Also, is this cross-posted elsewhere? Also, if you solve it yourself, please post that here asap so we don't spin our wheels on an already solved problem.Java Code:new SwingWorker<Void, String>() { public Void doInBackground() { while (queue.size() > 0) { new Thread(new Runnable() { public void run() { SwingUtilities.invokeLater(new Runnable() { public void run() { // *** this now is all run on the event dispatch thread *** // ... if (instances < 2 && queue.size() > 0) { SCPActivity act = queue.pop(); act.execute(); // how long does this take? //... BufferedReader reader = new BufferedReader( new InputStreamReader(stream)); try { // *** this should freeze the EDT while (!reader.ready()) { } line = reader.readLine(); while (!(line == null)) { console.append(line + newline + newline); line = reader.readLine(); } updateProgressIndicators(); } catch (IOException e1) { e1.printStackTrace(); } } } }); } }).start(); } return null; } }.execute();
Luck.
-
Edit: I was thinking along these lines for the SwingWorker:
Java Code:new SwingWorker<Void, String>() { private int taskCount = queue.size(); private CountDownLatch latch = new CountDownLatch(queue.size()); private ExecutorService pool = Executors .newFixedThreadPool(taskCount); @Override protected Void doInBackground() throws Exception { // if wanted to do tasks all at once // Set<Future<String>> futures = new HashSet<Future<String>>(taskCount); for (int i = 0; i < queue.size(); i++) { MyTask task = new MyTask("My Task " + i, latch); // futures.add(pool.submit(task)); // to do tasks all at once publish(pool.submit(task).get()); // to do tasks one at a time } // to do tasks all at once // for (Future<String> future : futures) { // publish(future.get()); // } latch.await(); // wait for countdown to finish return null; } @Override protected void process(List<String> chunks) { for (String chunk : chunks) { updateProgressIndicators(taskCount, (int) latch.getCount()); console.append(chunk + "\n"); } } @Override protected void done() { updateProgressIndicators(taskCount, (int) latch.getCount()); } }.execute();
And using a separate class to do most of the "innards" of the SwingWorker:
Requiring a change in updateProgressIndicators:Java Code:// test class just for demonstration purposes class MyTask implements Callable<String> { private String text; private CountDownLatch latch; public MyTask(String text, CountDownLatch latch) { this.text = text; this.latch = latch; } @Override public String call() throws Exception { Thread.sleep(4000); latch.countDown(); return text; } }
Java Code:public void updateProgressIndicators(int totals, int count) { String status = ""; int progress = Utilities.getPercentage(totals - count, totals); if (progress >= 100) status = "complete!"; else status = "executing..."; setProgLabel("Number of items in queue: " + queue.size() + " | Status: " + status); pBar.setValue(progress); }
-
Not quite working yet, but almost:
Java Code:import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import javax.swing.*; import javax.swing.SwingWorker.StateValue; @SuppressWarnings("serial") public class ActivityQueue2 extends JPanel { // instance variables // private LinkedList<SCPActivity> queue; // the queue of activities that were // added to execute private JProgressBar pBar; // progress bar showing the overall progress of // the execution private JLabel progLabel; // label displaying the status of the execution and // the number of activities remaining private JTextArea console; // main window of the UI; output of the activities // will be printed here private static final String newline = "\n"; // IV used for a new line in the // console private int total; // the total number of activities that were added to the // queue /** * Constructor for the ActivityQueue, initializes the IVs * * @param queue * - an ArrayList from which the queue is built */ public ActivityQueue2(ArrayList<SCPActivity> queue) { this.queue = new LinkedList<SCPActivity>(); // initializes the counter used to update the progress indicators to 0. total = 0; // create and initialize the progress bar pBar = new JProgressBar(0, 100); pBar.setValue(0); pBar.setStringPainted(true); // initialize the console and the progress label progLabel = new JLabel(""); console = new JTextArea(25, 50); console.setEditable(false); // add each item from the ArrayList to the queue for (SCPActivity act : queue) { addToQueue(act); } // initialize and set up the panel that holds the start // button, progress bar and progress label. JPanel buttonPanel = new JPanel(); setLayout(new BorderLayout()); buttonPanel.add(new JButton(new StartAction())); buttonPanel.add(progLabel); buttonPanel.add(pBar); // add the console and the button panel to the frame add(buttonPanel, BorderLayout.SOUTH); add(new JScrollPane(console), BorderLayout.CENTER); } /** * Method called in order to show the UI and set up the ActivityQueue * * @param queue * - ArrayList passed into the ActivityQueue constructor */ public static void createAndShowGui(ArrayList<SCPActivity> queue) { JFrame frame = new JFrame("Activity Console"); frame.getContentPane().add(new ActivityQueue2(queue)); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(750, 600); frame.pack(); frame.setResizable(false); frame.setLocation(1700, 200); frame.setLocationRelativeTo(null); frame.setVisible(true); } /** * Adds the activity parameter to the queue if it doesn't already exist * * @param activity * - an activity that will be added to the queue */ public void addToQueue(SCPActivity activity) { if (!queue.contains(activity)) { // the the queue doesn't contain the activity, it is added to the queue queue.add(activity); // updates the console to note that the activity was added writeToConsole("*" + activity.getActivityID() + " added to queue."); // increments the number of total activities in the queue total++; } // updates the progress label to indicate the number of activities in the // queue setProgLabel("Number of items in queue: " + queue.size() + " | Status: waiting..."); } /** * Updates all indicators that display the overall progress of the activity * execution * * @param count * @param totals */ public void updateProgressIndicators(int totals, int count) { String status = ""; int progress = Utilities.getPercentage(totals - count, totals); if (progress >= 100) status = "complete!"; else status = "executing..."; setProgLabel("Number of items in queue: " + queue.size() + " | Status: " + status); pBar.setValue(progress); } /** * Writes the provided message to the console then prints a new line * * @param message * - the message to print to the console */ public void writeToConsole(String message) { if (!message.equals("")) console.append(message + newline); } /** * Sets the progress label to the value of 'message' * * @param message * - the message which to set the progress label */ public void setProgLabel(String message) { if (!(message.equals(""))) progLabel.setText(message); } /** * Private inner class that is used to execute the activities in the queue */ private class StartAction extends AbstractAction { // constructor for StartAction - sets the name to 'Execute'. public StartAction() { super("Execute"); } @Override public void actionPerformed(ActionEvent e) { if (queue.size() > 0) { new SwingWorker<Void, String>() { private int taskCount = queue.size(); private CountDownLatch latch = new CountDownLatch(queue.size()); private ExecutorService pool = Executors .newFixedThreadPool(taskCount); private Map<MyTask, Future<String>> taskFutureMap = new HashMap<MyTask, Future<String>>(); @Override protected Void doInBackground() throws Exception { PropertyChangeListener myPropChngListener = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { String name = evt.getPropertyName(); SwingWorker.StateValue state = (StateValue) evt.getNewValue(); System.out.printf("property name: %s; state value: %s%n", name, state); if (name.equals(MyTask.STATE) && (state == SwingWorker.StateValue.DONE)) { MyTask task = (MyTask) evt.getSource(); Future<String> future = taskFutureMap.get(task); System.out.println("here 006"); try { String text = future.get(); System.out.println("Text: " + text); publish(text); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } }; while (queue.size() > 0) { SCPActivity act = queue.pop(); MyTask task = new MyTask("My Task", latch, act); task.addPropertyChangeListener(myPropChngListener); taskFutureMap.put(task, pool.submit(task)); } latch.await(); // wait for countdown to finish return null; } @Override protected void process(List<String> chunks) { for (String chunk : chunks) { updateProgressIndicators(taskCount, (int) latch.getCount()); console.append(chunk + "\n"); } } @Override protected void done() { updateProgressIndicators(taskCount, (int) latch.getCount()); } }.execute(); } else { // note if there are no activities in the queue writeToConsole("There are no activities in the queue. Please select modules to " + "execute or wait for" + newline + "the queue to populate." + newline); } } } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { // create an ArrayList of activities and add them to the queue ArrayList<SCPActivity> q = new ArrayList<SCPActivity>(); SCPping act = new SCPping("google.com"); q.add(act); act = new SCPping("yahoo.com"); q.add(act); act = new SCPping("facebook.com"); q.add(act); createAndShowGui(q); } }); } } // test class just for demonstration purposes class MyTask implements Callable<String> { public static final String STATE = "state"; private String text; private CountDownLatch latch; private PropertyChangeSupport propChngSupport = new PropertyChangeSupport( this); private SwingWorker.StateValue state = SwingWorker.StateValue.PENDING; private SCPActivity act; public MyTask(String text, CountDownLatch latch, SCPActivity act) { this.text = text; this.latch = latch; this.act = act; } @Override public String call() throws Exception { setState(SwingWorker.StateValue.STARTED); System.out.println("here 004"); // !! // Thread.sleep(4000); while (state != SwingWorker.StateValue.DONE) { System.out.println("here 003"); // !! int instances = Utilities.getNumberOfProcesses("ping.exe"); if (instances < 2) { act.execute(); InputStream stream = act.getStream(); String line = ""; // create a new reader for the stream BufferedReader reader = new BufferedReader(new InputStreamReader( stream)); try { System.out.println("here 001"); // !! while (!reader.ready()) { } line = reader.readLine(); while (!(line == null)) { text += " " + line; line = reader.readLine(); } } catch (IOException e1) { e1.printStackTrace(); } System.out.println("here 002"); // !! latch.countDown(); setState(SwingWorker.StateValue.DONE); } } // TODO: finish return text; } private void setState(SwingWorker.StateValue newValue) { SwingWorker.StateValue oldValue = this.state; this.state = newValue; PropertyChangeEvent evt = new PropertyChangeEvent(this, STATE, oldValue, newValue); propChngSupport.firePropertyChange(evt); } public void addPropertyChangeListener(PropertyChangeListener listener) { propChngSupport.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { propChngSupport.removePropertyChangeListener(listener); } }
- 08-05-2011, 04:03 PM #19
Member
- Join Date
- Jun 2011
- Posts
- 23
- Rep Power
- 0
I'm trying to wrap my head around what you've done - it actually completes and updates the indicators now which is a major step forward. I am going to try to figure out how to get the console to print the output from the ping calls.
I greatly appreciate the help you've given me and will continue to work on it. And no, this is the only place it's posted.Last edited by unaligned; 08-05-2011 at 04:07 PM.
-
Next incarnation: works better:
Java Code:import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.beans.*; import java.io.*; import java.util.*; import java.util.concurrent.*; import javax.swing.*; @SuppressWarnings("serial") public class ActivityQueue2b extends JPanel { // instance variables // private LinkedList<SCPActivity> queue; // the queue of activities that were // added to execute private JProgressBar pBar; // progress bar showing the overall progress of // the execution private JLabel progLabel; // label displaying the status of the execution and // the number of activities remaining private JTextArea console; // main window of the UI; output of the activities // will be printed here private static final String newline = "\n"; // IV used for a new line in the // console private int total; // the total number of activities that were added to the // queue /** * Constructor for the ActivityQueue, initializes the IVs * * @param queue * - an ArrayList from which the queue is built */ public ActivityQueue2b(ArrayList<SCPActivity> queue) { this.queue = new LinkedList<SCPActivity>(); // initializes the counter used to update the progress indicators to 0. total = 0; // create and initialize the progress bar pBar = new JProgressBar(0, 100); pBar.setValue(0); pBar.setStringPainted(true); // initialize the console and the progress label progLabel = new JLabel(""); console = new JTextArea(25, 50); console.setEditable(false); // add each item from the ArrayList to the queue for (SCPActivity act : queue) { addToQueue(act); } // initialize and set up the panel that holds the start // button, progress bar and progress label. JPanel buttonPanel = new JPanel(); setLayout(new BorderLayout()); buttonPanel.add(new JButton(new StartAction())); buttonPanel.add(progLabel); buttonPanel.add(pBar); // add the console and the button panel to the frame add(buttonPanel, BorderLayout.SOUTH); add(new JScrollPane(console), BorderLayout.CENTER); } /** * Method called in order to show the UI and set up the ActivityQueue * * @param queue * - ArrayList passed into the ActivityQueue constructor */ public static void createAndShowGui(ArrayList<SCPActivity> queue) { JFrame frame = new JFrame("Activity Console"); frame.getContentPane().add(new ActivityQueue2b(queue)); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(750, 600); frame.pack(); frame.setResizable(false); frame.setLocation(1700, 200); frame.setLocationRelativeTo(null); frame.setVisible(true); } /** * Adds the activity parameter to the queue if it doesn't already exist * * @param activity * - an activity that will be added to the queue */ public void addToQueue(SCPActivity activity) { if (!queue.contains(activity)) { // the the queue doesn't contain the activity, it is added to the queue queue.add(activity); // updates the console to note that the activity was added writeToConsole("*" + activity.getActivityID() + " added to queue."); // increments the number of total activities in the queue total++; } // updates the progress label to indicate the number of activities in the // queue setProgLabel("Number of items in queue: " + queue.size() + " | Status: waiting..."); } /** * Updates all indicators that display the overall progress of the activity * execution * * @param count * @param totals */ public void updateProgressIndicators(int totals, int count) { String status = ""; int progress = Utilities.getPercentage(totals - count, totals); if (progress >= 100) status = "complete!"; else status = "executing..."; setProgLabel("Number of items in queue: " + queue.size() + " | Status: " + status); pBar.setValue(progress); } /** * Writes the provided message to the console then prints a new line * * @param message * - the message to print to the console */ public void writeToConsole(String message) { if (!message.equals("")) console.append(message + newline); } /** * Sets the progress label to the value of 'message' * * @param message * - the message which to set the progress label */ public void setProgLabel(String message) { if (!(message.equals(""))) progLabel.setText(message); } /** * Private inner class that is used to execute the activities in the queue */ private class StartAction extends AbstractAction { // constructor for StartAction - sets the name to 'Execute'. public StartAction() { super("Execute"); } @Override public void actionPerformed(ActionEvent e) { if (queue.size() > 0) { new SwingWorker<Void, String>() { private int taskCount = queue.size(); private CountDownLatch latch = new CountDownLatch(queue.size()); private ExecutorService pool = Executors .newFixedThreadPool(taskCount); private Map<MyTask2b, Future<String>> taskFutureMap = new HashMap<MyTask2b, Future<String>>(); @Override protected Void doInBackground() throws Exception { PropertyChangeListener myPropChngListener = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { String name = evt.getPropertyName(); Object newValue = evt.getNewValue(); System.out.printf( "property name: %s; new value: %s%n", name, newValue); if (name.equals(MyTask2b.STATE) && (newValue == SwingWorker.StateValue.DONE)) { MyTask2b task = (MyTask2b) evt.getSource(); Future<String> future = taskFutureMap.get(task); try { String text = future.get(); System.out.println("Text: " + text); publish(text); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } else if (name.equals(MyTask2b.LINE)) { MyTask2b task = (MyTask2b) evt.getSource(); publish(task.getLine()); //!! } } }; while (queue.size() > 0) { SCPActivity act = queue.pop(); MyTask2b task = new MyTask2b("My Task", latch, act); task.addPropertyChangeListener(myPropChngListener); taskFutureMap.put(task, pool.submit(task)); } latch.await(); // wait for countdown to finish return null; } @Override protected void process(List<String> chunks) { for (String chunk : chunks) { updateProgressIndicators(taskCount, (int) latch.getCount()); console.append(chunk + "\n"); } } @Override protected void done() { updateProgressIndicators(taskCount, (int) latch.getCount()); } }.execute(); } else { // note if there are no activities in the queue writeToConsole("There are no activities in the queue. Please select modules to " + "execute or wait for" + newline + "the queue to populate." + newline); } } } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { // create an ArrayList of activities and add them to the queue ArrayList<SCPActivity> q = new ArrayList<SCPActivity>(); SCPping act = new SCPping("google.com"); q.add(act); act = new SCPping("yahoo.com"); q.add(act); act = new SCPping("facebook.com"); q.add(act); createAndShowGui(q); } }); } } class MyTask2b implements Callable<String> { public static final String STATE = "state"; public static final String LINE = "line"; private String text; private CountDownLatch latch; private PropertyChangeSupport propChngSupport = new PropertyChangeSupport( this); private SwingWorker.StateValue state = SwingWorker.StateValue.PENDING; private SCPActivity act; private String line = ""; public MyTask2b(String text, CountDownLatch latch, SCPActivity act) { this.text = text; this.latch = latch; this.act = act; } @Override public String call() throws Exception { setState(SwingWorker.StateValue.STARTED); while (state != SwingWorker.StateValue.DONE) { System.out.println("state: " + state); int instances = Utilities.getNumberOfProcesses("ping.exe"); if (instances < 2) { act.execute(); InputStream stream = act.getStream(); String line = ""; BufferedReader reader = new BufferedReader(new InputStreamReader( stream)); try { while (!reader.ready()) { } line = reader.readLine(); while (!(line == null)) { setLine(line); line = reader.readLine(); } } catch (IOException e1) { e1.printStackTrace(); } latch.countDown(); setState(SwingWorker.StateValue.DONE); } } System.out.println("just before return text"); //!! return text; } private void setState(SwingWorker.StateValue newValue) { SwingWorker.StateValue oldValue = this.state; this.state = newValue; PropertyChangeEvent evt = new PropertyChangeEvent(this, STATE, oldValue, newValue); propChngSupport.firePropertyChange(evt); } private void setLine(String newValue) { String oldValue = this.line; this.line = newValue; PropertyChangeEvent evt = new PropertyChangeEvent(this, LINE, oldValue, newValue); propChngSupport.firePropertyChange(evt); } public String getLine() { return act.getActivityID() + ": " + line; } public void addPropertyChangeListener(PropertyChangeListener listener) { propChngSupport.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { propChngSupport.removePropertyChangeListener(listener); } }
Similar Threads
-
Center text in a JComponent?
By Zman3359 in forum New To JavaReplies: 4Last Post: 04-17-2011, 10:44 PM -
Question on getGraphics() in a JComponent
By Shayke_ in forum Java 2DReplies: 2Last Post: 02-10-2011, 07:31 PM -
Using JComponent methods on a JComponent that was found using .getComponents()
By tashimoto in forum New To JavaReplies: 2Last Post: 10-01-2010, 07:18 PM -
SetBackground for JComponent
By tulasi.neppali in forum AWT / SwingReplies: 5Last Post: 09-12-2010, 10:14 PM -
Random size of JComponent
By Karl-von-bahnhof in forum AWT / SwingReplies: 0Last Post: 04-13-2010, 08:14 PM


LinkBack URL
About LinkBacks
Reply With Quote

Bookmarks