更改JButton颜色并同时移动JTextArea Caret

时间:2014-08-02 01:55:49

标签: java swing import jbutton jtextarea

我正在编写一个有键盘和JTextArea的程序。按下按钮后,按钮的颜色应与插入符号位置一起改变。我使用了Key Binding。现在,如果我先改变颜色然后移动插入符号,只有插入符号移动但颜色不会改变,反之亦然。以下是我的代码示例:(我有许多面板来组织其余按钮......)

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.ButtonGroup;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;

public class KeyboardTest extends JFrame {

public static final JTextArea textToType = new JTextArea("jjj jjj jjj jjj kkk kkk kkk kkk jjj kkk jjj kkk jjj kkk jkj jkj jkj jkj kjk kjk kjk \r\nkjk jjj jjj jjj kkk kkk kkk jk jk jk kj kj kj jj kk jk kj kj jk jj jk kk kj j j j j k \r\nk k k j k k j j k k j jkj jjk kjj kkj jkk kkk jjj kjk");
public static final int caretPosition = 0;

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

public KeyboardTest() {
    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            try {
        UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
            } catch (Exception ex) {
                try {
                    UIManager.setLookAndFeel(UIManager
                            .getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException
                        | IllegalAccessException
                        | UnsupportedLookAndFeelException e) {
                    e.printStackTrace();
                }
            }
            JFrame frame = new JFrame("Testing");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLayout(new BorderLayout());
            frame.add(new TestPane());
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
            frame.setBounds(100, 100, 650, 390);
        }
    });

}

public class TestPane extends JPanel {

    public TestPane() {
        JPanel contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        add(contentPane);
        GridBagLayout gbl_contentPane = new GridBagLayout();
        gbl_contentPane.columnWidths = new int[] { 614, 0 };
        gbl_contentPane.rowHeights = new int[] { 31, 14, 51, 181, 25, 0 };
        gbl_contentPane.columnWeights = new double[] { 0.0,
                Double.MIN_VALUE };
        gbl_contentPane.rowWeights = new double[] { 0.0, 0.0, 0.0, 0.0,
                0.0, Double.MIN_VALUE };
        contentPane.setLayout(gbl_contentPane);

        JLabel title = new JLabel(
                "Our first touch typing lesson introduces 2 home row keys for the right hand: j k");
        GridBagConstraints gbc_title = new GridBagConstraints();
        gbc_title.fill = GridBagConstraints.BOTH;
        gbc_title.insets = new Insets(0, 0, 5, 0);
        gbc_title.gridx = 0;
        gbc_title.gridy = 1;
        contentPane.add(title, gbc_title);

        textToType.setEditable(false);
        textToType.setFont(new Font("Lucida Console", Font.PLAIN, 12));
        textToType.setBackground(new Color(255, 250, 205));
        textToType
                .setText("jjj jjj jjj jjj kkk kkk kkk kkk jjj kkk jjj kkk jjj kkk jkj jkj jkj jkj kjk kjk kjk \r\nkjk jjj jjj jjj kkk kkk kkk jk jk jk kj kj kj jj kk jk kj kj jk jj jk kk kj j j j j k \r\nk k k j k k j j k k j jkj jjk kjj kkj jkk kkk jjj kjk");
        textToType.getCaret().setVisible(true);
        textToType.setCaretPosition(caretPosition);
        textToType.setFocusable(false);
        GridBagConstraints gbc_textToType = new GridBagConstraints();
        gbc_textToType.fill = GridBagConstraints.BOTH;
        gbc_textToType.insets = new Insets(0, 0, 5, 0);
        gbc_textToType.gridx = 0;
        gbc_textToType.gridy = 2;
        contentPane.add(textToType, gbc_textToType);

        JPanel keyboardPanel = new JPanel();
        GridBagConstraints gbc_keyboardPanel = new GridBagConstraints();
        gbc_keyboardPanel.fill = GridBagConstraints.BOTH;
        gbc_keyboardPanel.insets = new Insets(0, 0, 5, 0);
        gbc_keyboardPanel.gridx = 0;
        gbc_keyboardPanel.gridy = 3;
        contentPane.add(keyboardPanel, gbc_keyboardPanel);
        keyboardPanel.setLayout(new GridLayout(5, 0, 0, 0));

        JPanel kPanel1 = new JPanel();
        keyboardPanel.add(kPanel1);
        kPanel1.setLayout(null);

        JPanel buttonspanel1 = new JPanel();
        buttonspanel1.setBounds(0, 0, 523, 36);
        kPanel1.add(buttonspanel1);
        buttonspanel1.setLayout(new GridLayout(0, 13, 0, 5));

        JButton one = new JButton("1");
        one.setFocusable(false);
        buttonspanel1.add(one);

        addKeyBindingGreen(one, "1", KeyEvent.VK_1);

        addKeyBinding(one, "1", KeyEvent.VK_1);
}
//Key Binding to change the button to green...

        protected void addKeyBindingGreen(JButton btn, String name,
            int virtualKey) {
        ActionMap am = getActionMap();
        InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);

        im.put(KeyStroke.getKeyStroke(virtualKey, 0, false), name
                + ".pressed");
        im.put(KeyStroke.getKeyStroke(virtualKey, 0, true), name
                + ".released");

