extending DefaultCaret... and it won't blink!!!
Ok so I'm making a class to extend DefaultCaret, its a custom caret to look a bit different... I've got it all working except the blinking!
As you can see by the code below I have made calls to the 'setBlinkRate(..' function but for some reason it still won't blink!
Anyone know what I'm doing wrong?
the only thing i'm not sure about is the 'damage()' function call that i implemented, i suspect this may be the cause but I'm not sure...
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.plaf.*;
import javax.swing.text.*;
/**
*
*/
publicclass NewCaretextends DefaultCaret{
/** Creates a new instance of NewCaret */
public NewCaret (){
setBlinkRate(500);
}//end constructor
/**
* When the component containing this caret gains focus this is called.
*
* Here a caretlistener is added this repaints the component when the caret
* moves and text is deleted.
*/
publicvoid focusGained(FocusEvent e){
super.focusGained(e);
this.getComponent().addCaretListener(new CaretListener(){
publicvoid caretUpdate(CaretEvent e){
getComponent().repaint();
}
});
}//end focusGained
/**
* When the component containing this caret loses focus this is called.
*
* Here the container is repainted to removed old artifacts, and the
* caret listners are removed as they are not needed anymore.
*/
publicvoid focusLost(FocusEvent e){
super.focusLost(e);
getComponent().repaint();
CaretListener listeners[] = this.getComponent().getCaretListeners();
for (int i = 0; i < listeners.length; i++){
this.getComponent().removeCaretListener(listeners[i]);
}
}//end focusLost
/**
* Overriding this method to display the custom cursor
*/
publicvoid paint(Graphics g){
if (isVisible()){
// Determine where to draw the cursor
JTextComponent c = getComponent();
TextUI ui = c.getUI();
Rectangle r =null;
int dot = getDot();
int mark = getMark();
Color selectCol = javax.swing.UIManager.getLookAndFeel().getDefaults().getColor("TextField.selectionBackground");
Font f = getComponent().getFont();
FontMetrics currentFontMetrics = Toolkit.getDefaultToolkit().getFontMetrics(f);
int height = currentFontMetrics.getAscent();
try{
r = ui.modelToView(c, dot);
String s = getComponent().getText().substring(dot);
g.setColor(getComponent().getBackground());
g.fillRect(r.x, r.y, currentFontMetrics.stringWidth(s) + 8, height + 4);
g.setColor(c.getCaretColor());
//top section
g.drawLine(r.x + 0, r.y + 0, r.x + 1, r.y + 0);
g.drawLine(r.x + 1, r.y + 1, r.x + 6, r.y + 1);
g.drawLine(r.x + 6, r.y + 0, r.x + 7, r.y + 0);
//middle section
g.drawLine(r.x + 3, r.y + 2, r.x + 3, r.y + 2 + height - 1);
g.drawLine(r.x + 4, r.y + 2, r.x + 4, r.y + 2 + height - 1);
//bottom section
g.drawLine(r.x + 1, r.y + 2 + height, r.x + 6, r.y + 2 + height);
g.drawLine(r.x + 0, r.y + 3 + height, r.x + 1, r.y + 3 + height);
g.drawLine(r.x + 6, r.y + 3 + height, r.x + 7, r.y + 3 + height);
//color for text
g.setColor(getComponent().getForeground());
if (dot < c.getDocument().getLength()){
g.drawString(s, r.x + 8, r.y + height);
}
if (mark > dot){
//selection - so display it.
String substr = getComponent().getText().substring(dot, mark);
int len = currentFontMetrics.stringWidth(substr);
g.setColor(selectCol);
g.fillRect(r.x + 8, r.y, len, height + 4);
g.setColor(getComponent().getBackground());
g.drawString(substr, r.x + 8, r.y + height);
}
}
catch (BadLocationException ex){
return;
}
}
}//end paint
/**
* Overriding this to destroy the current cursor
*/
publicvoid damage(Rectangle r){
if (r !=null){
getComponent().repaint(r.x, r.y, r.width, r.height);
}
}
}
Maybe I am wrong, but you might try repaint(50L), without damage().
You're right: damage() is only affecting the area where a normal DefaultCaret would appear. You need to alter the rectangle that it repaints to match what you're painting. Adding ten pixels to the width and five to the height should do it.
I noticed some other problems, too. One has to do with the code that repaints the character under the caret--which you don't need to do anyway. The View takes care of painting the text, so just get rid of that stuff. Another problem is that the caret appears right on top of a character. You don't really want that, do you? I suggest you shift the whole thing leftward so it appears between characters.
I've changed the code around with no success...
I ended up changing the order of the drawing due to some horrible redraw problems when selecting text from the midde of a string. I've fixed those problems now,
BUT IT STILL WON' BLINK! :(((
I've taken your advice as to the damage method and playted with that, still no joy there though.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.plaf.*;
import javax.swing.text.*;
public class NewCaret extends DefaultCaret {
private int dmgwidth;
private boolean repainted;
/** Creates a new instance of NewCaret */
public NewCaret() {
setBlinkRate(1000);
this.dmgwidth = 0;
this.repainted = false;
}//end constructor
/**
* When the component containing this caret gains focus this is called.
*
* Here a caretlistener is added this repaints the component when the caret
* moves and text is deleted.
*/
public void focusGained(FocusEvent e) {
super.focusGained(e);
this.getComponent().addCaretListener(new CaretListener() {
public void caretUpdate(CaretEvent e) {
getComponent().repaint();
}
});
}//end focusGained
/**
* When the component containing this caret loses focus this is called.
*
* Here the container is repainted to removed old artifacts, and the
* caret listners are removed as they are not needed anymore.
*/
public void focusLost(FocusEvent e) {
super.focusLost(e);
getComponent().repaint();
CaretListener listeners[] = this.getComponent().getCaretListeners();
for (int i = 0; i < listeners.length; i++) {
this.getComponent().removeCaretListener(listeners[i]);
}
}//end focusLost
/**
* Overriding this method to display the custom cursor
*/
public void paint(Graphics g) {
if (isVisible()) {
int dot = getDot();
int mark = getMark();
// Determine where to draw the cursor
JTextComponent c = getComponent();
TextUI ui = c.getUI();
Rectangle r = null;
Color selectColBG = javax.swing.UIManager.getLookAndFeel().getDefaults().getColor("TextField.selectionBackground");
Color selectColFG = javax.swing.UIManager.getLookAndFeel().getDefaults().getColor("TextField.selectionForeground");
Color colFG = getComponent().getForeground();
Color colBG = getComponent().getBackground();
Font f = getComponent().getFont();
FontMetrics currentFontMetrics = Toolkit.getDefaultToolkit().getFontMetrics(f);
int height = currentFontMetrics.getAscent();
String wholetext = getComponent().getText();
String selString = null;
String endString = null;
int selwidth = 0;
int strwidth = currentFontMetrics.stringWidth(wholetext);
int filth = currentFontMetrics.stringWidth(wholetext.substring(dot, wholetext.length()));
if (null != wholetext && wholetext.length() > 0) {
if (mark > dot) {
selString = wholetext.substring(dot, mark);
endString = wholetext.substring(mark);
selwidth = currentFontMetrics.stringWidth(selString);
} else {
if (dot < wholetext.length()) {
endString = wholetext.substring(dot);
}
}
}
int cursorWidth = 8;
//Here we paint
try {
r = ui.modelToView(c, dot);
g.setColor(colBG);
g.fillRect(r.x, r.y, filth, height + 4);
if (null != selString && selString.length() > 0) {
g.setColor(selectColBG);
g.fillRect(r.x + cursorWidth, r.y, selwidth, height + 4);
g.setColor(selectColFG);
g.drawString(selString + cursorWidth, r.x + cursorWidth, r.y + height);
}
if (null != endString && endString.length() > 0) {
g.setColor(colFG);
g.drawString(endString, r.x + cursorWidth + selwidth, r.y + height);
}
g.setColor(c.getCaretColor());
//top section
g.drawLine(r.x + 0, r.y + 0, r.x + 1, r.y + 0);
g.drawLine(r.x + 1, r.y + 1, r.x + 6, r.y + 1);
g.drawLine(r.x + 6, r.y + 0, r.x + 7, r.y + 0);
//middle section
g.drawLine(r.x + 3, r.y + 2, r.x + 3, r.y + 2 + height - 1);
g.drawLine(r.x + 4, r.y + 2, r.x + 4, r.y + 2 + height - 1);
//bottom section
g.drawLine(r.x + 1, r.y + 2 + height, r.x + 6, r.y + 2 + height);
g.drawLine(r.x + 0, r.y + 3 + height, r.x + 1, r.y + 3 + height);
g.drawLine(r.x + 6, r.y + 3 + height, r.x + 7, r.y + 3 + height);
this.dmgwidth = strwidth;
//incrementing width value by width of cursor
this.dmgwidth += 8;
}
catch (BadLocationException ex) {
return;
}
}
}//end paint
/**
* Overriding this to destroy the current cursor
*/
protected synchronized void damage(Rectangle r) {
if (r != null) {
int x = r.x;
int y = r.y;
int width = dmgwidth;
int height = r.height;
getComponent().repaint(x, y, width, height);
}
}
}
I think you're just trying to do way too much. The View draws the text and the Highlighter paints the selection background; leave that to them. This pared-down class works fine when I plug it into a JTextArea (except that it leaves a little garbage behind when I sweep out a selection). Try it out.import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.plaf.*;
import javax.swing.text.*;
/**
*
*/
public class NewCaret extends DefaultCaret {
/** Creates a new instance of NewCaret */
public NewCaret () {
setBlinkRate(500);
}//end constructor
/**
* Overriding this method to display the custom cursor
*/
public void paint(Graphics g) {
if (isVisible()) {
// Determine where to draw the cursor
JTextComponent c = getComponent();
TextUI ui = c.getUI();
Rectangle r = null;
int dot = getDot();
int mark = getMark();
Font f = getComponent().getFont();
FontMetrics currentFontMetrics = getComponent().getFontMetrics(f);
int height = currentFontMetrics.getAscent();
try {
r = ui.modelToView(c, dot);
g.setColor(c.getCaretColor());
//top section
g.drawLine(r.x - 3, r.y - 1,r.x - 2, r.y - 1);
g.drawLine(r.x - 2, r.y + 0,r.x + 2, r.y + 0);
g.drawLine(r.x + 3, r.y - 1,r.x + 3, r.y - 1);
//middle section
g.drawLine(r.x + 0, r.y + 1,r.x + 0, r.y + 1 + height);
//bottom section
g.drawLine(r.x - 2, r.y + 2 + height, r.x + 2, r.y + 2 + height);
g.drawLine(r.x - 3, r.y + 3 + height, r.x - 2, r.y + 3 + height);
g.drawLine(r.x + 2, r.y + 3 + height, r.x + 3, r.y + 3 + height);
}
catch (BadLocationException ex) {
ex.printStackTrace();
}
}
}//end paint
/**
* Overriding this to destroy the current cursor
*/
public void damage(Rectangle r) {
if (r != null) {
getComponent().repaint(r.x - 4, r.y - 2, 9, r.height + 5);
}
}
}
This posting has a custom Caret that blinks: http://forum.java.sun.com/thread.jspa?forumID=57&threadID=667407
Thanks I'll give that a go...
I was doing so much in the caret because I can't afford to have any garbage left behind (its got to look as pretty as possible :P).
I've been moved onto another project for the rest of the week, so I'll get back to the cursor in my own time and see what I can do :)
I figured out how to get rid of that garbage I mentioned: just implement the damage() method the same way DefaultCaret does.public void damage(Rectangle r) {
if (r != null) {
x = r.x - 4;
y = r.y - 2;
width = 9;
height = r.height + 5;
repaint();
}
}