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

5
  • 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. Commented May 15, 2012 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. Commented May 15, 2012 at 11:40
  • 2
    how to use progress bars Commented May 15, 2012 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. Commented May 15, 2012 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 or do the updates yourself on EDT. Commented May 15, 2012 at 11:49

1 Answer 1

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(); } }); } } 
Sign up to request clarification or add additional context in comments.

2 Comments

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
@mr.nothing please read my question , that could be demonstrated the most complex way

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.