Java / Swing: перетаскивание проблем с двумя дочерними окнами - PullRequest
1 голос
/ 09 февраля 2010

У меня есть два дочерних окна, которые я хочу принимать перетаскиванием из объектов перетаскивания + отбрасывания двумя разными способами.

Одним из них является JPanel, который я хочу принять список файлов. Работает нормально.

Другой является JTable, я хочу принять список строк. Это прекрасно работает, если я не включаю JPanel как цель отбрасывания.

Когда я пытаюсь включить оба, цель перетаскивания JPanel, кажется, маскирует цель перетаскивания JTable, даже если JTable не является дочерним окном JPanel, и два компонента находятся в неперекрывающихся областях.

Также JFrame, который содержит их обоих, похоже, получает значок выпадения ... не знаю почему.

Любой совет? Это трудно отладить.


Далее следует пример приложения, которое аналогично, здесь я не могу заставить JTable принимать капли вообще. : /

Есть еще один вопрос, который мне хотелось бы понять: если я перетаскиваю из «перетащить источник 1» на «опустить цель 1», но не отпускаю мышь, мой курсор мерцает каждый раз, когда изменяется метка источника перетаскивания 1 (один раз в секунду) в этом тестовом приложении). Почему он это делает? Есть ли способ остановить его мерцание?

package com.example.test.gui;

import java.awt.Component;
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 java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;

public class DragAndDropQuestion {
    public enum Color { 
        RED, ORANGE, YELLOW, GREEN, BLUE, VIOLET, WHITE, BLACK;
        @Override public String toString() 
            { return this.name().toLowerCase(); }
        static public Color randomColor(Random r)
        {
            Color[] colors = Color.values();
            return colors[r.nextInt(colors.length)];
        }
    }
    public static class SampleBean
    {
        final private Color color;
        final private char letter;
        final static public DataFlavor dataFlavor = 
            new DataFlavor(SampleBean.class, "SampleBean");
        public Color getColor() { return this.color; }
        public char getLetter() { return this.letter; }
        private SampleBean(Color color, char letter)
        {
            this.color = color;
            this.letter = letter;
        }
        static public SampleBean randomBean(Random r)
        {
            String letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            return new SampleBean(Color.randomColor(r),
                    letters.charAt(r.nextInt(letters.length())));
        }
        @Override public String toString() {
            return this.color.toString()+" "+this.letter; 
        }
    }
    public static class BorderPanel extends JPanel {
        public BorderPanel(String title)
        {
            setBorder(BorderFactory.createTitledBorder(title));
        }
    }
    public static class BeanTransferable implements Transferable
    {
        final private SampleBean value;
        static final private List<DataFlavor> flavors = Arrays.asList(
                DataFlavor.stringFlavor,
                SampleBean.dataFlavor
            );
        public BeanTransferable(SampleBean x) { this.value=x; }
        @Override public Object getTransferData(DataFlavor flavor) 
        throws UnsupportedFlavorException, IOException {
            if (flavors.get(0).equals(flavor))
            {
                return this.value.toString(); 
            }
            else if (flavors.get(1).equals(flavor))
            {
                return this.value;
            }
            else
            {
                throw new UnsupportedFlavorException(flavor);
            }
        }

        @Override public DataFlavor[] getTransferDataFlavors() {
            return flavors.toArray(new DataFlavor[0]);
        }
        @Override public boolean isDataFlavorSupported(DataFlavor flavor) {
            return flavors.contains(flavor);
        }
    }
    public abstract static class SimpleDropTarget 
       implements DropTargetListener
    {
        final private String debugString;
        public SimpleDropTarget(String debugString) {
            this.debugString=debugString; 
        }
        @Override public void dragEnter(DropTargetDragEvent event) 
            { System.out.println(this.debugString+":dragEnter"); }
        @Override public void dragExit(DropTargetEvent event) {}
            { System.out.println(this.debugString+":dragExit"); }
        @Override public void dragOver(DropTargetDragEvent event) {}    
        @Override public void dropActionChanged(DropTargetDragEvent event) {}
        public void install(JComponent component) {
            new DropTarget(component, this);
        }
    }
    public abstract static class SimpleDragSource 
        implements DragSourceListener, DragGestureListener
    {
        final private String debugString;
        final private DragSource ds = new DragSource();
        public SimpleDragSource(String debugString) { 
            this.debugString=debugString; 
        }
        @Override public void dragDropEnd(DragSourceDropEvent event) {}
        @Override public void dragEnter(DragSourceDragEvent event) 
        { System.out.println(this.debugString+":dragEnter"); }
        @Override public void dragExit(DragSourceEvent event) 
        { System.out.println(this.debugString+":dragExit"); }
        @Override public void dragOver(DragSourceDragEvent event) {}
        @Override public void dropActionChanged(DragSourceDragEvent event) {}   
        public void install(JComponent component) {
            DragGestureRecognizer dgr = 
                this.ds.createDefaultDragGestureRecognizer(component,
                        DnDConstants.ACTION_COPY, this);
        }
        abstract public Transferable prepareTransferable();
        @Override public void dragGestureRecognized(DragGestureEvent dge)
        {
            this.ds.startDrag(dge,
                    DragSource.DefaultCopyDrop, prepareTransferable(), this);
        }
    }
    public static class BeanListModel implements TableModel {
        final private List<SampleBean> list = new ArrayList<SampleBean>();
        enum ColumnType {
            COLOR(Color.class, "color") {
                @Override public Color extractValue(SampleBean sampleBean) {
                    return sampleBean.getColor();
                }
            },
            LETTER(String.class, "letter") {
                @Override public String extractValue(SampleBean sampleBean) {
                    return Character.toString(sampleBean.getLetter());
                }
            },
            ;
            final private Class<?> cl;
            final private String name;
            public Class<?> getColumnClass() { return this.cl; }
            public String getColumnName() { return this.name; }
            ColumnType(Class<?> cl, String name) 
            { this.cl=cl; this.name=name; }
            abstract public Object extractValue(SampleBean sampleBean);
        }
        final static private ColumnType[] columns 
            = new ColumnType[]{ColumnType.COLOR, ColumnType.LETTER};

