2

ok, I'm here again to ask one dummy question. I have a custom dialog frame and have progress bar on it. So also I have a genetic algorithm (which works pretty big amount of time).

As I understand all the situation, I need to execute separate threads for algorithm, progress bar and leave the main thread for the dialog (to give him an opportunity to respond to user actions). So I tried to implement this, and got the following:

public class ScheduleDialog extends JDialog {

    private final JPanel contentPanel = new JPanel();

    private static Data data;
    private static GeneticEngine geneticEngine;
    private static Schedule schedule;

    private static JProgressBar progressBar;
    private static JLabel statusLabel;

    public static void showProgress() {
        try {
            ScheduleDialog dialog = new ScheduleDialog();
            dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
            dialog.setVisible(true);
            startScheduleComposing();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void startScheduleComposing() {
        BackGroundWorker backGroundWorker = new BackGroundWorker();
        GeneticEngineWorker geneticEngineWorker = new GeneticEngineWorker();
        new Thread(geneticEngineWorker).start();
        new Thread(backGroundWorker).start();
    }

    private ScheduleDialog() {

        this.data = Data.getInstance();

        setTitle("");
        setModal(true);
        setBounds(100, 100, 405, 150);
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        Dimension dialogSize = getSize();
        setLocation((screenSize.width - dialogSize.width) / 2, (screenSize.height - dialogSize.height) / 2);
        getContentPane().setLayout(new BorderLayout());
        contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
        getContentPane().add(contentPanel, BorderLayout.CENTER);
        contentPanel.setLayout(new GridLayout(0, 1, 0, 0));
        {
            progressBar = new JProgressBar();
            progressBar.setBackground(Color.RED);
            contentPanel.add(progressBar);
        }
        {
            statusLabel = new JLabel("");
            contentPanel.add(statusLabel);
        }
        {
            JPanel buttonPane = new JPanel();
            buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
            getContentPane().add(buttonPane, BorderLayout.SOUTH);
            {
                JButton okButton = new JButton("Прервать");
                okButton.setActionCommand("OK");
                buttonPane.add(okButton);
                getRootPane().setDefaultButton(okButton);
            }
        }


    }

    protected static class BackGroundWorker implements Runnable {
        @Override
        public void run() {
          while(true){
            int barValue = 100 - (geneticEngine.getCurrentBestFitness() / geneticEngine.getInitialFitness());
            progressBar.setValue(barValue);
            progressBar.repaint();
            statusLabel.setText(String.valueOf(geneticEngine.getCurrentBestFitness()));
            statusLabel.repaint();
            try{
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();  
            }
          }
        }
    }

    protected static class GeneticEngineWorker implements Runnable{

        @Override
        public void run() {
            geneticEngine = new GeneticEngine(data);
            schedule = geneticEngine.GeneticAlgorithm();
        }
    }
}

it seems, that new Thread(geneticEngineWorker).start(); is working but nothing happens with progress bar. I think this part of code:

private static void startScheduleComposing() {
            BackGroundWorker backGroundWorker = new BackGroundWorker();
            GeneticEngineWorker geneticEngineWorker = new GeneticEngineWorker();
            new Thread(geneticEngineWorker).start();
            new Thread(backGroundWorker).start();
        }

we get new Thread(backGroundWorker).start(); executed only after new Thread(geneticEngineWorker).start(); will be stopped.
So if I'm right could you please tell me how code can be reorganized to make the work, and if I'm wrong could you point me to my mistakes?

Thanks everyone in advance!


ADDITION

I debuged it and as I thought, backGroundWorker starts working only after geneticEngineWorker ends or user closes dialog(exception in this case);

mKorbel
  • 109,525
  • 20
  • 134
  • 319
mr.nothing
  • 5,141
  • 10
  • 53
  • 77
  • 2
    Maybe i am missing something, but the thread to update the ProgressBar just updates the Bar once and then sleeps for 10 seconds before completing. Check the Timer & TimerTask classes for scheduling repeated updates. – Helmuth M. May 15 '12 at 11:36
  • sorry, I accidently posted old version. Edited. Actually nothing changes if I add a while loop, i don't think that there is problem in it. – mr.nothing May 15 '12 at 11:40
  • 2
    [how to use progress bars](http://docs.oracle.com/javase/tutorial/uiswing/components/progress.html) – oers May 15 '12 at 11:44
  • 3
    Your understanding is wrong. A progress bar, like all the Swing components, must always be updated from the EDT. Not rom a background thread. – JB Nizet May 15 '12 at 11:48
  • 1
    The theory of non functioning states that you are not updating your GUI on `EDT-Event Dispatcher Thread` you need to use either [SwingWorker](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html) or do the updates yourself on EDT. – nIcE cOw May 15 '12 at 11:49

1 Answers1

4

yes there are two basics ways by using

SwingWorker, required deepest knowledge about Java Essential Classes inc. Generics too

and

Runnable#Thread required only wrapping output to the GUI into invokeLater()

simple example about no special effort required for idea Runnable#Thread, JProgressBar all in JTable, thats means that code line model.setValueAt(value, row, column); should be wrapped into invokeLater, but in other hands setText() is declared as thread safe, I'd to suggest wrapping that into invokeLater in all cases

enter image description here enter image description here

import java.awt.Component;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;

public class TableWithProgressBars {

    private static final int maximum = 100;

    public void createGUI() {
        final JFrame frame = new JFrame("Progressing");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Integer[] oneRow = {0, 0, 0, 0};
        String[] headers = {"One", "Two", "Three", "Four"};
        Integer[][] data = {oneRow, oneRow, oneRow, oneRow, oneRow,};
        final DefaultTableModel model = new DefaultTableModel(data, headers);
        final JTable table = new JTable(model);
        table.setDefaultRenderer(Object.class, new ProgressRenderer(0, maximum));
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        frame.add(new JScrollPane(table));
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        new Thread(new Runnable() {

            @Override
            public void run() {
                Object waiter = new Object();
                synchronized (waiter) {
                    int rows = model.getRowCount();
                    int columns = model.getColumnCount();
                    Random random = new Random(System.currentTimeMillis());
                    boolean done = false;
                    while (!done) {
                        int row = random.nextInt(rows);
                        int column = random.nextInt(columns);
                        Integer value = (Integer) model.getValueAt(row, column);
                        value++;
                        if (value <= maximum) {
                            model.setValueAt(value, row, column);
                            try {
                                waiter.wait(15);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        done = true;
                        for (row = 0; row < rows; row++) {
                            for (column = 0; column < columns; column++) {
                                if (!model.getValueAt(row, column).equals(maximum)) {
                                    done = false;
                                    break;
                                }
                            }
                            if (!done) {
                                break;
                            }
                        }
                    }
                    frame.setTitle("All work done");
                }
            }
        }).start();
    }

    public static class ProgressRenderer extends JProgressBar implements TableCellRenderer {

        private static final long serialVersionUID = 1L;

        public ProgressRenderer(int min, int max) {
            super(min, max);
            this.setStringPainted(true);
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value,
                boolean isSelected, boolean hasFocus, int row, int column) {
            this.setValue((Integer) value);
            return this;
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new TableWithProgressBars().createGUI();
            }
        });

    }
}
Community
  • 1
  • 1
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • this is a nice example, but I think the override of getTableCellRendererComponent and the implicit setting of the progress is hard to grasp for someone who is not familiar with table models and stuff :D – oers May 15 '12 at 12:22
  • 1
    @mr.nothing please [read my question](http://stackoverflow.com/questions/8169964/is-mvc-in-swing-thread-safe) , that could be demonstrated the most complex way – mKorbel May 15 '12 at 13:01