亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Swing Worker 無法更新模態 jdialog 中的 GUI 組件

Swing Worker 無法更新模態 jdialog 中的 GUI 組件

翻過高山走不出你 2022-06-04 09:21:23
我有一個帶有進度條和文本區域的模態 Jdialog。我正在啟動一個 Swing Worker 來執行一些后臺任務并使用發布過程更新 jdialog 中的文本區域。但是,在運行程序時,我觀察到即使調用了 process 方法,它仍然沒有更新 jdialog 中的文本區域。另外,請注意,我在 swing worker 的 done 方法中關閉了 jdialog,它工作正常。誰能告訴我為什么沒有從(SwingWorker 的)流程方法進行 gui 更新?JDialog 類 -public class ProgressDialog extends JDialog {private static final long serialVersionUID = 1L;private GridBagLayout gridBag;private GridBagConstraints constraints;private ProgressDialog.ProgressBar progressBar;private JScrollPane scrollPane;private JTextArea textArea;ProgressDialog(Frame owner, String title, boolean modal, int numTasks) {    super(owner,title,modal);    gridBag = new GridBagLayout();    constraints = new GridBagConstraints();    this.progressBar = new ProgressDialog.ProgressBar();    this.progressBar.init(numTasks);    this.textArea = new JTextArea(10,30);    this.textArea.setEditable(false);    this.scrollPane = new JScrollPane(this.textArea);    this.scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);    this.scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);    this.setLayout(gridBag);    constraints.gridx = 0;    constraints.gridy = 0;    gridBag.setConstraints(progressBar, constraints);    constraints.gridx = 0;    constraints.gridy = 1;    constraints.insets = new Insets(10,0,10,0);    gridBag.setConstraints(scrollPane, constraints);    this.add(progressBar);    this.add(scrollPane);    this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);    this.setSize(400, 300);    this.setLocationRelativeTo(null);}class ProgressBar extends JProgressBar {    ProgressBar() {    }    void init(int numTasks) {        setMaximum(numTasks);        setStringPainted(true);        setValue(0);    }    void setProgress(int taskCompleted) {        int totalTasks = getMaximum();        setValue(taskCompleted);        setString(taskCompleted+"/"+totalTasks);    }}
查看完整描述

2 回答

?
達令說

TA貢獻1821條經驗 獲得超6個贊

一個巨大的問題就在這里:


protected void done() {

    try {

        Thread.sleep(5000);

    } catch (InterruptedException e) {

        e.printStackTrace();

    }

    pDialog.dispose();

}

在 EDT 或事件調度線程上調用worker 的done()方法,并且您知道當您休眠該線程時會發生什么——整個 GUI 進入休眠狀態并變得完全沒有響應。如果您想延遲對話框的處理并保持您的 GUI 正常運行,請不要這樣做,實際上永遠不要調用Thread.sleepEDT。


選項1:

相反,在大多數其他 Swing 延遲策略中,使用 Swing Timer,例如,類似這樣的東西(代碼未測試):


protected void done() {

    int timerDelay = 5000;

    new Timer(timerDelay, new ActionListener() {

        public void actionPerformed(ActionEvent e) {

            pDialog.dispose();

            ((Timer) e.getSource).stop();

        }

    }).start();

}

如果您不熟悉 Swing Timer 的使用,請查看Swing Timer 教程


選項 2:

把你放在Thread.sleep(5000)你方法的最后doInBackground(),就在之前return null;


另一個問題:您正在使用發布/處理方法對,但只使用了一次,這違背了它的目的。也許您打算在輪詢 while 循環中調用發布?當然你只能調用get()一次,但是有沒有另一種方法可以從你正在調用的正在運行的進程中提取信息?如果是這樣,則需要間歇性地獲取信息,無論是在輪詢 while 循環中,還是通過任何允許您提取臨時結果的過程。


例如:


import java.awt.BorderLayout;

import java.awt.Dialog.ModalityType;

import java.awt.Dimension;

import java.awt.Window;

import java.awt.event.ActionEvent;

import java.beans.*;

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.*;

import javax.swing.*;



public class TestProgressDialog extends JPanel {

    private static final long serialVersionUID = 1L;

    private ProgressDialog pDialog;

    private JSpinner taskNumberSpinner = new JSpinner(new SpinnerNumberModel(10, 1, 20, 1));


