Results 1 to 9 of 9
  1. #1
    jurka is offline Member
    Join Date
    Jul 2008
    Posts
    67
    Rep Power
    0

    Default SwingWorker and my small internet page downloader

    I wrote this code to understand the processes of SwingWorker class which i have been trying to implement. I want to know is this right way to use SwingWorker or not ?

    Java Code:
    import java.awt.BorderLayout;
    import java.awt.FlowLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.URL;
    import java.util.concurrent.ExecutionException;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTextArea;
    import javax.swing.JTextField;
    import javax.swing.SwingUtilities;
    import javax.swing.SwingWorker;
    
    
    public class GetDataFromWeb extends JFrame {
    
    	JTextArea downloadedDataArea;
    	
    	public GetDataFromWeb() {
    		setTitle("Download data from internet!");
    		setSize(200, 250);
    	
    		JPanel northPanel = new JPanel(new FlowLayout());
    		final JTextField internetTextField = new JTextField(10);
    		internetTextField.setText("http://www.google.com");
    		final JButton downloadButton = new JButton("Go!");
    
    		
    		northPanel.add(internetTextField);
    		northPanel.add(downloadButton);
    		
    		downloadedDataArea = new JTextArea();
    		JScrollPane downloadDataAreaScrollPane = new JScrollPane(downloadedDataArea);
    		
    		setLayout(new BorderLayout());
    		add(northPanel, BorderLayout.NORTH);
    		add(downloadDataAreaScrollPane, BorderLayout.CENTER);
    		
    		downloadButton.addActionListener(new ActionListener() {
    			@Override
    			public void actionPerformed(ActionEvent e) {
    				String address = internetTextField.getText();
    				if (address.length() > 0) {
    					
    					try {
    						InternetDataTask task = new InternetDataTask(downloadedDataArea,
    								address);
    						task.execute();
    					} catch (IOException e1) {
    						// TODO Auto-generated catch block
    						e1.printStackTrace();
    					}
    					
    				}
    			}
    		});
    		
    		setVisible(true);
    	}
    	
    	public static void main(String[] args) {
    		
    		SwingUtilities.invokeLater(new Runnable() {
    			@Override
    			public void run() {
    				new GetDataFromWeb();
    			}
    		});
    	}
    
    }
    
    class InternetDataTask extends SwingWorker<String, Void> {
    	URL url;
    	InputStream in;
    	JTextArea textArea;
    	String address;
    	
    	public InternetDataTask(JTextArea area, String address) throws IOException {
    		this.textArea = area;
    		this.address = address;
    		url = new URL(address);
    		url.openConnection();
    		in = url.openStream();
    	}
    	
    	@Override
    	protected String doInBackground() throws Exception {
    		StringBuilder sb = new StringBuilder();
    		
    		byte[] buffer = new byte[128];
    		while ((in.read(buffer)) != -1) {
    			for (byte b : buffer) {
    //				System.out.print((char)b);
    				sb.append((char)b);
    			}
    		}
    		
    		in.close();
    //		textArea.append(sb + "\n");
    		return sb.toString();
    	}	
    	
    	@Override
    	protected void done() {
    		try {
    			textArea.append(get());
    		} catch (InterruptedException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (ExecutionException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	}
    }

  2. #2
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    Just on quick overview, it looks good. Question though: does it work as you'd expect it should?

  3. #3
    jurka is offline Member
    Join Date
    Jul 2008
    Posts
    67
    Rep Power
    0

    Default

    Yes, but i am thinking about doInbackground method is implemented correctly? I am reading all the content into one string, is it right ?

  4. #4
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    As written, I see nothing wrong with your doInBackground method as you don't call any Swing code directly from it, which is good. Whether you wish to store the content in one String is a design issue that I think is distinct from whether or not the SwingWorker is written correctly.

    Now if you want to show information in your app incrementally as the SwingWorker is doing its actions, then you should look into the process and publish methods.

  5. #5
    Steve11235's Avatar
    Steve11235 is offline Senior Member
    Join Date
    Dec 2008
    Posts
    1,046
    Rep Power
    7

    Default

    It looks good to me. The point of SwingWorker is that runs the logic on a background thread, but its done() method executes on the EDT, allowing you to update you Swing components.

    What you do in doInBackground() is up to you. You can put the results in a String, or you could create an ArrayList and put each result as an entry in that. Bottom line, SwingWorker provides flexibility in how you return information.

    You can also use the publish() and process() methods to handle results one at a time, so the display components will update incrementally. publish() operates in the worker thread, process() operates on the EDT.

    Note that SwingWorker also allows you to add listeners for process events, and the listeners are also called on the EDT. The basic events are START and DONE; DONE is useful if you limit what the user can do while they are waiting. It also has other useful features.

  6. #6
    jurka is offline Member
    Join Date
    Jul 2008
    Posts
    67
    Rep Power
    0

    Default

    Here is my next code i get it working but i dont get the exact that result which should be. Progressbar is not working correctly, like it's not receiving the progressbar state.

    Also, this forum needs java highlighting!
    Java Code:
    import java.awt.BorderLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import java.io.IOException;
    import java.util.ArrayList;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JProgressBar;
    import javax.swing.JScrollPane;
    import javax.swing.JTextArea;
    import javax.swing.SwingUtilities;
    import javax.swing.SwingWorker;
    
    
    public class SwingWorkerProgress extends JFrame {
    
    	JTextArea downloadedDataArea;
    	JProgressBar progressBar;
    	
    	public SwingWorkerProgress() {
    		setTitle("Download data from internet!");
    		setSize(200, 250);
    		
    		downloadedDataArea = new JTextArea();
    		JScrollPane downloadDataAreaScrollPane = new JScrollPane(downloadedDataArea);
    		
    		progressBar = new JProgressBar();
    		progressBar.setMinimum(0);
    		progressBar.setMaximum(100);
    		
    		JButton startButton = new JButton("Start");
    
    		startButton.addActionListener(new ActionListener() {
    			@Override
    			public void actionPerformed(ActionEvent e) {
    				try {
    					NumbersShow task = new NumbersShow(downloadedDataArea);
    					task.addPropertyChangeListener(
    						new PropertyChangeListener() {
    							@Override
    							public void propertyChange(PropertyChangeEvent evt) {
    								if ("progress".equals(evt.getPropertyName())) {
    									progressBar.setValue((Integer)evt.getNewValue());
    								}
    							}
    						});
    					task.execute();
    						
    									
    				} catch (IOException e1) {
    					// TODO Auto-generated catch block
    					e1.printStackTrace();
    				}
    			}
    		});
    		
    		setLayout(new BorderLayout());
    		add(progressBar, BorderLayout.NORTH);
    		add(downloadDataAreaScrollPane, BorderLayout.CENTER);
    		add(startButton, BorderLayout.SOUTH);
    		setVisible(true);
    	}
    	
    	public static void main(String[] args) {
    		
    		SwingUtilities.invokeLater(new Runnable() {
    			@Override
    			public void run() {
    				new SwingWorkerProgress();
    			}
    		});
    	}
    
    }
    
    class NumbersShow extends SwingWorker<java.util.List<Integer>, Integer> {
    	JTextArea textArea;
    	int repeatTo = 100000;
    	
    	public NumbersShow(JTextArea area) throws IOException {
    		this.textArea = area;
    	}
    	
    	@Override
    	protected java.util.List<Integer> doInBackground() throws Exception {
    		int i = 0;
    		java.util.List<Integer> numbers = new ArrayList<Integer>();
    		
    		while (repeatTo > i && !isCancelled()) {
    			publish(i);
    			numbers.add(i);
    			int progressAt = (int)(i / repeatTo * 100);
    //			setProgress(progressAt);
    			i++;
    		}
    		return numbers;
    	}	
    	
    	@Override
    	protected void process(java.util.List<Integer> chunks) {
    		for (int num : chunks) {
    			textArea.append(num + "\n");
    		}
    	}
    }

  7. #7
    Steve11235's Avatar
    Steve11235 is offline Senior Member
    Join Date
    Dec 2008
    Posts
    1,046
    Rep Power
    7

    Default

    setProgress causes a propertyChangeEvent to be fired. You must listen for these events, which include start and done as well.

  8. #8
    jurka is offline Member
    Join Date
    Jul 2008
    Posts
    67
    Rep Power
    0

    Default

    Ok I actually gave up, but i am back again so i didn't understand your last post, so please give deeper explanation.
    Do you mean by listening also start and done property or what ? In this block of code ?
    PHP Code:
    							public void propertyChange(PropertyChangeEvent evt) {
    								if ("progress".equals(evt.getPropertyName())) {
    									progressBar.setValue((Integer)evt.getNewValue());
    								}
    							}
    Ok i made a more useful example
    Java Code:
    import java.awt.BorderLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import java.io.File;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.ExecutionException;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JProgressBar;
    import javax.swing.JScrollPane;
    import javax.swing.JTextArea;
    import javax.swing.SwingUtilities;
    import javax.swing.SwingWorker;
    
    
    public class SwingWorkerProgress extends JFrame {
    
    	JTextArea downloadedDataArea;
    	JProgressBar progressBar;
    	
    	public SwingWorkerProgress() {
    		setTitle("Download data from internet!");
    		setSize(200, 250);
    		
    		downloadedDataArea = new JTextArea();
    		JScrollPane downloadDataAreaScrollPane = new JScrollPane(downloadedDataArea);
    		
    		progressBar = new JProgressBar();
    		progressBar.setMinimum(0);
    //		progressBar.setMaximum(100);
    		
    		JButton startButton = new JButton("Start");
    
    		startButton.addActionListener(new ActionListener() {
    			@Override
    			public void actionPerformed(ActionEvent e) {
    				try {
    					NumbersShow task = new NumbersShow(downloadedDataArea);
    					task.addPropertyChangeListener(
    						new PropertyChangeListener() {
    							@Override
    							public void propertyChange(PropertyChangeEvent evt) {
    								if ("progress".equals(evt.getPropertyName())) {
    									progressBar.setValue((Integer)evt.getNewValue());
    								}
    							}
    						});
    					task.execute();
    						
    									
    				} catch (IOException e1) {
    					// TODO Auto-generated catch block
    					e1.printStackTrace();
    				}
    			}
    		});
    		
    		setLayout(new BorderLayout());
    		add(progressBar, BorderLayout.NORTH);
    		add(downloadDataAreaScrollPane, BorderLayout.CENTER);
    		add(startButton, BorderLayout.SOUTH);
    		setVisible(true);
    	}
    	
    	public static void main(String[] args) {
    		
    		SwingUtilities.invokeLater(new Runnable() {
    			@Override
    			public void run() {
    				new SwingWorkerProgress();
    			}
    		});
    	}
    
    }
    
    class NumbersShow extends SwingWorker<String, String> {
    	JTextArea textArea;
    	final File path = new File("C:\\");
    	
    	
    	public NumbersShow(JTextArea area) throws IOException {
    		this.textArea = area;
    	}
    	
    	@Override
    	protected String doInBackground() throws Exception {
    		StringBuilder sb = new StringBuilder();
    		int size = path.list().length;
    		int current = 0;
    		
    		for (String f : path.list()) {
    			String temp = f;
    			publish(temp);
    			sb.append(temp);
    			int progressAt = (int)(current / size * 100);
    			setProgress(progressAt);
    			current++;
    			
    		}
    
    		return sb.toString();
    	}	
    	
    	
    	@Override
    	protected void process(List<String> chunks) {
    		for (String line : chunks) {
    			textArea.append(line + "\n");
    		}
    		
    	}
    }

  9. #9
    Steve11235's Avatar
    Steve11235 is offline Senior Member
    Join Date
    Dec 2008
    Posts
    1,046
    Rep Power
    7

    Default

    You've made a lot of progress. I took your code and dumped it into Eclipse. I had to remove the code to retrieve data and replace it with a loop and a Thread.sleep() in doInBackGround(), but you app runs and updates the progress bar.

    There is one significant issue! Do *not* use the process() method to do the data retrieval. Put that code back in doInBackground().

    If you look carefully at the SwingWorker API, the publish() and process() methods work together. publish() allows the worker thread to store chunks of results, so the process() can retrieve the chunks and update the GUI *on the event dispatcher thread*. The goal is to allow the GUI to incrementally display data as it becomes available.

    If that doesn't make sense, don't worry about it. It's an advanced capability, and you don't need to use it.

    Good job on what you have so far. You also need to listen to "done" events, which indicate that the SwingWorker has completed its task. Often, you partially lock the GUI while work is done in background, perhaps only allowing the user a cancel option. When the task is done, the GUI is unlocked.

Similar Threads

  1. SwingWorker Problem
    By Berkan in forum Threads and Synchronization
    Replies: 10
    Last Post: 03-11-2010, 03:28 AM
  2. Replies: 3
    Last Post: 10-02-2008, 05:48 AM
  3. Creating a Downloader using JAVA
    By shinojkk in forum New To Java
    Replies: 0
    Last Post: 01-08-2008, 05:08 PM
  4. Replies: 1
    Last Post: 01-05-2008, 07:48 PM
  5. swingworker
    By musiigedeo in forum AWT / Swing
    Replies: 1
    Last Post: 07-26-2007, 12:59 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •