Clear previously drawn string over an image

2019-09-03 02:51发布

问题:

I am wondering how I can clear a previously drawn string before drawing a new one over an image, if I do not clear the strings overlap. I have tried graphics#drawRect and overriding paintComponent(Graphics), still no eval.

Here is my code: paintComponent(Graphics)

public class SplashScreen extends JLabel
{

    private static final long serialVersionUID = 5515310205953670741L;

    private static final String ROOT = "./assets/img/";

    private static final SplashScreen INSTANCE = new SplashScreen( get( new File( ROOT, "splash.png" ) ), get( new File( ROOT, "splash-bar.png" ) ) );

    private final BufferedImage background;

    private final BufferedImage foreground;

    private final JLabel label;


    private SplashScreen( BufferedImage background, BufferedImage foreground )
    {
        this.background = background;
        this.foreground = foreground;
        label = new JLabel( new ImageIcon( background ) );

        JWindow window = new JWindow();
        window.setSize( background.getWidth(), background.getHeight() );
        window.getContentPane().add( label );
        Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
        window.setLocation( dimension.width / 2 - window.getSize().width / 2, dimension.height / 2 - window.getSize().height / 2 );
        window.setVisible( true );
    }


    public void updateStatus( String status )
    {
        Graphics g = background.getGraphics();

        g.drawString( status, 304, 301 );
        g.dispose();

        label.repaint();
    }


    public void updateBar( int width )
    {
        Graphics g = background.getGraphics();

        g.drawImage( foreground, 73, 309, width, foreground.getHeight(), null );
        g.dispose();

        label.repaint();
    }


    private static BufferedImage get( File file )
    {
        try {
            return ImageIO.read( file );
        } catch( IOException e ) {
            throw new RuntimeException( e.getMessage() );
        }
    }


    public static SplashScreen getInstance()
    {
        return INSTANCE;
    }

}

Any help is greatly appreciated. :-)

Thanks.

回答1:

You don't need to do custom painting.

Here are a couple of different ways to paint text on a label with an Icon:

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

public class LabelImageText extends JPanel
{
    public LabelImageText()
    {
        JLabel label1 = new JLabel( new ColorIcon(Color.ORANGE, 100, 100) );
        label1.setText( "Easy Way" );
        label1.setHorizontalTextPosition(JLabel.CENTER);
        label1.setVerticalTextPosition(JLabel.CENTER);
        add( label1 );

        //

        JLabel label2 = new JLabel( new ColorIcon(Color.YELLOW, 200, 150) );
        label2.setLayout( new BoxLayout(label2, BoxLayout.Y_AXIS) );
        add( label2 );

        JLabel text = new JLabel( "More Control" );
        text.setAlignmentX(JLabel.CENTER_ALIGNMENT);
        label2.add( Box.createVerticalGlue() );
        label2.add( text );
        label2.add( Box.createVerticalStrut(10) );

        //

        JLabel label3 = new JLabel( new ColorIcon(Color.GREEN, 200, 150) );
        add( label3 );

        JLabel text3 = new JLabel();
        text3.setText("<html><center>Text<br>over<br>Image<center></html>");
        text3.setLocation(20, 20);
        text3.setSize(text3.getPreferredSize());
        label3.add( text3 );

        //

        JLabel label4 = new JLabel( new ColorIcon(Color.CYAN, 200, 150) );
        add( label4 );

        JTextPane textPane = new JTextPane();
        textPane.setText("Add some text that will wrap at your preferred width");
        textPane.setEditable( false );
        textPane.setOpaque(false);
        SimpleAttributeSet center = new SimpleAttributeSet();
        StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
        StyledDocument doc = textPane.getStyledDocument();
        doc.setParagraphAttributes(0, doc.getLength(), center, false);
        textPane.setBounds(20, 20, 75, 100);
        label4.add( textPane );
    }

    public static class ColorIcon implements Icon
    {
        private Color color;
        private int width;
        private int height;

        public ColorIcon(Color color, int width, int height)
        {
            this.color = color;
            this.width = width;
            this.height = height;
        }

        public int getIconWidth()
        {
            return width;
        }

        public int getIconHeight()
        {
            return height;
        }

        public void paintIcon(Component c, Graphics g, int x, int y)
        {
            g.setColor(color);
            g.fillRect(x, y, width, height);
        }
    }

    private static void createAndShowUI()
    {
        JFrame frame = new JFrame("LabelImageText");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( new LabelImageText() );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowUI();
            }
        });
    }
}

Then to change the text you just change the text in the component you are using to display the text.

If none of these help then the way to do custom painting is to override the paintCompnent() method of the JLabel. You should not be painting the text directly on the BufferedImage.



回答2:

Basically, you can't.

What you should try doing is keep a reference to the original background image and when you need to change the text, copy it to a temp image and draw the String there, replacing it (the temp copy) as the label's icon...

A better solution might be to paint the text directly as part of the labels paint process by overriding the paintComponent method