Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8187603

Undecorated non-opaque JDialog doesn't reappear on screen after its parent JFrame minimized/maximized

XMLWordPrintable

      FULL PRODUCT VERSION :
      Tried on multiple JDK 7 and 8 versions:
      JDK 1.7.0_45 x32
      JDK 1.7.0_45 x64
      JDK 1.7.0_75 x32
      JDK 1.7.0_75 x64
      JDK 1.7.0_80 x32
      JDK 1.7.0_80 x64
      JDK 1.8.0_25 x32
      JDK 1.8.0_25 x64
      JDK 1.8.0_45 x32
      JDK 1.8.0_45 x64
      JDK 1.8.0_66 x32
      JDK 1.8.0_66 x64
      JDK 1.8.0_91 x32
      JDK 1.8.0_91 x64
      JDK 1.8.0_121 x32
      JDK 1.8.0_121 x64
      JDK 1.8.0_144 x32
      JDK 1.8.0_144 x64
      Result is the same on all of them.
      Though I cannot reproduce it on older (JDK 6) versions.

      ADDITIONAL OS VERSION INFORMATION :
      Tried on multiple Windows versions on different machines:
      Windows 10 x64
      Windows 8.1 x64
      Windows 8 x64
      Windows 7 x64
      Result is the same on all of them.

      EXTRA RELEVANT SYSTEM CONFIGURATION :
      Common Windows/JDK installation.
      Application was launched using IntelliJ IDE and from raw JAR - result is the same.

      A DESCRIPTION OF THE PROBLEM :
      Whenever undecorated non-opaque JDialog is minimized because of its parent JFrame being minimized - that JDialog becomes invisible upon JFrame state restoration. You can actually check that JDialog is physically there because the whole rectangle where that JDialog should be visible is not letting any mouse events through even though you don't see JDialog at all. That JDialog even takes focus because you can see that JFrame loses it if you click where JDialog should be placed.

      Also exactly the same bug happens with JWindow if it is used in the same way JDialog used in the example below.

      REGRESSION. Last worked in version 6u45

      ADDITIONAL REGRESSION INFORMATION:
      This bug only appear under Windows OS and only on JDK 7 and later. Everything works perfectly fine with JDK 6 and earlier. Also everything works perfectly fine on other OS (tried latest Ubuntu and Mac OS X).

      Effect might slightly vary depending on Windows/JDK version - on some configurations dialog will be visible, but its graphics completely goes nuts and paints glitched elements from the original JFrame.

      Also exactly the same bug happens with JWindow if it is used in the same way JDialog used in the example below.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Launch provided code example
      2. Click the button to open JDialog slightly below the button
      3. Minimize JFrame by clicking on minimize button on native frame decoration
      4. Restore JFrame by clicking in OS task bar
      5. JDialog is invisible/glitched
      6. If it is invisible for you - try clicking below the button to ensure that it still blocks events

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      JDialog should properly become visible upon its parent JFrame restoration.
      Same goes for JWindow which has the very same issue if used in a similar manner.
      ACTUAL -
      JDialog becomes invisible/glitched (depending on JDK/OS version) and you are unable to use it starting from that point.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      There are no errors or crashes happening upon this bug appearance, so there is really nothing to attach.

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import javax.swing.*;
      import java.awt.*;
      import java.awt.event.ActionEvent;
      import java.awt.event.ActionListener;

      public class TransparentDialogTest
      {
          public static void main ( final String[] args )
          {
              final JFrame frame = new JFrame ( "Dialog test frame" );
              final JButton button = new JButton ( "Show dialog" );
              frame.add ( button );
              frame.setDefaultCloseOperation ( WindowConstants.EXIT_ON_CLOSE );
              frame.pack ();
              frame.setLocationRelativeTo ( null );

              final JDialog dialog = new JDialog ( frame, "Sample dialog" );
              final JLabel label = new JLabel ( "Sample dialog content" )
              {
                  protected void paintComponent ( Graphics g )
                  {
                      g.setColor ( Color.RED );
                      g.fillOval ( 0, 0, getWidth (), getHeight () );

                      super.paintComponent ( g );
                  }
              };
              label.setBorder ( BorderFactory.createEmptyBorder ( 50, 50, 50, 50 ) );
              dialog.add ( label );
              dialog.setUndecorated ( true );
              dialog.setBackground ( new Color ( 255, 255, 255, 0 ) );
              dialog.pack ();

              button.addActionListener ( new ActionListener ()
              {
                  public void actionPerformed ( ActionEvent e )
                  {
                      final Dimension size = dialog.getSize ();
                      final Point los = button.getLocationOnScreen ();
                      dialog.setLocation ( los.x + button.getWidth () / 2 - size.width / 2, los.y + button.getHeight () );
                      dialog.setVisible ( true );
                  }
              } );

              frame.setVisible ( true );
          }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      It is possible to workaround this issue but the fix is inconvenient and won't properly for all possible window states (at least in the basic form) - we simply need to hide JDialog whenever parent JFrame is minimized and we also need to show it again whenever parent JFrame is restored. In that case JDialog doesn't become invisible/glitched.

      Here is an SSCCE:

      import javax.swing.*;
      import java.awt.*;
      import java.awt.event.ActionEvent;
      import java.awt.event.ActionListener;
      import java.awt.event.WindowEvent;
      import java.awt.event.WindowStateListener;

      public class FixTest
      {
          public static void main ( final String[] args )
          {
              final JFrame frame = new JFrame ( "Dialog test frame" );
              final JButton button = new JButton ( "Show dialog" );
              frame.add ( button );
              frame.setDefaultCloseOperation ( WindowConstants.EXIT_ON_CLOSE );
              frame.pack ();
              frame.setLocationRelativeTo ( null );

              final JDialog dialog = new JDialog ( frame, "Sample dialog" );
              final JLabel label = new JLabel ( "Sample dialog content" )
              {
                  protected void paintComponent ( Graphics g )
                  {
                      g.setColor ( Color.RED );
                      g.fillOval ( 0, 0, getWidth (), getHeight () );

                      super.paintComponent ( g );
                  }
              };
              label.setBorder ( BorderFactory.createEmptyBorder ( 50, 50, 50, 50 ) );
              dialog.add ( label );
              dialog.setUndecorated ( true );
              dialog.setBackground ( new Color ( 255, 255, 255, 0 ) );
              dialog.pack ();

              button.addActionListener ( new ActionListener ()
              {
                  public void actionPerformed ( ActionEvent e )
                  {
                      final Dimension size = dialog.getSize ();
                      final Point los = button.getLocationOnScreen ();
                      dialog.setLocation ( los.x + button.getWidth () / 2 - size.width / 2, los.y + button.getHeight () );
                      dialog.setVisible ( true );
                  }
              } );

              frame.setVisible ( true );

              frame.addWindowStateListener ( new WindowStateListener ()
              {
                  private boolean wasVisible = false;

                  public void windowStateChanged ( WindowEvent e )
                  {
                      if ( e.getID () == WindowEvent.WINDOW_STATE_CHANGED )
                      {
                          if ( e.getNewState () == Frame.ICONIFIED && dialog.isVisible () )
                          {
                              dialog.setVisible ( false );
                              wasVisible = true;
                          }
                          if ( e.getOldState () == Frame.ICONIFIED && wasVisible )
                          {
                              dialog.setVisible ( true );
                              wasVisible = false;
                          }
                      }
                  }
              } );
          }
      }

        1. FixTest.java
          3 kB
        2. FixTest.java
          3 kB
        3. TransparentDialogTest.java
          2 kB
        4. TransparentDialogTest.java
          2 kB

            scfitch Stephen Fitch
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: