3

Having developed my application against Java 5 I recently tested in 6 and found that I have a paintComponent problem.

What happens is in jre5 is the screen begins to dim and the button "foreground" appears on top of a dimming panel (as expected). In jre6 the button does not appear at all but you do get the dimming. You can coax the button out by moving your mouse over its location (forcing the rollover to repaint it). I can rearrange the code slightly to get the button to appear in jre6 but the dimmed panel is always painted over the top of the button.

I'm assuming its more by luck than good judgment that it works at all in jre5 but couldn't find much assistance online. Any help you can shed on the situation would be most appreciated.

I have produced the below code to show the problem:

    import java.awt.AlphaComposite;
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;

    import javax.swing.BorderFactory;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.Timer;

    @SuppressWarnings( "serial" )
    public class TranslucentGlass extends JPanel
    {
        public static void main( String[] args )
        {
            // Create a frame
            JFrame f = new JFrame();
            JPanel mainPanel = new JPanel( new BorderLayout() );

            JLabel bgLabel = new JLabel( System.getProperty( "java.version" ) );
            mainPanel.add( bgLabel, BorderLayout.SOUTH );

            // create a panel for the glasspane
            final JPanel glassPane = new JPanel();
            glassPane.setLayout( new BorderLayout() );
            glassPane.setVisible( false );
            glassPane.setOpaque( false );

            // create the containing panel for the 'foreground' button
            final JPanel largePanel = new JPanel( new BorderLayout() );
            largePanel.setOpaque( false );
            largePanel.setBorder( BorderFactory.createEmptyBorder( 0, 20, 50, 20 ) );
            largePanel.add( new JButton( "Foreground" ), BorderLayout.SOUTH );

            // set the glass pane and mainpanel
            f.add( mainPanel );
            f.setGlassPane( glassPane );
            f.setPreferredSize( new Dimension( 250, 250 ) );

            f.addWindowListener( new WindowAdapter()
            {
                @Override
                public void windowClosing( WindowEvent e )
                {
                    System.exit( 0 );
                }
            } );

            // an action to show or hide the panel on mouse clicked
            f.addMouseListener( new MouseAdapter()
            {
                boolean panelVisible = false;

                @Override
                public void mouseClicked( MouseEvent e )
                {
                    if( !panelVisible )
                    {
                        glassPane.removeAll();

                        TranslucentGlass dimmingPanel = new TranslucentGlass( false );
                        dimmingPanel.add( largePanel );

                        glassPane.add( dimmingPanel );

                        dimmingPanel.startTimer();
                        glassPane.setVisible( true );

                        panelVisible = true;
                    }
                    else
                    {
                        glassPane.setVisible( false );
                        panelVisible = false;
                    }
                }
            } );

            f.pack();
            f.setVisible( true );
        }

        private Timer timer;
        private float opacity = 0;
        private long sysTime = System.currentTimeMillis();

        private static final int TIMER_INTERVAL = 50; // measured in milliseconds
        private static final int TIMER_TOTAL = 750; // measured in milliseconds

        private static final Color FADE_COLOUR = Color.RED;
        private static final float FINAL_OPACITY = 0.3f;

        public TranslucentGlass()
        {
            this( true );
        }

        public TranslucentGlass( boolean startTimer )
        {
            super();
            setOpaque( false );
            setLayout( new BorderLayout() );

            // Create a new timer to change the opacity over time and repaint the panel
            timer = new Timer( TIMER_INTERVAL, new ActionListener()
            {
                public void actionPerformed( ActionEvent e )
                {
                    long newSysTime = System.currentTimeMillis();
                    opacity += FINAL_OPACITY * ( newSysTime - sysTime ) / TIMER_TOTAL;
                    sysTime = newSysTime;
                    validate();
                    repaint();

                    if( opacity >= FINAL_OPACITY )
                    {
                        timer.stop();
                    }
                }
            } );

            if( startTimer )
            {
                timer.start();
            }
        }

        public void startTimer()
        {
            timer.start();
        }

        // Override the paintComponent calling paintComponent*s* to ensure the panels contents are painted
        @Override
        protected void paintComponent( Graphics g )
        {
            final Graphics2D g2 = ( Graphics2D ) g;

            g2.setComposite( AlphaComposite.getInstance( AlphaComposite.SRC_OVER, opacity ) );
            g2.setColor( FADE_COLOUR );
            g2.fillRect( 0, 0, getWidth(), getHeight() );
            g2.dispose();

            super.paintComponents( g );
        }
    }
Remlap21
  • 871
  • 1
  • 7
  • 15

3 Answers3

2

you have to try these code and then put together

Community
  • 1
  • 1
mKorbel
  • 109,525
  • 20
  • 134
  • 319
1

Create a copy of the Graphics context in the paintComponent function. This will fix the problem.

public void paintComponent( Graphics g )
{       
    super.paintComponent( g ); 
    Graphics2D g2 = (Graphics2D) g.create();
    ...
}
Tony
  • 1,401
  • 9
  • 11
  • I've not seen this before in any of the custom components I've made, but for some reason disposing the `Graphics2D` was causing issues. Removing that line of code made it better, but didn't fix it altogether. Creating a copy of the `Graphics` and using that copy seems to do the trick. – Tony Feb 16 '12 at 18:46
0

The first statement in paintComponent should be

   super.paintComponent(g);

inorder to clear the off-screen bitmap. Otherwise, you can get unexpected results.

Amir Afghani
  • 37,814
  • 16
  • 84
  • 124