创建新行时看不到覆盖光标
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_WIDTH
。 paint
和 damage
方法都必须这样做。同样重要的是要注意 \n
是 JTextArea
系统独立的行分隔符,但其他文本组件的设置可能不同。
备注:
- 捕获异常时,您至少可以打印堆栈跟踪。
- 我看不出有什么理由在
paint
中创建新的 Graphics
对象,请使用给定的对象。
- 适用时使用
@Override
。
- 我只是需要做一些清理(重构),你可能想从中得到一些东西。我还更改了构造函数,因为您不需要将
DefaultCaret
传递给扩展它的 class。
我正在尝试创建覆盖光标。我明白了,除了当我点击前面的一行时插入符号消失,然后当我点击 '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_WIDTH
。 paint
和 damage
方法都必须这样做。同样重要的是要注意 \n
是 JTextArea
系统独立的行分隔符,但其他文本组件的设置可能不同。
备注:
- 捕获异常时,您至少可以打印堆栈跟踪。
- 我看不出有什么理由在
paint
中创建新的Graphics
对象,请使用给定的对象。 - 适用时使用
@Override
。 - 我只是需要做一些清理(重构),你可能想从中得到一些东西。我还更改了构造函数,因为您不需要将
DefaultCaret
传递给扩展它的 class。