Forum Stats

  • 3,750,837 Users
  • 2,250,259 Discussions
  • 7,867,172 Comments

Discussions

Line Number in JTextPane

843804
843804 Member Posts: 45,751
edited Jan 21, 2005 11:59AM in Swing
Hi Experts;

How do I add a caret listener on this code so that it will just add a number
when the user goes to the next line.
import java.awt.*;
import javax.swing.*;
 
public class LineNumber extends JComponent
{
	private final static Color DEFAULT_BACKGROUND = new Color(213, 213, 234);
	private final static Color DEFAULT_FOREGROUND = Color.white;
	private final static Font DEFAULT_FONT = new Font("arial", Font.PLAIN, 11);
	
	// LineNumber height (abends when I use MAX_VALUE)
	private final static int HEIGHT = Integer.MAX_VALUE - 1000000;
	
	// Set right/left margin
	private final static int MARGIN = 5;
	
	// Line height of this LineNumber component
	private int lineHeight;
	
	// Line height of this LineNumber component
	private int fontLineHeight;
	
	// With of the LineNumber component
	private int currentRowWidth;
	
	// Metrics of this LineNumber component
	private FontMetrics fontMetrics;
	
	/**
	 * Convenience constructor for Text Components
	 */
	public LineNumber(JComponent component)
	{
		if (component == null)
		{
			setBackground( DEFAULT_BACKGROUND );
			setForeground( DEFAULT_FOREGROUND );
			setFont( DEFAULT_FONT );
		}
		else
		{
			setBackground( DEFAULT_BACKGROUND );
			setForeground( DEFAULT_FOREGROUND );
			setFont( component.getFont() );
		}
		
		setPreferredSize( 99 );
	}
	
	public void setPreferredSize(int row)
	{
		int width = fontMetrics.stringWidth( String.valueOf(row) );
		
		if (currentRowWidth < width)
		{
			currentRowWidth = width;
			setPreferredSize( new Dimension(2 * MARGIN + width, HEIGHT) );
		}
	}
	
	public void setFont(Font font)
	{
		super.setFont(font);
		fontMetrics = getFontMetrics( getFont() );
		fontLineHeight = fontMetrics.getHeight();
	}
	
	/**
	 * The line height defaults to the line height of the font for this
	 * component. The line height can be overridden by setting it to a
	 * positive non-zero value.
	 */
	public int getLineHeight()
	{
		if (lineHeight == 0)
			return fontLineHeight;
		else
			return lineHeight;
	}
	
	public void setLineHeight(int lineHeight)
	{
		if (lineHeight > 0)
			this.lineHeight = lineHeight;
	}
	
	public int getStartOffset()
	{
		return 4;
	}
	
	public void paintComponent(Graphics g)
	{
		 int lineHeight = getLineHeight();
		 int startOffset = getStartOffset();
		 Rectangle drawHere = g.getClipBounds();

		 g.setColor( getBackground() );
		 g.fillRect(drawHere.x, drawHere.y, drawHere.width, drawHere.height);

		 g.setColor( getForeground() );
		 int startLineNumber = (drawHere.y / lineHeight) + 1;
		 int endLineNumber = startLineNumber + (drawHere.height / lineHeight);

		 int start = (drawHere.y / lineHeight) * lineHeight + lineHeight - startOffset;

		 for (int i = startLineNumber; i <= endLineNumber; i++)
		 {
		 String lineNumber = String.valueOf(i);
		 int width = fontMetrics.stringWidth( lineNumber );
		 g.drawString(lineNumber, MARGIN + currentRowWidth - width, start);
		 start += lineHeight;
		 }

		 setPreferredSize( endLineNumber );
	}
} 
Thanks for your time . . .
The_Developer
«134567

Comments

  • 843804
    843804 Member Posts: 45,751
    I don't have the slightest idea of what your LineNumber JComponent is for. Why passing a JComponent in the constructor when all you want is its Font?

    Could you add a main method so that we can see how you intend to use it in the context of a real test?
  • 843804
    843804 Member Posts: 45,751
    Joops its just for any text component.

    Here's the code again, thanks :
     
    import java.awt.*;
    import javax.swing.*;
    import javax.swing.border.*;
    import javax.swing.text.*;
    
    public class LineNumber extends JComponent
    {
    	private final static Color DEFAULT_BACKGROUND = new Color(230, 163, 4);
    	private final static Color DEFAULT_FOREGROUND = Color.black;
    	private final static Font DEFAULT_FONT = new Font("monospaced", Font.PLAIN, 12);
    	
    	// LineNumber height (abends when I use MAX_VALUE)
    	private final static int HEIGHT = Integer.MAX_VALUE - 1000000;
    	
    	// Set right/left margin
    	private final static int MARGIN = 5;
    	
    	// Line height of this LineNumber component
    	private int lineHeight;
    	
    	// Line height of this LineNumber component
    	private int fontLineHeight;
    	
    	//
    	private int currentRowWidth;
    	
    	// Metrics of this LineNumber component
    	private FontMetrics fontMetrics;
    	
    	/**
    	 * Convenience constructor for Text Components
    	 */
    	public LineNumber(JComponent component)
    	{
    		if (component == null)
    		{
    			setBackground( DEFAULT_BACKGROUND );
    			setForeground( DEFAULT_FOREGROUND );
    			setFont( DEFAULT_FONT );
    		}
    		else
    		{
    			setBackground( DEFAULT_BACKGROUND );
    			setForeground( component.getForeground() );
    			setFont( component.getFont() );
    		}
    		
    		setPreferredSize( 9999 );
    	}
    	
    	public void setPreferredSize(int row)
    	{
    		int width = fontMetrics.stringWidth( String.valueOf(row) );
    		
    		if (currentRowWidth < width)
    		{
    			currentRowWidth = width;
    			setPreferredSize( new Dimension(2 * MARGIN + width, HEIGHT) );
    		}
    	}
    	
    	public void setFont(Font font)
    	{
    		super.setFont(font);
    		fontMetrics = getFontMetrics( getFont() );
    		fontLineHeight = fontMetrics.getHeight();
    	}
    	
    	/**
    	 * The line height defaults to the line height of the font for this
    	 * component. The line height can be overridden by setting it to a
    	 * positive non-zero value.
    	 */
    	public int getLineHeight()
    	{
    		if (lineHeight == 0)
    			return fontLineHeight;
    		else
    			return lineHeight;
    	}
    	
    	public void setLineHeight(int lineHeight)
    	{
    		if (lineHeight > 0)
    			this.lineHeight = lineHeight;
    	}
    	
    	public int getStartOffset()
    	{
    		return 4;
    	}
    	
    	public void paintComponent(Graphics g)
    	{
    		int lineHeight = getLineHeight();
    		int startOffset = getStartOffset();
    		Rectangle drawHere = g.getClipBounds();
    		// System.out.println( drawHere );
    		
    		// Paint the background
    		
    		g.setColor( getBackground() );
    		g.fillRect(drawHere.x, drawHere.y, drawHere.width, drawHere.height);
    		
    		// Determine the number of lines to draw in the foreground.
    		
    		g.setColor( getForeground() );
    		int startLineNumber = (drawHere.y / lineHeight) + 1;
    		int endLineNumber = startLineNumber + (drawHere.height / lineHeight);
    		
    		int start = (drawHere.y / lineHeight) * lineHeight + lineHeight - startOffset;
    		
    		// System.out.println( startLineNumber + " : " + endLineNumber + " : " + start );
    		
    		for (int i = startLineNumber; i <= endLineNumber; i++)
    		{
    			String lineNumber = String.valueOf(i);
    			int width = fontMetrics.stringWidth( lineNumber );
    			g.drawString(lineNumber, MARGIN + currentRowWidth - width, start);
    			start += lineHeight;
    		}
    		
    		setPreferredSize( endLineNumber );
    	}
    	
    	public static void main(String[] args)
    	{
    		JFrame frame = new JFrame("LineNumberDemo");
    		frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
    		
    		JPanel panel = new JPanel();
    		frame.setContentPane( panel );
    		panel.setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
    		panel.setLayout(new BorderLayout());
    		
    		JTextPane textPane = new JTextPane();
    		
    		JScrollPane scrollPane = new JScrollPane(textPane);
    		panel.add(scrollPane);
    		scrollPane.setPreferredSize(new Dimension(300, 250));
    		
    		LineNumber lineNumber = new LineNumber( textPane );
    		lineNumber.setPreferredSize(99999);
    		scrollPane.setRowHeaderView( lineNumber );
    		
    		frame.pack();
    		frame.setVisible(true);
    	}
    }
  • 843804
    843804 Member Posts: 45,751
    Anyone wants to help ?
  • 843804
    843804 Member Posts: 45,751
    How do I add a caret listener on this code so that it will just add a number
    when the user goes to the next line.
  • 843804
    843804 Member Posts: 45,751
    I'm working on it. I have to admit it's kinda tricky. I have a question : do you want to show line numbers for all lines (including those wrapped lines) or just lines after a '\n' (in the paragraph meaning of a line)?
    Also, I'm wondering why you want to add a Caret listener. If you want to react on updates to the document, add a DocumentListener to the Document and implement the three methods (insertUpdate, removeUpdate, changeUpdate).
  • 843804
    843804 Member Posts: 45,751
    Sure do whatever you want. I just wanna show the who'll line bar and show the
    numbers if the user goes to a new line. like : an ide.

    | 1 |
    | 2 |
    | 3 | This is where the caret is : |
    | |
    | |

    So if the user press enter or goes to a new line the next number displays.
  • 843804
    843804 Member Posts: 45,751
    If we can finish this. It would be one good free line number for all :)
  • 843804
    843804 Member Posts: 45,751
    No problem, as soon as I have something worth it, I'll post it.
    The thing is : most IDEs I know don't wrap lines so it's easier for them. I still don't know what your exact requirements are on the matter. Try and resize your frame to see what happens.
    I also am trying to extend your functionality in the case of a StyledDocument where the Font may change from one line to the other.
  • 843804
    843804 Member Posts: 45,751
    Try and resize your frame to see what happens.
    There is no problem there. The problem is from my codes, my codes automatically generates all the numbers, it calculates it all even if you maximize or add 1000 lines of codes. What I wanna do is to illiminate that by just showing the number in every new line.
  • 843804
    843804 Member Posts: 45,751
    There is no problem there. The problem is from my
    codes, my codes automatically generates all the
    numbers, it calculates it all even if you maximize or
    add 1000 lines of codes. What I wanna do is to
    illiminate that by just showing the number in every
    new line.
    My bad. I'm already working on a version that updates automatically (using a DocumentListener). My question was about whether you wanted the number of lines to remain the same when resizing the JTextComponent (equivalent to counting Paragraphs) or you wanted to take into account the wrapped lines. From your answers, I guess you want to count wrapped lines as well.
This discussion has been closed.