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

SwingNode or SwingNode content doesn't resize as expected under Windows 10

XMLWordPrintable

    • x86_64
    • windows_10

      ADDITIONAL SYSTEM INFORMATION :
      Microsoft Windows [Version 10.0.17763.316]
      JDK 11 and JDK 12 same issue
      JavaFX 11.0.2

      A DESCRIPTION OF THE PROBLEM :
      The javafx.embed.swing.SwingNode works fine under Windows 7 and MacOS, but not under Windows 10.
      The content of the SwingNode gets cleared by resizing the frame (ie. pulling on the corner of the window).

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Compile and start the given program example. Two frames will be displayed. The "Swing Example" is a javax.swing.JFrame.
      The "SwingNode for JavaFX Example" is a Java-FX solution with Swing-content in a SwingNode. The content will break after resizing the frame. A click on a "Press me" button will activate the hack-around.
      But this hack is not a clean solution.
      Additional artifacts will be shown if the UI is more complex.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The expected behavior on Windows 10 is like the behavior on Windows 7: The content is cleanly updated while resizing the frame.
      ACTUAL -
      The display of the SwingNode content is incorrect after resizing (flickering, artifacts, missing components, incorrect component sizes, ghosting).

      ---------- BEGIN SOURCE ----------
      import javafx.application.Application;
      import javafx.application.Platform;
      import javafx.beans.value.ChangeListener;
      import javafx.embed.swing.SwingNode;
      import javafx.scene.Scene;
      import javafx.scene.layout.StackPane;
      import javafx.stage.Stage;

      import javax.swing.*;
      import java.awt.*;

      public final class SwingNodeTest extends Application {

        public static void main(String[] args) {
          SwingUtilities.invokeLater(SwingNodeTest::createAndShowSwingFrame);
          launch(args);
        }

        private static boolean useWin10Hack = false;

        @Override
        public void start(Stage primaryStage) {
          if (Platform.isFxApplicationThread() && SwingUtilities.isEventDispatchThread()) {
            createAndShowJavaFXFrame(primaryStage);
          }
          else {
            throw new IllegalStateException("add vm parameter '-Djavafx.embed.singleThread=true'");
          }
        }

        private void createAndShowJavaFXFrame(Stage primaryStage) {
          printHackState();
          primaryStage.setTitle("SwingNode for JavaFX Example");
          final SwingNode swingNode = new SwingNode();
          SwingUtilities.invokeLater(() -> {
            JPanel swingPanel = createSwingPanel();
            swingNode.setContent(swingPanel);
          });
          ChangeListener<Number> sizeChangeListener = (observable, oldValue, newValue) -> evilWin10Hack(swingNode.getContent());
          primaryStage.widthProperty().addListener(sizeChangeListener);
          primaryStage.heightProperty().addListener(sizeChangeListener);
          primaryStage.setScene(new Scene(new StackPane(swingNode), 300, 300));
          primaryStage.show();
        }

        private void evilWin10Hack(JComponent content) {
          if (useWin10Hack) {
            SwingUtilities.invokeLater(() -> { // must be twice :-/ Don't know why
              SwingUtilities.invokeLater(() -> {
                if (content != null) {
                  content.revalidate();
                  content.repaint();
                }
              });
            });
          }
        }

        private static void createAndShowSwingFrame() {
          JFrame swingFrame = new JFrame("Swing Example");
          swingFrame.setSize(300, 300);
          swingFrame.setLocationRelativeTo(null);
          swingFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          swingFrame.add(createSwingPanel());
          swingFrame.setVisible(true);
        }

        private static JPanel createSwingPanel() {
          JButton button = new JButton();
          button.setText("Press me");
          button.addActionListener((event) -> {
            useWin10Hack = !useWin10Hack;
            printHackState();
          });

          JPanel panel = new JPanel();
          panel.setLayout(new GridLayout(1, 2));
          panel.add(new JLabel("This is a label!"));
          panel.add(button);
          return panel;
        }

        private static void printHackState() {
          System.out.println(useWin10Hack ? "hack activated" : "hack deactivated");
        }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      No clean solution exists.

      FREQUENCY : always


            psadhukhan Prasanta Sadhukhan
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: