[英]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()
方法? 這很關鍵。
建議:
這個演示應該會有所幫助。 如果我通過調用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.