Java 将节点放置在不同嵌套级别的JTree中
我正在JTree中实现拖放。 我希望用户能够删除树中不同级别的节点 在下面的示例中,假设用户在“孙子A2”和“子C”之间插入一项: 现在有两种选择:Java 将节点放置在不同嵌套级别的JTree中,java,swing,drag-and-drop,jtree,Java,Swing,Drag And Drop,Jtree,我正在JTree中实现拖放。 我希望用户能够删除树中不同级别的节点 在下面的示例中,假设用户在“孙子A2”和“子C”之间插入一项: 现在有两种选择: 在“子a”后附加一个新的孙辈,即“孙辈A3”,或 在“子a”和“子B”之间插入新的“子B” 在SWT中,这可以通过在垂直方向上稍微移动节点来实现。水平线指示器将显示插入树节点的嵌套级别 这有可能吗?我似乎找不到这方面的信息。Swing中的线路指示器始终仅在一个级别显示 如果没有,有解决办法吗?我认为使用Swing内置的拖放功能不可能实现您想要的行为
如果没有,有解决办法吗?我认为使用Swing内置的拖放功能不可能实现您想要的行为 一种可能的解决方法是按如下方式将拖放模式设置为ON_或插入:
tree.setDropMode(DropMode.ON_或插入)代码>
ON_或_INSERT支持直接在节点上或在节点之间拖放。插入件支持在“A”和“B”之间下降。然后,您可以允许用户通过以下两种方式之一(或同时使用这两种方式)在“A3”之后添加新的孙子“a”:
- 将直接在“a”上的拖放解释为将该项添加为“a”的最后一个子项
- 将节点上的放置解释为在节点后添加元素(如果节点不是叶,则会出现问题,因为预期的行为是将元素作为子元素添加)
如果您确实需要所描述的行为,您可能需要为表编写一个自定义DropTarget,并自己绘制所需的效果(显示放置位置的线条)。我建议尽可能避免这种情况。这是一个问题,如果不修改JDK源代码,很难解决。它仍然没有解决,但也有一个可能的不切实际的解决办法,已关闭,因为无法修复
我能够做到这一点的唯一方法是添加一个虚拟节点作为任何容器节点的最后一个子节点。这很复杂,添加的行可能不理想,但允许用户作为容器节点的最后一个子节点删除
public class TreeDragAndDrop {
private static final int CONTAINER_ROW = 0;
private static final int PLACEHOLDER_ROW = 3;
private JScrollPane getContent() {
JTree tree = new JTree(getTreeModel()) {
// Overridden to prevent placeholder selection via the keyboad
@Override
public void setSelectionInterval(int index0, int index1) {
int index = index0;
// Probably would use a better check for placeholder row in production
// and use a while loop in case the new index is also a placeholder
if (index == PLACEHOLDER_ROW) {
int currentSelection = getSelectionCount() > 0 ? getSelectionRows()[0] : -1;
if (currentSelection < index) {
index++;
} else {
index--;
}
}
super.setSelectionInterval(index, index);
}
// Overridden to prevent placeholder selection via the mouse
@Override
public void setSelectionPath(TreePath path) {
if (path != null && getRowForPath(path) != PLACEHOLDER_ROW) {
super.setSelectionPath(path);
}
}
};
tree.setRootVisible(false);
tree.setDragEnabled(true);
tree.setDropMode(DropMode.INSERT);
tree.setTransferHandler(...);
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
tree.expandRow(CONTAINER_ROW);
return new JScrollPane(tree);
}
protected static TreeModel getTreeModel() {
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
DefaultMutableTreeNode a;
a = new DefaultMutableTreeNode("A");
root.add(a);
a.add(new DefaultMutableTreeNode("X"));
a.add(new DefaultMutableTreeNode("Y"));
a.add(new DefaultMutableTreeNode("")); // Placeholder node
root.add(new DefaultMutableTreeNode("B"));
root.add(new DefaultMutableTreeNode("C"));
return new DefaultTreeModel(root);
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new TreeDragAndDrop().getContent());
f.setSize(400, 400);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
// TransferHandler code omitted
}
公共类TreeDragAndDrop{
私有静态final int CONTAINER_ROW=0;
私有静态最终整型占位符_行=3;
私有JScrollPane getContent(){
JTree树=新的JTree(getTreeModel()){
//重写以防止通过键盘选择占位符
@凌驾
公共无效设置选择间隔(int index0,int index1){
int指数=index0;
//可能会在生产中使用更好的占位符行检查
//并使用while循环,以防新索引也是占位符
如果(索引==占位符行){
int currentSelection=getSelectionCount()>0?getSelectionRows()[0]:-1;
if(当前选择<索引){
索引++;
}否则{
索引--;
}
}
super.setSelectionInterval(索引,索引);
}
//重写以防止通过鼠标选择占位符
@凌驾
公共无效设置选择路径(树路径){
if(path!=null&&getRowForPath(path)!=占位符行){
super.setSelectionPath(路径);
}
}
};
tree.setRootVisible(false);
tree.setDragEnabled(true);
tree.setDropMode(DropMode.INSERT);
setTransferHandler(…);
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_tree_SELECTION);
tree.expandRow(容器行);
返回新的JScrollPane(树);
}
受保护的静态树模型getTreeModel(){
DefaultMutableTreeNode根=新的DefaultMutableTreeNode(“根”);
DefaultMutableTreeNode a;
a=新的默认可变树节点(“a”);
加上(a);
a、 添加(新的DefaultMutableTreeNode(“X”);
a、 添加(新的DefaultMutableTreeNode(“Y”);
a、 添加(新的DefaultMutableTreeNode(“”);//占位符节点
添加(新的DefaultMutableTreeNode(“B”);
添加(新的DefaultMutableTreeNode(“C”);
返回新的DefaultTreeModel(根);
}
公共静态void main(字符串[]args){
JFrame f=新的JFrame();
f、 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f、 添加(新的TreeDragAndDrop().getContent());
f、 设置大小(400400);
f、 setLocationRelativeTo(空);
f、 setVisible(真);
}
//TransferHandler代码省略
}
您可能希望使用自定义渲染器来更改占位符行的外观(例如,隐藏图标、降低高度(尽管无法将其设置为0高度)等)
public class TreeDragAndDrop {
private static final int CONTAINER_ROW = 0;
private static final int PLACEHOLDER_ROW = 3;
private JScrollPane getContent() {
JTree tree = new JTree(getTreeModel()) {
// Overridden to prevent placeholder selection via the keyboad
@Override
public void setSelectionInterval(int index0, int index1) {
int index = index0;
// Probably would use a better check for placeholder row in production
// and use a while loop in case the new index is also a placeholder
if (index == PLACEHOLDER_ROW) {
int currentSelection = getSelectionCount() > 0 ? getSelectionRows()[0] : -1;
if (currentSelection < index) {
index++;
} else {
index--;
}
}
super.setSelectionInterval(index, index);
}
// Overridden to prevent placeholder selection via the mouse
@Override
public void setSelectionPath(TreePath path) {
if (path != null && getRowForPath(path) != PLACEHOLDER_ROW) {
super.setSelectionPath(path);
}
}
};
tree.setRootVisible(false);
tree.setDragEnabled(true);
tree.setDropMode(DropMode.INSERT);
tree.setTransferHandler(...);
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
tree.expandRow(CONTAINER_ROW);
return new JScrollPane(tree);
}
protected static TreeModel getTreeModel() {
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
DefaultMutableTreeNode a;
a = new DefaultMutableTreeNode("A");
root.add(a);
a.add(new DefaultMutableTreeNode("X"));
a.add(new DefaultMutableTreeNode("Y"));
a.add(new DefaultMutableTreeNode("")); // Placeholder node
root.add(new DefaultMutableTreeNode("B"));
root.add(new DefaultMutableTreeNode("C"));
return new DefaultTreeModel(root);
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new TreeDragAndDrop().getContent());
f.setSize(400, 400);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
// TransferHandler code omitted
}