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

DefaultTreeCellEditor does not dispatch mouseEvents to child components

XMLWordPrintable

      FULL PRODUCT VERSION :
      java version "1.7.0_05"
      Java(TM) SE Runtime Environment (build 1.7.0_05-b05)
      Java HotSpot(TM) Client VM (build 23.1-b03, mixed mode, sharing)

      ADDITIONAL OS VERSION INFORMATION :
      Windows XP SP3, WIndows 7

      A DESCRIPTION OF THE PROBLEM :
      Jtree has uses a custom CellEditor that returns a JPanel containing a checkbox and a label.
      In java 1.5 and java1.6 one mouseclick will trigger the actionlistener in the checkbox. Java 1.7 breaks comptibility. The first click will only activate the celleditor and a second click is needed to selct the checkbox.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Create a Jtree with a CellEdito that returns a JPanel with a nested checkbox.
      Now run your program an click on the checkbox.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      One click will select a checkbox
      ACTUAL -
      First click does not select the checkbox, a second click is needed.

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.awt.BorderLayout;
      import java.awt.Component;
      import java.awt.event.ActionEvent;
      import java.awt.event.ActionListener;
      import java.awt.event.MouseAdapter;
      import java.awt.event.MouseEvent;
      import java.util.EventObject;
      import java.util.Vector;

      import javax.swing.JCheckBox;
      import javax.swing.JFrame;
      import javax.swing.JLabel;
      import javax.swing.JPanel;
      import javax.swing.JScrollPane;
      import javax.swing.JTree;
      import javax.swing.SwingUtilities;
      import javax.swing.tree.DefaultMutableTreeNode;
      import javax.swing.tree.DefaultTreeCellEditor;
      import javax.swing.tree.DefaultTreeCellRenderer;

      public class SimpleTreeTest extends JFrame
      {

      public static void main(String[] args)
      {
      SimpleTreeTest stt = new SimpleTreeTest();
      stt.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      stt.setSize(250, 250);
      stt.setVisible(true);
      }

      public SimpleTreeTest()
      {
      Vector<Person> v = new Vector<Person>();
      v.addElement(new Person(false, "john"));
      v.addElement(new Person(false, "peter"));
      v.addElement(new Person(false, "mike"));
      v.addElement(new Person(false, "sandra"));

      JTree tree = new JTree(v);
      tree.setRootVisible(true);
      tree.setEditable(true);
      tree.setCellRenderer(new CheckboxTreeRenderer());
      tree.setCellEditor(new CheckboxCellEditor(tree,
      new CheckboxTreeRenderer()));
      JScrollPane jsp = new JScrollPane(tree);
      getContentPane().add(jsp);
      }

      class Person
      {
      boolean alive;
      String name;

      private Person(boolean alive, String name)
      {
      super();
      this.alive = alive;
      this.name = name;
      }

      }

      class CheckboxTreeRenderer extends DefaultTreeCellRenderer
      {

      public Component getTreeCellRendererComponent(JTree tree, Object value,
      boolean isSelected, boolean expanded, boolean leaf, int row,
      boolean hasFocus)
      {

      if (value instanceof DefaultMutableTreeNode)
      {
      DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
      if (node.getUserObject() instanceof Person)
      {
      Person p = (Person) node.getUserObject();
      JCheckBox checkBox = new JCheckBox();
      JPanel panel = new JPanel(new BorderLayout());
      JLabel label = new JLabel();
      label.setText(p.name);
      checkBox.setSelected(p.alive);
      panel.add(checkBox, BorderLayout.WEST);
      panel.add(label, BorderLayout.CENTER);
      return panel;
      }
      else
      {
      Object o = node.getUserObject();
      JLabel label = new JLabel();
      label.setText(o.toString());
      return label;
      }

      }
      return new JLabel("unknown");

      }

      }

      class CheckboxCellEditor extends DefaultTreeCellEditor
      {

      JPanel panel;
      JCheckBox checkBox;

      public CheckboxCellEditor(JTree tree, DefaultTreeCellRenderer renderer)
      {
      super(tree, renderer);
      // TODO Auto-generated constructor stub
      }

      public boolean isCellEditable(EventObject evt)
      {
      return true;
      }

      /** possible workaround for java1.7 to allow singleclick on checkbox */
      /*
      public boolean shouldSelectCell(EventObject anEvent)
      {
      if (anEvent instanceof MouseEvent)
      {
      MouseEvent me = (MouseEvent) anEvent;
      Component c = SwingUtilities.getDeepestComponentAt(me
      .getComponent(), me.getX(), me.getY());
      // System.out.println("deeepest component from tree "+ c);
      final MouseEvent ev = SwingUtilities.convertMouseEvent(me
      .getComponent(), me, panel);

      SwingUtilities.invokeLater(new Runnable()
      {
      public void run()
      {
      // panel.dispatchEvent(ev); //does not work ???????????
      // so the do the click directly through clickmethod
      if (checkBox.contains(ev.getPoint()))
      {
      System.out.println("clicked in checkbox");
      checkBox.doClick();
      }
      }
      });
      }
      return false;
      }
      */

      public Component getTreeCellEditorComponent(JTree tree, Object value,
      boolean isSelected, boolean expanded, boolean leaf, int row)
      {
      if (value instanceof DefaultMutableTreeNode)
      {
      DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
      if (node.getUserObject() instanceof Person)
      {
      final Person p = (Person) node.getUserObject();
      checkBox = new JCheckBox();
      checkBox.addActionListener(new ActionListener()
      {

      public void actionPerformed(ActionEvent e)
      {
      System.out.println("got event");
      p.alive = (!(p.alive));

      }

      });

      panel = new JPanel(new BorderLayout());
      panel.addMouseListener(new MouseAdapter()
      {

      public void mouseClicked(MouseEvent arg0)
      {
      System.out.println("MouseEvent " + arg0);

      }
      });

      JLabel label = new JLabel();
      label.setText(p.name);
      checkBox.setSelected(p.alive);
      panel.add(checkBox, BorderLayout.WEST);
      panel.add(label, BorderLayout.CENTER);
      return panel;
      }
      else
      {
      Object o = node.getUserObject();
      JLabel label = new JLabel();
      label.setText(o.toString());
      return label;
      }

      }
      return new JLabel("unknown");

      }

      }

      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      public boolean shouldSelectCell(EventObject anEvent)
      {
      if (anEvent instanceof MouseEvent)
      {
      MouseEvent me = (MouseEvent) anEvent;
      Component c = SwingUtilities.getDeepestComponentAt(me
      .getComponent(), me.getX(), me.getY());
      // System.out.println("deeepest component from tree "+ c);
      final MouseEvent ev = SwingUtilities.convertMouseEvent(me
      .getComponent(), me, panel);

      SwingUtilities.invokeLater(new Runnable()
      {
      public void run()
      {
      // panel.dispatchEvent(ev); //does not work ???????????
      // so the do the click directly through clickmethod
      if (checkBox.contains(ev.getPoint()))
      {
      System.out.println("clicked in checkbox");
      checkBox.doClick();
      }
      }
      });
      }
      return false;
      }

            alexsch Alexandr Scherbatiy
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: