Отбросить узлы в JTree на разных уровнях вложенности - PullRequest
4 голосов
/ 31 января 2011

Я реализую перетаскивание в JTree. Я хочу, чтобы пользователь мог отбрасывать узел на разных уровнях дерева.

В приведенном ниже примере представьте, что пользователь вставляет элемент между «внучатым А2» и «дочерним С»:

root
  child A
    grandchild A1
    grandchild A2
  child C
    grandchild C1

Теперь есть два варианта:

  1. Добавить нового внука к "child A", который будет "внучкой A3", или
  2. Вставьте новый «ребенок B» между «ребенок A» и «ребенок B».

В SWT это возможно, немного сместив узел в вертикальном направлении. Индикатор горизонтальной линии покажет, на каком уровне вложенности вставлен узел дерева.

Возможно ли это вообще в Swing? Я не могу найти информацию об этом. Индикатор линии в Swing всегда отображается только на одном уровне.

А если нет, то есть ли обходной путь?

Ответы [ 2 ]

2 голосов
/ 01 февраля 2011

Я не верю, что можно добиться именно того поведения, которое вы хотите, используя встроенные в Swing функции перетаскивания.

Возможный обходной путь - установить режим отбрасывания на ON_OR_INSERT следующим образом: tree.setDropMode(DropMode.ON_OR_INSERT);

ON_OR_INSERT поддерживает удаление либо узла напрямую, либо между узлами. Часть INSERT поддерживает переключение между "A" и "B". Затем вы можете разрешить пользователям добавлять нового внука «A» после «A3» одним из двух способов (или обоих):

  • Интерпретировать каплю непосредственно на "A" как добавление элемента как последнего потомка "A"
  • Интерпретация отбрасывания на узле как добавления элемента после узла (это проблематично, если узел не является листом, поскольку ожидаемое поведение заключается в добавлении элемента в качестве дочернего элемента)

Если вам нужно именно то поведение, которое вы описываете, вам, вероятно, нужно написать собственный DropTarget для таблицы и нарисовать нужные эффекты (линия, показывающая, где произойдет падение), самостоятельно. Я бы рекомендовал избегать этого, если это вообще возможно.

1 голос
/ 24 июня 2015

Это ошибка в обработке местоположения отбрасывания java , и ее трудно устранить без изменения источника 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
}

Возможно, вы захотите иметь пользовательское средство визуализации, чтобы изменить внешний вид строк заполнителей (например, скрыть значок, уменьшить высоту (хотя вы не можете сделать это 0 высотой) и т. Д.).

...