3
  • 我对 Caret 有疑问,如果没有 focusGained(参见 Swing Action 中的代码)到第二个,Caret 不会闪烁。JTextField 并回到第一个。JTextField

  • 如何正确覆盖 DefaultCaret#setBlinkRate()

  • (没有覆盖插入符号)默认情况下是文档末尾的插入符号并在第 1 次闪烁。获得焦点


  • 在 win7_32b、Java7.011/025 / Java6 上测试

  • 使用一些标准 L&F 进行了测试,也是自定义的,每个都导致相同的问题

  • 有关更多详细信息,请参阅我对焦点丢失时如何在 JTextField 中保留选定文本的问题的回答以及@kleopatra 可能的解决方法


我的SSCCE

import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.text.DefaultCaret;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Highlighter;

public class TestTextComponents {

    private static final long serialVersionUID = 1L;
    private Timer timer;
    private JTextField jTextField0 = new JTextField();
    private JTextField jTextField1 = new JTextField();
    private JTextField jTextField2 = new JTextField();
    private JFrame frame = new JFrame("Default Caret");
    private JPanel panel = new JPanel();

    public TestTextComponents() {
        jTextField0.setText("jTextField0");
        jTextField1.setText("jTextField1");
        jTextField2.setText("jTextField2");
        jTextField1.setCaret(new HighlightCaret());
        jTextField2.setCaret(new HighlightCaret());
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        panel.add(new JLabel("Please skip between text fields and watch persistent selection: "));
        panel.add(jTextField0);
        panel.add(jTextField1);
        panel.add(jTextField2);
        frame.add(panel);
        frame.setTitle("Text component persistent selection");
        frame.pack();
        frame.setVisible(true);
        /*timer = new javax.swing.Timer(250, updateCol());
        timer.setRepeats(false);
        timer.start();*/
    }

    private Action updateCol() {
        return new AbstractAction("Hello World") {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                jTextField2.grabFocus();
                jTextField2.requestFocusInWindow();
                jTextField1.grabFocus();
                jTextField1.requestFocusInWindow();
            }
        };
    }

    private class HighlightCaret extends DefaultCaret {

        private static final long serialVersionUID = 1L;
        private final Highlighter.HighlightPainter unfocusedPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.RED);
        private final Highlighter.HighlightPainter focusedPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.ORANGE);
        private boolean isFocused;

        @Override
        protected Highlighter.HighlightPainter getSelectionPainter() {
            return isFocused ? focusedPainter /*super.getSelectionPainter()*/ : unfocusedPainter;
        }

        @Override
        public void setSelectionVisible(boolean hasFocus) {
            super.repaint();
            super.setBlinkRate(500);
            if (hasFocus != isFocused) {
                isFocused = hasFocus;
                super.setSelectionVisible(false);
                super.setSelectionVisible(true);
            }
        }
    }

    public static void main(String args[]) {
        /*try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(laf.getName())) {
                    UIManager.setLookAndFeel(laf.getClassName());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }*/
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TestTextComponents();
            }
        });
    }
}
4

3 回答 3

2

闪烁的插入符号由setVisible()DefaultCaret 的方法控制。所选文本由该setSelectionVisible()方法控制。

DefaultCaret的focusGained/focusLost方法使用这两种方法来控制 Caret 的行为。默认情况下,focusGained 的两个属性都设置为 true。在 focusLost 上,它们被设置为 false。使用不同荧光笔的基本逻辑,您可以执行以下操作:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;

public class SelectionCaret extends DefaultCaret
{
    private final Highlighter.HighlightPainter unfocusedPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.RED);
    private final Highlighter.HighlightPainter focusedPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.ORANGE);

    public SelectionCaret()
    {
        setBlinkRate( UIManager.getInt("TextField.caretBlinkRate") );
    }

    @Override
    protected Highlighter.HighlightPainter getSelectionPainter()
    {
        return getComponent().hasFocus() ? focusedPainter : unfocusedPainter;
    }

    @Override
    public void focusGained(FocusEvent e)
    {
        setSelectionVisible(false);
        super.focusGained(e);
    }

    @Override
    public void focusLost(FocusEvent e)
    {
        super.focusLost(e);
        setSelectionVisible(true);
    }

    private static void createAndShowUI()
    {
        JTextField textField1 = new JTextField("Text Field1   ");
        JTextField textField2 = new JTextField("Text Field2   ");
        JTextField textField3 = new JTextField("Non Editable   ");
        textField3.setEditable(false);

        textField1.setCaret(new SelectionCaret());
        textField2.setCaret(new SelectionCaret());
        textField3.setCaret(new SelectionCaret());

        textField1.select(5, 11);
        textField2.select(5, 11);
        textField3.select(5, 11);
        ((DefaultCaret)textField1.getCaret()).setSelectionVisible(true);
        ((DefaultCaret)textField2.getCaret()).setSelectionVisible(true);
        ((DefaultCaret)textField3.getCaret()).setSelectionVisible(true);

        JPanel north = new JPanel();
        north.add( new JTextField("Text Field0   ") );
        north.add(textField1);
        north.add(textField2);
        north.add(textField3);

        JFrame frame = new JFrame("Selection Caret");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( north );
        frame.pack();
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowUI();
            }
        });
    }
}

现在将在两个文本字段中选择任何文本,但只有具有焦点的文本字段会闪烁。

于 2013-08-15T00:59:04.900 回答
2

我找到了解决方案。覆盖focusGained您的方法HighlightCaret并在那里设置闪烁率。

    @Override
    public void focusGained(FocusEvent e)
    {
        isFocused = true;
        super.setBlinkRate(500);
        super.focusGained(e);
    }

这在 OS X 中对我有用。

于 2013-08-14T22:47:01.527 回答
1

但是如果放在类构造函数中,您之前的代码可以正常工作:setBlinkRate(500);HighlightCaret

class HighlightCaret extends DefaultCaret {

    private static final Highlighter.HighlightPainter unfocusedPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.RED);
    private static final Highlighter.HighlightPainter focusedPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.YELLOW);
    private static final long serialVersionUID = 1L;
    private boolean isFocused;

    HighlightCaret(){
     setBlinkRate(500);//Placed here
    }

    @Override
    protected Highlighter.HighlightPainter getSelectionPainter() {
       // setBlinkRate(500); // otherwise is disabled, stopped
        return isFocused ? focusedPainter/*super.getSelectionPainter()*/ : unfocusedPainter;
    }

    @Override
    public void setSelectionVisible(boolean hasFocus) {
        if (hasFocus != isFocused) {
            isFocused = hasFocus;
            super.setSelectionVisible(false);
            super.setSelectionVisible(true);
        }
    }
}

在 Java7 WinXP 中测试。你试过了吗?

于 2013-08-15T07:24:48.617 回答