Opacity in Color is not being drawn on JPanel

62 views Asked by At

I am using paintComponent to make a fade-in opening. Though I can use transparent images to create this effect, I feel like drawing is both space conservative and efficient, but when I had tried to make code for it which is provided below

Graphics2D painter = (Graphics2D)g;
        int paint = 0;
        
        
        if (paint!=255) {
            painter.setColor(new Color(0, 0, 0, paint));
            paint+=17;
            painter.drawImage(frm1,0,-16,768,576,null);
            painter.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
            
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

The window starts with a white screen, later showing frm1 (the image that I want the opacity to overlay)

In the Frame's code, I tried typing the constructor (which contains the start to the game loop) after the frame.setVisible(true); line of code, this affected the code in no way whatsoever. Even though I can use transparent images, I am trying to make the game more lightweight, therefore I would prefer paintComponent.

The code for the panel is provided below

package studios.masterpiece.pts.display;

//AWT
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
//IO
import java.io.IOException;

//ImageIO
import javax.imageio.ImageIO;
//Swing
import javax.swing.JPanel;
import javax.swing.Timer;

public class GameScene extends JPanel implements Runnable{
    
    private static final long serialVersionUID = -1892599432299801189L;
    
    Timer timer;
    
    Graphics painter;
    BufferedImage frm1;
    
    Thread repeat;
    
    //References
    static int tileSize = 48;
    
    static int rows = 16;
    static int columns = 12;
    
    public static int SCREEN_WIDTH = tileSize*rows; //768  
    public static int SCREEN_HEIGHT = tileSize*columns;
    
    //GameScene Properties
    public GameScene() {
        this.setSize(SCREEN_WIDTH,SCREEN_HEIGHT);
        this.setBackground(Color.BLACK);
        
        this.setFocusable(true);
        this.setDoubleBuffered(true);
        
        startRepeat();
        
        //Getting the image I want the opacity to overlay
        try {
            frm1 = ImageIO.read(getClass().getResourceAsStream("/studios/masterpiece/pts/animations/intro/Intro1.png"));
        } 
        catch (IOException e) {e.printStackTrace();}
    }
    
    public void startRepeat() {
        repeat = new Thread(this);
        repeat.start();
        
        //CURRENTLY DOES NOT WORK
        timer = new Timer(250, new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent event) {
                Timer timer = (Timer) event.getSource();
                int opacity = this.getOpacity();
                opacity += 15;
                if (opacity < 255) {
                    this.setOpacity(opacity);
                } else {
                    opacity = 255;
                    this.setOpacity(opacity);
                    timer.stop();
                }
                this.repaint();
            }
        });
        timer.start();
        //UNTIL HERE
    }
    public void paintComponent(Graphics g) {
        
        super.paintComponent(g);
        
        Graphics2D painter = (Graphics2D)g;
        
        this.painter=painter;       
    }

    @Override
    public void run() {
        while (repeat!=null) {
            repaint();
            
        }
    }

}
1

There are 1 answers

8
Gilbert Le Blanc On BEST ANSWER

Here's an example of a fade-in GUI.

Here's the initial GUI:

Initial GUI

Here's the GUI after the image is faded in:

Final GUI

So, How did I do this?

I created a JFrame and a drawing JPanel. I drew the background and the text using Color instances with a specified opacity or alpha component.

I used a Swing Timer to adjust the opacity every 250 milliseconds and repaint the drawing JPanel.

Here's the complete runnable code. I made the additional class an inner class so I could post the code as one block.

import java.awt.BorderLayout;
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.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class FadeInGUI implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new FadeInGUI());
    }

    private final DrawingPanel drawingPanel;

    public FadeInGUI() {
        this.drawingPanel = new DrawingPanel();
    }

    @Override
    public void run() {
        JFrame frame = new JFrame("Fade In GUI");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.add(drawingPanel, BorderLayout.CENTER);

        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);

        Timer timer = new Timer(250, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                Timer timer = (Timer) event.getSource();
                int opacity = drawingPanel.getOpacity();
                opacity += 15;
                if (opacity < 255) {
                    drawingPanel.setOpacity(opacity);
                } else {
                    opacity = 255;
                    drawingPanel.setOpacity(opacity);
                    timer.stop();
                }
                drawingPanel.repaint();
            }
        });
        timer.start();
    }

    public class DrawingPanel extends JPanel {

        private static final long serialVersionUID = 1L;

        private int opacity;

        public DrawingPanel() {
            this.opacity = 0;
            this.setPreferredSize(new Dimension(640, 480));
        }

        public void setOpacity(int opacity) {
            this.opacity = opacity;
        }

        public int getOpacity() {
            return opacity;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            Color backgroundColor = new Color(255, 255, 0, opacity);
            Color textColor = new Color(0, 0, 255, opacity);

            g.setColor(backgroundColor);
            g.fillRect(0, 0, getWidth(), getHeight());

            String text = "Amazing Game";
            Font titleFont = getFont().deriveFont(Font.BOLD, 48f);
            Rectangle r = new Rectangle(0, 0, getWidth(), getHeight() / 3);
            drawCenteredString(g, text, r, textColor, titleFont);

            text = "by Amazing Company";
            Font subtitleFont = getFont().deriveFont(Font.BOLD, 32f);
            r = new Rectangle(0, getHeight() * 2 / 3, getWidth(),
                    getHeight() / 3);
            drawCenteredString(g, text, r, textColor, subtitleFont);
        };

        /**
         * Draw a String centered in the middle of a Rectangle.
         *
         * @param g    The Graphics instance.
         * @param text The String to draw.
         * @param rect The Rectangle to center the text in.
         */
        private void drawCenteredString(Graphics g, String text, Rectangle rect,
                Color color, Font font) {
            FontMetrics metrics = g.getFontMetrics(font);
            int x = rect.x + (rect.width - metrics.stringWidth(text)) / 2;
            int y = rect.y + ((rect.height - metrics.getHeight()) / 2)
                    + metrics.getAscent();
            g.setFont(font);
            g.setColor(color);
            g.drawString(text, x, y);
        }

    }

}