2013-01-11 10 views
6

Próbuję zaimplementować kopiowanie i wklejanie obiektów między różnymi instancjami tej samej aplikacji. Obecnie działa tylko w jednej aplikacji (tzn. Kopiuje i wkleja w tym samym wystąpieniu aplikacji), ale nie działa między różnymi instancjami.Java: użyj schowka do skopiowania i wklejenia obiektów java między różnymi instancjami tej samej aplikacji.

kod Kopiowanie:

// MyObject is a class of objects I want to copy/paste; 
// MyObjectSelection is a class that impements Transferable and ClipboardOwner interfaces 

Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); 
MyObject data = new MyObject(selectedItems); 
MyObjectSelection dataSelection = new MyObjectSelection(data); 
clipboard.setContents(dataSelection, this); 

Po tym, można sprawdzić zawartość schowka, tak:

Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); 
Transferable clipboardContent = clipboard.getContents(this); 

DataFlavor[] flavors = clipboardContent.getTransferDataFlavors(); 
System.out.println("flavors.length=" + flavors.length); 
for (int i = 0; i < flavors.length; i++){ 
    System.out.println("flavor=" + flavors[i]); 
} 

Jeśli mogę to zrobić z tej samej instancji aplikacji że kopiowanego obiektu, działa: flavors.length jest 1, typ MIME to application/x-java-serialized-object, i, cóż, działa.

Ale jeśli otworzę aplikację, wykonaj kopię, a następnie otwórz tę samą aplikację ponownie (pierwsza nie jest zamknięta, tj. Obie instancje działają jednocześnie) i spróbuj sprawdzić zawartość schowka stamtąd, następnie flavors.length jest 0.

Przeanalizowałem dokumenty i te przykłady: one, two, ale nadal nie mogę znaleźć błędów w mojej implementacji.

Czy coś mi umknęło?


UPD: I dodaje sscce: clipboard_test.zip.

Jest to aplikacja testu (używam Eclipse ją zbudować) z plikami 3 Źródło:

  • ClipboardTest.java - główny app klasa
  • MyObject.java - klasa obiektów do kopiuj/wklej (klasa ta zawiera tylko tablicę od String)
  • MyObjectSelection.java - klasa, która implementuje Transerable i ClipboardOwner interfejsy

    Istnieje tw o przyciski: "copy", "test".

    Po naciśnięciu przycisku "Kopiuj" zostanie utworzona nowa instancja MyObject i umieszczona w schowku.

    Po naciśnięciu przycisku "test", zawartość schowka są sprawdzane i echo do konsoli (liczba obsługiwanych DataFlavor „s, a każdy DataFlavor)

    więc replikować kroki:

  • Rozpocznij aplikacja

  • Naciśnij przycisk „Kopiuj”: widać "object copied" wiadomość w dzienniku
  • Naciśnij przycisk „TEST”: widać zawartość schowka w :

    flavors.length = 1 
        flavor[0] = java.awt.datatransfer.DataFlavor[mimetype=application/x-java-serialized-object;representationclass=MyObject] 
    
  • Rozpocznij kolejną instancję aplikacji (nie zamykają pierwszy)

  • przycisk
  • przycisk "test": widać, że schowek jest pusty:

    flavors.length = 0 
    

Dlaczego tak jest?


UPD2: sscce wysłane bezpośrednio tutaj:

