2015-03-04 34 views
5

Ho cercato su Internet per esempi come trascinare JButtons su un oggetto ma non riuscivo a farlo funzionare.Drag and Drop da JButton a JComponent in Java

Quello che il mio programma fa è che quando faccio clic su un pulsante, l'oggetto ha aggiornato un campo (con un oggetto selezionato.setField()). Voglio essere in grado di farlo non facendo clic, ma trascinando il JButton.

Come posso fare questo? ho trovato questo, e ho provato a mettere nel mio codice:

btn.setTransferHandler(new ImageHandler()); 
btn.addMouseListener(new MouseAdapter() { 
public void mousePressed(MouseEvent e) { 
     JComponent c = (JComponent)e.getSource(); 
     TransferHandler handler = c.getTransferHandler(); 
     handler.exportAsDrag(c, e, TransferHandler.COPY); 
      }   
}); 

ho preso la classe ImageHandler da here.

+0

Cosa fare significa "ottiene un nuovo valore"? Vuoi trascinare il "valore" del pulsante su qualcos'altro? – MadProgrammer

+0

Il pulsante aggiunge un'animazione all'oggetto selezionato. Voglio essere in grado di aggiungere la stessa animazione a un oggetto casuale trascinandoli. – user3450862

risposta

9

Drag'n'drop è un divertente sacchetto di carote croccanti e munchy ... non aiutato dal fatto che esiste un'API "core" e la più recente API "transfer", quindi è davvero facile confondersi

L'esempio seguente utilizza l'API "trasferimento" e sostanzialmente trasferisce un valore String da un pulsante a JLabel.

Drag Numbers

import java.awt.Color; 
import java.awt.Component; 
import java.awt.EventQueue; 
import java.awt.GridBagConstraints; 
import java.awt.GridBagLayout; 
import java.awt.GridLayout; 
import java.awt.datatransfer.DataFlavor; 
import java.awt.datatransfer.StringSelection; 
import java.awt.datatransfer.Transferable; 
import java.awt.dnd.DnDConstants; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import javax.swing.JButton; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.TransferHandler; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 
import javax.swing.border.CompoundBorder; 
import javax.swing.border.EmptyBorder; 
import javax.swing.border.LineBorder; 

public class Test { 

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

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

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

    public class TestPane extends JPanel { 

     public TestPane() { 
      setLayout(new GridLayout(1, 2)); 
      add(createLeftPanel()); 
      add(createRightPanel()); 

     } 

     protected JPanel createLeftPanel() { 
      JPanel panel = new JPanel(new GridBagLayout()); 
      GridBagConstraints gbc = new GridBagConstraints(); 
      gbc.gridwidth = GridBagConstraints.REMAINDER; 
      gbc.fill = GridBagConstraints.HORIZONTAL; 
      gbc.weightx = 1; 
      for (int index = 0; index < 10; index++) { 
       JButton btn = new JButton(Integer.toString(index + 1)); 
       panel.add(btn, gbc); 
       btn.setTransferHandler(new ValueExportTransferHandler(Integer.toString(index + 1))); 

       btn.addMouseMotionListener(new MouseAdapter() { 
        @Override 
        public void mouseDragged(MouseEvent e) { 
         JButton button = (JButton) e.getSource(); 
         TransferHandler handle = button.getTransferHandler(); 
         handle.exportAsDrag(button, e, TransferHandler.COPY); 
        } 
       }); 
      } 
      return panel; 
     } 

     protected JPanel createRightPanel() { 
      JPanel panel = new JPanel(new GridBagLayout()); 
      JLabel label = new JLabel("Drop in"); 
      label.setBorder(new CompoundBorder(new LineBorder(Color.DARK_GRAY), new EmptyBorder(20, 20, 20, 20))); 
      label.setTransferHandler(new ValueImportTransferHandler()); 
      panel.add(label); 
      return panel; 
     } 

    } 

    public static class ValueExportTransferHandler extends TransferHandler { 

     public static final DataFlavor SUPPORTED_DATE_FLAVOR = DataFlavor.stringFlavor; 
     private String value; 

     public ValueExportTransferHandler(String value) { 
      this.value = value; 
     } 

     public String getValue() { 
      return value; 
     } 

     @Override 
     public int getSourceActions(JComponent c) { 
      return DnDConstants.ACTION_COPY_OR_MOVE; 
     } 

     @Override 
     protected Transferable createTransferable(JComponent c) { 
      Transferable t = new StringSelection(getValue()); 
      return t; 
     } 

     @Override 
     protected void exportDone(JComponent source, Transferable data, int action) { 
      super.exportDone(source, data, action); 
      // Decide what to do after the drop has been accepted 
     } 

    } 

    public static class ValueImportTransferHandler extends TransferHandler { 

     public static final DataFlavor SUPPORTED_DATE_FLAVOR = DataFlavor.stringFlavor; 

     public ValueImportTransferHandler() { 
     } 

     @Override 
     public boolean canImport(TransferHandler.TransferSupport support) { 
      return support.isDataFlavorSupported(SUPPORTED_DATE_FLAVOR); 
     } 

     @Override 
     public boolean importData(TransferHandler.TransferSupport support) { 
      boolean accept = false; 
      if (canImport(support)) { 
       try { 
        Transferable t = support.getTransferable(); 
        Object value = t.getTransferData(SUPPORTED_DATE_FLAVOR); 
        if (value instanceof String) { 
         Component component = support.getComponent(); 
         if (component instanceof JLabel) { 
          ((JLabel) component).setText(value.toString()); 
          accept = true; 
         } 
        } 
       } catch (Exception exp) { 
        exp.printStackTrace(); 
       } 
      } 
      return accept; 
     } 
    } 
} 

ho passato il mio modo di separare i TransferHandler s consentendo un "drag" e "drop" versione. Non "devi" fare questo e potresti "usare" un singolo TransferHandler per eseguire entrambe le operazioni, dipende solo da te.

Si dovrà modificare il ValueExportTransferHandler per accettare valori diversi e modificare il SUPPORTED_DATE_FLAVOR accordingingly, ma queste sono le basi

Si potrebbe anche dare un'occhiata a Drag and Drop custom object from JList into JLabel come un altro esempio ...

+0

C'è qualcosa che non va. Voglio dire, "exportAsDrag" non dovrebbe essere chiamato per * ogni singolo evento di trascinamento *, giusto? Anche se potrebbe funzionare nella pratica. EDIT: ho appena eseguito. Funziona, e il metodo mouseDragged è, per qualche ragione, eseguito solo * una volta *, quindi tutto sembra andare bene. –

+0

@DreamspacePresident Perché no? 'exportAsDrag' è stato chiamato su' mouseDragged', se non allora, allora quando dovrebbe essere chiamato? ps- Penso che stai pensando a 'mouseMoved';) – MadProgrammer

+0

Perché i documenti di exportAsDrag dicono" Fa sì che il supporto per il trascinamento di Swing venga avviato. " e "Il trasferimento non sarà necessariamente completato alla restituzione di questa chiamata (ad esempio, la chiamata non blocca l'attesa del rilascio)." che, a mio avviso, implica chiaramente che questa cosa deve essere chiamata * una volta * per D & D. Ma vedi la mia modifica del mio altro commento, tutto sembra andare bene. –