Java перетаскивание

Я пытаюсь познакомиться с перетаскиванием в Java, но все уроки, которые я нашел, были... (меня это злит)

Все, что я хочу, это перетащить «PublicUserLabel» из JList (включенного в самодельный JPanel под названием «UserPanel») и поместить его в самодельный класс, наследуемый от JTabbedPanel. Очень важно перетаскивать сам объект, а не его строковое представление!!!

Это то, что у меня есть до сих пор: PublicUserLabel

public class PublicUserLabel extends JLabel implements DragSourceListener, DragGestureListener, Transferable
    {
        private DragSource ds;
        private PublicUser user;

        public PublicUserLabel(PublicUser user)
        {
            super(user.getName());
            this.user = user;
            ds = new DragSource();
            ds.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY_OR_MOVE, this);
        }

        @Override
        public void dragGestureRecognized(DragGestureEvent e)
        {
            ds.startDrag(e, DragSource.DefaultCopyDrop, this, this);
        }

        @Override
        public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException
        {
            if (flavor.equals(PublicUserFlavor.publicUserFlavor))
            {
                return this;//TODO ?
            }
            throw new UnsupportedFlavorException(flavor);
        }

        @Override
        public DataFlavor[] getTransferDataFlavors()
        {
            DataFlavor[] df = new DataFlavor[2];
            df[0] = DataFlavor.stringFlavor;
            df[1] = PublicUserFlavor.publicUserFlavor;
            return df;
        }

        @Override
        public boolean isDataFlavorSupported(DataFlavor flavor)
        {
            return flavor.equals(PublicUserFlavor.publicUserFlavor);
        }

    //some more methods
    }

Пользовательская панель:

public class UserPanel extends JPanel
{
    private JTextField search;
    private List<PublicUser> allUser;
    private JList<PublicUserLabel> list;
    private JScrollPane scrollPane;
    private DefaultListModel<PublicUserLabel> listModel;

    public UserPanel()
    {
        allUser = new LinkedList<PublicUser>();
        listModel = new DefaultListModel<PublicUserLabel>();
        list = new JList<PublicUserLabel>(listModel);
        list.setDragEnabled(true);

PublicUserFlavor:

public class PublicUserFlavor extends DataFlavor
{
    public static DataFlavor publicUserFlavor;

    static
    {
        publicUserFlavor = new DataFlavor(PublicUser.class, "PublicUser");
    }
}

Панель вкладок:

public class TabPanel extends JTabbedPane implements DropTargetListener
{
    public TabPanel()
    {
        setTabPlacement(JTabbedPane.BOTTOM);
        addNewTabComponent("bla");
        addNewTabComponent("blub");
        setDropTarget(new DropTarget(this, this));
    }

    @Override
    public void drop(DropTargetDropEvent e)
    {
        Transferable transferable = e.getTransferable();
        if (transferable.isDataFlavorSupported(PublicUserFlavor.publicUserFlavor))
        {
            e.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
            try
            {
                Object o = transferable.getTransferData(PublicUserFlavor.publicUserFlavor);
                System.out.println(o);
                if (o instanceof PublicUserLabel)
                {
                    PublicUserLabel l = (PublicUserLabel)o;
                    PublicUser u = l.getUser();
                    System.out.println(u);
                }
            }
            catch (UnsupportedFlavorException e1)
            {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            catch (IOException e1)
            {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            e.getDropTargetContext().dropComplete(true);
        }
    }

В методе drop есть некоторые syso, которые должны выполняться, если пользователь перетаскивается в панель. Но это не факт. Я делаю что-то совершенно неправильно? Спасибо за помощь!


person Coding    schedule 20.03.2013    source источник
comment
Что не так с онлайн-уроками?   -  person Zach Latta    schedule 20.03.2013
comment
Очень важно перетаскивать сам объект, а не его строковое представление 1) Почему? 2) Будет сложно, если вы начнете перетаскивание с JList, так как JList не будет даже содержать этот JLabel, а только отрендеренную версию.   -  person Robin    schedule 20.03.2013
comment
Это важно, потому что у пользователя есть не только имя. У пользователя также есть открытый ключ rsa и uuid. Я должен получить хотя бы uuid и ключ от брошенного объекта. Я сохранил список с PublicUser, содержащий всю необходимую мне информацию, поэтому мне не нужно использовать для этого JList. Одним из примеров плохого учебника был заголовок «Собираем все вместе». Там было совсем не ВСЕ вместе. Отсутствовала даже подпись перезаписанного метода.   -  person Coding    schedule 20.03.2013
comment
@zachlatta Онлайн-уроки противоречивы. Если вы не знаете, что вы ищете. Как правило, в Swing есть два разных API-интерфейса. Есть низкоуровневый API и более новый компонентный API. Не многие учебники открыто объясняют, какой из них они используют, и это делает и без того сложную тему еще более запутанной - ИМХО.   -  person MadProgrammer    schedule 20.03.2013
comment
Написание хороших руководств — это тяжелая работа. Если эта тяжелая работа не дает желаемого результата, вы можете подумать о найме личного репетитора...   -  person kleopatra    schedule 20.03.2013


Ответы (1)


Основные проблемы, которые я вижу, это то, что вы смешиваете два разных API. Вы используете как низкоуровневый D'n'D API, так и более новый компонентный D'n'D API.

Лично меня более новый API раздражает, поэтому я стараюсь его избегать.

Я не понимаю, зачем вам нужно передавать метку, когда было бы лучше передать базовый объект PublicUser, но это только я.

введите здесь описание изображения

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragGestureRecognizer;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.io.IOException;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestDnD {

    public static void main(String[] args) {
        new TestDnD();
    }

    public TestDnD() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public class TestPane extends JPanel {

        private JList list;

        public TestPane() {
            setLayout(new BorderLayout());
            list = new JList();
            DefaultListModel model = new DefaultListModel();
            model.addElement(new User("Shaun"));
            model.addElement(new User("Andy"));
            model.addElement(new User("Luke"));
            model.addElement(new User("Han"));
            model.addElement(new User("Liea"));
            model.addElement(new User("Yoda"));
            list.setModel(model);
            add(new JScrollPane(list), BorderLayout.WEST);

            DragGestureRecognizer dgr = DragSource.getDefaultDragSource().createDefaultDragGestureRecognizer(
                            list,
                            DnDConstants.ACTION_COPY_OR_MOVE,
                            new DragGestureHandler(list));

            JPanel panel = new JPanel(new GridBagLayout());
            add(panel);

            DropTarget dt = new DropTarget(
                            panel,
                            DnDConstants.ACTION_COPY_OR_MOVE,
                            new DropTargetHandler(panel),
                            true);

        }

    }

    public static class User {

        private String name;

        public User(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        @Override
        public String toString() {
            return name;
        }

    }

    public static class UserTransferable implements Transferable {

        public static final DataFlavor USER_DATA_FLAVOR = new DataFlavor(User.class, "User");
        private User user;

        public UserTransferable(User user) {
            this.user = user;
        }

        @Override
        public DataFlavor[] getTransferDataFlavors() {
            return new DataFlavor[]{USER_DATA_FLAVOR};
        }

        @Override
        public boolean isDataFlavorSupported(DataFlavor flavor) {
            return USER_DATA_FLAVOR.equals(flavor);
        }

        @Override
        public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
            Object value = null;
            if (USER_DATA_FLAVOR.equals(flavor)) {
                value = user;
            } else {
                throw new UnsupportedFlavorException(flavor);
            }
            return value;
        }

    }

    protected class DragGestureHandler implements DragGestureListener {

        private JList list;

        public DragGestureHandler(JList list) {
            this.list = list;
        }

        @Override
        public void dragGestureRecognized(DragGestureEvent dge) {
            Object selectedValue = list.getSelectedValue();
            if (selectedValue instanceof User) {
                User user = (User) selectedValue;
                Transferable t = new UserTransferable(user);
                DragSource ds = dge.getDragSource();
                ds.startDrag(
                                dge,
                                null,
                                t,
                                new DragSourceHandler());
            }

        }

    }

    protected class DragSourceHandler implements DragSourceListener {

        public void dragEnter(DragSourceDragEvent dsde) {
        }

        public void dragOver(DragSourceDragEvent dsde) {
        }

        public void dropActionChanged(DragSourceDragEvent dsde) {
        }

        public void dragExit(DragSourceEvent dse) {
        }

        public void dragDropEnd(DragSourceDropEvent dsde) {

            System.out.println("Drag ended...");

        }

    }

    protected class DropTargetHandler implements DropTargetListener {

        private JPanel panel;

        public DropTargetHandler(JPanel panel) {
            this.panel = panel;
        }

        public void dragEnter(DropTargetDragEvent dtde) {
            if (dtde.getTransferable().isDataFlavorSupported(UserTransferable.USER_DATA_FLAVOR)) {
                System.out.println("Accept...");
                dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
            } else {
                System.out.println("Drag...");
                dtde.rejectDrag();
            }
        }

        public void dragOver(DropTargetDragEvent dtde) {
        }

        public void dropActionChanged(DropTargetDragEvent dtde) {
        }

        public void dragExit(DropTargetEvent dte) {
        }

        public void drop(DropTargetDropEvent dtde) {
            System.out.println("Dropped...");
            if (dtde.getTransferable().isDataFlavorSupported(UserTransferable.USER_DATA_FLAVOR)) {
                Transferable t = dtde.getTransferable();
                if (t.isDataFlavorSupported(UserTransferable.USER_DATA_FLAVOR)) {
                    try {
                        Object transferData = t.getTransferData(UserTransferable.USER_DATA_FLAVOR);
                        if (transferData instanceof User) {
                            User user = (User) transferData;
                            dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
                            panel.add(new JLabel(user.getName()));
                            panel.revalidate();
                            panel.repaint();
                        } else {
                            dtde.rejectDrop();
                        }
                    } catch (UnsupportedFlavorException ex) {
                        ex.printStackTrace();
                        dtde.rejectDrop();
                    } catch (IOException ex) {
                        ex.printStackTrace();
                        dtde.rejectDrop();
                    }
                } else {
                    dtde.rejectDrop();
                }
            }
        }

    }

}
person MadProgrammer    schedule 20.03.2013
comment
отсутствует или перемешивается - опять твой ангелочек ?-) - person kleopatra; 20.03.2013
comment
лично я думаю, что более новый API намного проще в использовании - жаль, что его так сложно реализовать с компонентами, у которых его нет по умолчанию. - person kleopatra; 20.03.2013
comment
@клеопатра А? Какой новый API? - person Andrew Thompson; 20.03.2013
comment
@AndrewThompson часть, которая подключается при настройке setDragEnabled/setTransferHandler, то есть абстракция поверх низкоуровневого (пакет .dnd) для некоторых компонентов, таких как дерево/таблица/список... :-) - person kleopatra; 20.03.2013
comment
@kleopatra Как вы сказали, если он не встроен в компонент, это боль. Я также обнаружил, что он намеренно отключает части API таким образом, что другие разработчики не могут повторно ввести их, например, перетащить курсор/изображение. Я хотел реализовать некоторые идеи из блога Кроличья нора, но не смог я нашел время, чтобы сесть и сделать это - person MadProgrammer; 20.03.2013
comment
УХ ТЫ! Я не знал, что существуют разные API. Вы правы, мне не нужно экспортировать Ярлык, только его содержимое (было исправление проблемы с dnd). Я видел, как ваш код выполнил его и встроил большинство небольших классов в мой проект. Я думаю, это сработает. Но у меня есть один вопрос: DropTarget dt = new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, new DropTargetHandler(), true); Объект никогда не трогается, но если я его удалю, он не будет работать. почему панель знает DropTarget? Вы мне очень помогли. Удивительно, что ты сделал. Может быть, вы сделаете учебник? Большое спасибо! - person Coding; 21.03.2013
comment
DropTarget выполняет большую внутреннюю регистрацию, чтобы настроить компонент, чтобы он мог реагировать на события перетаскивания (в частности, события мыши). Причина, по которой я сохраняю здесь ссылку, заключается в том, что я могу отменить регистрацию позже, если захочу (удалив DropTargetListener - person MadProgrammer; 21.03.2013
comment
Этому уже несколько лет, но это все еще был лучший учебник, который я мог найти, чтобы реализовать это! Спасибо - person barna10; 23.07.2017