2011-11-14 68 views
1

我需要爲我的JTree使用自定義單元格渲染器來在每個單元格上添加一些JLabel。然後允許用戶點擊這些標籤,而無需先選擇單元格。TreeCellEditor:即使ShouldSelectCell返回false,也必須選擇要編輯的單元格

所以,我創建了一個Renderer,它返回一個包含DefaultTreeCellRenderer和2個JLabel的JPanel。

public class TreeNodeRenderer extends DefaultTreeCellRenderer implements TreeCellRenderer 
    { 
     private JPanel panel1 = new JPanel(); 
     private JLabel delete = new JLabel(""); 
     private JLabel upload = new JLabel(""); 

     public Component getTreeCellRendererComponent(JTree tree, 
          Object value, 
       boolean selected, boolean expanded, boolean leaf, int row, 
       boolean hasFocus) 
     { 
      // 
      // DELETE label 
      // 
      delete.setName("delete"); 
      delete.setIcon(new ImageIcon("Data/trash.png")); 

      // 
      // UPLOAD label 
      // 
      upload.setName("upload"); 
      upload.setIcon(new ImageIcon("Data/app_up.png")); 


      DefaultTreeCellRenderer defaultRenderer = new DefaultTreeCellRenderer(); 
      Color backgroundSelectionColor = defaultRenderer.getBackgroundSelectionColor(); 
      Color backgroundNonSelectionColor = defaultRenderer.getBackgroundNonSelectionColor(); 

      if(selected) 
       panel1.setBackground(backgroundSelectionColor); 
      else 
       panel1.setBackground(backgroundNonSelectionColor); 


      component = (DefaultTreeCellRenderer) super.getTreeCellRendererComponent(tree, 
        value, selected, expanded, leaf, row, hasFocus); 

      panel1.add(component); 
      panel1.add(delete); 
      panel1.add(upload); 

      return panel1; 
     } 
    } 

然後,我創建了編輯器,允許用戶點擊這些標籤感謝MouseListener。除了用戶必須在點擊標籤之前選擇單元格之外,一切運行良好。 我試圖用「ShouldSelectCell」方法返回「false」,但它不起作用。

有人知道爲什麼嗎?

這裏編輯:

public class TreeNodeEditor extends AbstractCellEditor implements TreeCellEditor 
{ 
    private TreeNodeRenderer renderer; 

    public TreeNodeEditor(TreeNodeRenderer treeRenderer) 
    { 
     this.renderer = treeRenderer; 

    //change the cursor when it's over a label renderer.getDeleteButton().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); 
    renderer.getUploadButton().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));  renderer.getDownloadButton().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); 

       //add labels' mouse listeners 
     addLabelMouseListener(renderer.getDeleteButton()); 
     addLabelMouseListener(renderer.getUploadButton()); 
    } 

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

     return renderer.getTreeCellRendererComponent(
       tree, value, isSelected, 
       expanded, leaf, row, true); 
    } 

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

    public boolean shouldSelectCell(EventObject anEvent) 
    { 
     return false; 
    } 


    public boolean stopCellEditing() 
    { 
     return super.stopCellEditing(); 
    } 

    public void cancelCellEditing() 
    { 
     super.cancelCellEditing(); 
    } 

    public void addCellEditorListener(CellEditorListener l) 
    { 
     super.addCellEditorListener(l); 
    } 

    public void removeCellEditorListener(CellEditorListener l) 
    { 
     super.removeCellEditorListener(l); 
    } 

    public Object getCellEditorValue() 
    { 
     return null; 
    } 
} 

編輯 - 在這裏一個SSCCE:

import java.awt.Color; 
import java.awt.Component; 
import java.awt.Cursor; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 
import java.util.EventObject; 

import javax.swing.AbstractCellEditor; 
import javax.swing.ImageIcon; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JTree; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 
import javax.swing.event.CellEditorListener; 
import javax.swing.tree.DefaultMutableTreeNode; 
import javax.swing.tree.DefaultTreeCellRenderer; 
import javax.swing.tree.DefaultTreeModel; 
import javax.swing.tree.TreeCellEditor; 
import javax.swing.tree.TreeCellRenderer; 



