Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8211144

JComponent revalidateRunnableScheduled does not reset as expected

XMLWordPrintable

    • x86_64
    • generic

      ADDITIONAL SYSTEM INFORMATION :
      Java 7 to Java 12 (tested 7u80,8u101,8u181,10.0.2, 12 build 11 (2018/9/13))

      A DESCRIPTION OF THE PROBLEM :
      If a component called JComponent.revalidate() in non-EDT, then removed from GUI, revalidateRunnableScheduled will not reset, preventing further revalidate call from non-EDT forever, even the component add back to GUI.

      Problem because of the event scheduled in JComponent.revalidate() will be removed when the component removed from GUI, and revalidateRunnableScheduled cannot set back to false forever.

      The problem should be after JDK-6459213 : Optimize revalidate. Java 7u55 still not have revalidateRunnableScheduled in JComponent.revalidate() so it works.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      (Please check the source code part)
      Click "Bug", then "Add". The table will not show the newly added rows. Click "Revalidate" will be able to show back the rows.
      (If cannot reproduce, click "Bug" a few more times to trigger the bug)

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Click "Add" should always show the newly added rows.
      ACTUAL -
      Does not show the rows.

      ---------- BEGIN SOURCE ----------
      import java.awt.BorderLayout;
      import java.awt.EventQueue;
      import java.awt.GridLayout;
      import java.awt.event.ActionEvent;
      import java.awt.event.ActionListener;
      import java.util.Map;
      import java.util.concurrent.ExecutorService;
      import java.util.concurrent.Executors;
      import java.util.concurrent.atomic.AtomicInteger;

      import javax.swing.JButton;
      import javax.swing.JFrame;
      import javax.swing.JPanel;
      import javax.swing.JScrollPane;
      import javax.swing.JTable;
      import javax.swing.table.DefaultTableModel;

      public class TableRevalidateTest extends JFrame
      {
          private ExecutorService services = Executors.newFixedThreadPool(1);

          public static void main(String[] args)
          {
              EventQueue.invokeLater(new Runnable()
              {
                  @Override
                  public void run()
                  {
                      try
                      {
                          TableRevalidateTest frame = new TableRevalidateTest();
                          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                          frame.setVisible(true);
                      }
                      catch (Exception e)
                      {
                          e.printStackTrace();
                      }
                  }
              });
          }

          public TableRevalidateTest()
          {
              super("Table Revalidate Test");
              setLocation(500, 200);
              setSize(500, 350);

              setContentPane(new JPanel(new BorderLayout()));

              JButton buttonA = new JButton("Bug"); // Add row in non-EDT and re-add table
              JButton buttonB = new JButton("Add"); // Add row in non-EDT
              JButton buttonC = new JButton("Revalidate"); // Revalidate in EDT
              JButton buttonD = new JButton("Clear"); // Clear rows

              final DefaultTableModel tableModel = new DefaultTableModel(new String[] { "Action", "ID" }, 0);
              for (Map.Entry<Object, Object> entry : System.getProperties().entrySet())
                  if (String.valueOf(entry.getKey()).contains("version"))
                      tableModel.addRow(new Object[] { String.valueOf(entry.getKey()), String.valueOf(entry.getValue()) });

              final JTable table = new JTable(tableModel);
              final JScrollPane tablePane = new JScrollPane(table);

              JPanel northPanel = new JPanel(new GridLayout(1, 0));
              northPanel.add(buttonA);
              northPanel.add(buttonB);
              northPanel.add(buttonC);
              northPanel.add(buttonD);
              getContentPane().add(northPanel, BorderLayout.NORTH);
              getContentPane().add(tablePane, BorderLayout.CENTER);

              // Listeners
              final AtomicInteger id = new AtomicInteger();
              buttonA.addActionListener(new ActionListener()
              {
                  @Override
                  public void actionPerformed(ActionEvent e)
                  {
                      services.submit(new Runnable()
                      {
                          @Override
                          public void run()
                          {
                              tableModel.addRow(new Object[] { "Bug", String.valueOf(id.getAndIncrement()) });
                          }
                      });
                      getContentPane().remove(tablePane);
                      getContentPane().add(tablePane, BorderLayout.CENTER);
                  }
              });
              buttonB.addActionListener(new ActionListener()
              {
                  @Override
                  public void actionPerformed(ActionEvent e)
                  {
                      services.submit(new Runnable()
                      {
                          @Override
                          public void run()
                          {
                              tableModel.addRow(new Object[] { "Add", String.valueOf(id.getAndIncrement()) });
                          }
                      });
                  }
              });
              buttonC.addActionListener(new ActionListener()
              {
                  @Override
                  public void actionPerformed(ActionEvent e)
                  {
                      table.revalidate();
                  }
              });
              buttonD.addActionListener(new ActionListener()
              {
                  @Override
                  public void actionPerformed(ActionEvent e)
                  {
                      while (tableModel.getRowCount() > 0)
                          tableModel.removeRow(tableModel.getRowCount() - 1);
                  }
              });
          }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Currently no workaround as the component corrupted forever.

      FREQUENCY : always


            psadhukhan Prasanta Sadhukhan
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: