Java Forum / GUI / November 2005
Using JProgressBar to show file upload progress
mpalermo@vt.edu - 02 Nov 2005 07:41 GMT Hello all. I'm building a small FTP file upload applet. This is just a very basic applet that allows a user to drag and drop files into a JTextArea component, then they click a button and it takes the files one by one and uploads them via FTP. I have all of this working, but I've been trying to put a JProgressBar into it to show the status of the current file being uploaded. The problem I have is that the progress bar isn't getting updated until the file is finished getting uploaded (which causes a jump from 0% to 100% all at once). Can someone please help point me in the right direction? Here is the code I have so far:
import javax.swing.JApplet; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JProgressBar; import javax.swing.JSplitPane; import javax.swing.JTextArea; import javax.swing.Timer;
import java.awt.BorderLayout; import java.awt.Color; import java.awt.dnd.DropTarget;
import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.StringTokenizer;
import sun.net.ftp.FtpClient; import java.io.*;
public class FileUpload extends JApplet { public static FileUpload selfRef = null; public JProgressBar progressBar = new JProgressBar(); public JTextArea fileListArea; private JSplitPane splitPane; private DropTarget dropTargetItem; private JButton uploadButton = new JButton("Upload Files"); private ButtonListener btnList = new ButtonListener(); private FtpClient ftp; private int appletWidth = 300; private int appletHeight = 300; public int currentFileUpPercent = 0;
public void init() { selfRef = this; }
public void stop() { }
public void destroy() { }
// ActionListener for the "Upload Files" button class ButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { preUpload(); String allText = fileListArea.getText(); StringTokenizer st = new StringTokenizer(allText, "\n"); if (st.countTokens() > 0) { connectToFTP(); while (st.hasMoreTokens()) { String line = st.nextToken(); doUpload(line); System.out.println("FILE: " + line); } disconnectFTP(); } postUpload(); } }
public void start() { // Set applet size setSize(appletWidth, appletHeight);
// Create new container splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); // splitPane.setOneTouchExpandable(true);
// Add label add(new JLabel("Drag files here to upload..."), BorderLayout.NORTH);
// Create file list text box fileListArea = new JTextArea(); fileListArea.setBounds(0, 0, appletWidth, appletHeight); fileListArea = new JTextArea(); fileListArea.setBackground(Color.white); fileListArea.setEditable(false); add(fileListArea, BorderLayout.CENTER);
// Progress bar progressBar.setValue(0);
// Upload button uploadButton.addActionListener(btnList); uploadButton.setEnabled(false);
// Setup bottom area splitPane.setLeftComponent(uploadButton); splitPane.setRightComponent(progressBar); add(splitPane, BorderLayout.SOUTH); splitPane.setDividerSize(0);
// Set up our text area to recieve drops... DropZone dropZone = new DropZone(); dropTargetItem = new DropTarget(fileListArea, dropZone); setVisible(true); }
// This is called after files are dragged into TextArea public void postDragDrop() { uploadButton.setEnabled(true); }
// Called right before each file gets uploaded public void preUpload() { progressBar.setValue(0); progressBar.setStringPainted(true); }
// Called right after each file is finished uploading public void postUpload() { progressBar.setValue(0); progressBar.setStringPainted(false); fileListArea.setText(""); }
// Make FTP connection public void connectToFTP() { try { ftp = new FtpClient(); String serverName = "<MY FTP SERVER>"; ftp.openServer(serverName, 21); if (ftp.serverIsOpen()) { System.out.println("Connected to " + serverName); try { ftp.login("<MY USERNAME>", "<MY PASSWORD>"); System.out.println("Welcome message:\n" + ftp.welcomeMsg); System.out.println("Current Directory: " + ftp.pwd()); } catch (Exception ftpe) { ftpe.printStackTrace(); } } else { System.out.println("Unable to connect to" + serverName); } System.out.println("Finished"); } catch (Exception e) { e.printStackTrace(); } }
// Disconnect from FTP public void disconnectFTP() { try { ftp.closeServer(); } catch (Exception ioe) {
} }
// Upload a given file public void doUpload(String filename) { if (ftp.serverIsOpen()) { try { System.out.println("Uploading file " + filename); ftp.binary(); String basename; basename = filename.substring(filename .lastIndexOf(File.separator) + 1, filename.length()); int i = 0; double bytesUploaded = 0; File fileInfo = new File(filename); byte[] bytesIn = new byte[1024]; try { FileInputStream in = new FileInputStream(filename); BufferedOutputStream out = new BufferedOutputStream(ftp .put(basename)); int percVal = 0; while ((i = in.read(bytesIn)) >= 0) { bytesUploaded += i; percVal = (int) ((bytesUploaded / fileInfo.length()) * 100); currentFileUpPercent = percVal; progressBar.setValue(currentFileUpPercent);
System.out.println("Percent Uploaded: " + percVal); out.write(bytesIn, 0, i); } in.close(); out.close(); } catch (Exception e) { } } catch (Exception ftpe) { ftpe.printStackTrace(); }
} else { System.out.println("Not connected..."); } }
public static void main(String[] args) {
} }
Andrew Thompson - 02 Nov 2005 07:47 GMT > Hello all. I'm building a small FTP file upload applet. This is just > a very basic applet .. There is no such thing. At least, not when it comes to *deploying* applets.
[ And adding Swing and file upload (trusted code) to the mix sure don't make it 'simpler'. ;-) ]
mpalermo@vt.edu - 02 Nov 2005 08:41 GMT Well, I've got the functionality of the file upload working by signing the jar file to make it a "trusted" applet. This allows the FTP upload capabilities. The only thing now working with this is the progress bar being updated during the file transfer. Everything else works fine.
mpalermo@vt.edu - 02 Nov 2005 08:43 GMT I made a typo above... Everything works with the applet right now except for the progress bar being updated...
Andrew Thompson - 02 Nov 2005 10:30 GMT > Well, I've got the functionality of the file upload working by signing > the jar file to make it a "trusted" applet. This allows the FTP upload > capabilities. (chuckles) OK. Actually I tried your code, and after replacing the 'DropZone' with a DropTarget and chucking a little stuff in the empty main()* I managed to see it on screen..
Which is when I realised the applet/D'n'D was all irrelevent to the basic problem of the progress bar updating.
I suspect that comes down to one of the common 'gotchas' of GUI development 'Blocking the EDT' More information in the c.l.j.gui FAQ "Q3.1 My GUI freezes or doesn't update."
* Why did you define a main but do nothing in it? A main() is handy while developing an applet, especially if it might need to be *signed* to work as an applet!
>..The only thing now working with this is the progress bar > being updated during the file transfer. Everything else works fine. Yep. ( I noted your correction to the above statement in your following post, and only *then* noticed your typo.! Your meaning was clear to me from the start. )
mpalermo@vt.edu - 02 Nov 2005 17:11 GMT I only defined a main because the jar file needed a main class and the applet wouldn't run without it. I'm pretty new to Java, so I'm not sure what you mean above when you say "Blocking the EDT". Can you elaborate on this or give me a link to read about it. You're right, the whole GUI freezes when the file upload is taking place and the progress bar does not get updated until it is finished. For testing and support purposes, would it help if I also posted the code for the DropZone class? Like you said, I don't think it has anything to do with the problem. Thanks for the help so far, I hope I can get this working.
mpalermo@vt.edu - 02 Nov 2005 17:20 GMT Sorry to keep multi-posting, but what did you need to put inside the main? As I said, I pretty new to Java, so I don't have a whole lot of knowledge with it yet.
Andrew Thompson - 02 Nov 2005 18:26 GMT > I only defined a main because the jar file needed a main class Nope, and..
>..and the applet wouldn't run without it. ..nope.
An applet does not *require* a main() though it can often make sense to include one.
A jar does not require a main() either. It might be a library jar with no mains() (or many mains, depending on the task). It might be an applet Jar, with the applet itself having no main().
>..I'm pretty new to Java, so I'm not > sure what you mean above when you say "Blocking the EDT". Can you > elaborate on this or give me a link to read about it. The GUI FAQ to which I referred is posted regularly to this group <http://groups.google.com/group/comp.lang.java.gui/search?group=comp.lang.java.gu i&q=faq> ..though I have an older copy at my site.. <http://www.physci.org/guifaq.jsp#2.1>
Note that entry has been expanded, AFAIR. You are best off to check the latest one posted to the group..
>....You're right, > the whole GUI freezes when the file upload is taking place and the > progress bar does not get updated until it is finished. For testing > and support purposes, would it help if I also posted the code for the > DropZone class? Not so much, no. It would be better if you could simulate a 'time consuming task' that did not involve D'n'D at all, as that would display the problem without all the complications, (but that is assuming you made the mental connection between 'GUI freezing' and 'time consuming task' - of course).
For general tips on preparing code examples for others to see, check this page.. <http://www.physci.org/codes/sscce.jsp>
It has lots of handy tips. One that seems relevant to this one is that it is a lot easier for us to see the problem if you post an URL to your applet (broken or not). A picture paints a thousand words, but the applet itself (often) screams them.
In your next post you mentioned 'multi-posting'.
Please note that sending muliple replies to this single thread is *not* multi-posting, you are simply responding to one thread - nobody (in their right mind) that I know of, objects to that.
Multi-posting is a very different thing, and the cause of considerable problems. For more details.. <http://www.physci.org/codes/javafaq.jsp#xpost>
Roedy Green - 03 Nov 2005 05:51 GMT >so I'm not >sure what you mean above when you say "Blocking the EDT" see http://mindprod.com/jgloss/swingthreads.html
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Nigel Wade - 03 Nov 2005 11:06 GMT > I only defined a main because the jar file needed a main class and the > applet wouldn't run without it. I'm pretty new to Java, so I'm not [quoted text clipped - 6 lines] > with the problem. Thanks for the help so far, I hope I can get this > working. You need to read the Java Swing Tutorial "Creating a GUI with JFC/Swing" at http://java.sun.com/docs/books/tutorial/uiswing/index.html.
Especially, look at the sections "How to Use Threads" and "How to Use Swing Timers" which deal with the EDT, threads, and show how to use progress bars.
 Signature Nigel Wade, System Administrator, Space Plasma Physics Group, University of Leicester, Leicester, LE1 7RH, UK E-mail : nmw@ion.le.ac.uk Phone : +44 (0)116 2523548, Fax : +44 (0)116 2523555
mpalermo@vt.edu - 04 Nov 2005 03:47 GMT I've already looked through all this. I've tried using threads and timers to update the progress bar, but since the GUI get frozen during the file upload process, they don't work. I just don't know how to put the file upload process into another thread, since it goes through the whole while loop to upload the files byte by byte. How do I get this into it's own thread to work separately from the EDT?
mpalermo@vt.edu - 04 Nov 2005 06:52 GMT Okay, I just found the solution. Just in case anyone else out there is having a similar problem, all I did was change the above ButtonListener class code to this instead:
class ButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { preUpload(); new Thread(new Runnable() { public void run() { String allText = fileListArea.getText(); StringTokenizer st = new StringTokenizer(allText, "\n"); if (st.countTokens() > 0) { connectToFTP(); while (st.hasMoreTokens()) { String line = st.nextToken(); doUpload(line); System.out.println("FILE: " + line); } disconnectFTP(); } } }).start(); postUpload(); } }
Thanks for all your help guys. I really appreciate it!
Nigel Wade - 04 Nov 2005 10:49 GMT > Okay, I just found the solution. Just in case anyone else out there is > having a similar problem, all I did was change the above ButtonListener [quoted text clipped - 24 lines] > > Thanks for all your help guys. I really appreciate it! The SwingWorker class is good for doing this sort of thing (that's what it was written for). It's not part of the API, but it is freely available. There is an explanation of it in the Swing threads tutorial along with a download link for it.
 Signature Nigel Wade, System Administrator, Space Plasma Physics Group, University of Leicester, Leicester, LE1 7RH, UK E-mail : nmw@ion.le.ac.uk Phone : +44 (0)116 2523548, Fax : +44 (0)116 2523555
Roedy Green - 02 Nov 2005 11:52 GMT On Wed, 02 Nov 2005 06:47:49 GMT, Andrew Thompson <seemysites@www.invalid> wrote, quoted or indirectly quoted someone who said :
>> Hello all. I'm building a small FTP file upload applet. This is just >> a very basic applet .. > >There is no such thing. At least, not when it comes to >*deploying* applets. A FTP upload needs access to read files in the local file system, the Applet would need to be signed.
If it just made up stuff out of its head to upload or was uploading keystrokes, it could get by unsigned it if talked only to the server from which it was loaded.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|