Can not sync with view after filling rectange of line in JTextPane java swing

51 Views Asked by At

I have trouble regarding highlighting the specific line in jtextpane java swing. I have main class named Solution and Modified LinePainter that i found it online. Whenever sl() function is called, it paints specific line. that is due to call to paint method. I printed dummy lines in paint method. that dummy line printed frequently. That means paint method is called after predefined period. after running code i found that whenever i maximize or minimize the window then only it shows correct desired line highlight. i want that whenever i call the sl function (sl means set line means highlight line number that is passed). What should change or learn ? Thanks for reading.

Solution.java file

import javax.swing.*;
import java.util.Scanner;

public class Solution {
    public static void main(String[] args) {
        JFrame f = new JFrame("Swing Paint Demo");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JTextPane jTextPane=new JTextPane();
        jTextPane.setText("abc\nbcd\nmm\njjjjj");
        LinePainter linePainter=new LinePainter(jTextPane);
        Scanner sc=new Scanner(System.in);
        f.add(jTextPane);
        f.setSize(250,250);
        f.setVisible(true);
        int x=sc.nextInt();
        linePainter.sl(2);
        x=sc.nextInt();
        linePainter.sl(3);
    }
}

LinePainter.java File

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;

/*
 *  Track the movement of the Caret by painting a background line at the
 *  current caret position.
 */
public class LinePainter
        implements Highlighter.HighlightPainter, CaretListener, MouseListener, MouseMotionListener
{
    private JTextComponent component;

    private Color color;

    private Rectangle lastView;

    /*
     *  The line color will be calculated automatically by attempting
     *  to make the current selection lighter by a factor of 1.2.
     *
     *  @param component  text component that requires background line painting
     */
    public LinePainter(JTextComponent component)
    {
        this(component, null);
        setLighter(component.getSelectionColor());
    }

    /*
     *  Manually control the line color
     *
     *  @param component  text component that requires background line painting
     *  @param color      the color of the background line
     */
    public LinePainter(JTextComponent component, Color color)
    {
        this.component = component;
        setColor( color );

        //  Add listeners so we know when to change highlighting

        component.addCaretListener( this );
        component.addMouseListener( this );
        component.addMouseMotionListener( this );

        //  Turn highlighting on by adding a dummy highlight

        try
        {
            component.getHighlighter().addHighlight(0, 0, this);
        }
        catch(BadLocationException ble) {}
    }

    /*
     *  You can reset the line color at any time
     *
     *  @param color  the color of the background line
     */
    public void setColor(Color color)
    {
        this.color = color;
    }

    /*
     *  Calculate the line color by making the selection color lighter
     *
     *  @return the color of the background line
     */
    public void setLighter(Color color)
    {
        int red   = Math.min(255, (int)(color.getRed() * 1.2));
        int green = Math.min(255, (int)(color.getGreen() * 1.2));
        int blue  = Math.min(255, (int)(color.getBlue() * 1.2));
        setColor(new Color(red, green, blue));
    }
    public int ln=1;
    public void sl(int l) { ln=l;
        System.out.println("hii"); }
    //  Paint the background highlight

    public void paint(Graphics g, int p0, int p1, Shape bounds, JTextComponent c)
    {
        try
        {
            System.out.println("calling paint");
//            resetHighlight();
            Rectangle r = c.modelToView((c).getDocument().getDefaultRootElement().getElement(ln-1).getStartOffset());
            g.setColor( color );
//            if(lastView != null){
//                g.clearRect(0,lastView.y,c.getWidth(),lastView.height);
//            }
            g.fillRect(0, r.y, c.getWidth(), r.height);

//            if (lastView == null)
//                lastView = r;
        }
        catch(BadLocationException ble) {System.out.println(ble);}
    }

    /*
     *   Caret position has changed, remove the highlight
     */
    private void resetHighlight()
    {
        System.out.println("reset");
        //  Use invokeLater to make sure updates to the Document are completed,
        //  otherwise Undo processing causes the modelToView method to loop.

        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                try
                {

                    Rectangle currentView = component.modelToView(component.getDocument().getDefaultRootElement().getElement(ln-1).getStartOffset());;

                    //  Remove the highlighting from the previously highlighted line

                    if (lastView.y != currentView.y)
                    {
                        component.repaint(0, lastView.y, component.getWidth(), lastView.height);
                        lastView = currentView;
                    }
                }
                catch(BadLocationException ble) {}
            }
        });
    }

    //  Implement CaretListener

    public void caretUpdate(CaretEvent e)
    {
//        resetHighlight();
    }

    //  Implement MouseListener

    public void mousePressed(MouseEvent e)
    {
//        resetHighlight();
    }

    public void mouseClicked(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
    public void mouseReleased(MouseEvent e) {}

    //  Implement MouseMotionListener

    public void mouseDragged(MouseEvent e)
    {
//        resetHighlight();
    }

    public void mouseMoved(MouseEvent e) {}
}

UPDATE:

I updated my LinePainter file as following.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;

