java swing swingworker thread-sleep jprogressbar

java - SwingWorker no actualiza JProgressBar sin Thread.sleep() en el panel de diálogo personalizado



thread-sleep (2)

Tengo una clase SwingWorker que carga un archivo de texto y lo corta en trozos para su posterior procesamiento.

Esta es la clase 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; }

Esto funciona bien cuando Thread.sleep(1); No está comentado. Sin embargo, cuando comento el Thread.sleep(1); la clase no actualiza la barra de progreso.

Llamo a mi clase a través de un botón, aquí está el 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(); } } });

Esto debería funcionar bien sin dormir, entonces, ¿qué es lo que estoy haciendo mal aquí?

ACTUALIZAR:

Resultó que mi DialogPanel no es el mejor y causa este comportamiento.

Aquí está la clase 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); } }

Probablemente sea un desastre para los ojos profesionales. ¿Cómo puedo mostrar la barra de progreso en un cuadro de diálogo que tendrá un botón de confirmación para eliminar el cuadro de diálogo cuando el proceso haya finalizado?

Solución:

He cambiado de mi clase DialogPanel a ProgressMonitor y ahora todo está bien. Gracias por su tiempo y consejos.


La API setProgress() señala: "Para fines de rendimiento, todas estas invocaciones se fusionan en una invocación con el último argumento de invocación solamente". Agregar Thread.sleep(1) simplemente difiere la fusión; Invocar println() introduce un retraso comparable. Anímate a que tu sistema de archivos sea tan rápido; Sería reacio a introducir un retraso artificial. Como ejemplo concreto que ilustra el efecto, agregué informes intermedios a este example completo, como se muestra a continuación.

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); } } });


Quería seguir el SwingWorker mi SwingWorker con una JProgressBar dentro de un JDialog . Sin embargo, mi clase SwingWorker no pudo manejar mi clase personalizada DialogPanel . Para lograr el mismo resultado, usar la clase ProgressMonitor predeterminada era la mejor opción.

He pasado el ProgressMonitor al SwingWorker través de su constructor:

private final File f; private final ProgressMonitor pm public FileLoadWorker(File f, ProgressMonitor pm) { this.f = f; this.pm = pm; }

y cambió los siguientes métodos como este:

@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)); }

La propertyChangeListener la tarea cambió así:

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();

Gracias a por la respuesta y los comentarios sobre la propiedad del state .