SwingWorker не обновляет JProgressBar без Thread.sleep() в пользовательской диалоговой панели
У меня есть SwingWorker
Класс, который загружает текстовый файл и разбивает его на куски для дальнейшей обработки.
Это SwingWorker
учебный класс:
public class ConverterWorker extends SwingWorker<String, String>
{
private final File f;
private final JLabel label;
public ConverterWorker(File f, JLabel label)
{
this.f = f;
this.label = label;
}
@Override
protected String doInBackground() throws Exception
{
NMTMain.convertableData = getDataSets(f);
if(!NMTMain.convertableData.isEmpty())
{
return "Done";
}
else
{
publish("Failed to load the file!");
return "Failed";
}
}
@Override
public void done()
{
try
{
label.setText(get());
}
catch (Exception e)
{
e.printStackTrace(System.err);
System.out.println("error");
}
}
@Override
protected void process(List<String> chunks)
{
label.setText(chunks.get(chunks.size() - 1));
}
public ArrayList<ArrayList<Convertable>> getDataSets(File f)
{
ArrayList<ArrayList<Convertable>> dataSets = new ArrayList<ArrayList<Convertable>>();
publish("Loading file...");
setProgress(0);
String[] data = loadFile(f);
for(int i = 0; i< NMTMain.nodes.size(); i++)
{
dataSets.add(splitByNode(data, NMTMain.nodes.get(i).getName()));
}
setProgress(100);
return dataSets;
}
private ArrayList<Convertable> splitByNode(String[] data, String name)
{
ArrayList<Convertable> temp = new ArrayList<Convertable>();
for(int i = 0; i < data.length; i++)
{
if(data[i].contains(name))
{
temp.add(new Convertable(data[i]));
}
}
Collections.sort(temp);
return temp;
}
private String[] loadFile(File f)
{
String data = "";
String[] nodes;
long fileLength = f.length();
int bytesRead = -1;
int totalBytesRead = 0;
try
{
if(f.exists())
{
Scanner scan = new Scanner(f);
while(scan.hasNextLine())
{
String line = scan.nextLine();
data = data + line + "\n";
bytesRead = line.getBytes().length;
totalBytesRead += bytesRead;
int progress = (int) Math.round(((double) totalBytesRead / (double) fileLength) * 100d);
/* try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
//publish("loading... " + String.valueOf(progress));
setProgress(progress);
}
scan.close();
}
}
catch (FileNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
nodes = data.split("\n\"\n");
return nodes;
}
Это прекрасно работает, когда Thread.sleep(1);
не комментируется. Однако, когда я комментирую Thread.sleep(1);
класс не обновляет индикатор выполнения.
Я называю свой класс кнопкой, вот ActionListener
:
loadInput.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent arg0)
{
int returnval=NMTMain.fileChooser.showOpenDialog(NMTMain.MainFrame);
if(returnval == 0)
{
File f=NMTMain.fileChooser.getSelectedFile();
final ConverterWorker worker = new ConverterWorker(f, dialogPanel.getLabel());
worker.addPropertyChangeListener(new PropertyChangeListener()
{
@Override
public void propertyChange(final PropertyChangeEvent evt)
{
if("progress".equalsIgnoreCase(evt.getPropertyName()))
{
dialogPanel.showProgressDialog("Conversion");
dialogPanel.setProgressBarValue((int) evt.getNewValue());
}
if(worker.isDone())
{
dialogPanel.showConfirmDialog("Conversion", "OK");
}
}
});
worker.execute();
}
}
});
Это должно нормально работать без сна, так что я тут делаю не так?
ОБНОВИТЬ:
Оказалось, что мой DialogPanel
не самый лучший и вызывает такое поведение.
Здесь DialogPanel
учебный класс:
public class DialogPanel extends JDialog
{
private JLabel label;
private JPanel panel;
private JButton button;
private JProgressBar progressBar;
public DialogPanel()
{
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(5,10,5,10);
panel = new JPanel();
panel.setLayout(new GridBagLayout());
progressBar = new JProgressBar(0,100);
progressBar.setVisible(false);
progressBar.setStringPainted(true);
setLabel(new JLabel("def text", SwingConstants.CENTER));
button = new JButton("OK");
button.setVisible(false);
button.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent arg0)
{
// TODO Auto-generated method stub
dispose();
}
});
gbc.gridx = 0;
gbc.gridy = 0;
panel.add(getLabel(), gbc);
gbc.gridy = 1;
panel.add(progressBar, gbc);
panel.add(button, gbc);
this.setContentPane(panel);
this.setLocationRelativeTo(null);
this.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
this.setResizable(false);
}
public void setProgressBarValue(int value)
{
progressBar.setValue(value);
}
public void setProgressBarVisibility(boolean value)
{
progressBar.setVisible(value);
}
public void setText(String text)
{
getLabel().setText(text);
}
public void showProgressDialog(String title)
{
progressBar.setVisible(true);
button.setVisible(false);
this.setTitle(title);
this.pack();
if(!this.isVisible())
{
this.setVisible(true);
}
}
public void showConfirmDialog(String title, String buttontext)
{
progressBar.setVisible(false);
button.setVisible(true);
this.setTitle(title);
button.setText(buttontext);
this.pack();
if(!this.isVisible())
{
this.setVisible(true);
}
}
public JLabel getLabel()
{
return label;
}
public void setLabel(JLabel label)
{
this.label = label;
}
public JProgressBar getProgressBar()
{
return progressBar;
}
@Override
public Dimension getPreferredSize()
{
return new Dimension(200, 100);
}
}
Это, вероятно, беспорядок для профессиональных глаз. Как я могу показать индикатор в диалоговом окне, в котором будет кнопка подтверждения, чтобы закрыть диалоговое окно после завершения процесса?
Решение:
Я изменился от моего DialogPanel
Класс ProgressMonitor и теперь все в порядке. Спасибо за ваше время и советы.
2 ответа
Я хотел отследить SwingWorker
прогресс с JProgressBar
в пределах JDialog
, Однако мой SwingWorker
класс не мог справиться с моим обычаем DialogPanel
учебный класс. Для достижения того же результата, используя значение по умолчанию ProgressMonitor
класс был лучшим вариантом.
Я прошел ProgressMonitor
к SwingWorker
через его конструктор:
private final File f;
private final ProgressMonitor pm
public FileLoadWorker(File f, ProgressMonitor pm)
{
this.f = f;
this.pm = pm;
}
и изменил следующие методы, как это:
@Override
public void done()
{
try
{
pm.setNote(get());
}
catch (Exception e)
{
e.printStackTrace(System.err);
System.out.println("error");
}
}
@Override
protected void process(List<String> chunks)
{
pm.setNote(chunks.get(chunks.size() - 1));
}
Задачи propertyChangeListener
изменилось так:
final FileLoadWorker worker = new FileLoadWorker(f, pm);
worker.addPropertyChangeListener(new PropertyChangeListener()
{
@Override
public void propertyChange(final PropertyChangeEvent evt)
{
if("progress".equalsIgnoreCase(evt.getPropertyName()))
{
pm.setProgress((int) evt.getNewValue());
}
if("state".equals(evt.getPropertyName()))
{
SwingWorker.StateValue s = (SwingWorker.StateValue) evt.getNewValue();
if(s.equals(SwingWorker.StateValue.DONE))
{
pm.setProgress(100);
pm.close();
Toolkit.getDefaultToolkit().beep();
}
}
if(pm.isCanceled())
{
pm.close();
worker.cancel(true);
}
}
});
worker.execute();
Спасибо trashgod за ответ и комментарии о state
имущество.
setProgress()
Примечания API: "В целях производительности все эти вызовы объединены в один вызов только с последним аргументом вызова". Добавление Thread.sleep(1)
просто откладывает слияние; ссылающееся println()
вводит сопоставимую задержку. Будьте уверены, что ваша файловая система работает так быстро; Я не хотел бы вводить искусственную задержку. В качестве конкретного примера, иллюстрирующего эффект, я добавил промежуточные отчеты к этому полному примеру, как показано ниже.
private static class LogWorker extends SwingWorker<TableModel, String> {
private long fileLength;
private long bytesRead;
...
this.fileLength = file.length();
...
while ((s = br.readLine()) != null) {
publish(s);
bytesRead += s.length();
int progress = (int)(100 * bytesRead / fileLength);
// System.out.println(progress);
setProgress(progress);
}
...
}
lw.addPropertyChangeListener((PropertyChangeEvent e) -> {
if ("progress".equals(e.getPropertyName())) {
jpb.setValue((Integer)e.getNewValue());
}
if ("state".equals(e.getPropertyName())) {
SwingWorker.StateValue s = (SwingWorker.StateValue) e.getNewValue();
if (s.equals(SwingWorker.StateValue.DONE)) {
jpb.setValue(100);
}
}
});