Java - repaint(x, y, w, h) doesn't call paintC

2019-02-24 22:28发布

问题:

I asked this before, but only theoretically, without an SSCCE. Now, I've created one, and the problem persists. I'd like to know why paintComponent is not called on repaint(x, y, w, h), but is called on repaint().

Two classes:

SANDBOX

import java.awt.Dimension;
import java.awt.FlowLayout;

import javax.swing.JFrame;

public class Sandbox {
    public static void main(String[] args) {
        JFrame f = new JFrame();
        f.setMinimumSize(new Dimension(800, 600));
        f.setLocationRelativeTo(null);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLayout(new FlowLayout());

        // Add label
        f.getContentPane().add(new TLabel());

        f.setVisible(true);
    }
}

and TLabel (with a little styling):

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JLabel;
import javax.swing.SwingConstants;
import javax.swing.border.LineBorder;

@SuppressWarnings("serial")
public class TLabel extends JLabel {
    public TLabel() {
    super("TEST LABEL, NON-STATIC");
    this.setHorizontalAlignment(SwingConstants.CENTER);
    TLabel.this.setPreferredSize(new Dimension(200, 50));
    TLabel.this.setMaximumSize(new Dimension(200, 50));
    TLabel.this.setMinimumSize(new Dimension(200, 50));

    TLabel.this.setOpaque(true);
    TLabel.this.setBackground(Color.cyan.darker().darker());
    TLabel.this.setForeground(Color.white);
    TLabel.this.setBorder(new LineBorder(Color.orange, 2));

    this.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                // EXPECTED BEHAVIOR HERE: This line will call paint and paintComponent.
                //repaint();

                // PROBLEM HERE: This line will not call paint or paintComponent.
                repaint(TLabel.this.getBounds());
        }
    });
    }

    @Override
    public void paint(Graphics g) {
    // Note: This is called once when the label is realised.
    // Note: This is called when the mouse enters the frame.
    System.out.println("PAINT.");
    super.paint(g);
    }

    @Override
    public void paintComponent(Graphics g) {
    // Note: This is called once when the label is realised.
    // Note: This is called when the mouse enters the frame.
    System.out.println("REPAINT.");
    super.paintComponent(g);
    }
}

回答1:

You're calling this

repaint(TLabel.this.getBounds());

inside of the TLabel object. So repaint will try to paint a rectangle located relative to itself at the Bounds location, but getBounds() returns a rectangle located relative to this components containing object's location while repaint expects bounds relative to the component itself. So you're trying to paint a rectangle that has the width and height of your JLabel but which is located at x = 292 and y = 5 relative to the JLabel, when instead you want x and y to both be 0. In essence you're trying to draw way outside of this component.

Instead try this:

        //!! repaint(TLabel.this.getBounds());
        Dimension d = TLabel.this.getSize();
        repaint(new Rectangle(0, 0, d.width, d.height));