Problem with Invisible Caret in JTextPane

Hi there,

Using latest JDK, I'm running into the following problem - a JTextPane, placed in a JScrollPane, made editable by doubleclicking on it, doesn't show the caret after having been made editable.

privateclass EditableTextPaneextends JTextPane{

private String preEditString;

protected EditableTextPane(){

super();

setFont( TicketPanel.ticketFont );

setMargin(new Insets( 24, 5, 5, 5 ) );

setEditable(false );

addMouseListener(new MouseAdapter(){

publicvoid mouseClicked( MouseEvent e ){

if( e.getClickCount() == 2 ){

if( !isEditable() ){

preEditString = getText();

setEditable(true );

//added these two in an attempt to solve the problem

EditableTextPane.this.requestFocus();

EditableTextPane.this.setCaretPosition( getText().length() );

}

else{

performEdit();

setEditable(false );

}

}

}

});

}

publicvoid setText( String s ){

super.setText( s );

if( isEditable() )

setEditable(false );

preEditString =null;

}

privatevoid performEdit(){

if( preEditString ==null )

return;

}

publicvoid setEditable(boolean b ){

super.setEditable( b );

setForeground( b ? Color.blue : Color.black );

}

}

Any ideas?

Thanks!

Alex

[2909 byte] By [Saevena] at [2007-11-27 5:10:38]
# 1
I should add that clicking outside the custom text pane, and then clicking back in after it was made editable, does show the caret. Seems to be a focus problem.
Saevena at 2007-7-12 10:30:48 > top of Java-index,Desktop,Core GUI APIs...
# 2

You could try wrapping the setCaretPostion() method in a SwingUtilities.invokeLater() to make sure it is the last piece of code executed. (maybe the setEditable() method adds some code to the end of the EDT).

If you need further help then you need to create a [url http://homepage1.nifty.com/algafield/sscce.html]Short, Self Contained, Compilable and Executable, Example Program[/url] (SSCCE) that demonstrates the incorrect behaviour, because I can't guess exactly what you are doing based on the information provided.

Don't forget to use the [url http://forum.java.sun.com/help.jspa?sec=formatting]Code Formatting Tags[/url] so the posted code retains its original formatting.

camickra at 2007-7-12 10:30:48 > top of Java-index,Desktop,Core GUI APIs...
# 3

Thanks for the post camickr, didn't think of that, but unfortunately that didn't do it. Here's the SSCE:

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

public class TestClass {

public static void main( String args[] ){

JFrame f = new JFrame();

EditableTextPane e = new EditableTextPane();

e.setText( "This is some test text" );

JScrollPane p = new JScrollPane( e, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS );

f.getContentPane().add( p );

f.setSize( 400, 400 );

f.setVisible( true );

}

private static class EditableTextPane extends JTextPane{

private static final long serialVersionUID = 1;

private String preEditString;

protected EditableTextPane(){

super();

setMargin( new Insets( 24, 5, 5, 5 ) );

setEditable( false );

addMouseListener( new MouseAdapter(){

public void mouseClicked( MouseEvent e ){

if( e.getClickCount() == 2 ){

if( !isEditable() ){

preEditString = getText();

setEditable( true );

EditableTextPane.this.requestFocus();

SwingUtilities.invokeLater( new Runnable(){

public void run(){

EditableTextPane.this.setCaretPosition( getText().length() );

}

});

}

else{

performEdit();

setEditable( false );

}

}

}

});

}

public void setText( String s ){

super.setText( s );

if( isEditable() )

setEditable( false );

preEditString = null;

}

private void performEdit(){

if( preEditString == null )

return;

}

public void setEditable( boolean b ){

super.setEditable( b );

setForeground( b ? Color.blue : Color.black );

}

}

}

Thanks again.

Alex

Saevena at 2007-7-12 10:30:48 > top of Java-index,Desktop,Core GUI APIs...
# 4

Perhaps in the right direction towards a solution, if I programmatically remove and return focus to the component, it works. If I just request focus off the bat however, it doesn't.

addMouseListener( new MouseAdapter(){

public void mouseClicked( MouseEvent e ){

if( e.getClickCount() == 2 ){

if( !isEditable() ){

preEditString = getText();

setEditable( true );

EditableTextPane.this.getParent().requestFocus();

SwingUtilities.invokeLater( new Runnable(){

public void run(){

EditableTextPane.this.requestFocus();

EditableTextPane.this.setCaretPosition( getText().length() );

EditableTextPane.this.setCaretColor( Color.black );

}

});

}

else{

performEdit();

setEditable( false );

}

}

}

});

Saevena at 2007-7-12 10:30:48 > top of Java-index,Desktop,Core GUI APIs...
# 5

> Perhaps in the right direction towards a solution...

Makes sense. An uneditable text pane sets the caret visibility to false. You would think that making the text pane editable again would reset the visibility, but apparently not.

So your solution works because when the text pane loses and regains focus the caret visibility is reset, This time because the text pane is editable the caret is made visible.

A better solution would probably be just to change the visiblility of the caret directly:

textPane.getCaret().setVisible( true );

Should work without the invokeLater() code.

camickra at 2007-7-12 10:30:48 > top of Java-index,Desktop,Core GUI APIs...
# 6

Well, here's the answer..

if( e.getClickCount() == 2 ){

if( !isEditable() ){

EditableTextPane.this.select( 0, 0 );

preEditString = getText();

setEditable( true );

SwingUtilities.invokeLater( new Runnable(){

public void run(){

EditableTextPane.this.setCaretPosition( getText().length() );

EditableTextPane.this.getCaret().setVisible( true );

}

});

}

else{

performEdit();

setEditable( false );

}

}

Saevena at 2007-7-12 10:30:48 > top of Java-index,Desktop,Core GUI APIs...