簡體   English   中英

嘗試在模態對話框中更新JLabel

[英]Trying To Update the JLabel in a Modal Dialog

我有一個包含JLabel的模態對話框。 此對話框調用另一個類中的方法,該類執行長時間運行的查找活動。 我希望這個查找類更新從模式對話框傳遞的JLabel。

我已經嘗試在查找過程中從代碼循環中更新JLabel。 (我發現當模式對話框運行時,永遠不會調用Swing計時器的actionPerformed方法。)自實現Timer以來,我將查找過程移到了一個單獨的Thread中。

我的查找工作,但JLabel仍然沒有重新粉刷,直到過程結束。 我會感激任何幫助。

這是相關的方法。 DictionaryTuple是一個POJO,包含兩個字段:List和String。 只是getter和setter,但是dictionaryThread確實可以訪問tupleList; 請注意,在dictionaryThread完成之前,我們不會觸摸它。

public List<DictionaryTuple> findTuples() {
    tupleList = new ArrayList<DictionaryTuple>();
    Thread dictionaryThread = new Thread(this);  // This is the long-running lookup thread
    dictionaryThread.start();

    progressTimer = new Timer();
    progressTimer.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
                       //  progressCaption is updated in dictionaryThread
            synchronized (progressCaption) {
                lblProgress.setText(progressCaption);
            }
            lblProgress.repaint();
            Thread.yield();
        }
    }, 250, 250);

     try {
        dictionaryThread.join();
    } catch (InterruptedException e) {
    } finally {
      progressTimer.cancel();
      lblProgress.setText("");
      progressCaption = "";
    }
    return tupleList;
}

我也嘗試過這種變化; 在這種情況下,內部run()調用將保持到處理完成為止:

    progressTimer.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            synchronized (progressCaption) {
            System.out.println("Fire!");
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    System.out.println("Update");
                    lblProgress.setText(progressCaption);
                    lblProgress.repaint();
                }});
            }
        }
    }, 250, 250);

你需要准確地告訴我們你的對話框中設置為可見-它之前或調用之后findTuples()方法? 這很關鍵。

建議:

  • 始終在Swing事件線程或EDT(事件分派線程)上更新JLabel。
  • 不要使用java.util.Timer來更新Swing應用程序的組件。
  • 您可以使用javax.swing.Timer來更新Swing組件,但這不會在這里工作,除非您使用它來輪詢后台進程。
  • 考慮使用SwingWorker進行背景線程處理,然后通過工作者的發布/處理方法或添加到SwingWorker的PropertyChangeListener更新JLabel。
  • 在將對話框設置為可見之前 ,調用對話框運行時要運行的所有方法。

這個演示應該會有所幫助。 如果我通過調用run vs在一個單獨的線程中運行它來運行長作業,請查看不同的內容


    public static void modalDialogTest() {
        JDialog dialog = new JDialog((JFrame)null);
        final JLabel jl = new JLabel("Need some space");
        JButton jb = new JButton ("Click me");
        Timer t = new Timer(1000, new AbstractAction() {
            int it = 0;
            @Override
            public void actionPerformed(ActionEvent arg0) {
                // TODO Auto-generated method stub
                jl.setText("" + it);
                jl.repaint();
                it++;
            }

        });
        t.start();

        AbstractAction wait = new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent e) {
                Runnable r = new Runnable() {
                    public void run() {
                        try {
                            Thread.sleep(10000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                };
                //r.run();
                new Thread(r).start();
            }
        };

        jb.addActionListener(wait);
        dialog.getContentPane().add(jl);
        dialog.getContentPane().add(jb);
        dialog.getContentPane().setLayout(new FlowLayout());
        dialog.pack();
        dialog.setVisible(true);
        dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
    }

謝謝大家的建議。 我實現的是Hovercraft,使用SwingWorker。

我的方法所在的Dictionary類現在擴展了SwingWorker。 findTuples()方法變為doInBackground()。 不再需要Timer和我自己的Thread代碼。

doInBackground()使用帶有屬性名稱“progress”的publish()來提供要在更新的JLabel中顯示的文本。

回到對話框代碼中,調用涉及創建Dictionary實例,並使用PropertyChangeListener處理JLabel中的更改(名為lblProgress)並檢測處理何時完成:

private void myCallingMethod() {
    final Dictionary dictionary = new Dictionary();

    dictionary.addPropertyChangeListener(new PropertyChangeListener() {
        @Override
        public void propertyChange(PropertyChangeEvent event) {
            List<DictionaryTuple> tupleList;

            // Is processing complete?
            if (event.getNewValue() instanceof StateValue
                    && event.getNewValue() == StateValue.DONE) {
                try {
                    tupleList = dictionary.get();
                    lblProgress.setText(tupleList.size() + " Tuples Found");
                } catch (Exception e) {
                    JOptionPane.showMessageDialog(
                            null,
                            "Error in processing dictionary: "
                                    + e.getMessage());
                    tupleList = new ArrayList<DictionaryTuple>();
                    lblProgress.setText("");
                }

                // Process the results.
                processTuples(tupleList);

            } else {
                // The process isn't done yet.
                // Is this a request to change lblProgress?
                if (event.getPropertyName().equals("progress")) {  
                    lblProgress.setText((String) event.getNewValue());
                }
            }
        }
    });

    // Start the dictionary lookup to run asynchronously.
    dictionary.execute();
}

我學會了不依賴SwingWorker.isDone()來確定SwingWorker的處理是否完整。 在我的例子中,PropertyChangeListener在該狀態下被調用兩次:一次是使用上一次發布()調用的結果,一次是在任務實際完成時。

暫無
暫無

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

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