Java 如何使用Ctrl+;Z和Ctrl+;所有文本组件的Y?

Java 如何使用Ctrl+;Z和Ctrl+;所有文本组件的Y?,java,swing,undo,swingx,redo,Java,Swing,Undo,Swingx,Redo,事实上,我知道如何在一个JTextField中使用CTRL+Z(Undo)和CTRL+Y(Redo)。但是我的Swing应用程序中有数百个文本组件,所以有没有办法将其应用于我的应用程序中的所有文本组件,所以当我在任何文本组件中单击CTRL+Z时,它会撤消该字段中的最后一个条目 我曾尝试在中实现它,但没有成功 如果您想在应用程序上运行“全局事件”,而不管您当前的焦点在哪里,则需要使用KeyboardFocusManager: KeyboardFocusManager kfm = Keybo

事实上,我知道如何在一个JTextField中使用CTRL+Z(Undo)和CTRL+Y(Redo)。但是我的Swing应用程序中有数百个文本组件,所以有没有办法将其应用于我的应用程序中的所有文本组件,所以当我在任何文本组件中单击CTRL+Z时,它会撤消该字段中的最后一个条目

我曾尝试在中实现它,但没有成功

如果您想在应用程序上运行“全局事件”,而不管您当前的焦点在哪里,则需要使用KeyboardFocusManager:

    KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
    kfm.addKeyEventDispatcher(new KeyEventDispatcher() {

        @Override
        public boolean dispatchKeyEvent(KeyEvent e) {
            // do your stuff here
            return done;
        }
    });
希望这有帮助。

  • 您可以在API的

  • 请注意,您必须检查或准备代码以获得所有可访问的外观

  • 您可以使用内置的键绑定快捷方式,并按预期替换,系统剪贴板经常被修改

  • 从未尝试过,但在这个论坛上,你可以提供相关信息如何更改、替换键绑定快捷方式

内置键绑定快捷方式列表

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
import javax.swing.filechooser.*;

public class KeyBindings implements ItemListener {

    private static final String PACKAGE = "javax.swing.";
    private static final String[] COLUMN_NAMES = {"Action", "When Focused", "When In Focused Window", "When Ancestor"};
    private static String selectedItem;
    private JComponent contentPane;
    private JMenuBar menuBar;
    private JTable table;
    private JComboBox comboBox;
    private Hashtable<String, DefaultTableModel> models;

    /*
     *  Constructor
     */
    public KeyBindings() {
        models = new Hashtable<String, DefaultTableModel>();
        contentPane = new JPanel(new BorderLayout());
        contentPane.add(buildNorthComponent(), BorderLayout.NORTH);
        contentPane.add(buildCenterComponent(), BorderLayout.CENTER);
        resetComponents();
    }

    /*
     *  The content pane should be added to a high level container
     */
    public JComponent getContentPane() {
        return contentPane;
    }

    /*
     *  A menu can also be added which provides the ability to switch
     *  between different LAF's.
     */
    public JMenuBar getMenuBar() {
        if (menuBar == null) {
            menuBar = createMenuBar();
        }
        return menuBar;
    }

    /*
     *  This panel is added to the North of the content pane
     */
    private JComponent buildNorthComponent() {
        comboBox = new JComboBox();
        JLabel label = new JLabel("Select Component:");
        label.setDisplayedMnemonic('S');
        label.setLabelFor(comboBox);
        JPanel panel = new JPanel();
        panel.setBorder(new EmptyBorder(15, 0, 15, 0));
        panel.add(label);
        panel.add(comboBox);
        return panel;
    }

    /*
     *  Check the key name to see if it is the UI property
     */
    private String checkForUIKey(String key) {
        if (key.endsWith("UI") && key.indexOf('.') == -1) {
            String componentName = key.substring(0, key.length() - 2);//  Ignore these components
            if (componentName.equals("PopupMenuSeparator") || componentName.equals("ToolBarSeparator") || componentName.equals("DesktopIcon")) {
                return null;
            } else {
                return componentName;
            }
        }
        return null;
    }

    /*
     **  Build the emtpy table to be added in the Center
     */
    private JComponent buildCenterComponent() {
        DefaultTableModel model = new DefaultTableModel(COLUMN_NAMES, 0);
        table = new JTable(model) {

            private static final long serialVersionUID = 1L;

            @Override
            public boolean isCellEditable(int row, int column) {
                return false;
            }
        };
        table.setAutoCreateColumnsFromModel(false);
        table.getColumnModel().getColumn(0).setPreferredWidth(200);
        table.getColumnModel().getColumn(1).setPreferredWidth(200);
        table.getColumnModel().getColumn(2).setPreferredWidth(200);
        table.getColumnModel().getColumn(3).setPreferredWidth(200);
        Dimension d = table.getPreferredSize();
        d.height = 350;
        table.setPreferredScrollableViewportSize(d);
        table.getTableHeader().setFocusable(true);
        return new JScrollPane(table);
    }

    /*
     *  When the LAF is changed we need to reset all the items
     */
    private void resetComponents() {
        models.clear();
        ((DefaultTableModel) table.getModel()).setRowCount(0);
        Vector<String> comboBoxItems = new Vector<String>(50);//        buildItemsMap();
        UIDefaults defaults = UIManager.getLookAndFeelDefaults();
        for (Object key : defaults.keySet()) { //  All Swing components will have a UI property.
            String componentName = checkForUIKey(key.toString());
            if (componentName != null) {
                comboBoxItems.add(componentName);
            }
        }
        Collections.sort(comboBoxItems);
        comboBox.removeItemListener(this);
        comboBox.setModel(new DefaultComboBoxModel(comboBoxItems));
        comboBox.setSelectedIndex(-1);
        comboBox.addItemListener(this);
        comboBox.requestFocusInWindow();
        if (selectedItem != null) {
            comboBox.setSelectedItem(selectedItem);
        }
    }

    /**
     *  Create menu bar
     */
    private JMenuBar createMenuBar() {
        JMenuBar menuBar1 = new JMenuBar();
        menuBar1.add(createFileMenu());
        menuBar1.add(createLAFMenu());
        return menuBar1;
    }

    /**
     *  Create menu items for the Application menu
     */
    private JMenu createFileMenu() {
        JMenu menu = new JMenu("Application");
        menu.setMnemonic('A');
        menu.addSeparator();
        menu.add(new ExitAction());
        return menu;
    }

    /**
     *  Create menu items for the Look & Feel menu
     */
    private JMenu createLAFMenu() {
        ButtonGroup bg = new ButtonGroup();
        JMenu menu = new JMenu("Look & Feel");
        menu.setMnemonic('L');
        String lafId = UIManager.getLookAndFeel().getID();
        UIManager.LookAndFeelInfo[] lafInfo = UIManager.getInstalledLookAndFeels();
        for (int i = 0; i < lafInfo.length; i++) {
            String laf = lafInfo[i].getClassName();
            String name = lafInfo[i].getName();
            Action action = new ChangeLookAndFeelAction(laf, name);
            JRadioButtonMenuItem mi = new JRadioButtonMenuItem(action);
            menu.add(mi);
            bg.add(mi);
            if (name.equals(lafId)) {
                mi.setSelected(true);
            }
        }
        return menu;
    }

    /*
     *  Implement the ItemListener interface
     */
    @Override
    public void itemStateChanged(ItemEvent e) {
        String componentName = (String) e.getItem();
        changeTableModel(getClassName(componentName));
        selectedItem = componentName;
    }

    /*
     *  Use the component name to build the class name
     */
    private String getClassName(String componentName) {
        if (componentName.equals("TableHeader")) {//  The table header is in a child package
            return PACKAGE + "table.JTableHeader";
        } else {
            return PACKAGE + "J" + componentName;
        }
    }

    /*
     *  Change the TabelModel in the table for the selected component
     */
    private void changeTableModel(String className) {
        DefaultTableModel model = models.get(className); //  Check if we have already built the table model for this component
        if (model != null) {
            table.setModel(model);
            return;
        }
        model = new DefaultTableModel(COLUMN_NAMES, 0); //  Create an empty table to start with
        table.setModel(model);
        models.put(className, model);
        JComponent component = null; //  Create an instance of the component so we can get the default Action map and Input maps
        try {
            if (className.endsWith("JFileChooser")) {//  Hack so I don't have to sign the jar file for usage in  Java Webstart
                component = new JFileChooser(new DummyFileSystemView());
            } else {
                Object o = Class.forName(className).newInstance();
                component = (JComponent) o;
            }
        } catch (Exception e) {
            Object[] row = {e.toString(), "", "", ""};
            model.addRow(row);
            return;
        }
        ActionMap actionMap = component.getActionMap(); //  Not all components have Actions defined
        Object[] keys = actionMap.allKeys();
        if (keys == null) {
            Object[] row = {"No actions found", "", "", ""};
            model.addRow(row);
            return;
        }
        //  In some ActionMaps a key of type Object is found (I have no idea why)
        //  which causes a ClassCastExcption when sorting so we will ignore it
        //  by converting that entry to the empty string
        for (int i = 0; i < keys.length; i++) {
            Object key = keys[i];
            if (key instanceof String) {
                continue;
            } else {
                keys[i] = "";
            }
        }
        Arrays.sort(keys);
        for (int i = 0; i < keys.length; i++) { //  Create a new row in the model for every Action found
            Object key = keys[i];
            if (key != "") {
                Object[] row = {key, "", "", ""};
                model.addRow(row);
            }
        }
        //  Now check each InputMap to see if a KeyStroke is bound the the Action
        updateModelForInputMap(model, 1, component.getInputMap(JComponent.WHEN_FOCUSED));
        updateModelForInputMap(model, 2, component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW));
        updateModelForInputMap(model, 3, component.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT));
    }

    /*
     *  The model is potentially update for each of the 3 different InputMaps
     */
    private void updateModelForInputMap(TableModel model, int column, InputMap inputMap) {
        if (inputMap == null) {
            return;
        }
        KeyStroke[] keys = inputMap.allKeys();
        if (keys == null) {
            return;
        }
        //  The InputMap is keyed by KeyStroke, however we want to be able to
        //  access the action names that are bound to a KeyStroke so we will create
        //  a Hashtble that is keyed by action name.
        //  Note that multiple KeyStrokes can be bound to the same action name.
        Hashtable<Object, String> actions = new Hashtable<Object, String>(keys.length);
        for (int i = 0; i < keys.length; i++) {
            KeyStroke key = keys[i];
            Object actionName = inputMap.get(key);
            Object value = actions.get(actionName);
            if (value == null) {
                actions.put(actionName, key.toString().replace("pressed ", ""));
            } else {
                actions.put(actionName, value + ", " + key.toString().replace("pressed ", ""));
            }
        }
        for (int i = 0; i < model.getRowCount(); i++) {
            //  Now we can update the model for those actions that have  KeyStrokes mapped to them
            String o = actions.get(model.getValueAt(i, 0));
            if (o != null) {
                model.setValueAt(o.toString(), i, column);
            }
        }
    }

    /*
     *  Change the LAF and recreate the UIManagerDefaults so that the properties
     *  of the new LAF are correctly displayed.
     */
    private class ChangeLookAndFeelAction extends AbstractAction {

        private static final long serialVersionUID = 1L;
        private String laf;

        protected ChangeLookAndFeelAction(String laf, String name) {
            this.laf = laf;
            putValue(Action.NAME, name);
            putValue(Action.SHORT_DESCRIPTION, getValue(Action.NAME));
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            try {
                JMenuItem mi = (JMenuItem) e.getSource();
                JPopupMenu popup = (JPopupMenu) mi.getParent();
                JRootPane rootPane = SwingUtilities.getRootPane(popup.getInvoker());
                Component c = rootPane.getContentPane().getComponent(0);
                rootPane.getContentPane().remove(c);
                UIManager.setLookAndFeel(laf);
                KeyBindings bindings = new KeyBindings();
                rootPane.getContentPane().add(bindings.getContentPane());
                SwingUtilities.updateComponentTreeUI(rootPane);
                rootPane.requestFocusInWindow();
            } catch (Exception ex) {
                System.out.println("Failed loading L&F: " + laf);
                System.out.println(ex);
            }
        }
    }

    private class ExitAction extends AbstractAction {

        private static final long serialVersionUID = 1L;

        public ExitAction() {
            putValue(Action.NAME, "Exit");
            putValue(Action.SHORT_DESCRIPTION, getValue(Action.NAME));
            putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_X));
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            System.exit(0);
        }
    }

    private class DummyFileSystemView extends FileSystemView {

        @Override
        public File createNewFolder(File containingDir) {
            return null;
        }

        @Override
        public File getDefaultDirectory() {
            return null;
        }

        @Override
        public File getHomeDirectory() {
            return null;
        }
    }

    private static void createAndShowGUI() {
        KeyBindings application = new KeyBindings();
        JFrame.setDefaultLookAndFeelDecorated(true);
        JFrame frame = new JFrame("Key Bindings");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setJMenuBar(application.getMenuBar());
        frame.getContentPane().add(application.getContentPane());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        //UIManager.put("swing.boldMetal", Boolean.FALSE);
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                createAndShowGUI();
            }
        });
    }
}
import java.awt.*;
导入java.awt.event.*;
导入java.io.*;
导入java.util.*;
导入javax.swing.*;
导入javax.swing.border.*;
导入javax.swing.table.*;
导入javax.swing.filechooser.*;
公共类键绑定实现ItemListener{
私有静态最终字符串包=“javax.swing。”;
private static final String[]COLUMN_NAMES={“操作”、“聚焦时”、“在聚焦窗口中时”、“祖先时”};
私有静态字符串selectedItem;
私有JComponentContentPane;
私人杰门努巴·梅努巴;
专用JTable表;
专用JComboBox组合框;
私有哈希表模型;
/*
*建造师
*/
公钥绑定(){
models=新哈希表();
contentPane=newjpanel(newborderlayout());
添加(buildNorthComponent(),BorderLayout.NORTH);
添加(buildCenterComponent(),BorderLayout.CENTER);
重置组件();
}
/*
*内容窗格应添加到高级容器中
*/
公共JComponent getContentPane(){
返回内容窗格;
}
/*
*还可以添加一个提供切换功能的菜单
*在不同的LAF之间。
*/
公共JMenuBar getMenuBar(){
如果(菜单栏==null){
menuBar=createMenuBar();
}
返回菜单栏;
}
/*
*此面板将添加到内容窗格的北部
*/
专用JComponent buildNorthComponent(){
comboBox=新的JComboBox();
JLabel标签=新的JLabel(“选择组件:”);
label.setDisplayedMnemonic('S');
label.setLabelFor(组合框);
JPanel面板=新的JPanel();
面板。设定顺序(新的清空顺序(15,0,15,0));
面板。添加(标签);
panel.add(组合框);
返回面板;
}
/*
*检查键名称以查看它是否是UI属性
*/
私有字符串checkForUIKey(字符串密钥){
if(key.endsWith(“UI”)&&key.indexOf('.')=-1){
String componentName=key.substring(0,key.length()-2);//忽略这些组件
if(componentName.equals(“PopupMenuSeparator”)| | componentName.equals(“工具栏分隔符”)| | componentName.equals(“桌面图标”)){
返回null;
}否则{
返回组件名称;
}
}
返回null;
}
/*
**构建要添加到中心的emtpy表
*/
私有JComponent buildCenterComponent(){
DefaultTableModel=新的DefaultTableModel(列名称,0);
表=新JTable(型号){
私有静态最终长serialVersionUID=1L;
@凌驾
公共布尔值可编辑(int行,int列){
返回false;
}
};
表.setAutoCreateColumnsFromModel(false);
table.getColumnModel().getColumn(0).setPreferredWidth(200);
table.getColumnModel().getColumn(1).setPreferredWidth(200);
table.getColumnModel().getColumn(2).setPreferredWidth(200);
table.getColumnModel().getColumn(3).setPreferredWidth(200);
维度d=table.getPreferredSize();
d、 高度=350;
表.setPreferredScrollableViewportSize(d);
table.getTableHeader().setFocusable(true);
返回新的JScrollPane(表);
}
/*
*更改LAF时,我们需要重置所有项目
*/
私有组件(){
模型。清除();
((DefaultTableModel)table.getModel()).setRowCount(0);
Vector comboBoxItems=新向量(50);//buildItemsMap();
UIDefaults=UIManager.getLookAndFeelDefaults();
对于(对象键:defaults.keySet()){//所有Swing组件都将具有UI属性。
String componentName=checkForUIKey(key.toString());
if(组件名称!=null){
comboBoxItems.add(组件名称);
}
}
Collections.sort(comboBoxItems);
comboBox.removeItemListener(此);
setModel(新的DefaultComboxModel(comboBoxItems));
comboBox.setSelectedIndex(-1);
comboBox.addItemListener(此);
comboBox.requestFocusInWindow();
如果(selectedItem!=null){
comboBox.setSelectedItem(selectedItem);
}
}
/**
*创建菜单栏
*/
私有JMenuBar createMenuBar(){
JMenuBar menuBar1=新的JMenuBar();
添加(createFileMenu());
menuBar1.add(createLAFMenu());
返回菜单1;
}
/**
*为应用程序菜单创建菜单项
*/
私有JMenu createFileMenu(){
JMenu菜单=新JMenu(“应用程序”);
menu.set助记符('A');
menu.addSeparator();
menu.add(newexitAction());
public class MyTextField extends JTextField {
    public MyTextField() {
        final UndoManager undoMgr = new UndoManager();

        // Add listener for undoable events
        getDocument().addUndoableEditListener(new UndoableEditListener() {
            public void undoableEditHappened(UndoableEditEvent pEvt) {
                undoMgr.addEdit(pEvt.getEdit());
            }
        });

        // Add undo/redo actions
        getActionMap().put(UNDO_ACTION, new AbstractAction(UNDO_ACTION) {
            public void actionPerformed(ActionEvent pEvt) {
                try {
                    if (undoMgr.canUndo()) {
                        undoMgr.undo();
                    }
                } catch (CannotUndoException e) {
                    e.printStackTrace();
                }
            }
        });
        getActionMap().put(REDO_ACTION, new AbstractAction(REDO_ACTION) {
            public void actionPerformed(ActionEvent pEvt) {
                try {
                    if (undoMgr.canRedo()) {
                        undoMgr.redo();
                    }
                } catch (CannotRedoException e) {
                    e.printStackTrace();
                }
            }
        });

        // Create keyboard accelerators for undo/redo actions (Ctrl+Z/Ctrl+Y)
        getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK),
            UNDO_ACTION);
        getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK),
            REDO_ACTION);
    }
}
public final static String UNDO_ACTION = "Undo";