        @Override 
            public void addTableModelListener(TableModelListener arg0) {}
        @Override 
            public void removeTableModelListener(TableModelListener arg0) {}

        @Override public Class<?> getColumnClass(int column) {
            return columns[column].getColumnClass();
        }
        @Override public int getColumnCount() { 
            return columns.length; 
        }
        @Override public String getColumnName(int column) {
            return columns[column].getColumnName();
        }
        @Override public int getRowCount() { return list.size(); }
        @Override public Object getValueAt(int row, int column) {
            return columns[column].extractValue(list.get(row));
        }

        @Override public boolean isCellEditable(int row, int column) {
            return false;
        }

        @Override public void setValueAt(Object obj, int row, int column) {
            throw new UnsupportedOperationException();
        }       

        public void addBean(SampleBean bean)
        {
            this.list.add(bean);
        }
    }
    public static class BeanTablePanel extends BorderPanel {
        final private JTable table;
        final private BeanListModel tableModel;

        public BeanTablePanel(String title)
        {
            super(title);
            this.table = new JTable();
            this.tableModel = new BeanListModel();
            this.table.setModel(this.tableModel);
            add(new JScrollPane(this.table));
            SimpleDropTarget dt = new SimpleDropTarget("BeanTable"){
                @Override public void drop(DropTargetDropEvent dtde) {
                    Transferable tr = dtde.getTransferable();
                    if (tr.isDataFlavorSupported(SampleBean.dataFlavor))
                    {
                        try {
                            SampleBean b = (SampleBean) 
                                tr.getTransferData(SampleBean.dataFlavor);
                            addBean(b);
                        }
                        catch (UnsupportedFlavorException e) {
                            e.printStackTrace();
                        }
                        catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            };
            dt.install(this.table);
            // !!! This doesn't seem to work...
        }
        void addBean(SampleBean b) {
            this.tableModel.addBean(b);         
        }
    }
    public static class BeanLabelPanel extends BorderPanel {
        final private JLabel label;
        public BeanLabelPanel(String title)
        {
            super(title);
            this.label = new JLabel("drop item here");
            add(this.label);
            SimpleDropTarget dt = new SimpleDropTarget("BeanLabel"){
                @Override public void drop(DropTargetDropEvent dtde) {
                    Transferable tr = dtde.getTransferable();
                    if (tr.isDataFlavorSupported(DataFlavor.stringFlavor))
                    {
                        try {
                            String s = (String) 
                                tr.getTransferData(DataFlavor.stringFlavor);
                            setLabel(s);
                        }
                        catch (UnsupportedFlavorException e) {
                            e.printStackTrace();
                        }
                        catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            };
            dt.install(this.label);
        }       
        void setLabel(String s) { this.label.setText(s); }
    }
    public static class BeanSourcePanel extends BorderPanel {
        final private JLabel label;
        final private Random randomizer;
        private SampleBean x;

        public BeanSourcePanel(
         String title, ScheduledExecutorService scheduler)
        {
            super(title);
            this.label = new JLabel(" ");
            this.randomizer = new Random();
            add(this.label);

            scheduler.scheduleAtFixedRate(new Runnable()
            { public void run() { changeBean(); } }, 
            0, 1000, TimeUnit.MILLISECONDS);

            (new SimpleDragSource("RandomBean"){
                @Override public Transferable prepareTransferable() {
                    return new BeanTransferable(getBean());
                }
            }).install(this.label);
        }       
        public SampleBean getBean() { return this.x; }
        void changeBean()
        {
            this.x = SampleBean.randomBean(this.randomizer);
            this.label.setText(this.x.toString());
        }       
    }

    public static class DNDQFrame extends JFrame
    {
        public DNDQFrame(String title, ScheduledExecutorService scheduler)
        {
            setTitle(title);
            getContentPane().setLayout(
                    new BoxLayout(getContentPane(), BoxLayout.PAGE_AXIS)
            );
            add(new JLabel("Drag and Drop Question"));
            add(new BeanSourcePanel("drag source 1", scheduler));
            add(new BeanLabelPanel("drop target 1"));
            add(new BeanTablePanel("drop target 2"));
        }
        @Override public Component add(Component component)
        {
            if (component instanceof JComponent)
                ((JComponent) component).setAlignmentX(0.0f);
            return super.add(component);            
        }       
    }

    static public void main(String[] args)
    {
        ScheduledExecutorService scheduler = 
            new ScheduledThreadPoolExecutor(1);
        DNDQFrame frame = new DNDQFrame("DragAndDropQuestion", scheduler);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

1 Ответ

2 голосов
/ 09 февраля 2010

Вместо этого добавьте слушатель отбрасывания в JScrollPane. У вас есть вложенная таблица, поэтому она не получает события. Кроме того, в вашем методе addBean () вы должны добавить table.revalidate (), иначе он не отобразит обновленные данные в вашей табличной модели.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...