簡體   English   中英

在Swing中使用ProgressMonitorInputStream監視壓縮文件解壓縮時未更新UI

[英]UI not updated while using ProgressMonitorInputStream in Swing to monitor compressed file decompression

我正在開發依賴於嵌入式H2數據庫的swing應用程序。 因為我不想將數據庫與應用程序捆綁在一起(數據庫經常更新,並且我希望應用程序的新用戶從最近的副本開始),所以我實現了一個解決方案,可以下載數據庫的壓縮副本。第一次啟動應用程序並將其提取。 由於提取過程可能很慢,因此我添加了ProgressMonitorInputStream來顯示提取過程的進度-不幸的是,當提取開始時,會顯示進度對話框,但根本不會更新。 似乎事件正在進入事件分配線程。 方法如下:

public static String extractDbFromArchive(String pathToArchive) {
    if (SwingUtilities.isEventDispatchThread()) {
        System.out.println("Invoking on event dispatch thread");
    }

    // Get the current path, where the database will be extracted
    String currentPath = System.getProperty("user.home") + File.separator + ".spellbook" + File.separator;
    LOGGER.info("Current path: " + currentPath);

    try {
        //Open the archive
        FileInputStream archiveFileStream = new FileInputStream(pathToArchive);
        // Read two bytes from the stream before it used by CBZip2InputStream

        for (int i = 0; i < 2; i++) {
            archiveFileStream.read();
        }

        // Open the gzip file and open the output file
        CBZip2InputStream bz2 = new CBZip2InputStream(new ProgressMonitorInputStream(
                              null,
                              "Decompressing " + pathToArchive,
                              archiveFileStream));
        FileOutputStream out = new FileOutputStream(ARCHIVED_DB_NAME);

        LOGGER.info("Decompressing the tar file...");
        // Transfer bytes from the compressed file to the output file
        byte[] buffer = new byte[1024];
        int len;
        while ((len = bz2.read(buffer)) > 0) {
            out.write(buffer, 0, len);
        }

        // Close the file and stream
        bz2.close();
        out.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException ex) {
        ex.printStackTrace();
    }

    try {
        TarInputStream tarInputStream = null;
        TarEntry tarEntry;
        tarInputStream = new TarInputStream(new ProgressMonitorInputStream(
                              null,
                              "Extracting " + ARCHIVED_DB_NAME,
                              new FileInputStream(ARCHIVED_DB_NAME)));

        tarEntry = tarInputStream.getNextEntry();

        byte[] buf1 = new byte[1024];

        LOGGER.info("Extracting tar file");

        while (tarEntry != null) {
            //For each entry to be extracted
            String entryName = currentPath + tarEntry.getName();
            entryName = entryName.replace('/', File.separatorChar);
            entryName = entryName.replace('\\', File.separatorChar);

            LOGGER.info("Extracting entry: " + entryName);
            FileOutputStream fileOutputStream;
            File newFile = new File(entryName);
            if (tarEntry.isDirectory()) {
                if (!newFile.mkdirs()) {
                    break;
                }
                tarEntry = tarInputStream.getNextEntry();
                continue;
            }

            fileOutputStream = new FileOutputStream(entryName);
            int n;
            while ((n = tarInputStream.read(buf1, 0, 1024)) > -1) {
                fileOutputStream.write(buf1, 0, n);
            }

            fileOutputStream.close();
            tarEntry = tarInputStream.getNextEntry();

        }
        tarInputStream.close();
    } catch (Exception e) {
    }

    currentPath += "db" + File.separator + DB_FILE_NAME;

    if (!currentPath.isEmpty()) {
        LOGGER.info("DB placed in : " + currentPath);
    }

    return currentPath;
}

在事件分發線程上調用此方法(SwingUtilities.isEventDispatchThread()返回true),因此應更新UI組件。 我尚未將其實現為SwingWorker,因為無論如何我都需要等待提取,然后才能繼續進行程序的初始化。 在應用程序的主JFrame可見之前,將調用此方法。 我不會基於SwingWorker +屬性已更改的偵聽器的解決方案-我認為ProgressMonitorInputStream正是我所需要的,但我想我做的事情不正確。 我正在使用Sun JDK 1.6.18。 任何幫助將不勝感激。

在EDT上運行提取過程時,它將阻止對GUI的所有更新,甚至進度監視器也是如此。 這正是SwingWorker將提供幫助的情況。

實際上,您是通過拖延EDT來提取數據庫來阻止繪畫。 任何GUI更新請求(例如對repaint()調用)都將排隊,但是實際上重繪這些更新永遠不會運行,因為EDT已經很忙。

它可能唯一可行的方法是將處理任務卸載到另一個線程。 SwingWorker使其更容易做到這一點。

@Ash關於SwingWorker是正確的。 准備好后,可以使用done()啟用其他GUI功能。 done()方法將“在doInBackground()方法完成后在事件調度線程上執行”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM