Welcome to the Java Programming Forums


The professional, friendly Java community. 21,500 members and growing!


The Java Programming Forums are a community of Java programmers from all around the World. Our members have a wide range of skills and they all have one thing in common: A passion to learn and code Java. We invite beginner Java programmers right through to Java professionals to post here and share your knowledge. Become a part of the community, help others, expand your knowledge of Java and enjoy talking with like minded people. Registration is quick and best of all free. We look forward to meeting you.


>> REGISTER NOW TO START POSTING


Members have full access to the forums. Advertisements are removed for registered users.

Results 1 to 4 of 4

Thread: Jtable only updates at the end of a buton event.

  1. #1
    Junior Member
    Join Date
    Apr 2013
    Posts
    3
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default Jtable only updates at the end of a buton event.

    My problem is the following :

    I have a jtable that displays some data in the rows.
    I have a button whose event is to loop slowly through the rows of this table and change the values of the data - in this case flip true/false .. and slowly is due to a sleep (The actual problem I have is a lengthy calculation)
    I would like the table to update after each change, as it currently only updates at the end of the button event.
    What am i doing wrong ? I have tried all sorts of combinations.


    The (self contained) code that demonstrates the problem is below -
    I have adapted the TableDemo example for the orcale/java How to Use Tables tutorial


     
    /** 
     * TableDemo is just like SimpleTableDemo, except that it
     * uses a custom TableModel.
     */
    public class TableDemo extends JPanel {
     
        private JButton looper;
        JTable table;
        MyTableModel mdl;
        private static JFrame frame;
     
        public TableDemo() {
            super(new GridLayout(2,0));
     
            looper = new JButton();
            looper.setText("Hit Me to loop thru table and flip vegetarian preference");
     
            looper.addActionListener(new java.awt.event.ActionListener() {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    HitButtonActionPerformed(evt);
                }
            });
     
            mdl = new MyTableModel();       
            table = new JTable(mdl);
            table.setPreferredScrollableViewportSize(new Dimension(500, 70));
            table.setFillsViewportHeight(true);
     
            //Create the scroll pane and add the table to it.
            JScrollPane scrollPane = new JScrollPane(table);
     
            //Add the scroll pane to this panel.
            add(scrollPane);
            //add button
            add(looper);
        }
     
        public void HitButtonActionPerformed(ActionEvent e) {
     
            for (int row=0; row<table.getRowCount();row++)
            {
                try {
                    Thread.currentThread().sleep(1000);//sleep for 1000 ms
                    System.out.println("one more flip");
     
                    Object p = table.getValueAt(row, 4);
                    table.setValueAt( !((Boolean)p), row, 4);
     
                    /* no hope
                    ( (AbstractTableModel)table.getModel()).fireTableCellUpdated(row, 4);
                    mdl.fireTableCellUpdated(row, 4);
                    mdl.fireTableDataChanged();
                    table.validate();  
                    frame.repaint();
                    */
     
                } catch (InterruptedException ex) {
                    Logger.getLogger(TableDemo.class.getName()).log(Level.SEVERE, null, ex);
                }
     
            }
        }
     
        class MyTableModel extends AbstractTableModel {
            private String[] columnNames = {"First Name",
                                            "Last Name",
                                            "Sport",
                                            "# of Years",
                                            "Vegetarian"};
            private Object[][] data = {
            {"Kathy", "Smith","Snowboarding", new Integer(5), false},
            {"John", "Doe","Rowing", new Integer(3), true},
            {"Sue", "Black", "Knitting", new Integer(2), false},
            {"Jane", "White", "Speed reading", new Integer(20), true},
            {"Joe", "Brown","Pool", new Integer(10), false}
            };
     
            @Override
            public int getColumnCount() {
                return columnNames.length;
            }
     
            @Override
            public int getRowCount() {
                return data.length;
            }
     
            @Override
            public String getColumnName(int col) {
                return columnNames[col];
            }
     
            @Override
            public Object getValueAt(int row, int col) {
                return data[row][col];
            }
     
            /*
             * JTable uses this method to determine the default renderer/
             * editor for each cell.  If we didn't implement this method,
             * then the last column would contain text ("true"/"false"),
             * rather than a check box.
             */
            @Override
            public Class getColumnClass(int c) {
                return getValueAt(0, c).getClass();
            }
     
            /*
             * Don't need to implement this method unless your table's
             * editable.
             */
            @Override
            public boolean isCellEditable(int row, int col) {
                //Note that the data/cell address is constant,
                //no matter where the cell appears onscreen.
                if (col < 2) {
                    return false;
                } else {
                    return true;
                }
            }
     
            /*
             * Don't need to implement this method unless your table's
             * data can change.
             */
            @Override
            public void setValueAt(Object value, int row, int col) {          
                data[row][col] = value;
                fireTableCellUpdated(row, col);
            }
        }
     
        /**
         * Create the GUI and show it.  For thread safety,
         * this method should be invoked from the
         * event-dispatching thread.
         */
        private static void createAndShowGUI() {
            //Create and set up the window.
            frame = new JFrame("TableDemo");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     
            //Create and set up the content pane.
            TableDemo newContentPane = new TableDemo();
            newContentPane.setOpaque(true); //content panes must be opaque
            frame.setContentPane(newContentPane);
     
            //Display the window.
            frame.pack();
            frame.setVisible(true);
        }
     
        public static void main(String[] args) {
            //Schedule a job for the event-dispatching thread:
            //creating and showing this application's GUI.
            javax.swing.SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    createAndShowGUI();
                }
            });
        } 
    }


  2. #2
    Administrator copeg's Avatar
    Join Date
    Oct 2009
    Location
    US
    Posts
    5,431
    Thanks
    191
    Thanked 844 Times in 786 Posts
    Blog Entries
    5

    Default Re: Jtable only updates at the end of a buton event.

    Use a Thread or a SwingWorker - any long running tasks placed on the EDT will clog up the UI.
    Worker Threads and SwingWorker (The Java™ Tutorials > Creating a GUI With JFC/Swing > Concurrency in Swing)

  3. #3
    Junior Member
    Join Date
    Apr 2013
    Posts
    3
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default Re: Jtable only updates at the end of a buton event.

    Quote Originally Posted by copeg View Post
    Use a Thread or a SwingWorker - any long running tasks placed on the EDT will clog up the UI.
    Worker Threads and SwingWorker (The Java� Tutorials > Creating a GUI With JFC/Swing > Concurrency in Swing)
    Thank you for your answer. However it hasn't really explained what the underlying problem is. Neither do I really want to use a thread to
    run the loop through the table rows - I want to block the UI whilst this section is runninng as in my (real) program i have a lot of preferences
    and I dont want the user to be able to alter them whilst this part of the code is running.
    Also will running the loop through the table rows ina seperate permit the table to update ??..if so ok i could run this section in a thread whilst the "main program thread" waits on a semaphore - but it seems like a sledgehammer to solve a trivial problem.

  4. #4
    Junior Member
    Join Date
    Apr 2013
    Posts
    3
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default Re: Jtable only updates at the end of a buton event.

    Thank you for the reply concerning the use of thread/SwingWorker.
    However it does not totally resolve the question.

    The solution is given below. I hope that it may help anyone who has a similar problem.

    The problem seems to be that all events fired during the button click event are simpy queued up and only dealt with when control returns to the EDT. The solution is to use a SwingWorker and run the work inside a new thread. The problem then is the UI is now active and the user can access all the other components .. which if we need must therefore be protected.

    buttonClick()
    {
    if (worker !=null && !worker.isdone() ) return;
    worker = new SwingWorker {
    ...loop through table and do some work
    }
    worker.exeucte
    }

    This seems unsatisfactory but I found a better solution consulting the docs for the swingworker

    """Note: calling get on the Event Dispatch Thread blocks all events, including repaints, from being processed until this SwingWorker is complete.
    When you want the SwingWorker to block on the Event Dispatch Thread we recommend that you use a modal dialog."""

    An example in the docs is given which implements a PropertyChangeListener.
    The idea is to start the swingworker thread and then start a dialog ..saying something or nothing...
    which remains visible and modal (hence blocking the UI) until the swingworker finishes.

    The solution : scce is here

    /** 
     * TableDemo is just like SimpleTableDemo, except that it
     * uses a custom TableModel.
     */
    import java.awt.Dimension;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import java.util.Random;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.swing.*;
    import javax.swing.table.AbstractTableModel;
     
    public class TableDemoSwingWorker3  extends JPanel {
     
         //java doc is wrong... need to implement the interface and not extend it
        public class SwingWorkerCompletionWaiter implements PropertyChangeListener {
         private JDialog dialog;
         private JLabel label1;
     
         public SwingWorkerCompletionWaiter(JDialog dialog) {
             this.dialog = dialog;
             label1 = new JLabel();
             label1.setText("Processing ");
             this.dialog.add(label1);
             this.dialog.setSize(100, 100); 
         }
     
          @Override
          public void propertyChange(PropertyChangeEvent event) {
             if ("state".equals(event.getPropertyName())
                     && SwingWorker.StateValue.DONE == event.getNewValue()) {
                 dialog.setVisible(false);
                 dialog.dispose();
             }
         }
        }
     
     
        private JButton looper;
        JTable table;
        MyTableModel mdl;
        private static JFrame frame;
        SwingWorker<Void, Integer> worker;
     
        public TableDemoSwingWorker3() {
            super(new GridLayout(2,0));
     
            looper = new JButton();
            looper.setText("Hit Me to loop thru table and flip vegetarian preference");
     
            looper.addActionListener(new java.awt.event.ActionListener() {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    HitButtonActionPerformed(evt);
                }
            });
     
            mdl = new MyTableModel();       
            table = new JTable(mdl);
            table.setPreferredScrollableViewportSize(new Dimension(500, 70));
            table.setFillsViewportHeight(true);
     
            //Create the scroll pane and add the table to it.
            JScrollPane scrollPane = new JScrollPane(table); 
            //Add the scroll pane to this panel.
            add(scrollPane);
            //add button
            add(looper);      
        }
     
        public void runThread()
        {
            ;
        }
     
        public void HitButtonActionPerformed(ActionEvent e) {       
     
              worker = new SwingWorker<Void, Integer>() {
     
                  @Override
                  protected Void doInBackground() throws Exception {
                      for (int row = 0; row < table.getRowCount(); row++) {
                          try {
                              Thread.currentThread().sleep(1000);//sleep for 1000 ms
                              System.out.println("one more flip");
                              Object p = table.getValueAt(row, 4);
                              table.setValueAt(!((Boolean) p), row, 4);                   
                          } catch (InterruptedException ex) {
                              Logger.getLogger(TableDemoSwingWorker1.class.getName()).log(Level.SEVERE, null, ex);
                          }
                      }
                      System.out.println("all vegetarians changed");
                     return null;
                };        
                @Override
                protected void done() {
                    try {
                        get(); // This will get any Exceptions thrown by doInBackground()
                    } catch (Exception e) {  
                          // Handle the Exception!
                    }
                }
            };
     
            JDialog dialog = new JDialog(frame, true);
            worker.addPropertyChangeListener( new SwingWorkerCompletionWaiter(dialog));
            worker.execute();
            //the dialog will be visible until the SwingWorker is done
            dialog.setVisible(true);       
        }
     
        class MyTableModel extends AbstractTableModel {
            private String[] columnNames = {"First Name","Last Name",
                                            "Sport","# of Years",
                                            "Vegetarian"};
            private Object[][] data = {
            {"Kathy", "Smith","Snowboarding", new Integer(5), false},
            {"John", "Doe","Rowing", new Integer(3), true},
            {"Sue", "Black", "Knitting", new Integer(2), false},
            {"Jane", "White", "Speed reading", new Integer(20), true},
            {"Joe", "Brown","Pool", new Integer(10), false}};
     
            @Override
            public int getColumnCount() {return columnNames.length;}
            @Override
            public int getRowCount() { return data.length;}
            @Override
            public String getColumnName(int col) {return columnNames[col]; }
            @Override
            public Object getValueAt(int row, int col) {return data[row][col];}
            @Override
            public Class getColumnClass(int c) { return getValueAt(0, c).getClass();}
     
            /*
             * Don't need to implement this method unless your table's editable.
             */
            @Override
            public boolean isCellEditable(int row, int col) {
                if (col < 2) { 
    			   return false;
                } else {
                    return true;
                }
            }
     
            /*
             * Don't need to implement this method unless your table's data can change.
             */
            @Override
            public void setValueAt(Object value, int row, int col) {          
                data[row][col] = value;
                fireTableCellUpdated(row, col);
            }
        }
     
        /**
         * Create the GUI and show it.  For thread safety,
         * this method should be invoked from the event-dispatching thread.
         */
        private static void createAndShowGUI() {
            //Create and set up the window.
            frame = new JFrame("TableDemo");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     
            //Create and set up the content pane.
            TableDemoSwingWorker3 newContentPane = new TableDemoSwingWorker3();
            newContentPane.setOpaque(true); //content panes must be opaque
            frame.setContentPane(newContentPane);
     
            //Display the window.
            frame.pack();
            frame.setVisible(true);
        }
     
        public static void main(String[] args) {
            //Schedule a job for the event-dispatching thread:
            //creating and showing this application's GUI.
            javax.swing.SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    createAndShowGUI();
                }
            });
        }   
    }

Similar Threads

  1. [SOLVED] How to get Progress updates from multiple threads...
    By Becca in forum Threads
    Replies: 4
    Last Post: February 7th, 2012, 12:34
  2. [SOLVED] A question about updates. (Program dosent update until refreshed)
    By DusteroftheCentury in forum What's Wrong With My Code?
    Replies: 4
    Last Post: February 1st, 2012, 22:59
  3. Variable updates after loop
    By tecno40 in forum Loops & Control Statements
    Replies: 1
    Last Post: November 9th, 2011, 04:34
  4. [SOLVED] jTable event help
    By banny7 in forum AWT / Java Swing
    Replies: 12
    Last Post: August 1st, 2011, 07:42
  5. [SOLVED] Trojans with last few updates of NetBeans
    By Melawe in forum Java IDEs
    Replies: 11
    Last Post: May 22nd, 2010, 08:33