public final static String REDO_ACTION = "Redo";

public static void makeUndoable(JTextComponent pTextComponent) {
    final UndoManager undoMgr = new UndoManager();

    // Add listener for undoable events
    pTextComponent.getDocument().addUndoableEditListener(new UndoableEditListener() {
        public void undoableEditHappened(UndoableEditEvent evt) {
            undoMgr.addEdit(evt.getEdit());
        }
    });

    // Add undo/redo actions
    pTextComponent.getActionMap().put(UNDO_ACTION, new AbstractAction(UNDO_ACTION) {
        public void actionPerformed(ActionEvent evt) {
            try {
                if (undoMgr.canUndo()) {
                    undoMgr.undo();
                }
            } catch (CannotUndoException e) {
                e.printStackTrace();
            }
        }
    });
    pTextComponent.getActionMap().put(REDO_ACTION, new AbstractAction(REDO_ACTION) {
        public void actionPerformed(ActionEvent evt) {
            try {
                if (undoMgr.canRedo()) {
                    undoMgr.redo();
                }
            } catch (CannotRedoException e) {
                e.printStackTrace();
            }
        }
    });

    // Create keyboard accelerators for undo/redo actions (Ctrl+Z/Ctrl+Y)
    pTextComponent.getInputMap().put(
        KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK), UNDO_ACTION);
    pTextComponent.getInputMap().put(
        KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK), REDO_ACTION);
}