如何覆盖 DefaultCaret#setBlinkRate()

Posted

技术标签:

【中文标题】如何覆盖 DefaultCaret#setBlinkRate()【英文标题】:How to override DefaultCaret#setBlinkRate() 【发布时间】:2013-08-17 01:50:23 【问题描述】:

我的插入符号有问题,插入符号没有焦点没有闪烁(参见 Swing Action 中的代码)到第二个。 JTextField 并回到第一个。 JTextField

如何正确覆盖 DefaultCaret#setBlinkRate()

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


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

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

更多详情请查看我对问题How to retain selected text in JTextField when focus lost?和possible workaround by @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();
            
        );
    

【问题讨论】:

这没有意义。焦点插入符号只会显示具有当前键盘焦点的文本组件之一。恕我直言,在没有焦点的字段上显示插入符号是没有意义的,因为您最终会在屏幕上显示多个插入符号并使用户混淆他们实际输入的是哪个插入符号... 我将您的 SSCCE 复制到了我的 IDE 中。你能解释一下在运行这段代码时你希望看到什么不同的行为吗? 我知道会发生什么。这仅在使用 TAB 时才会发生,对吗? aaach 我看到禁用,删除 panel.add(jTextField0); 按键或鼠标事件无关紧要 【参考方案1】:

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

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

这在 OS X 中为我解决了问题。

【讨论】:

已在 Java 6 上确认,AquaLookAndFeel【参考方案2】:

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

DefaultCaret 的focusGained/focusLost 方法使用这两种方法控制插入符号的行为。默认情况下,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();
            
        );
    

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

【讨论】:

【参考方案3】:

但是如果将setBlinkRate(500); 放在HighlightCaret 类构造函数中,您的previous code 工作正常:

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 中测试。你试过了吗?

【讨论】:

+1 同意,正如我所描述的,我想要更多,我想要控制这个过程,现在@camickr 的回答对 L&F 很不敏感,他的解决方法很安全,也许 (StanislavL) 会如果此处的答案缺少重要内容,请评论此帖子, 闪烁的插入符号由 setVisible() 控制并可在 focusGained/focusLost 中进行管理,我需要了解此信息...

以上是关于如何覆盖 DefaultCaret#setBlinkRate()的主要内容,如果未能解决你的问题,请参考以下文章

如何提高 atpg 故障覆盖率

请教如何使用dve查看覆盖率

如何:获取代码覆盖率数据

你好,LABVIEW复制文件,如何做到不覆盖?

如何自动给文件命名,避免覆盖同名文件?

安卓软件升级软件如何覆盖旧版