在JTextPane java swing中填充直线矩形后无法与视图同步

Posted

技术标签:

【中文标题】在JTextPane java swing中填充直线矩形后无法与视图同步【英文标题】:Can not sync with view after filling rectange of line in JTextPane java swing 【发布时间】:2018-12-03 11:15:21 【问题描述】:

我在突出显示 jtextpane java swing 中的特定行时遇到了麻烦。我有一个名为 Solution 和 Modified LinePainter 的主类,我在网上找到了它。每当调用 sl() 函数时,它都会绘制特定的行。那是由于调用paint方法。我用 paint 方法打印了虚拟线。那条虚拟线经常打印。这意味着在预定义的时间段后调用paint方法。运行代码后,我发现每当我最大化或最小化窗口时,它只会显示正确的所需行突出显示。我希望每当我调用 sl 函数时(sl 表示设置行表示突出显示传递的行号)。应该改变或学习什么?感谢阅读。

Solution.java 文件

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 文件

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) 

更新:

我更新了我的 LinePainter 文件如下。

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) 

我仍然没有得到我想要的输出。调用 sl() 后突出显示不更新。如果有任何建议,请告诉我。谢谢.....

【问题讨论】:

【参考方案1】:

您似乎从Line Painter 获得了代码。

该代码的关键是resetHighlight() 方法。每次更改插入符号位置时都会调用该方法,因此可以在新行处绘制突出显示。

您已注释掉对该方法的所有调用。

所以我认为你需要做两件事:

    您的 sl(...) 方法需要调用 resetHighlight() 方法。

    您需要修改resetHighlight()方法,以根据行号而不是插入符号位置来计算要重绘的Rectangle。

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

不确定该代码的意义是什么。 LinePainter 一次只会绘制一条线,因此调用该方法两次将导致第 3 行被突出显示。

【讨论】:

@Hiatus_9,很高兴这个建议有所帮助。不要忘记“接受”答案,这样人们就知道问题已经解决了。 @camicrk 但无法获得正确的输出。仍然遇到同步问题。每当调用 sl(...) 方法时,如果我没有最大化或最小化窗口,则不会显示更新。请帮我。谢谢。 当我仔细查看原始代码时,代码的关键是 caretPosition 和该位置行高的 Rectangle。插入符号在paint() 和resetHighlight() 方法中被引用。所以我猜你需要更改这些方法以根据行号访问 Rectangle 。我看不出有任何理由保留前一个行号。我还建议您在更改要突出显示的行号时需要调用 resetHighlight() 方法。如果这不起作用,我不知道问题出在哪里。

以上是关于在JTextPane java swing中填充直线矩形后无法与视图同步的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Java Swing 中使用 Label 实现视图?

Java Swing 文本字段中的 ANSI 颜色

如何让 java jTextPane 接受拖动外部文件?

JTextField 和 JTextPane 之间的根本区别是啥?

如何防止 JTextPane.setCaretPosition(int) 中的内存泄漏?

在 java swing 中显示在一行中的 Blob 数据