1 votes

java/swing : problèmes de glisser-déposer avec deux fenêtres enfants

J'ai deux fenêtres enfants dont je veux qu'elles acceptent le dépôt d'objets par glisser-déposer de deux manières différentes.

L'un d'eux est un JPanel qui doit accepter une liste de fichiers. Cela fonctionne bien.

L'autre est un JTable dont je veux qu'il accepte une liste de chaînes de caractères. Cela fonctionne bien si je n'active pas le JPanel comme cible de dépôt.

Lorsque j'essaie d'activer les deux, la cible de dépôt de JPanel semble masquer la cible de dépôt de JTable, même si JTable n'est pas une fenêtre enfant de JPanel et que les deux composants sont dans des zones qui ne se chevauchent pas.

De même, le JFrame qui contient les deux semble obtenir l'icône de chute... je ne sais pas trop pourquoi.

Des conseils ? C'est difficile à déboguer.


L'exemple d'application, qui est similaire, suit, ici je n'arrive pas à faire en sorte que la JTable accepte les gouttes du tout. :/

Il y a une autre question que j'aimerais comprendre : si je glisse de la "source de glissement 1" vers la "cible de glissement 1" sans relâcher la souris, mon curseur clignote à chaque fois que l'étiquette de la source de glissement 1 change (une fois par seconde dans cette application de test). Pourquoi fait-il cela ? Y a-t-il un moyen d'empêcher le clignotement ?

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);
    }
}

2voto

Kylar Points 3435

Ajoutez plutôt l'écouteur de dépôt au JScrollPane. La table est imbriquée, elle ne reçoit donc pas les événements. De plus, dans votre méthode addBean(), vous devriez ajouter une fonction table.revalidate(), sinon les données mises à jour ne s'afficheront pas dans votre modèle de table.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X