public class EditJTreeCell extends JFrame 
{ 
    /** 
    * 
    */ 
    private static final long serialVersionUID = 4745146614430249610L; 

    private JTree tree; 
    private DefaultTreeModel treeModel; 
    private DefaultMutableTreeNode root; 

    public EditJTreeCell() 
    { 
     super("Sample"); 
     root = new DefaultMutableTreeNode("Root folder"); 
     treeModel = new DefaultTreeModel(root); 
     tree = new JTree(treeModel); 

     TreeNodeRenderer renderer = new TreeNodeRenderer(); 
     tree.setCellRenderer(renderer); 
     tree.setCellEditor(new TreeNodeEditor()); 
     tree.setEditable(true); 

     //tree creation 
     DefaultMutableTreeNode folder = new DefaultMutableTreeNode("folder1"); 
     DefaultMutableTreeNode file = new DefaultMutableTreeNode("file1"); 
     folder.add(file); 
     file = new DefaultMutableTreeNode("file2"); 
     folder.add(file); 
     root.add(folder); 
     folder = new DefaultMutableTreeNode("folder2"); 
     file = new DefaultMutableTreeNode("file1"); 
     folder.add(file); 
     file = new DefaultMutableTreeNode("file2"); 
     folder.add(file); 
     file = new DefaultMutableTreeNode("file3"); 
     folder.add(file); 
     root.add(folder); 

     this.setSize(400, 800); 
     this.add(tree); 
     this.setVisible(true); 
    } 

    public static void main(String[] args) 
    { 
     try { 
      UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"); 
     } catch (ClassNotFoundException e) { 
      e.printStackTrace(); 
     } catch (InstantiationException e) { 
      e.printStackTrace(); 
     } catch (IllegalAccessException e) { 
      e.printStackTrace(); 
     } catch (UnsupportedLookAndFeelException e) { 
      e.printStackTrace(); 
     } 
     new EditJTreeCell(); 
    } 
} 

class TreeNodeRenderer extends DefaultTreeCellRenderer implements TreeCellRenderer 
{ 
    /** 
    * 
    */ 
    private static final long serialVersionUID = 1L; 

    private JPanel panel1 = new JPanel(); 
    private JLabel delete = new JLabel("DELETE"); 
    private JLabel upload = new JLabel("UPLOAD"); 

    public Component getTreeCellRendererComponent(JTree tree, Object value, 
      boolean selected, boolean expanded, boolean leaf, int row, 
      boolean hasFocus) 
    { 
     // 
     // DELETE label 
     // 
     delete.setName("delete"); 
     delete.setIcon(new ImageIcon("trash.png")); 
     //addLabelMouseListener(delete); 
     // 
     // UPLOAD label 
     // 
     upload.setName("upload"); 
     upload.setIcon(new ImageIcon("app_up.png")); 
     //addLabelMouseListener(upload); 


     DefaultTreeCellRenderer defaultRenderer = new DefaultTreeCellRenderer(); 
     Color backgroundSelectionColor = defaultRenderer.getBackgroundSelectionColor(); 
     Color backgroundNonSelectionColor = defaultRenderer.getBackgroundNonSelectionColor(); 

     DefaultTreeCellRenderer component = (DefaultTreeCellRenderer) super.getTreeCellRendererComponent(tree, 
       value, selected, expanded, leaf, row, hasFocus); 

     if(selected) 
     { 
      panel1.setBackground(backgroundSelectionColor); 
     } 
     else 
     { 
      panel1.setBackground(backgroundNonSelectionColor); 
     } 

     panel1.add(component); 
     panel1.add(delete); 
     panel1.add(upload); 

     return panel1; 
    } 
} 

class TreeNodeEditor extends AbstractCellEditor implements TreeCellEditor 
{ 
    /** 
    * 
    */ 
    private static final long serialVersionUID = 1L; 
    private JLabel button1; 
    private JLabel button2; 
    private JPanel panel1; 
    private DefaultMutableTreeNode node = null; 
    private DefaultTreeCellRenderer defaultRenderer; 


