2

I'm coding a swing App. Here the tasks are to download the file from a given URL and then get the counts of them. The program works with no issues/errors.

The problem is I've a testarea in my frame, when file 1 is downloaded I want the text area to show downloaded file 1 and when file 2 is done downloaded file 1 and so on...

Currently in my program the message is displayed but all at once. I mean if I've 10 files, it shows.

downloaded file 1
downloaded file 2
.
.
.
.
.
downloaded file 10

But this is shown only after all the 10 files are downloaded. To see if there is any other problem, I've added sysout just below the textarea code. And to my surprise, sysouts are printed 10 times, I mean each time a file is processed, this is triggered, but the textarea is appended with all the data at a time.

Below are my codes.

GuiForPDFs

import java.awt.BorderLayout;

public class GuiForPDFs extends JFrame {

    private JPanel contentPane;
    private JTextField srcTextField;
    private JTextArea textArea;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    GuiForPDFs frame = new GuiForPDFs();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    FileDownloadTest downloadTest = new FileDownloadTest();

    public GuiForPDFs() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 552, 358);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(null);

        srcTextField = new JTextField();
        srcTextField.setBounds(10, 26, 399, 20);
        contentPane.add(srcTextField);
        srcTextField.setColumns(10);

        JButton srcBtn = new JButton("Source Excel");
        srcBtn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                JFileChooser fChoose = new JFileChooser();
                if (fChoose.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
                    srcTextField.setText(fChoose.getSelectedFile().getAbsolutePath());
                } else {
                    System.out.println("No Selection");
                }
            }
        });

        textArea = new JTextArea();
        textArea.setEditable(false);
        textArea.setBounds(10, 106, 516, 203);
        contentPane.add(textArea);

        srcBtn.setBounds(419, 25, 107, 23);
        contentPane.add(srcBtn);

        JButton dNcButton = new JButton("Process");
        dNcButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                try {
                    downloadTest.fileDownloadTest(srcTextField.getText(), textArea);
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
        dNcButton.setBounds(212, 70, 89, 23);
        contentPane.add(dNcButton);

    }
}

FileDownloadTest

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.swing.JTextArea;

import org.apache.commons.io.FileUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class FileDownloadTest {

    public void fileDownloadTest(String src, JTextArea textArea) throws IOException, InterruptedException {
        String path = src;
        FileInputStream fin = new FileInputStream(new File(path));
        XSSFWorkbook workbook = new XSSFWorkbook(fin);
        XSSFSheet sheet = workbook.getSheetAt(0);
        int rows = sheet.getPhysicalNumberOfRows();
        System.out.println("rows are " + rows);
        XSSFCell cell;
        // Make sure that this directory exists
        String dirName = src.substring(0, src.lastIndexOf("\\"));
        File f = new File(dirName);
        if (!f.exists()) {
            f.mkdir();
        }
        System.out.println(f.getAbsolutePath() + " is Directory Name " + src + " is the file");
        for (int i = 1; i < rows; i++) {
            XSSFCell url = sheet.getRow(i).getCell(0);
            String URLString = url.toString();
            cell = sheet.getRow(i).getCell(7);
            String fileName = URLString.substring(URLString.lastIndexOf("/") + 1);
            int pageNumbers = downloadFiles(dirName, url.toString().replace("http", "https"));
            if (cell == null) {
                cell = sheet.getRow(i).createCell(1);
            }
            cell.setCellType(Cell.CELL_TYPE_NUMERIC);
            cell.setCellValue(pageNumbers);
            FileOutputStream fileOut = new FileOutputStream(path);
            workbook.write(fileOut);
            fileOut.close();
            textArea.append("downloaded " + fileName + "\n");
            System.out.println("Done");
        }
        workbook.close();
        fin.close();

    }

    public static int downloadFiles(String dirName, String urlString) {
        System.out.println("Downloading \'" + urlString + "\' PDF document...");
        String fileName = urlString.substring(urlString.lastIndexOf("/") + 1);
        System.out.println(fileName + " is file name");
        try {
            saveFileFromUrlWithJavaIO(dirName + "\\" + fileName, urlString);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("Downloaded \'" + urlString + "\' PDF document...");
        int pageNumber = 0;
        try {
            pageNumber = getNoOfPages(dirName + "\\" + fileName);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return pageNumber;
    }

    public static int getNoOfPages(String fileName) throws IOException {
        PDDocument document = PDDocument.load(new File(fileName));
        int numberOfPages = document.getNumberOfPages();
        return numberOfPages;
    }

    public static void saveFileFromUrlWithJavaIO(String fileName, String fileUrl)
            throws MalformedURLException, IOException {
        BufferedInputStream in = null;
        FileOutputStream fout = null;
        try {
            in = new BufferedInputStream(new URL(fileUrl).openStream());
            fout = new FileOutputStream(fileName);

            byte data[] = new byte[1024];
            int count;
            while ((count = in.read(data, 0, 1024)) != -1) {
                fout.write(data, 0, count);
            }
        } finally {
            if (in != null)
                in.close();
            if (fout != null)
                fout.close();
        }
    }

    public static void saveFileFromUrlWithCommonsIO(String fileName, String fileUrl)
            throws MalformedURLException, IOException {
        FileUtils.copyURLToFile(new URL(fileUrl), new File(fileName));
    }

}

please let me know How can I fix this.

Thanks

Rakesh
  • 564
  • 1
  • 8
  • 25
  • 1
    I didn't fully read your code but you're probably doing it on the EDT (event dispatch thread) which is responsible for updating the ui and is blocked by your action. Use a SwingWorker or something similar instead. – Thomas Mar 23 '16 at 13:11
  • Hint: it is great that you have a separate class to test your stuff. But don't write static mains() to do testing. Turn to Junit; and write unit tests. That is how you do testing in 2016. static main is like 1999. – GhostCat Mar 23 '16 at 13:11
  • 1
    Read about [concurrency in swing](https://docs.oracle.com/javase/tutorial/uiswing/concurrency/) – Sergiy Medvynskyy Mar 23 '16 at 13:15

2 Answers2

1

The above comments are correct, you are on the EDT when adding text to the TextArea. This is because you are calling downloadTest.fileDownloadTest from the dNcButton ActionListener implementation.

It's good practice to get off the EDT is you have a long running operation to perform, and downloading a file is often given as as example of the sort of thing you don't want to do on the EDT.

There are lots of resources online as to how to get off the EDT, including many on this great site;

On Event Dispatch Thread---want to get off of it

Make thread run on non EDT (event dispatch thread) thread from EDT

Community
  • 1
  • 1
Paul MacGuiheen
  • 628
  • 5
  • 17
0

As with the other comments, you need to keep only UI related tasks on the EDT. Otherwise if your user is downloading 100 files the UI will lock up until the download task is finished. SwingWorker is the perfect class to do this for Swing applications. Here is a quick example:

// Run your FileDownloadTest inside a SwingWorker
// or have the class extend SwingWorker
new SwingWorker<Void, String>() {

    @Override
    protected Void doInBackground() throws Exception {
        //Perform downloading here (done off the EDT)
        //Call publish(downloadedFileName) to be sent to the process method()
        return null;
    }

    @Override
    protected void process(List<String> chunks) {
        // Modify textArea (done on the EDT)
        StringBuilder downloadedFiles = new StringBuilder();
        for (String fileName : chunks) {
            downloadedFiles.append("downloaded" + fileName + "\n");
        }
        textArea.setText(downloadedFiles);
    }

    @Override
    protected void done() {
        //Anything you want to happen after doInBackground() finishes
    }
}.execute();
apicellaj
  • 233
  • 1
  • 3
  • 16
  • Hi Friend, Here I'm doing some excel data operations, and it is done inside the `fileDownloadTest()`, all at once, it is not like i process one and return the value and the process 2nd and return the value. – Rakesh Mar 23 '16 at 13:59
  • You can call `publish(fileName)` after a file has downloaded which then gets sent to the `process()` method by SwingWorker. This allows `textArea` to be updated after each file is downloaded from your `downloadFiles()` method. – apicellaj Mar 23 '16 at 14:13
  • I'm sorry, I'm unable to get you. My question is I've a loop in my class that loops through cells in Excel. And the operation is done there, And I've pasted the above code in my Swing Class `GuiForPDFs`, If you don't mind Can you please create the same as mine with where I need to Change, I'm learning and working on Swings – Rakesh Mar 23 '16 at 14:21
  • Sorry if I misunderstood. Do you want to update the `textArea` after each file is downloaded? – apicellaj Mar 23 '16 at 14:32
  • Yes My Friend, That's what I needed :) – Rakesh Mar 23 '16 at 14:35
  • Okay, great. And you want to update the `textArea` in the `public void fileDownloadTest()` , right? – apicellaj Mar 23 '16 at 14:39
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/107147/discussion-between-rakesh-and-apicellaj). – Rakesh Mar 23 '16 at 14:49