Search code examples
javaswingjpanelbufferedimagepaintcomponent

JPanel Image Gets Run more than once


I am trying to get these two sections of code to work together, but I am having issues. This first section of code builds the form, which is generated by my editor (Netbeans GUI Builder for Java), not sure if this is what is causing the problem or not.

What is happening is when I run the project, my code (second block of code) gets run and inverts the colors of the image (exactly what it is supposed to do) then it gets rest back to the original image (Non-inverted) which shouldn't happen, the image should display in the panel as a non-inverted image. Then when I click on the frame border to re-size the panel image flashes to inverted, then non-inverted, then inverted. Clicking on it again it does the same thing but stops on non-inverted. What is causing this strange issue?

package weblaftest;

/**
 *
 * @author Ryan
 */
public class Main extends javax.swing.JFrame{
    /**
     * Creates new form Main
     */
    public Main(){
        initComponents();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        jInternalFrame1 = new javax.swing.JInternalFrame();
        test1 = new weblaftest.test();

        jInternalFrame1.setVisible(true);

        javax.swing.GroupLayout jInternalFrame1Layout = new javax.swing.GroupLayout(jInternalFrame1.getContentPane());
        jInternalFrame1.getContentPane().setLayout(jInternalFrame1Layout);
        jInternalFrame1Layout.setHorizontalGroup(
            jInternalFrame1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 0, Short.MAX_VALUE)
        );
        jInternalFrame1Layout.setVerticalGroup(
            jInternalFrame1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 0, Short.MAX_VALUE)
        );

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        javax.swing.GroupLayout test1Layout = new javax.swing.GroupLayout(test1);
        test1.setLayout(test1Layout);
        test1Layout.setHorizontalGroup(
            test1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 409, Short.MAX_VALUE)
        );
        test1Layout.setVerticalGroup(
            test1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 362, Short.MAX_VALUE)
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(test1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(262, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap(83, Short.MAX_VALUE)
                .addComponent(test1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(74, 74, 74))
        );

        pack();
    }// </editor-fold>

    /**
     * @param args the command line arguments
     */

    public static void main(String args[]){
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
         */
        try{
            for(javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()){
                if("Nimbus".equals(info.getName())){
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        }catch(ClassNotFoundException ex){
            java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }catch(InstantiationException ex){
            java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }catch(IllegalAccessException ex){
            java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }catch(javax.swing.UnsupportedLookAndFeelException ex){
            java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable(){
            @Override
            public void run(){
                new Main().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify
    private javax.swing.JInternalFrame jInternalFrame1;
    private weblaftest.test test1;
    // End of variables declaration
}

This section is what I wrote, it is the code for the panel that displays the image, for testing purposes, all It does is invert the colors on the image that displayed in the panel.

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package weblaftest;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import weblaftest.grapics.Colors;

/**
 *
 * @author Ryan
 */
public class test extends javax.swing.JPanel{
private BufferedImage image;
    /**
     * Creates new form test
     */
    public test(){
        try{
            image = ImageIO.read(new File("/Users/Public/Pictures/Sample Pictures/Chrysanthemum.jpg"));
        }catch(IOException e){
        }
    }

    @Override
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        int width = image.getWidth();
        int height = image.getHeight();
        for(int x = 0; x < width; x++){
            for(int y = 0; y < height; y++){
                int color = image.getRGB(x, y);
                int red = Colors.red(color);
                int green = Colors.green(color);
                int blue = Colors.blue(color);

                int rgb = Colors.rgba(255 - red, 255 - green, 255 - blue);
                image.setRGB(x, y, rgb);
            }
        }
        g.drawImage(image, 0, 0, width, height, Color.black, null);
    }


    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 300, Short.MAX_VALUE)
        );
    }// </editor-fold>
    // Variables declaration - do not modify
    // End of variables declaration
}

Here is the requested Colors class:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package weblaftest.grapics;

/**
 *
 * @author Ryan
 */
public class Colors{

    public static int rgba(int red, int green, int blue, Integer alpha){
        int rgba = alpha;
        rgba = (rgba << 8) + red;
        rgba = (rgba << 8) + green;
        rgba = (rgba << 8) + blue;
        return rgba;
    }
    public static int rgba(int red, int green, int blue){
        int rgba = 255;
        rgba = (rgba << 8) + red;
        rgba = (rgba << 8) + green;
        rgba = (rgba << 8) + blue;
        return rgba;
    }

    public static int alpha(int color){
        return color >> 24 & 0x0FF;
    }

    public static int red(int color){
        return color >> 16 & 0x0FF;
    }

    public static int green(int color){
        return color >> 8 & 0x0FF;
    }

    public static int blue(int color){
        return color & 0x0FF;
    }
}

Solution

    • Keep paintComponent() only for drawing no long running processing should be done in paintComponent(..)
    • Class names should begin with a capitalized letter i.e Test

    Here is the problem:

    @Override
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        int width = image.getWidth();
        int height = image.getHeight();
        for(int x = 0; x < width; x++){
            for(int y = 0; y < height; y++){
                int color = image.getRGB(x, y);
                int red = Colors.red(color);
                int green = Colors.green(color);
                int blue = Colors.blue(color);
    
                int rgb = Colors.rgba(255 - red, 255 - green, 255 - blue);
                image.setRGB(x, y, rgb);
            }
        }
        g.drawImage(image, 0, 0, width, height, Color.black, null);
    }
    

    You draw the inverted BufferedImage on the first call to paintComponent() on successive calls it will re-vert and invert again each time.

    Rather invert the BufferedImage in your constructor and paint only the inverted BufferedImage in paintComponent(..) do not do inverting in paintComponent(..) hence the switch between inverted and original image as JFrame is re-sized:

    /**
     *
     * @author Ryan
     */
    public class Test extends javax.swing.JPanel {
    
        private BufferedImage image;
        int width;
        int height;
    
        /**
         * Creates new form test
         */
        public Test() {
            try {
                image = ImageIO.read(new URL("http://imgs.mi9.com/uploads/flower/4533/tulip-flowers_400x300_80023.jpg"));
                invertImage();
            } catch (Exception e) {
            }
        }
    
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(image, 0, 0, width, height, Color.black, null);
        }
    
        /**
         * This method is called from within the constructor to initialize the form.
         * WARNING: Do NOT modify this code. The content of this method is always
         * regenerated by the Form Editor.
         */
        @SuppressWarnings("unchecked")
        // <editor-fold defaultstate="collapsed" desc="Generated Code">
        private void initComponents() {
    
            javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
            this.setLayout(layout);
            layout.setHorizontalGroup(
                    layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGap(0, 400, Short.MAX_VALUE));
            layout.setVerticalGroup(
                    layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGap(0, 300, Short.MAX_VALUE));
        }// </editor-fold>
        // Variables declaration - do not modify
        // End of variables declaration
    
        private void invertImage() {
            width = image.getWidth();
            height = image.getHeight();
            for (int x = 0; x < width; x++) {
                for (int y = 0; y < height; y++) {
                    int color = image.getRGB(x, y);
                    int red = Colors.red(color);
                    int green = Colors.green(color);
                    int blue = Colors.blue(color);
    
                    int rgb = Colors.rgba(255 - red, 255 - green, 255 - blue);
                    image.setRGB(x, y, rgb);
                }
            }
        }
    }