0

A few days ago, I encountered a Swing error when trying to change the transparency of the JFrame (undecorated), which lost its color and transparency information.

When the application starts, it starts as “transparent,” then I change it to ‘opaque’ (no problems up to that point), but when I try to change it back to “transparent,” the error mentioned above appears.

Here is the code that show the problem:

public class TheSwingError extends JFrame {

   Color transparent = new Color( 255, 0, 0, 100 ),
           opaque = new Color( 255, 0, 0, 255 );

   public TheSwingError() {
      feel();
      setDefaultCloseOperation( javax.swing.WindowConstants.EXIT_ON_CLOSE );
      setBounds( 10, 10, 500, 500 );
      setUndecorated( true );
      setLayout( null );
      
      setBackground( transparent );
      
      JButton alternate = new JButton( "Transparent" );
      alternate.setBounds( 10, 10, 160, 26 );
      add( alternate );

      setVisible( true );

      alternate.addMouseListener( new java.awt.event.MouseAdapter() {
         @Override
         public void mouseClicked( java.awt.event.MouseEvent evt ) {
            JButton aux = ( JButton ) evt.getSource();
            if( aux.getText().equals( "Transparent" ) ) {
               setBackground( opaque );
               aux.setText( "Opaque" );
            }
            else {
               setBackground( transparent );
               aux.setText( "Transparent" );
            }
         }
      } );
   }

   private void feel() {
      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 | InstantiationException
              | IllegalAccessException | UnsupportedLookAndFeelException e ) {
         e.printStackTrace();
      }
   }

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

How can I fix this without resorting to overwriting the paintComponent() method?.

As you will see in my response, this post is intended, rather than to provide a way to achieve the objective, to prevent others from wasting a considerable amount of time solving a problem that stems from a language bug.

4
  • You've presented code (thank you), but the question is very unclear about the nature of the problem it's supposed to demonstrate. I appreciate that you have provided a self-answer, but others will be unlikely to benefit from it if they don't recognize that it addresses their problem. Commented 7 hours ago
  • In fact, even running your code does not make the issue clear to me. I had supposed that it would be something like not being able to make the background transparent again, but I don't observe any such problem. Commented 7 hours ago
  • BTW, do not write applications like that. Your program should not itself be a JFrame. It may have a JFrame as the top-level element of a GUI, but you should distinguish. In most cases you can and should build your GUI with stock classes. This is certainly such a case. Commented 6 hours ago
  • Is setting the Look & feel necessary for you to observe the issue? If so, then you should call that out in the question. If not, then you should remove that whole bit from the example code. Commented 6 hours ago

1 Answer 1

0

The code that follows these lines, although an unpleasant solution, is the only way (or not?) to achieve the objective (following the rule of not overwriting paintComponent()).

public class TheSwingError extends JFrame {

   Color transparent = new Color( 255, 0, 0, 100 ),
           opaque = new Color( 255, 0, 0, 254 );

   public TheSwingError() {
      feel();
      setDefaultCloseOperation( javax.swing.WindowConstants.EXIT_ON_CLOSE );
      setBounds( 10, 10, 500, 500 );
      setUndecorated( true );
      setLayout( null );
      
      setBackground( transparent );
      
      JButton alternate = new JButton( "Transparent" );
      alternate.setBounds( 10, 10, 160, 26 );
      add( alternate );

      setVisible( true );

      alternate.addMouseListener( new java.awt.event.MouseAdapter() {
         @Override
         public void mouseClicked( java.awt.event.MouseEvent evt ) {
            JButton aux = ( JButton ) evt.getSource();
            if( aux.getText().equals( "Transparent" ) ) {
               setBackground( opaque );
               aux.setText( "Opaque" );
            }
            else {
               setBackground( transparent );
               aux.setText( "Transparent" );
            }
         }
      } );
   }

   private void feel() {
      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 | InstantiationException
              | IllegalAccessException | UnsupportedLookAndFeelException e ) {
         e.printStackTrace();
      }
   }

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

As can be seen, the solution to the problem (perhaps I should call it a “patch” rather than a solution) involves modifying the value of the opaque attribute, changing it from opaque = new Color( 255, 0, 0, 255 ); to opaque = new Color( 255, 0, 0, 254 );.
This patch does not have a valid explanation for “why it works,” since we are working on a bug; I only arrived at it through trial and error.

Here is the code I sent to Oracle reporting the bug, which was confirmed by them, and the address to follow up on it.

public class TheSwingError extends JFrame {

   Color transparent = new Color( 255, 0, 0, 100 ),
           almostOpaque = new Color( 255, 0, 0, 254 ),
           completelyOpaque = new Color( 255, 0, 0, 255 ),
           opaque = almostOpaque;

   public TheSwingError() {
      feel();
      setUndecorated( true );
      setDefaultCloseOperation( javax.swing.WindowConstants.EXIT_ON_CLOSE );
      setBounds( 10, 10, 500, 500 );
      setBackground( transparent );
      setLayout( null );

      JButton colorChooser = new JButton( "opaque = 255,0,0,254" );
      JButton alternate = new JButton( "Transparent" );

      colorChooser.setBounds( 10, 50, 160, 26 );
      alternate.setBounds( 10, 10, 160, 26 );
      add( colorChooser );
      add( alternate );

      setVisible( true );

      alternate.addMouseListener( new java.awt.event.MouseAdapter() {
         @Override
         public void mouseClicked( java.awt.event.MouseEvent evt ) {
            JButton aux = ( JButton ) evt.getSource();
            if( aux.getText().equals( "Transparent" ) ) {
               setBackground( opaque );
               aux.setText( "Opaque" );
            }
            else {
               setBackground( transparent );
               aux.setText( "Transparent" );
            }
         }
      } );

      colorChooser.addMouseListener( new java.awt.event.MouseAdapter() {
         @Override
         public void mouseClicked( java.awt.event.MouseEvent evt ) {
            JButton aux = ( JButton ) evt.getSource();
            if( aux.getText().equals( "opaque = 255,0,0,254" ) ) {
               opaque = completelyOpaque;
               aux.setText( "color = 255,0,0,255" );
            }
            else {
               opaque = almostOpaque;
               aux.setText( "opaque = 255,0,0,254" );
            }
         }
      } );
   }

   private void feel() {
      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 | InstantiationException
              | IllegalAccessException | UnsupportedLookAndFeelException e ) {
         e.printStackTrace();
      }

   }

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

If we repeatedly press the first button, we will see that the frame changes from transparent to opaque without any problems. As the second button “informs” us, you are using an opacity of “254.” If we press the second button, the opacity is set to “255,” and that's where the problem arises. When you try to make it transparent again, it loses its color and transparency. If you press it again, it returns to normal functioning.

You can follow the status here

1
  • 2
    1) Don't use a MouseLister to handle clicking of the button. If the mouse moves even a pixel between the mousePressed/mouseReleased events a click event will not be generated. You should be using an ActionListener for this. 2) I'm still using Java 11 and I don't have a problem, so I can't really test. 3) Maybe try adding a frame.repaint() to force repainting of the frame. Maybe add the repaint() to a SwingUtilities.invokeLater() to make sure it is added to the end of the EDT.
    – camickr
    Commented 6 hours ago

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.