    public TreeNodeEditor() 
    { 
     super(); 
     panel1 = new JPanel(); 
     defaultRenderer = new DefaultTreeCellRenderer(); 
     button1 = new JLabel("DELETE"); 
     button1.setOpaque(true); 
     button1.setIcon(new ImageIcon("trash.png")); 
     button1.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); 
     button1.addMouseListener(new MouseListener() 
     { 
      public void mouseClicked(MouseEvent arg0) { 
       System.out.println("Delete clicked"); 
      } 
      public void mouseEntered(MouseEvent arg0) {} 
      public void mouseExited(MouseEvent arg0) {} 
      public void mousePressed(MouseEvent arg0) {} 
      public void mouseReleased(MouseEvent arg0) {} 

     }); 
     button2 = new JLabel("UPLOAD"); 
     button2.setOpaque(true); 
     button2.setIcon(new ImageIcon("app_up.png")); 
     button2.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); 
     button2.addMouseListener(new MouseListener() 
     { 
      public void mouseClicked(MouseEvent arg0) { 
       System.out.println("Upload clicked"); 
      } 
      public void mouseEntered(MouseEvent arg0) {} 
      public void mouseExited(MouseEvent arg0) {} 
      public void mousePressed(MouseEvent arg0) {} 
      public void mouseReleased(MouseEvent arg0) {} 

     }); 
    } 


    public Component getTreeCellEditorComponent(JTree tree, Object value, 
      boolean isSelected, boolean expanded, boolean leaf, int row) 
    { 
     //in order to do some actions on a node 
     if(value instanceof DefaultMutableTreeNode) 
     { 
      node = (DefaultMutableTreeNode) value; 
     } 


     defaultRenderer.getTreeCellRendererComponent(tree, 
        value, isSelected, expanded, leaf, row, true); 

     panel1.add(defaultRenderer); 
     panel1.add(button1); 
     panel1.add(button2); 
     return panel1; 
    } 

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

    public boolean shouldSelectCell(EventObject anEvent) 
    { 
     return false; 
    } 


    public boolean stopCellEditing() 
    { 
     return super.stopCellEditing(); 
    } 

    public void cancelCellEditing() 
    { 
     super.cancelCellEditing(); 
    } 

    public void addCellEditorListener(CellEditorListener l) 
    { 
     super.addCellEditorListener(l); 
    } 

    public void removeCellEditorListener(CellEditorListener l) 
    { 
     super.removeCellEditorListener(l); 
    } 

    public Object getCellEditorValue() 
    { 
     return null; 
    } 
} 
+0

不回答你的問題(或者它是,沒有檢查),只是要小心:你不能使用同一個組件實例來渲染和編輯 – kleopatra

+1

時間sscce來演示究竟是什麼問題 – kleopatra

+0

謝謝你的建議。現在,我不使用同一個組件的實例進行渲染和編輯。但問題仍然存在。我編輯了我的帖子以添加sscce。 我正在考慮在光標位於節點(使用myTree.getRowAtPoint(x,y))時模擬鍵F2(版本鍵)。但是,如果我可以,我寧願避免它。 – bldcoco

回答

5

開始上的MouseEnter編輯是:-)

你的編輯器有效的解決方案,而另一方面是不是一個有效的實現:它失敗。如果編輯被終止不通知其監聽器由於內部事件(作爲任何按鈕連接點擊)下面是如何,同時實現您的目標的例子,有一個有效的實現

一對夫婦的意見:

如果你想
  • 就像一個按鈕..使用按鈕:否則用戶可能會感到困惑
  • 在你的編輯器,設置按鈕的動作需要
  • 做所有基本面板的配置(如添加的孩子)在構造函數)
  • 開始編輯/檢測被點擊的按鈕,再派遣在shouldSelect中收到的事件。在SwingUtilities.invokeLater中執行以確保任何內部未決事件(在樹中)準備就緒
  • 不會更改編輯器內的樹節點:a)這些更改將無法通知模型b)將被該樹的默認編輯終止行爲。DefaultTreeTable將重置與editorValue樹的userObject,這是在valueForPathChanged做到:實現自定義的行爲,重寫方法模型
代碼