/*
 *  Track the movement of the Caret by painting a background line at the
 *  current caret position.
 */
public class LinePainter
        implements Highlighter.HighlightPainter, CaretListener, MouseListener, MouseMotionListener
{
    private JTextComponent component;

    private Color color;

    private Rectangle lastView;

    /*
     *  The line color will be calculated automatically by attempting
     *  to make the current selection lighter by a factor of 1.2.
     *
     *  @param component  text component that requires background line painting
     */
    public LinePainter(JTextComponent component)
    {
        this(component, null);
        setLighter(component.getSelectionColor());
    }

    /*
     *  Manually control the line color
     *
     *  @param component  text component that requires background line painting
     *  @param color      the color of the background line
     */
    public LinePainter(JTextComponent component, Color color)
    {
        this.component = component;
        setColor( color );

        //  Add listeners so we know when to change highlighting

        component.addCaretListener( this );
        component.addMouseListener( this );
        component.addMouseMotionListener( this );

        //  Turn highlighting on by adding a dummy highlight

        try
        {
            component.getHighlighter().addHighlight(0, 0, this);
        }
        catch(BadLocationException ble) {}
    }

    /*
     *  You can reset the line color at any time
     *
     *  @param color  the color of the background line
     */
    public void setColor(Color color)
    {
        this.color = color;
    }

    /*
     *  Calculate the line color by making the selection color lighter
     *
     *  @return the color of the background line
     */
    public void setLighter(Color color)
    {
        int red   = Math.min(255, (int)(color.getRed() * 1.2));
        int green = Math.min(255, (int)(color.getGreen() * 1.2));
        int blue  = Math.min(255, (int)(color.getBlue() * 1.2));
        setColor(new Color(red, green, blue));
    }
    public int ln=1,prev=1;
    public void sl(int l) { prev=ln; ln=l;
        System.out.println("hii");
        //resetHighlight();
    }
    //  Paint the background highlight

    public void paint(Graphics g, int p0, int p1, Shape bounds, JTextComponent c)
    {
        try
        {
//            System.out.println("calling paint");
//            resetHighlight();
            if(prev != ln){
                Rectangle rect=c.modelToView((c).getDocument().getDefaultRootElement().getElement(prev-1).getStartOffset());
               prev=ln;
                System.out.println(rect.y+" " +c.getWidth()+" "+rect.height);
                g.clearRect(0,rect.y,c.getWidth(),rect.height);
            }
            Rectangle r = c.modelToView((c).getDocument().getDefaultRootElement().getElement(ln-1).getStartOffset());
            g.setColor( color );
//            if(lastView != null){
//                g.clearRect(0,lastView.y,c.getWidth(),lastView.height);
//            }
            System.out.println(r.y+" " +c.getWidth()+" "+r.height);
            g.fillRect(0, r.y, c.getWidth(), r.height);

            if (lastView == null)
                lastView = r;
        }
        catch(BadLocationException ble) {System.out.println(ble);}
    }

    /*
     *   Caret position has changed, remove the highlight
     */
    private void resetHighlight()
    {
        System.out.println("reset");
        //  Use invokeLater to make sure updates to the Document are completed,
        //  otherwise Undo processing causes the modelToView method to loop.

        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                try
                {
                    System.out.println("prev line "+prev+" "+ln);
                    Rectangle currentView = component.modelToView(component.getDocument().getDefaultRootElement().getElement(prev-1).getStartOffset());
                    //  Remove the highlighting from the previously highlighted line
                    if (lastView.y != currentView.y)
                    {
                        component.repaint(0, lastView.y, component.getWidth(), lastView.height);
                        lastView = currentView;
                    }
                    prev=ln;
                }
                catch(BadLocationException ble) {}
            }
        });
    }

    //  Implement CaretListener

    public void caretUpdate(CaretEvent e)
    {
//        resetHighlight();
    }

    //  Implement MouseListener

    public void mousePressed(MouseEvent e)
    {
//        resetHighlight();
    }

    public void mouseClicked(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
    public void mouseReleased(MouseEvent e) {}

    //  Implement MouseMotionListener

    public void mouseDragged(MouseEvent e)
    {
//        resetHighlight();
    }

    public void mouseMoved(MouseEvent e) {}
}

still i am not getting my desired output. highlight is not updated after sl() call. If any suggestion please inform me. Thank you.....

1

There are 1 best solutions below

4
camickr On

Looks like you got the code from Line Painter.

The key to that code is the resetHighlight() method. That method is invoked every time the caret position is changed, so the highlight can be painted at the new line.

You have commented out all the calls to that method.

So I would think that you need to do two things:

  1. your sl(...) method need to invoke the resetHighlight() method.
  2. you need to modify the resetHighlight() method to calculate the Rectangle to be repainted based on the line number instead of the caret position.

    linePainter.sl(2);
    x=sc.nextInt();
    linePainter.sl(3);
    

Not sure what the point of that code is. The LinePainter will only ever paint one line at a time, so invoking the method twice will result in the 3rd line being highlighted.