Line Number in JTextPane

843804
    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
      • 1. Re: Line Number in JTextPane
        843804
        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?
        • 2. Re: Line Number in JTextPane
          843804
          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);
               }
          }
          • 3. Re: Line Number in JTextPane
            843804
            Anyone wants to help ?
            • 4. Re: Line Number in JTextPane
              843804
              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.
              • 5. Re: Line Number in JTextPane
                843804
                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).
                • 6. Re: Line Number in JTextPane
                  843804
                  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.
                  • 7. Re: Line Number in JTextPane
                    843804
                    If we can finish this. It would be one good free line number for all :)
                    • 8. Re: Line Number in JTextPane
                      843804
                      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.
                      • 9. Re: Line Number in JTextPane
                        843804
                        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.
                        • 10. Re: Line Number in JTextPane
                          843804
                          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.
                          • 11. Re: Line Number in JTextPane
                            843804
                            I guess thats it, i'lll be waiting, thank you very much.
                            • 12. Re: Line Number in JTextPane
                              843804
                              Well, I guess you'll be disappointed. I was not able to implement the desired behavior. I am stuck with this line wrap problem. It's actually not that easy to get a hold on the wrapped lines. I also used a JTextArea instead of a JTextPane since styles didn't seem to be an issue. I also gave up the rowHeaderView system as I was facing major painting problems. I don't know, maybe I missed something but repainting while scrolling was completely screwed up. Anyway, I hope you'll get the idea :
                              import java.awt.*;
                              
                              import javax.swing.*;
                              import javax.swing.event.DocumentListener;
                              import javax.swing.event.DocumentEvent;
                              import javax.swing.text.BadLocationException;
                              
                              public class LineNumberedTextArea extends JPanel {
                                   private final static Color DEFAULT_BACKGROUND = new Color(230, 163, 4);
                                   private final static int MARGIN = 5;
                                   private JTextArea theTextArea;
                                   private LineNumberPanel theLineNumberPanel;
                                   private boolean isWrapped;
                              
                                   private class LineNumberPanel extends JPanel implements DocumentListener {
                                        private FontMetrics theFontMetrics;
                                        private int currentRowWidth;
                              
                                        public LineNumberPanel() {
                                             setOpaque(true);
                                             setBackground(DEFAULT_BACKGROUND);
                                             setFont(theTextArea.getFont());
                                             theFontMetrics = getFontMetrics(getFont());
                                             setForeground(theTextArea.getForeground());
                                             currentRowWidth = getDesiredRowWidth();
                                        }
                              
                                        private void update() {
                                             int desiredRowWidth = getDesiredRowWidth();
                                             if (desiredRowWidth != currentRowWidth) {
                                                  currentRowWidth = desiredRowWidth;
                                                  revalidate();
                                             }
                                             repaint();
                                        }
                              
                                        private int getDesiredRowWidth() {
                                             int result = 0;
                                             try {
                                                  int nbLines = theTextArea.getLineOfOffset(theTextArea.getText().length()) + 1;
                                                  result = theFontMetrics.stringWidth(Integer.toString(nbLines));
                                             } catch (BadLocationException e) {
                                                  e.printStackTrace();
                                             }
                                             return result;
                                        }
                              
                                        public void paintComponent(Graphics g) {
                                             super.paintComponent(g);
                                             try {
                                                  int startLine = theTextArea.getLineOfOffset(0);
                                                  int endline = theTextArea.getLineOfOffset(theTextArea.getText().length());
                              
                                                  for (int line = startLine; line <= endline; line++) {
                                                       int y = theTextArea.modelToView(theTextArea.getLineStartOffset(line)).y + theFontMetrics.getHeight() - theFontMetrics.getDescent();
                                                       String s = Integer.toString(line + 1);
                                                       int width = theFontMetrics.stringWidth(s);
                                                       g.drawString(s, MARGIN + currentRowWidth - width, y);
                                                  }
                                             } catch (BadLocationException e) {
                                                  e.printStackTrace();
                                             }
                                        }
                              
                                        public Dimension getPreferredSize() {
                                             return new Dimension(2 * MARGIN + currentRowWidth, theTextArea.getHeight());
                                        }
                              
                                        public void insertUpdate(DocumentEvent e) {
                                             update();
                                        }
                              
                                        public void removeUpdate(DocumentEvent e) {
                                             update();
                                        }
                              
                                        public void changedUpdate(DocumentEvent e) {
                                             update();
                                        }
                                   }
                              
                                   public LineNumberedTextArea(boolean wrap) {
                                        super(new BorderLayout(0, 0));
                                        isWrapped = wrap;
                                        theTextArea = new JTextArea();
                                        theTextArea.setLineWrap(isWrapped);
                                        theTextArea.setWrapStyleWord(isWrapped);
                                        add(theTextArea, BorderLayout.CENTER);
                                        theLineNumberPanel = new LineNumberPanel();
                                        add(theLineNumberPanel, BorderLayout.WEST);
                                        theTextArea.getDocument().addDocumentListener(theLineNumberPanel);
                                   }
                              
                                   public Dimension getPreferredSize() {
                                        Dimension dim = super.getPreferredSize();
                                        if (isWrapped) {
                                             dim.width = 1;
                                        }
                                        return dim;
                                   }
                              
                                   public JTextArea getTextArea() {
                                        return theTextArea;
                                   }
                              
                                   public static void main(String[] args) {
                                        final JFrame frame = new JFrame();
                                        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                                        frame.setContentPane(new JScrollPane(new LineNumberedTextArea(false)));
                                        SwingUtilities.invokeLater(new Runnable() {
                                             public void run() {
                                                  frame.setSize(new Dimension(400, 400));
                                                  frame.show();
                                             }
                                        });
                                   }
                              }
                              If you set the wrap to false, it does exactly what you wanted. I'll try and improve it tomorrow (it's getting late here).
                              I forgot to mention that the overriding of getPreferredSize on the top panel is a famous hack when dealing with JTextAreas that don't want to wrap.
                              • 13. Re: Line Number in JTextPane
                                843804
                                Here's what I use. It behaves correctly WRT wrapped lines, and should work equally well with a JTextArea or a JTextPane.
                                import java.awt.Color;
                                import java.awt.Dimension;
                                import java.awt.Font;
                                import java.awt.FontMetrics;
                                import java.awt.Graphics;
                                import java.awt.Rectangle;
                                import java.awt.event.ComponentAdapter;
                                import java.awt.event.ComponentEvent;
                                
                                import java.beans.PropertyChangeEvent;
                                import java.beans.PropertyChangeListener;
                                
                                import javax.swing.BorderFactory;
                                import javax.swing.JComponent;
                                import javax.swing.SizeSequence;
                                import javax.swing.UIManager;
                                import javax.swing.event.DocumentEvent;
                                import javax.swing.event.DocumentListener;
                                import javax.swing.text.BadLocationException;
                                import javax.swing.text.Document;
                                import javax.swing.text.Element;
                                import javax.swing.text.JTextComponent;
                                
                                /**
                                 * LineNumberView is a simple line-number gutter that works correctly
                                 * even when lines are wrapped in the associated text component.  This
                                 * is meant to be used as the RowHeaderView in a JScrollPane that
                                 * contains the associated text component.  Example usage:
                                 *<pre>
                                 *   JTextArea ta = new JTextArea();
                                 *   ta.setLineWrap(true);
                                 *   ta.setWrapStyleWord(true);
                                 *   JScrollPane sp = new JScrollPane(ta);
                                 *   sp.setRowHeaderView(new LineNumberView(ta));
                                 *</pre>
                                 *
                                 * @author Alan Moore
                                 */
                                public class LineNumberView extends JComponent
                                {
                                  // This is for the border to the right of the line numbers.
                                  // There's probably a UIDefaults value that could be used for this.
                                  private static final Color BORDER_COLOR = Color.GRAY;
                                
                                  private static final int WIDTH_TEMPLATE = 99999;
                                  private static final int MARGIN = 5;
                                
                                  private FontMetrics viewFontMetrics;
                                  private int maxNumberWidth;
                                  private int componentWidth;
                                
                                  private int textTopInset;
                                  private int textFontAscent;
                                  private int textFontHeight;
                                
                                  private JTextComponent text;
                                  private SizeSequence sizes;
                                  private int startLine = 0;
                                  private boolean structureChanged = true;
                                
                                  /**
                                   * Construct a LineNumberView and attach it to the given text component.
                                   * The LineNumberView will listen for certain kinds of events from the
                                   * text component and update itself accordingly.
                                   * 
                                   * @param startLine the line that changed, if there's only one
                                   * @param structureChanged if <tt>true</tt>, ignore the line number and 
                                   *     update all the line heights.
                                   */
                                  public LineNumberView(JTextComponent text)
                                  {
                                    if (text == null)
                                    {
                                      throw new IllegalArgumentException("Text component cannot be null");
                                    }
                                    this.text = text;
                                    updateCachedMetrics();
                                
                                    UpdateHandler handler = new UpdateHandler();
                                    text.getDocument().addDocumentListener(handler);
                                    text.addPropertyChangeListener(handler);
                                    text.addComponentListener(handler);
                                
                                    setBorder(BorderFactory.createMatteBorder(0, 0, 0, 1, BORDER_COLOR));
                                  }
                                
                                  /**
                                   * Schedule a repaint because one or more line heights may have changed.
                                   * 
                                   * @param startLine the line that changed, if there's only one
                                   * @param structureChanged if <tt>true</tt>, ignore the line number and 
                                   *     update all the line heights.
                                   */
                                  private void viewChanged(int startLine, boolean structureChanged)
                                  {
                                    this.startLine = startLine;
                                    this.structureChanged = structureChanged;
                                
                                    revalidate();
                                    repaint();
                                  }
                                
                                  /** Update the line heights as needed. */
                                  private void updateSizes()
                                  {
                                    if (startLine < 0)
                                    {
                                      return;
                                    }
                                
                                    if (structureChanged)
                                    {
                                      int count = getAdjustedLineCount();
                                      sizes = new SizeSequence(count);
                                      for (int i = 0; i < count; i++)
                                      {
                                        sizes.setSize(i, getLineHeight(i));
                                      }
                                      structureChanged = false;
                                    }
                                    else
                                    {
                                      sizes.setSize(startLine, getLineHeight(startLine));
                                    }
                                
                                    startLine = -1;
                                  }
                                
                                  /* Copied from javax.swing.text.PlainDocument */
                                  private int getAdjustedLineCount()
                                  {
                                    // There is an implicit break being modeled at the end of the
                                    // document to deal with boundary conditions at the end.  This
                                    // is not desired in the line count, so we detect it and remove
                                    // its effect if throwing off the count.
                                    Element map = text.getDocument().getDefaultRootElement();
                                    int n = map.getElementCount();
                                    Element lastLine = map.getElement(n - 1);
                                    if ((lastLine.getEndOffset() - lastLine.getStartOffset()) > 1)
                                    {
                                      return n;
                                    }
                                
                                    return n - 1;
                                  }
                                
                                  /**
                                   * Get the height of a line from the JTextComponent.
                                   * 
                                   * @param index the line number
                                   * @param the height, in pixels
                                   */
                                  private int getLineHeight(int index)
                                  {
                                    int lastPos = sizes.getPosition(index) + textTopInset;
                                    int height = textFontHeight;
                                    try
                                    {
                                      Element map = text.getDocument().getDefaultRootElement();
                                      int lastChar = map.getElement(index).getEndOffset() - 1;
                                      Rectangle r = text.modelToView(lastChar);
                                      height = (r.y - lastPos) + r.height;
                                    }
                                    catch (BadLocationException ex)
                                    {
                                      ex.printStackTrace();
                                    }
                                    return height;
                                  }
                                
                                  /**
                                   * Cache some values that are used a lot in painting or size
                                   * calculations. Also ensures that the line-number font is not
                                   * larger than the text component's font (by point-size, anyway).
                                   */
                                  private void updateCachedMetrics()
                                  {
                                    Font textFont = text.getFont();
                                    FontMetrics fm = getFontMetrics(textFont);
                                    textFontHeight = fm.getHeight();
                                    textFontAscent = fm.getAscent();
                                    textTopInset = text.getInsets().top;
                                
                                    Font viewFont = getFont();
                                    boolean changed = false;
                                    if (viewFont == null)
                                    {
                                      viewFont = UIManager.getFont("Label.font");
                                      changed = true;
                                    }
                                    if (viewFont.getSize() > textFont.getSize())
                                    {
                                      viewFont = viewFont.deriveFont(textFont.getSize2D());
                                      changed = true;
                                    }
                                
                                    viewFontMetrics = getFontMetrics(viewFont);
                                    maxNumberWidth = viewFontMetrics.stringWidth(String.valueOf(WIDTH_TEMPLATE));
                                    componentWidth = 2 * MARGIN + maxNumberWidth;
                                
                                    if (changed)
                                    {
                                      super.setFont(viewFont);
                                    }
                                  }
                                
                                  public Dimension getPreferredSize()
                                  {
                                    return new Dimension(componentWidth, text.getHeight());
                                  }
                                
                                  public void setFont(Font font)
                                  {
                                    super.setFont(font);
                                    updateCachedMetrics();
                                  }
                                
                                  public void paintComponent(Graphics g)
                                  {
                                    updateSizes();
                                    Rectangle clip = g.getClipBounds();
                                
                                    g.setColor(getBackground());
                                    g.fillRect(clip.x, clip.y, clip.width, clip.height);
                                
                                    g.setColor(getForeground());
                                    int base = clip.y - textTopInset;
                                    int first = sizes.getIndex(base);
                                    int last = sizes.getIndex(base + clip.height);
                                    String text = "";
                                    
                                    for (int i = first; i <= last; i++)
                                    {
                                      text = String.valueOf(i+1);
                                      int x = MARGIN + maxNumberWidth - viewFontMetrics.stringWidth(text);
                                      int y = sizes.getPosition(i) + textFontAscent + textTopInset;
                                      g.drawString(text, x, y);
                                    }
                                  }
                                
                                  class UpdateHandler extends ComponentAdapter
                                      implements PropertyChangeListener, DocumentListener
                                  {
                                    /**
                                     * The text component was resized. 'Nuff said.
                                     */
                                    public void componentResized(ComponentEvent evt)
                                    {
                                      viewChanged(0, true);
                                    }
                                
                                    /**
                                     * A bound property was changed on the text component. Properties
                                     * like the font, border, and tab size affect the layout of the
                                     * whole document, so we invalidate all the line heights here.
                                     */
                                    public void propertyChange(PropertyChangeEvent evt)
                                    {
                                      Object oldValue = evt.getOldValue();
                                      Object newValue = evt.getNewValue();
                                      String propertyName = evt.getPropertyName();
                                      if ("document".equals(propertyName))
                                      {
                                        if (oldValue != null && oldValue instanceof Document)
                                        {
                                          ((Document)oldValue).removeDocumentListener(this);
                                        }
                                        if (newValue != null && newValue instanceof Document)
                                        {
                                          ((Document)newValue).addDocumentListener(this);
                                        }
                                      }
                                
                                      updateCachedMetrics();
                                      viewChanged(0, true);
                                    }
                                
                                    /**
                                     * Text was inserted into the document.
                                     */
                                    public void insertUpdate(DocumentEvent evt)
                                    {
                                      update(evt);
                                    }
                                  
                                    /**
                                     * Text was removed from the document.
                                     */
                                    public void removeUpdate(DocumentEvent evt)
                                    {
                                      update(evt);
                                    }
                                  
                                    /**
                                     * Text attributes were changed.  In a source-code editor based on
                                     * StyledDocument, attribute changes should be applied automatically
                                     * in response to inserts and removals.  Since we're already 
                                     * listening for those, this method should be redundant, but YMMV.
                                     */
                                    public void changedUpdate(DocumentEvent evt)
                                    {
                                //      update(evt);
                                    }
                                  
                                    /**
                                     * If the edit was confined to a single line, invalidate that
                                     * line's height.  Otherwise, invalidate them all.
                                     */
                                    private void update(DocumentEvent evt)
                                    {
                                      Element map = text.getDocument().getDefaultRootElement();
                                      int line = map.getElementIndex(evt.getOffset());
                                      DocumentEvent.ElementChange ec = evt.getChange(map);
                                      viewChanged(line, ec != null);
                                    }
                                  }
                                }
                                • 14. Re: Line Number in JTextPane
                                  843804
                                  Nice piece of code indeed. Glad you were able to work out the flickering problems I was facing while scrolling.

                                  One last detail though : your solution behaves pretty much like mine in that wrapped lines are not added. I wonder if there is a simple solution to it.
                                  1 2 3 上一个 下一个