Копирование в глобальный буфер обмена не работает с Java в Ubuntu

Следующий код из автономного приложения работает в ubuntu:

import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;

public class ClipboardTest {

    public static void main(String[] args) throws Exception {
        Clipboard clipBoard = Toolkit.getDefaultToolkit().getSystemClipboard();        
        // print the last copied thing
        System.out.println(clipBoard.getContents(null).getTransferData(DataFlavor.stringFlavor));
        StringSelection data = new StringSelection("NOW");
        clipBoard.setContents(data, data);
        // prints NOW
        System.out.println(clipBoard.getContents(null).getTransferData(DataFlavor.stringFlavor));
    }

}

Вставка (Ctrl + V) в другое приложение ничего не дает; Я ожидаю "СЕЙЧАС". Вызов вышеуказанного кода второй раз дает следующее исключение:

Exception in thread "main" java.awt.datatransfer.UnsupportedFlavorException: Unicode String
    at sun.awt.datatransfer.ClipboardTransferable.getTransferData(ClipboardTransferable.java:160)

Как отдельное приложение, это должно работать даже после изменений безопасности 2011 года. Копирование через Ctrl + C изнутри JTextField, а затем вставка в другое место работает.

Неудачно на ubuntu 11.04 с последними java7 (jdk1.7.0_10) и jdk1.6.0_33; Он должен работать и работает как ожидается на Windows 7 с последним java7 и на mac osx 10.6 с java6_37. Также судимый xubuntu 12.04 с этими javas и там не работает. Это ошибка linux/ubuntu?

Связанный с этим вопрос

Ответ 1

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

Почему это происходит

Сохранение буфера обмена - это ошибка, которая затрагивает многие программы под Ubuntu и другими операционными системами на базе X11. Фиксация - это проект Google Summer of Code 2010. В Википедии есть хороший обзор проблемы. Если вы хотите исправить себя как пользователь, вы можете установить Parcellite или другой менеджер буфера обмена. Если вы хотите исправить это как программист, вы можете изменить свою программу, чтобы она соответствовала спецификации ClipboardManager.

X-Window wiki

Используя библиотеку gnome, вы можете вызвать метод хранилища в буфере обмена и исправить это. Это единственное, что, кажется, стоит попробовать. Также видел аналогичную вещь для GTK, но только в ошибке Eclipse.

Ответ 2

Я попробовал ваш код с debian testing (7.0) и openjdk 7u3. Результат тот же, но я думаю, что нашел проблему (решение).

Содержимое в буфере обмена действует только при условии, что процесс существует. Он работает, если я изменю код на это:

import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;

public class ClipboardTest {

    public static void main(String[] args) throws Exception {
        Clipboard clipBoard = Toolkit.getDefaultToolkit().getSystemClipboard();
        // print the last copied thing
        Transferable t = clipBoard.getContents(null);
        if (t.isDataFlavorSupported(DataFlavor.stringFlavor))
            System.out.println(t.getTransferData(DataFlavor.stringFlavor));
        StringSelection data = new StringSelection("NOW");
        clipBoard.setContents(data, data);
        // prints NOW
        System.out.println(clipBoard.getContents(null).getTransferData(DataFlavor.stringFlavor));
        System.in.read();
    }
}

Утверждение if не позволяет вашему коду исключать исключение, когда нет пригодного для использования контента, что происходит, если вы запускаете свой код один раз и процесс завершается.
System.in.read() просто сохраняет работоспособность. Пока не нажимайте enter, я могу вставить в другое приложение, и "СЕЙЧАС" выйдет, как ожидалось.

Подобно этому код работает каждый раз для меня.

Надеюсь, что это поможет.

Ответ 4

Здесь вы можете показать тест:

TextArea (его действия по копированию/вставке по умолчанию работают из коробки с любым другим приложением на ubuntu)

Я добавил две кнопки, которые копируют и вставляют из/в системный буфер обмена

import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.ActionEvent;
import java.io.IOException;

public class PruebaClipboard {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setTitle("Copy/Paste");
        frame.getContentPane().setLayout(new BorderLayout());
        JPanel btnPanel = new JPanel();
        JButton btnCopy = new JButton("copy");
        JButton btnPaste = new JButton("paste");
        btnPanel.add(btnCopy);
        btnPanel.add(btnPaste);
        final JTextArea textComp = new JTextArea(7,15);

        Action copyAction = new AbstractAction("copy") {
            public void actionPerformed(ActionEvent e) {
                Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
                StringSelection stringSelection = new StringSelection(textComp.getText());
                clipboard.setContents(stringSelection, stringSelection);
            }
        };

        btnCopy.setAction(copyAction);
        Action pasteAction = new AbstractAction("paste") {
            public void actionPerformed(ActionEvent e) {
                Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
                //odd: the Object param of getContents is not currently used
                Transferable contents = clipboard.getContents(null);
                boolean hasTransferableText = (contents != null) && contents.isDataFlavorSupported(DataFlavor.stringFlavor);
                if (hasTransferableText) {
                    try {
                        String result = "";
                        result = (String) contents.getTransferData(DataFlavor.stringFlavor);
                        textComp.append(result);
                    } catch (UnsupportedFlavorException ex) {
                        //highly unlikely since we are using a standard DataFlavor
                        System.out.println(ex);
                        ex.printStackTrace();
                    } catch (IOException ex) {
                        System.out.println(ex);
                        ex.printStackTrace();
                    }
                }
            }
        };
        btnPaste.setAction(pasteAction);

        frame.getContentPane().add(textComp);
        frame.getContentPane().add(btnPanel, BorderLayout.SOUTH);

        frame.setSize(new Dimension(400, 300));
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }
}

Я думаю, вы должны позаботиться о:

boolean hasTransferableText = (contents != null) && contents.isDataFlavorSupported(DataFlavor.stringFlavor);

И посмотрите, есть DataFlavor.plainTextFlavor, который, возможно, является тем, что вам нужно использовать (хотя он устарел)

Я тестировал код через java 1.4 в java 1.6 на Ubuntu 12.10, но код, в котором я его извлекаю, используется с ubuntu 9.0, я помню.