java - 将样式文本拖放到另一个 JTextPane

标签 java swing jtextpane jeditorpane

祝大家有美好的一天!

我正在开发支持样式的文本编辑器。在应用程序中会有几个文本编辑器。我认为允许将样式文本从一个 JTextPane 拖动到另一个 JTextPane 将是一个好主意。 看起来 JTextPane 支持拖动本身带有样式的文本。您可以启动下面的代码来检查它。但是,当我将样式文本拖到另一个 JTextPane 时,插入的文本是纯文本。 :( 我查看了源代码,发现了一个有趣的类——TextTransferHandler。调试后,很明显这个 TextTransferHandler 处理拖放。正如我在其代码中看到的,它支持通过将文本转换为 RTF 或 HTML 来拖动样式文本。我试过这个:

_tp.setEditorKit(new RTFEditorKit());

但没有成功。

我是不是漏掉了什么?

代码:

package apps.editor;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.ResourceBundle;

import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JTextPane;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.JTextComponent;
import javax.swing.text.Keymap;
import javax.swing.text.rtf.RTFEditorKit;

class EditorUtil2 {
    Action[] _actions;
    HashMap<String, Action> _actionHashMap = new HashMap<String, Action>();
    ResourceBundle _resourceBundle = BundleFactory.getBundle();
    JTextPane _initTextPane;
    Keymap _keymap;
    JPopupMenu _popupMenu; 
    ArrayList<JTextPane> _editors = new ArrayList<JTextPane>();

    public EditorUtil2() {
        _initTextPane = new JTextPane();
        hashDefaultActions();
        makeActionsPretty();
        makeKeymap();
        createPopupMenu();
    }

    private String getProperty(String key) {
        return _resourceBundle.getString(key);
    }

    private void hashDefaultActions() {
        _actions = _initTextPane.getActions();
        String name = null;
        for (int i=0; i<_actions.length; i++) {
            name = (String)_actions[i].getValue( Action.NAME );
            _actionHashMap.put( name, _actions[i] );
        }
    }    

    private Action getHashedAction(String name) {
        return (Action)_actionHashMap.get( name );
    }

    private void makeActionsPretty() {
        Action a;
        a = getHashedAction( DefaultEditorKit.cutAction );
        a.putValue( Action.SMALL_ICON, loadImage( getProperty("Toolbar.Icons.cut") ) );
        a.putValue( Action.NAME, getProperty("Toolbar.cut") );

        a = getHashedAction( DefaultEditorKit.copyAction );
        a.putValue( Action.SMALL_ICON, loadImage( getProperty("Toolbar.Icons.copy") ) );
        a.putValue( Action.NAME, getProperty("Toolbar.copy") );

        a = getHashedAction( DefaultEditorKit.pasteAction );
        a.putValue( Action.SMALL_ICON, loadImage( getProperty("Toolbar.Icons.paste") ) );
        a.putValue( Action.NAME, getProperty("Toolbar.paste") );

        a = getHashedAction("font-bold");
        a.putValue( Action.SMALL_ICON, loadImage( getProperty("Toolbar.Icons.bold") ) );
        a.putValue( Action.NAME, getProperty("Toolbar.bold") );

        a = getHashedAction("font-italic");
        a.putValue( Action.SMALL_ICON, loadImage( getProperty("Toolbar.Icons.italic") ) );
        a.putValue( Action.NAME, getProperty("Toolbar.italic") );

        a = getHashedAction("font-underline");
        a.putValue( Action.SMALL_ICON, loadImage( getProperty("Toolbar.Icons.underline") ) );
        a.putValue( Action.NAME, getProperty("Toolbar.underline") );
    }    

    private void makeKeymap() {
        _keymap = JTextComponent.addKeymap( "NewKeymap", _initTextPane.getKeymap() );

        //KeyStroke next       = KeyStroke.getKeyStroke( KeyEvent.VK_RIGHT, InputEvent.CTRL_MASK, false);
        //KeyStroke prev       = KeyStroke.getKeyStroke( KeyEvent.VK_LEFT, InputEvent.CTRL_MASK, false);
        //KeyStroke selectNext = KeyStroke.getKeyStroke( KeyEvent.VK_RIGHT, InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK, false);
        //KeyStroke selectPrev = KeyStroke.getKeyStroke( KeyEvent.VK_LEFT, InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK, false);
        KeyStroke cut        = KeyStroke.getKeyStroke( KeyEvent.VK_X, InputEvent.CTRL_MASK, false);
        KeyStroke copy       = KeyStroke.getKeyStroke( KeyEvent.VK_C, InputEvent.CTRL_MASK, false);
        KeyStroke paste      = KeyStroke.getKeyStroke( KeyEvent.VK_V, InputEvent.CTRL_MASK, false);
        KeyStroke bold       = KeyStroke.getKeyStroke( KeyEvent.VK_B, InputEvent.CTRL_MASK, false);
        KeyStroke italic     = KeyStroke.getKeyStroke( KeyEvent.VK_I, InputEvent.CTRL_MASK, false);
        KeyStroke underline  = KeyStroke.getKeyStroke( KeyEvent.VK_U, InputEvent.CTRL_MASK, false);

        //_keymap.addActionForKeyStroke( next, getHashedAction( DefaultEditorKit.nextWordAction ) );
        //_keymap.addActionForKeyStroke( prev, getHashedAction( DefaultEditorKit.previousWordAction ) );
        //_keymap.addActionForKeyStroke( selectNext, getHashedAction( DefaultEditorKit.selectionNextWordAction ) );
        //_keymap.addActionForKeyStroke( selectPrev, getHashedAction( DefaultEditorKit.selectionPreviousWordAction ) );
        _keymap.addActionForKeyStroke( cut, getHashedAction( DefaultEditorKit.cutAction) );
        _keymap.addActionForKeyStroke( copy, getHashedAction( DefaultEditorKit.copyAction ) );
        _keymap.addActionForKeyStroke( paste, getHashedAction( DefaultEditorKit.pasteAction ) );
        _keymap.addActionForKeyStroke( bold, getHashedAction( "font-bold" ) );
        _keymap.addActionForKeyStroke( italic, getHashedAction( "font-italic" ) );
        _keymap.addActionForKeyStroke( underline, getHashedAction( "font-underline" ) );
    }

    private ImageIcon loadImage(String path) {
        URL imageURL = this.getClass().getResource( path );
        return new ImageIcon( imageURL );
    }

    private void createPopupMenu() {
        _popupMenu = new JPopupMenu();

        ArrayList<Action> actions = new ArrayList<Action>();
        actions.add( getHashedAction( DefaultEditorKit.cutAction ) );
        actions.add( getHashedAction( DefaultEditorKit.copyAction ) );
        actions.add( getHashedAction( DefaultEditorKit.pasteAction ) );

        JMenuItem mi = null;
        for (Action a : actions) {
            mi = new JMenuItem();
            mi.setAction(a);
            mi.setAccelerator(_keymap.getKeyStrokesForAction( a )[0] );
            _popupMenu.add(mi);
        }

        _popupMenu.addPopupMenuListener(new PopupMenuListener() {

            @Override
            public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
                System.out.println("will be visible");

            }

            @Override
            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                System.out.println("will be invisible");
                System.out.println("stop freeze");
                JTextPane tp = (JTextPane)_popupMenu.getInvoker();
                tp.getCaret().setBlinkRate(500);
                tp.getCaret().setVisible(false);
                //_popupOpened = false;
                tp.repaint();
                //tp.requestFocus();                
            }

            @Override
            public void popupMenuCanceled(PopupMenuEvent e) {
                System.out.println("menu canceled");
            }
        } );

        _popupMenu.addComponentListener( new ComponentAdapter() {
            @Override
            public void componentShown(ComponentEvent e) {
                System.out.println("menu shown");
            }
            @Override
            public void componentHidden(ComponentEvent e) {

            }

        });
    }

    boolean _popupOpened = false;

    public JTextPane createTextEditor() {
        final JTextPane tp = new JTextPane();
        _editors.add( tp );
        tp.setKeymap(_keymap);

        tp.addFocusListener(new FocusAdapter() {
            @Override
            public void focusLost(FocusEvent e) {
                if (_popupMenu.isShowing() && _popupMenu.getInvoker() == tp) {
                    JTextPane tp = (JTextPane)_popupMenu.getInvoker();
                    tp.getCaret().setBlinkRate(0);
                    tp.getCaret().setVisible(true);
                    tp.repaint();  
                }
            }
            @Override
            public void focusGained(FocusEvent e) {
                System.out.println("focus gained");
                for ( JTextPane t : _editors )
                    if ( t != tp )
                        t.setCaretPosition( t.getCaretPosition() );
            }
        });

        tp.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(final MouseEvent e) {
                System.out.println("mouse pressed");
                tp.requestFocus();
                if ( tp.getSelectionStart() == tp.getSelectionEnd() )
                    tp.setCaretPosition( tp.viewToModel( e.getPoint() ) );


                if ( e.isPopupTrigger() ) {
                    _popupMenu.show( e.getComponent(), e.getX(), e.getY() );
                }
            }
            @Override
            public void mouseReleased(MouseEvent e) {
                System.out.println("mouse released");
//                tp.requestFocus();
//                if ( e.isPopupTrigger() ) {
//                    _popupMenu.show( e.getComponent(), e.getX(), e.getY() );
//                }
            }
        });

        return tp;
    }

    public ArrayList<Action> getActionsForToolBar() {
        ArrayList<Action> actions = new ArrayList<Action>();
        actions.add( getHashedAction( DefaultEditorKit.cutAction ) );
        actions.add( getHashedAction( DefaultEditorKit.copyAction ) );
        actions.add( getHashedAction( DefaultEditorKit.pasteAction ) );
        actions.add( getHashedAction("font-bold") );
        actions.add( getHashedAction("font-italic") );
        actions.add( getHashedAction("font-underline") );
        return actions;
    }

    public ArrayList<JMenuItem> getMenuItems() {
        ArrayList<JMenuItem> items = new ArrayList<JMenuItem>();

        ArrayList<Action> actions = new ArrayList<Action>();
        actions.add( getHashedAction( DefaultEditorKit.cutAction ) );
        actions.add( getHashedAction( DefaultEditorKit.copyAction ) );
        actions.add( getHashedAction( DefaultEditorKit.pasteAction ) );

        JMenuItem mi = null;
        for (Action a : actions) {
            mi = new JMenuItem();
            mi.setAction(a);
            mi.setAccelerator(_keymap.getKeyStrokesForAction( a )[0] );
            items.add(mi);
        }            
        return items;
    }

}