static class TreeNodeEditor extends AbstractCellEditor implements TreeCellEditor { 
    private static final long serialVersionUID = 1L; 
    private JButton button1; 
    private JButton button2; 
    private JPanel panel1; 
    // JW: do not modify the node inside the editor 
    //  private DefaultMutableTreeNode node = null; 
    private DefaultTreeCellRenderer defaultRenderer; 

    private Object editorValue; 

    public TreeNodeEditor() { 
     super(); 
     panel1 = new JPanel(); 
     defaultRenderer = new DefaultTreeCellRenderer(); 
     button1 = new JButton("DELETE"); 
     button1.setOpaque(true); 
     button1.setIcon(new ImageIcon("trash.png")); 
     button1.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); 
     button2 = new JButton("UPLOAD"); 
     button2.setOpaque(true); 
     button2.setIcon(new ImageIcon("app_up.png")); 
     button2.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); 
     button2.setAction(createAction("upload", "UPLOAD")); 
     button1.setAction(createAction("delete", "DELETE")); 
     panel1.add(defaultRenderer); 
     panel1.add(button1); 
     panel1.add(button2); 
    } 

    private Action createAction(final String actionCommand, String display) { 
     Action action = new AbstractAction(display) { 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       stopEditing(actionCommand); 
      } 

     }; 
     return action; 

    } 
    /** 
    * @param actionCommand 
    */ 
    protected void stopEditing(String actionCommand) { 
     editorValue = actionCommand; 
     stopCellEditing(); 
    } 

    @Override 
    public Component getTreeCellEditorComponent(JTree tree, Object value, 
      boolean isSelected, boolean expanded, boolean leaf, int row) { 
     // in order to do some actions on a node 
     //   if (value instanceof DefaultMutableTreeNode) { 
     //    node = (DefaultMutableTreeNode) value; 
     //   } 

     defaultRenderer.getTreeCellRendererComponent(tree, value, 
       isSelected, expanded, leaf, row, true); 

     return panel1; 
    } 

    /** 
    * 
    */ 
    private void reset() { 
     editorValue = null; 
    } 

    /** 
    * At this point in time the component is added to the tree (not documented!) but 
    * tree's internal cleanup might not yet be ready 
    */ 
    @Override 
    public boolean shouldSelectCell(EventObject anEvent) { 
     reset(); 
     if (anEvent instanceof MouseEvent) { 
      redirect((MouseEvent) anEvent); 
     } 
     return false; 
    } 

    private void redirect(final MouseEvent anEvent) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       MouseEvent ev = SwingUtilities.convertMouseEvent(anEvent.getComponent(), anEvent, panel1); 
       panel1.dispatchEvent(ev); 

      } 
     }); 
    } 

    @Override 
    public Object getCellEditorValue() { 
     return editorValue; 
    } 
} 
+0

+1有一個清晰的解釋。 – trashgod

+0

謝謝你的明確解釋。 – bldcoco

0

我認爲你需要添加treeNodeRenderer本身內部的鼠標監聽器。在您進入「編輯模式」並將編輯器放入單元格後,可能只會添加mouselistener。

+1

不,這種神奇的損失是不太可能的 - 聽衆肯定是在實例化的時候添加的;-)但是,只有當編輯組件是組件層次結構的一部分時,即處於編輯模式時,它纔會獲得_notified_。 – kleopatra

+0

我試圖在渲染器中添加mouseListener,但問題仍然相同。我必須先選擇節點並進入編輯模式。 – bldcoco

+1

@Bladcoconut你的眼睛在哪裏? – kleopatra

1

最後,我解決了我的問題與MouseMotionListener和方法:myTree.startEditingAtPath(path)。光標位於編輯模式時,節點現在處於編輯模式。

tree.addMouseMotionListener(new MouseMotionListener() { 
      public void mouseMoved(MouseEvent e) 
      { 
       if (tree.getRowForLocation(e.getX(), e.getY()) != -1) 
       { 
        tree.startEditingAtPath(tree.getPathForLocation(e.getX(), e.getY())); 
       }    
      } 
      public void mouseDragged(MouseEvent e) {} 
     }); 

但是,如果有人有一個更好的主意,請讓我知道。

相關問題