创建新行时看不到覆盖光标

Cant see Overwrinting Cursor when i create new Line

我正在尝试创建覆盖光标。我明白了,除了当我点击前面的一行时插入符号消失,然后当我点击 'enter' 换行时它再次出现。

我应该在我的代码中更改什么来解决这个问题?

这是我的插入符号 Class:

public class Mycaret extends DefaultCaret {

    protected static final int MIN_WIDTH = 8;

    protected DefaultCaret dc = null;

    JTextComponent com = null;

    public Mycaret(int rate, DefaultCaret dc) {

        this.dc = dc;
        super.setBlinkRate(rate);
    }

    protected synchronized void damage(Rectangle r) {

        if (r != null) {

            try {

                JTextComponent comp = getComponent();
                TextUI mapper = comp.getUI();
                char dotChar = 0;
                if(comp.getText().length()>0){
                 dotChar = comp.getText().charAt(comp.getText().length()-1);
                }
                this.com = comp;

                Rectangle r2 = mapper.modelToView(comp, getDot() + 1);

                int width = r2.x - r.x;

                if (width == 0 ) {

                    width = MIN_WIDTH;


                }

                comp.repaint(r.x, r.y, width, r.height);

                this.x = r.x;
                this.y = r.y;
                this.width = width;
                this.height = r.height;

            }

            catch (BadLocationException e) {

            }
        }

    }

    public void paint(Graphics g) {

        char dotChar;

        if (isVisible()) {

            try {

                JTextComponent comp = getComponent();
                TextUI mapper = comp.getUI();

                Rectangle r1 = mapper.modelToView(comp, getDot());
                Rectangle r2 = mapper.modelToView(comp, getDot() + 1);

                g = g.create();
                g.setColor(comp.getForeground());
                g.setXORMode(comp.getBackground());

                int width = r2.x - r1.x;

                dotChar = comp.getText(getDot(), 1).charAt(0);

                if (width == 0  ) {
                    width = MIN_WIDTH;

                }



                g.fillRect(r1.x, r1.y, width, r1.height);
                g.dispose();

            } catch (BadLocationException e) {

            }
        }

    }
}

这是一个示例:

public class MyFrameSample extends JFrame {

    DefaultCaret caret=null;

    public MyFrameSample() {

        JTextArea text = new JTextArea(10,20);
        caret = new DefaultCaret();

        text.setCaret(new Mycaret(500, caret));
        add(text);

        pack();
        setVisible(true);
    }

    public static void main(String[] args) {

        new MyFrameSample();
    }
}

根据@user1803551 的观察,我注意到宽度可能为负,所以我只是在 paint() 和 damage() 方法中将您的 if 条件更改为“<=”:

if (width <= 0  ) 
{
    width = MIN_WIDTH;
}

正如我在评论中提到的,问题来自换行符 (\n)。当插入符号放在非空行中的 \n 之前时,它不会出现,因为它试图占用 \n 的宽度。因此,我添加了检查 \n 是否与插入符号位于同一位置。

中写入编辑: @camickr 通过发现 不知何故 \n 的宽度找到了一个更好的方法否定(任何人,为什么?查看评论)。

public class Mycaret extends DefaultCaret {

    protected static final int MIN_WIDTH = 8;

    public Mycaret(int rate) {

        super.setBlinkRate(rate);
    }

    protected boolean isBeforeNewLine() throws BadLocationException {

        PlainDocument doc = (PlainDocument) getComponent().getDocument();
        if (doc.getText(getDot(), 1).equals("\n"))
            return true;
        return false;
    }

    @Override
    protected synchronized void damage(Rectangle r) {

        if (r != null) {
            try {
                JTextComponent comp = getComponent();

                Rectangle r2 = comp.getUI().modelToView(comp, getDot() + 1);
                int width = r2.x - r.x;
                if (width == 0 || isBeforeNewLine()) {
                    width = MIN_WIDTH;
                }
                comp.repaint(r.x, r.y, width, r.height);

                this.x = r.x;
                this.y = r.y;
                this.width = width;
                this.height = r.height;
            } catch (BadLocationException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void paint(Graphics g) {

        if (isVisible()) {
            try {
                JTextComponent comp = getComponent();

                g.setColor(comp.getForeground());
                g.setXORMode(comp.getBackground());

                Rectangle r1 = comp.getUI().modelToView(comp, getDot());
                Rectangle r2 = comp.getUI().modelToView(comp, getDot() + 1);
                int width = r2.x - r1.x;
                if (width == 0 || isBeforeNewLine()) {
                    width = MIN_WIDTH;
                }
                g.fillRect(r1.x, r1.y, width, r1.height);
            } catch (BadLocationException e) {
                e.printStackTrace();
            }
        }
    }
}

解释:

isBeforeNewLine 方法从文档中获取插入符号位置的文本。对于 JTextArea,它是 PlainDocument。如果它是 \n,则宽度设置为 MIN_WIDTHpaintdamage 方法都必须这样做。同样重要的是要注意 \nJTextArea 系统独立的行分隔符,但其他文本组件的设置可能不同。

备注:

  • 捕获异常时,您至少可以打印堆栈跟踪。
  • 我看不出有什么理由在 paint 中创建新的 Graphics 对象,请使用给定的对象。
  • 适用时使用 @Override
  • 我只是需要做一些清理(重构),你可能想从中得到一些东西。我还更改了构造函数,因为您不需要将 DefaultCaret 传递给扩展它的 class。