public class TextEditorFrame2 extends LFrame {
    EditorUtil _editorUtil = new EditorUtil();
    JTextPane _tp;
    JTextPane _tp2;
    HashMap<String, Action> actionHashMap = new HashMap<String, Action>();

    public TextEditorFrame2() {
        setTitle("Editor");
        setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        _tp = _editorUtil.createTextEditor();
        _tp2 = _editorUtil.createTextEditor();

        add( createToolBar(), BorderLayout.NORTH );
        add( _tp, BorderLayout.CENTER );
        add( _tp2, BorderLayout.SOUTH );

        setJMenuBar( createMenuBar() );

        _tp.setDragEnabled(true);
        _tp2.setDragEnabled(true);

        //_tp.setContentType("text/rtf");
        _tp.setEditorKit(new RTFEditorKit());
        _tp2.setEditorKit(new RTFEditorKit());
        //_tp2.setContentType("text/rtf");

        System.out.println(_tp.getEditorKit());

        pack();
        setVisible(true);
        setLocation(200, 300);
    }

    private JToolBar createToolBar() {
        JToolBar tb = new JToolBar();
        ArrayList<Action> actions = _editorUtil.getActionsForToolBar();
        for (Action a : actions)
            tb.add( a );

        JButton button = new JButton("dump");
        tb.add(button);
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                DefaultStyledDocument doc = (DefaultStyledDocument)_tp.getStyledDocument();
                doc.dump(System.out);
            }
        });

        return tb;
    }

    private JMenuBar createMenuBar() {
        JMenuBar mb = new JMenuBar();
        JMenu edit = new JMenu("Edit");
        mb.add(edit);

        ArrayList<JMenuItem> items = _editorUtil.getMenuItems();
        for (JMenuItem i : items)
            edit.add( i );

        return mb;
    }

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

最佳答案

您可以尝试该套件http://java-sl.com/advanced_rtf_editor_kit.html

它支持比默认功能更多的 RTF 功能。它还支持复制/粘贴样式的内容。我猜它也可以与 D&D 一起使用。

关于java - 将样式文本拖放到另一个 JTextPane,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15021245/

相关文章:

java - 如何使水平滚动条出现在包含 JTextPane 组件的 JScrollPane 中

java - 如何在 C# Selenium WebDriver 中等待登录 cookie?

java - 名称和说明的字体大小 PDF 数字签名

带有 GUI 的 java ChatServer

java - 在 JtextPane 中突出显示单词时性能非常慢

java - JTextPane 附加一个新字符串

java - Eclipse 不会导出为 JAR

java - 如何在 libgdx 上记录更长的触摸以获得更高的跳跃

java - 在 Plot3DPanel 中的线程 "AWT-EventQueue-0"java.lang.NullPointerException 中获取异常

java - GUI动画: Slider Value between Action and Change classes?