        am.put(name + ".pressed", new KeyActionGreen(btn, true));
        am.put(name + ".released", new KeyActionGreen(btn, false));
    }

 //Key binding to move the caret

        protected void addKeyBinding(JButton btn, String name,
            int virtualKey) {
        ActionMap am = getActionMap();
        InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);

        im.put(KeyStroke.getKeyStroke(virtualKey, 0, false), name
                + ".pressed");
        im.put(KeyStroke.getKeyStroke(virtualKey, 0, true), name
                + ".released");

        am.put(name + ".pressed", new KeyAction(btn, true, caretPosition));
        am.put(name + ".released", new KeyAction(btn, false, caretPosition ));
    }
}
public class KeyAction extends AbstractAction {

    private JButton btn;
    private boolean cur;
    private int caretPosition;

    public KeyAction(JButton btn, boolean cur, int caretPosition) {
        this.btn = btn;
        this.cur = cur;
        this.caretPosition = caretPosition;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (cur) {
            btn.getModel().setPressed(true);
            textToType.setCaretPosition(caretPosition++);
        } else {
            btn.getModel().setPressed(false);
        }
    }

}
public class KeyActionGreen extends AbstractAction {

    private JButton btn;
    private boolean highlight;

    public KeyActionGreen(JButton btn, boolean highlight) {
        this.btn = btn;
        this.highlight = highlight;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (highlight) {
            btn.getModel().setPressed(true);
            btn.setBackground(Color.GREEN);
            btn.setOpaque(true);
        } else {
            btn.getModel().setPressed(false);
            btn.setBackground(null);
            btn.setOpaque(false);
        }
    }

    }
}

2 个答案:

答案 0 :(得分:1)

您正在Actionname + ".pressed"方法中向name + ".released"ActionMap的{​​{1}}和addKeyBinding键添加addKeyBindingGreen

AcationMapMapMap的行为是每个键只能包含一个值。如果您尝试将两个值放在同一个键上,那么您输入的第一个值将被第二个值推出,在您的情况下,该值将是您添加第二个值的Action

唯一的选择是将您想要的代码合并到一个Action

答案 1 :(得分:1)

<强>更新

有三个核心问题,

问题#1

您将caretPosition(从KeyboardTest)的值传递给KeyAction,问题是KeyAction只会更新{的{1}}类实例{1}}相对于它自己,也就是说,如果您有两个caretPosition实例,它们将有两个单独的值,并将单独更新。

这是因为Java中的参数是按值传递的,而不是通过引用...

传递的

您可以传递包含KeyAction值的对象,确保将相同的实例传递给所有按钮。这样一来,动作就是修改相同的值,或者你可以简单地让动作引用类实例字段......

int

问题#2

您正在进行public int caretPosition = 0; //... public class KeyAction extends AbstractAction { private JButton btn; private boolean cur; public KeyAction(JButton btn, boolean cur) { this.btn = btn; this.cur = cur; } @Override public void actionPerformed(ActionEvent e) { if (cur) { btn.getModel().setPressed(true); textToType.setCaretPosition(caretPosition++); } else { btn.getModel().setPressed(false); } } } 的后期增量而不是预增量...

caretPosition

这意味着,textToType.setCaretPosition(caretPosition++); 的值仅在caretPosition返回后更改,这意味着第一次触发操作时,它的值为0,仍然......

您应该将其更改为更像......

setCaretPosition

问题#3

正如已经指出的那样,您只能通过textToType.setCaretPosition(++caretPosition); / Action绑定将KeyStroke附加到ActionMap

这给你留下了至少三个基本选项......

一...

您可以自行承认,您只能指定一个InputMap并且必须决定哪一个是最佳选择......

在这种情况下,您“可以”将另一个ActionAction附加到各个按钮,例如,可以执行另一个ActionListener ...但您需要确保键绑定Action触发了按钮,例如使用Action之类的内容...

双...

设计一个“可链接的”JButton#doClick,它能够获取Action的列表,并在触发时触发这些操作......

Action

上面的例子确实有一个问题,它没有“配置”属性,因此无法与public class ChainableAction extends AbstractAction { private List<Action> actions; public ChainableAction(Action... actions) { this.actions = new ArrayList<>(Arrays.asList(actions)); } @Override public void actionPerformed(ActionEvent e) { for (Action action : actions) { action.actionPerformed(e); } } } 之类的东西一起使用。您可以通过构造函数提供配置信息(例如图标和文本)。

三...

设置一个继承链,其中颜色JMenuItem和文本Action能够以形式或其他方式相互延伸,然后您只需使用最终的子Action对于绑定...

Action

然后你就可以将public class KeyAction extends ColorActionGreen { private JButton btn; private boolean cur; private int caretPosition; public KeyAction(JButton btn, boolean cur, int caretPosition, boolean highlight) { super(btn, highlight); this.btn = btn; this.cur = cur; this.caretPosition = caretPosition; } @Override public void actionPerformed(ActionEvent e) { super.actionPerformed(e); if (cur) { btn.getModel().setPressed(true); textToType.setCaretPosition(caretPosition++); } else { btn.getModel().setPressed(false); } } } public class ColorActionGreen extends AbstractAction { private JButton btn; private boolean highlight; public ColorActionGreen(JButton btn, boolean highlight) { this.btn = btn; this.highlight = highlight; } @Override public void actionPerformed(ActionEvent e) { if (highlight) { btn.getModel().setPressed(true); btn.setBackground(Color.GREEN); btn.setOpaque(true); } else { btn.getModel().setPressed(false); btn.setBackground(null); btn.setOpaque(false); } } } 用于所有绑定甚至KeyAction自己...