    public TestProgressDialog() {

        setPreferredSize(new Dimension(800, 650));

        add(new JButton(new AbstractAction("Launch Dialog") {

            private static final long serialVersionUID = 1L;


            @Override

            public void actionPerformed(ActionEvent e) {

                Window owner = SwingUtilities.windowForComponent(TestProgressDialog.this);

                String title = "Dialog";

                ModalityType modal = ModalityType.MODELESS;

                int numTasks = (int) taskNumberSpinner.getValue();

                pDialog = new ProgressDialog(owner, title, modal, numTasks);

                pDialog.pack();

                pDialog.setLocationByPlatform(true);

                pDialog.append("Initializing background tasks\n");

                MyWorker myWorker = new MyWorker(numTasks, pDialog);

                myWorker.addPropertyChangeListener(new WorkerListener(pDialog));

                myWorker.execute();

                pDialog.setVisible(true);

            }

        }));

        add(new JLabel("Number of Tasks:"));

        add(taskNumberSpinner);

    }


    private static void createAndShowGui() {

        TestProgressDialog mainPanel = new TestProgressDialog();


        JFrame frame = new JFrame("Test Progress Dialog");

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.getContentPane().add(mainPanel);

        frame.pack();

        frame.setLocationByPlatform(true);

        frame.setVisible(true);

    }


    public static void main(String[] args) {

        SwingUtilities.invokeLater(() -> createAndShowGui());

    }

}

interface Progressable {

    void setProgress(int progress);

    void append(String text);

}

class ProgressDialog extends JDialog implements Progressable {

    private static final long serialVersionUID = 1L;

    private JProgressBar progressBar = new JProgressBar(0, 100);

    private JTextArea textArea = new JTextArea(10, 30);

    private JScrollPane scrollPane = new JScrollPane(textArea);


    ProgressDialog(Window owner, String title, ModalityType modal, int nunTasks) {

        super(owner, title, modal);

        progressBar.setStringPainted(true);


        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

        add(progressBar, BorderLayout.PAGE_START);

        add(scrollPane);

    }


    @Override

    public void append(String text) {

        textArea.append(text);

    }


    @Override

    public void setProgress(int progress) {

        progressBar.setValue(progress);

    }


}

class MyCallable implements Callable<String> {

    private static final long MAX_DUR = 6 * 1000;

    private static final long MIN_DUR = 1000;

    private String text;


    public MyCallable(String text) {

        this.text = text;

    }


    public String getText() {

        return text;

    }


    @Override

    public String call() throws Exception {

        // just wait some random delay and then return a String

        long timeout = (long) (Math.random() * MAX_DUR + MIN_DUR);

        TimeUnit.MILLISECONDS.sleep(timeout);

        return text + " time out: " + timeout;

    }


}

class WorkerListener implements PropertyChangeListener {

    private Progressable progressable;


    public WorkerListener(Progressable progressable) {

        this.progressable = progressable;

    }


    @Override

    public void propertyChange(PropertyChangeEvent evt) {

        if (evt.getPropertyName() != null && evt.getPropertyName().equals("progress")) { 

            int progress = (int)evt.getNewValue();

            progressable.setProgress(progress);

        }

    }

}

class MyWorker extends SwingWorker<Void, String> {


    private Progressable progressable;

    private List<Future<String>> futures = new ArrayList<>();

    private CompletionService<String> completionService;

    private int numTasks;

    // private BlockingQueue<Future<String>> completionQueue;



    public MyWorker(int numTasks, Progressable progressable) {

        this.numTasks = numTasks;

        this.progressable = progressable;

        ExecutorService service = Executors.newFixedThreadPool(numTasks);

        completionService = new ExecutorCompletionService<>(service);


        for (int i = 0; i < numTasks; i++) {

            futures.add(completionService.submit(new MyCallable("My Callable " + i)));

        }

        service.shutdown();

    }


    @Override

    protected Void doInBackground() throws Exception {

        while (futures.size() > 0) {

            Future<String> future = completionService.take();

            futures.remove(future);

            int progress = (100 * (numTasks - futures.size())) / numTasks;

            progress = Math.min(100, progress);

            progress = Math.max(0, progress);

            setProgress(progress);

            if (future != null) {

                publish(future.get());

            }

        }

        return null;

    }


    @Override

    protected void process(List<String> chunks) {

        for (String chunk : chunks) {

            progressable.append(chunk + "\n");

        }

    }


    public Progressable getpDialog() {

        return progressable;

    }


}


查看完整回答
反對 回復 2022-06-04
?
郎朗坤

TA貢獻1921條經驗 獲得超9個贊

這里的問題是您的 Jdialog 框是模態的。每當彈出(或 JDialog)是setModal(true)EDT 線程被阻塞。這就是當使用 modal 彈出時用戶將無法執行任何操作的方式true

您必須制作它setmodal(false),然后在彈出窗口中更新內容,然后再制作它setmodal(true)。


查看完整回答
反對 回復 2022-06-04
  • 2 回答
  • 0 關注
  • 95 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號