import java.awt.BorderLayout; 

    import java.awt.datatransfer.Clipboard; 
    import java.awt.datatransfer.ClipboardOwner; 
    import java.awt.datatransfer.DataFlavor; 
    import java.awt.datatransfer.Transferable; 
    import java.awt.datatransfer.UnsupportedFlavorException; 

    import java.awt.event.ActionEvent; 
    import java.awt.event.ActionListener; 

    import java.awt.Toolkit; 

    import javax.swing.JButton; 
    import javax.swing.SwingUtilities; 
    import javax.swing.JFrame; 

    public final class ClipboardTest implements Runnable, ClipboardOwner { 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater (new ClipboardTest()); 
    } 

    public void run() { 

     JFrame f = new JFrame ("Clipboard test"); 
     f.setDefaultCloseOperation (JFrame.DISPOSE_ON_CLOSE); 

     //-- Create "copy" button. 
     // When you click it, new object "test_items" becomes created 
     // and put to the clipboard. 
     { 
      JButton button_copy = new JButton("copy"); 
      button_copy.addActionListener(new ActionListener(){ 
       public void actionPerformed(ActionEvent e){ 

       String[] test_items = { 
        "one", "two", "three" 
       }; 

       Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); 
       MyObject data = new MyObject(test_items); 
       MyObjectSelection dataSelection = new MyObjectSelection(data); 
       clipboard.setContents(dataSelection, ClipboardTest.this); 

       System.out.println("object copied"); 
       } 
      }); 
      f.add(button_copy, BorderLayout.NORTH); 
     } 

     //-- Create "test" button. 
     // When you click it, clipboard contents are checked 
     // and echoed to the console (count of supported DataFlavor's, and each DataFlavor) 
     { 
      JButton button_test = new JButton("test"); 
      button_test.addActionListener(new ActionListener(){ 
       public void actionPerformed(ActionEvent e){ 

       Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); 
       Transferable clipboardContent = clipboard.getContents(this); 

       DataFlavor[] flavors = clipboardContent.getTransferDataFlavors(); 
       System.out.println("flavors.length = " + flavors.length); 
       for (int i = 0; i < flavors.length; i++){ 
        System.out.println("flavor[" + i + "] = " + flavors[i]); 
       } 

       } 
      }); 
      f.add(button_test, BorderLayout.SOUTH); 
     } 

     f.pack(); 
     f.setVisible(true); 
    } 



    // ClipboardOwner implementation 

    @Override 
    public void lostOwnership(Clipboard clipboard, Transferable transferable){ 
     System.out.println("ClipboardTest: Lost ownership"); 
    } 







    /* ***************************************************************************************** 
     * Object that I want to copy/paste 
     * ****************************************************************************************/ 

    public static class MyObject { 

     private String[] items; 

     public MyObject(String[] items){ 
      this.setItems(items); 
     } 

     public String[] getItems(){ 
      return this.items; 
     } 

     public void setItems(String[] items){ 
      this.items = items; 
     } 

    } 




    public static class MyObjectSelection implements Transferable, ClipboardOwner { 

     private static DataFlavor dmselFlavor = new DataFlavor(MyObject.class, "Test data flavor"); 
     private MyObject selection; 



     public MyObjectSelection(MyObject selection){ 
      this.selection = selection; 
     } 


     // Transferable implementation 

     @Override 
     public DataFlavor[] getTransferDataFlavors(){ 
      System.out.println("getTransferDataFlavors"); 
      DataFlavor[] ret = {dmselFlavor}; 
      return ret; 
     } 

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

     @Override 
     public synchronized Object getTransferData (DataFlavor flavor) 
      throws UnsupportedFlavorException 
     { 
      if (isDataFlavorSupported(flavor)){ 
       return this.selection; 
      } else { 
       throw new UnsupportedFlavorException(dmselFlavor); 
      } 
     } 



     // ClipboardOwner implementation 

     @Override 
     public void lostOwnership(Clipboard clipboard, Transferable transferable){ 
      System.out.println("MyObjectSelection: Lost ownership"); 
     } 

    } 

    } 
+3

Aby uzyskać lepszą pomoc wcześniej, opublikuj [SSCCE] (http://sscce.org/). –

+0

System operacyjny i argumenty/konfiguracja maszyny JVM również mają wiele do powiedzenia na temat dostępu do globalnego schowka – tucuxi

+0

@AndrewThompson, dodałem go, sprawdź moje zaktualizowane pytanie. –

Odpowiedz

5

Cytowanie this tutorial:

Przesyłanie danych za pomocą tego mechanizmu używa Object serializacji, więc klasa użyć, aby przenieść dane muszą implementować interfejs Serializable, podobnie jak wszystko, co jest z nim serializowane. Jeśli wszystko nie będzie można serializować, zobaczysz NotSerializableException podczas upuszczania lub kopiowania do schowka.

Twoja MyObject nie jest Serializable, więc nie może działać. Struktura najwyraźniej wykrywa ten fakt (w przeciwieństwie do sytuacji z nieprzesuwialną podklasą macierzystej klasy podlegającej kodowaniu lub podobnymi scenariuszami, w których nie-serializowalność jest wykrywana tylko w procesie), więc nie będzie nawet oferować tego smaku innym procesom.

Zwykle dwa wystąpienia tej samej aplikacji java nie mają tej samej przestrzeni adresowej, więc nie mogą po prostu uzyskać dostępu do pamięci drugiej osoby. Dlatego wszystko, co przekazujesz, musi być serializowane.

+0

Dziękuję bardzo. Niestety, nie mogę znaleźć linku do tego samouczka z oficjalnej dokumentacji 'DataFlavor': http://docs.oracle.com/javase/7/docs/api/java/awt/datatransfer/DataFlavor.html –

+0

@DmitryFrank: Ten link nie działa, właśnie wysłałem do niego raport o błędzie. Ale używając tytułu łatwo było znaleźć wersję, do której się odwołałem. – MvG

Powiązane problemy