我需要为我的JTree使用自定义单元格渲染器在每个单元格上添加一些JLabel。然后允许用户单击这些标签,而无需先选择单元格。
所以,我创建了一个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 :(得分:5)
开始编辑mouseEnter是一个有效的解决方案: - )
另一方面,你的编辑器不是一个有效的实现:如果编辑因内部事件而终止(如点击任何按钮,则无法通知其监听器)下面是如何操作的示例实现目标并拥有有效的实施
几条评论:
代码:
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;
}
}
答案 1 :(得分: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) {}
});
但是,如果有人有更好的想法,请告诉我。
答案 2 :(得分:0)
我认为你需要在treeNodeRenderer本身中添加鼠标监听器。只有在您进入“编辑模式”并且编辑器被放入单元格后才会添加鼠标滑块。