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

Potential bug in JAVAFX > 12 (GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)

XMLWordPrintable

    • x86_64
    • linux_ubuntu

      ADDITIONAL SYSTEM INFORMATION :
      Ubuntu 20.04 LTS running on a HP Envy 17 laptop.
      Also Ubuntu SNAP base 20 container
      jdk 11 to 15.0.1 all show same error
      OpenJFX 13 to 15 show the same error, OpenJFX 11 and 12 do not display the error and work normally

      A DESCRIPTION OF THE PROBLEM :
      I have built a LINUX based Ubuntu snap app using BASE20 (i.e. Ubuntu 20.04) as a target OS, and it is in distribution through the Ubuntu snap store. The runtime is built using JLink to create a standalone JAVAFX package that is then wrapped into a UBuntu snap with the Base 20 image and a set of libraries for distribution in a totally self-contained snap container.
        
      The App works perfectly well using OpenJDK 11 through to 15.0.1 and on OpenJFX 11 and 12. However if I move to a more recent version of OpenJFX (e.g. 13 through 15) I get the following error for every scene change on my primaryStage following the opening scene which always opens correct. For all following scene changes the screen goes blank and the following error is displayed on the terminal:

      Incomplete attachment. (GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)(FBO - 820)
      Error creating framebuffer object with TexID 1)

      One thing - the application does not crash, it continues to run normally with a blank white screen until something forces a screen refresh e.g. manually opening another full screen app, then closing it again - the desired scene then appears when the screen refreshes!

      It fails running within a UBuntu 20 Snap and as a standalone JAVAFX application running on UBUNTO 20.04, and when running within my dev environment:
       
      Intellij IDEA IntelliJ IDEA 2020.3 (Community Edition)
      Build #IC-203.5981.155, built on November 30, 2020
      Runtime version: 11.0.9+11-b1145.21 amd64
      VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
      Linux 5.4.0-56-generic
      GC: ParNew, ConcurrentMarkSweep
      Memory: 1440M
      Cores: 8
      Non-Bundled Plugins: com.intellij.plugins.watcher
      Current Desktop: ubuntu:GNOME

      The javafx modules included are (extract from build.gradle file, complete file is below):
         modules = ['javafx.controls', 'javafx.graphics', 'javafx.base','javafx.fxml', 'javafx.swing', 'javafx.web' ]

      The Ubuntu Linux Libraries included in the snap are:
            - libxkbcommon0 # XKB_CONFIG_ROOT
            - ttf-ubuntu-font-family
            - dmz-cursor-theme
            - light-themes
            - adwaita-icon-theme
            - gnome-themes-standard
            - shared-mime-info
            - libgtk-3-0
            - libgdk-pixbuf2.0-0
            - libglib2.0-bin
            - libgtk-3-bin
            - unity-gtk3-module
            - libappindicator3-1
            - locales-all
            - xdg-user-dirs
            - ibus-gtk3
            - libibus-1.0-5
            - fontconfig-config
            - fonts-liberation
            - ttf-dejavu-core
            - hicolor-icon-theme
            - libgtk2.0-0
            - libcanberra-gtk-module
            - libcanberra-gtk0
            - libcanberra0

      Thread Library on Ubuntu 20:04:

      $getconf GNU_LIBPTHREAD_VERSION
      NPTL 2.31

      Architecture is AMD64
       
       I have managed to do some tracing of my own code and into the java library source.
       The error occurs after last line executed in the method below in file Scene.java.
       
       first line is at line 2578 in Scene.java (as shown in the IntelliJ IDE)
      //==
       @Override
              public void mouseEvent(EventType<MouseEvent> type, double x, double y, double screenX, double screenY,
                                     MouseButton button, boolean popupTrigger, boolean synthesized,
                                     boolean shiftDown, boolean controlDown, boolean altDown, boolean metaDown,
                                     boolean primaryDown, boolean middleDown, boolean secondaryDown,
                                     boolean backDown, boolean forwardDown)
              {
                  MouseEvent mouseEvent = new MouseEvent(type, x, y, screenX, screenY, button,
                          0, // click count will be adjusted by clickGenerator later anyway
                          shiftDown, controlDown, altDown, metaDown,
                          primaryDown, middleDown, secondaryDown, backDown, forwardDown,
                          synthesized, popupTrigger, false, null);
                  processMouseEvent(mouseEvent);
              }
              
      //===========================================================================
      Stack immediately prior to error:
              
      //====
      mouseEvent:2591, Scene$ScenePeerListener (javafx.scene)
      run:409, GlassViewEventHandler$MouseEventNotification (com.sun.javafx.tk.quantum)
      run:299, GlassViewEventHandler$MouseEventNotification (com.sun.javafx.tk.quantum)
      doPrivileged:-1, AccessController (java.security)
      lambda$handleMouseEvent$2:447, GlassViewEventHandler (com.sun.javafx.tk.quantum)
      get:-1, 2067987277 (com.sun.javafx.tk.quantum.GlassViewEventHandler$$Lambda$812)
      runWithoutRenderLock:412, QuantumToolkit (com.sun.javafx.tk.quantum)
      handleMouseEvent:446, GlassViewEventHandler (com.sun.javafx.tk.quantum)
      handleMouseEvent:556, View (com.sun.glass.ui)
      notifyMouse:942, View (com.sun.glass.ui)
      _runLoop:-1, GtkApplication (com.sun.glass.ui.gtk)
      lambda$runLoop$11:277, GtkApplication (com.sun.glass.ui.gtk)
      run:-1, 1159114532 (com.sun.glass.ui.gtk.GtkApplication$$Lambda$115)
      run:834, Thread (java.lang)

      //============================================================================

      Application code call stack:

      //==
      private void setupStage()
          {

              mLastTitle = mPrimaryStage.getTitle();
              mPrimaryStage.setScene(mScene);
              mPrimaryStage.setTitle("PhotoNoteBook" + MyConstants.TMMARK + " Photo Carousel");
              mPrimaryStage.show();
          }
          
      //===

      The Above Method is called by:

      //==
      public PhotoCarousel(ImageContainerCallBack imageContainerCallBack, Stage primaryStage, Scene lastScene, UUID photoNotebookUuid, int imageNumber)
          {
              DEBUG = (MyLogger.getTraceLevel() == MyLogger.TRACELEVELDEBUG);
              MyLogger.Logi(this.getClass(), " - Method: PhotoCarousel",
                      "Message: Starting constructor ", "");
              mImageContainerCallback = imageContainerCallBack;
              mPrimaryStage = primaryStage;
              mLastScene = lastScene;
              mPhotoNotebookUuid = photoNotebookUuid;
              mImageNumber = imageNumber;
              mPhotoNotebookDataList = PhotoNotebookDataList.get();
              setUpScene();
              setupStage();
          }
          
      //==
       NOTE setupscene() in the above method is a method that creates the scene, and works fine in JAVAFX 11.0.2 -> 11.0.5
      The Above Method is called by:

      //===
         private void openPhotoCarouselButtonClickHandler()
          {
              mOpenPhotoCarouselButton.setStyle("-fx-background-color:MediumSeaGreen");
              if ((mPhotoNotebookUuid != null) && (photosToWorkWith()))
              {
                  PhotoCarousel photoCarousel = new PhotoCarousel(this,
                          mPrimaryStage, mScene, mPhotoNotebookUuid, 0);

              }
          }
        
      //===

      the next code fragment is part of a method that creates buttons and places them on a tool bar. the button described in the fragment uses a lambda to set the button setOnAction variable

      The above Method is called by the following code fragment:

      //===
           .
          
              mOpenPhotoCarouselButton = new Button();
              mOpenPhotoCarouselButton.setOnAction(e -> openPhotoCarouselButtonClickHandler());
              mOpenPhotoCarouselButton.setPrefWidth(buttonWidth);
              mOpenPhotoCarouselButton.setText("Photos");

      //===

      build.gradle file for Application build

      //===
      plugins {
          id 'org.openjfx.javafxplugin' version '0.0.9'
      }

      plugins {
          id 'java'
          id 'application'
          id "org.beryx.jlink" version "2.22.0"
      }

      repositories {
          mavenCentral()
          jcenter()
          google()
      }

      jlink {
          options=['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
          launcher {
              name = 'photonotebook'
          }
      }

      group 'com.dryjointproductions.photonotebook'
      version '1.4.2'

      allprojects {
          apply plugin: 'idea'
          idea.module.outputDir file("out/production/classes")
      }

      allprojects {
          tasks.withType(JavaCompile) {
              options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
              }
          }


          sourceSets {
              main {
                  resources {
                      srcDirs += sourceSets.main.java.srcDirs + sourceSets.main.resources.srcDirs + 'resources'
                      exclude '**/*.java'
                  }
              }
          }

          javafx {
              version = "13.0.2"
              modules = ['javafx.controls', 'javafx.graphics', 'javafx.base','javafx.fxml', 'javafx.swing', 'javafx.web' ]
          }

      compileJava {
                  sourceCompatibility = 11
              }

      plugins.withType(JavaPlugin).configureEach {
          java {
              modularity.inferModulePath = true
          }
      }

      application {
          setMainModule ('PhotoNoteBook')
           setMainClassName('com.dryjointproductions.photonotebook.PhotoNoteBook')
      }

      dependencies {
         // implementation 'com.google.code.gson:gson:2.7'
          implementation 'com.google.code.gson:gson:2.8.5'
          implementation 'org.xerial:sqlite-jdbc:3.28.0'
          implementation group: 'javax.activation', name: 'activation', version: '1.1.1'
          implementation group: 'javax.mail', name: 'mail', version: '1.4.7'
          implementation 'com.drewnoakes:metadata-extractor:2.14.0'
          implementation 'net.coobird:thumbnailator:0.4.12'
      }
      //===
      the application is started using the following bash script:
      //===
      #!/bin/sh
      DIR="${0%/*}"
      "$DIR/java" -p "$DIR/../app" -m PhotoNoteBook/com.dryjointproductions.photonotebook.PhotoNoteBook "$@"
      //===


      REGRESSION : Last worked in version 11.0.9

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Approximate test code

      //=================
       public static void main(String[] args)
          {
              // TODO Test that thi
              // s cures the Windows scaling issue

              launch(args);
          }

          @Override
          public void start(Stage primaryStage)
          {
              //hostServices = getHostServices() ;
              primaryStage.initStyle(StageStyle.UNDECORATED);
              primaryStage.setTitle( PHOTO_NOTEBOOK_NAME);
              Image image = new Image("/icon_photonotebook_4_web.png");
              primaryStage.getIcons().add(image);
              EntryScreen entryScreen = new EntryScreen(primaryStage) ;
          }
          
      //====
      public class EntryScreen
      {
       public EntryScreen(Stage primaryStage)
          {
              
              setUpToolBar();
              mBorderPane.setBottom(mToolBar);

              mScene = new Scene(mBorderPane, mScreenWidth, mScreenHeight);
              
              setupStage();
              
          }
          
      //==

       private void setUpToolBar()
          {
              
              mOpenPhotoCarouselButton = new Button();
              mOpenPhotoCarouselButton.setOnAction(e -> openPhotoCarouselButtonClickHandler());
              mOpenPhotoCarouselButton.setPrefWidth(buttonWidth);
              mOpenPhotoCarouselButton.setText("Photos");
              
              mToolBar = new ToolBar();
              mToolBar.getItems().add(mOpenPhotoCarouselButton);
              
         }
         
         //===========================================================
          private void openPhotoCarousel()
          {
              mOpenPhotoNoteCarouselButton.setStyle("-fx-background-color:MediumSeaGreen");
              if ((mPhotoNotebookUuid != null) && (photosToWorkWith()))
              {
                      PhotoCarousel photoCarousel
                              = new PhotoCarousel(mPrimaryStage, mScene);
              }
          }
          //==
           private void setupStage()
          {
              //set the stage

              mPrimaryStage.setScene(mScene);
              mPrimaryStage.setResizable(true);
              mPrimaryStage.setMaximized(true);

              ScreenUtils screenUtils = new ScreenUtils() ;
              double minX = screenUtils.getMinX();
              double minY = screenUtils.getMinY();
              double height = screenUtils.getScreenHeight();
              double width = screenUtils.getScreenWidth();

              mPrimaryStage.setX(minX);
              mPrimaryStage.setY(minY);

              mPrimaryStage.setWidth(width);
              mPrimaryStage.setHeight(height);

              // attach a listener to capture changes to maximise property
             mPrimaryStage.maximizedProperty().addListener(new ChangeListener<Boolean>()
             {
               @Override
               public void changed(ObservableValue<? extends Boolean> prop, Boolean oldValue, Boolean newValue)
               {
               //use a local ScreenUtils as things have changed
                 ScreenUtils screenUtils = new ScreenUtils();
                 double minX = screenUtils.getMinX();
                 double minY = screenUtils.getMinY();
                 double height = screenUtils.getScreenHeight();
                 double width = screenUtils.getScreenWidth();
                 mPrimaryStage.setX(minX);
                 mPrimaryStage.setY(minY);
                 mPrimaryStage.setWidth(width);
                 mPrimaryStage.setHeight(height);
                 mPrimaryStage.setMaximized(true);
                });
              }
              mPrimaryStage.setAlwaysOnTop(false);
              mPrimaryStage.setTitle("PhotoNoteBook" + MyConstants.TMMARK);
              mPrimaryStage.widthProperty().addListener(new ChangeListener<Number>()
              {
                  @Override
                  public void changed(ObservableValue<? extends Number> observableValue, Number number, Number number2)
                  {
                     setCurrentWidthToStage(number2);
                  }
              });

              mPrimaryStage.heightProperty().addListener(new ChangeListener<Number>()
              {
                  @Override
                  public void changed(ObservableValue<? extends Number> observableValue, Number number, Number number2)
                  {
                      setCurrentHeightToStage(number2);
                  }
              });

              mPrimaryStage.show();
              
          }
      }// end class EntryScreen

      //=============================================================
      public class PhotoCarousel
      {
        public PhotoCarousel(Stage primaryStage, Scene lastScene)
          {
              
              mPrimaryStage = primaryStage;
              mLastScene = lastScene;
              
              setUpScene();
              setupStage();
          }
          
      //==
      private void setUpScene()
      {
        Rectangle2D bounds = Screen.getPrimary().getVisualBounds();
        mScreenHeight = bounds.getHeight() - bounds.getMinY();
        mScreenWidth = bounds.getWidth() - bounds.getMinX();

        mImageContainer = new ImageContainer();
        mImageContainer.refreshImage("myimage.png");

        setUpToolBar();

        mBorderpane = new BorderPane();

        mBorderpane.setCenter(mImageContainer.getmMainImageView());

        mBorderpane.setBottom(mToolBar);
        mScene = new Scene(mBorderpane, mScreenWidth, mScreenHeight);
      }
      //==
        private void setUpToolBar()
          {
              double buttonWidth = mScreenUtils.ratioXDimension(MyConstants.BASE_BUTTON_WIDTH);
              mCancelButton = new Button();
              mCancelButton.setOnAction(e -> buttonCancelClick());
              mCancelButton.setPrefWidth(buttonWidth);
              mCancelButton.setText("Back");

          }
          
      //==
          private void buttonCancelClick()
          {
              mPrimaryStage.toFront();
              mPrimaryStage.setScene(mLastScene);
              mPrimaryStage.setTitle(mLastTitle);
              mPrimaryStage.show();
          }
      //===
      private void setupStage()
          {
              mLastTitle = mPrimaryStage.getTitle();
              mPrimaryStage.setScene(mScene);
              mPrimaryStage.setTitle("PhotoNoteBook" + MyConstants.TMMARK + " Photo Carousel");
              mPrimaryStage.show();
          }
      //==

      }//class PhotoCarousel

      /=====================================
      public class ImageContainer
      {
       public ImageContainer(Image imagename)

          {
              mMainImageView = new ImageView();
              mMainImageView.setImage(imagename);
              mMainImageView.setSmooth(true);
              mMainImageView.setPreserveRatio(true);
             
              okUuid = photoNotebookUuid;
            
              setViewport(mMainImageView.getImage());
          }
           //===========================================================
          public ImageView getmMainImageView()
          {
              return mMainImageView;
          }




      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      On start up first scene will display normally. Pressing the toolbar button should initiate display of second scene, but a white rectangle will be displayed instead.
      Start another program to fill the screen, then minimise it. The second scene will be displayed as expected. Pressing the cancel button should cause the first scene to be displayed, however a white rectangle will appear. Maximise another application then minimise, and the white rectangle will disappear and the expected scene will be displayed.
      ACTUAL -
      Error Occurs:
      Incomplete attachment. (GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)(FBO - 820)
      Error creating framebuffer object with TexID 1)

       I have managed to do some tracing of my own application code (not the test code) and into the java library source.

       The error occurs after last line executed in the method below in file Scene.java.
       
       first line is at line 2578 in Scene.java
       ```
      //==
       @Override
              public void mouseEvent(EventType<MouseEvent> type, double x, double y, double screenX, double screenY,
                                     MouseButton button, boolean popupTrigger, boolean synthesized,
                                     boolean shiftDown, boolean controlDown, boolean altDown, boolean metaDown,
                                     boolean primaryDown, boolean middleDown, boolean secondaryDown,
                                     boolean backDown, boolean forwardDown)
              {
                  MouseEvent mouseEvent = new MouseEvent(type, x, y, screenX, screenY, button,
                          0, // click count will be adjusted by clickGenerator later anyway
                          shiftDown, controlDown, altDown, metaDown,
                          primaryDown, middleDown, secondaryDown, backDown, forwardDown,
                          synthesized, popupTrigger, false, null);
                  processMouseEvent(mouseEvent);
              }
              
      //===========================================================================
      ```
      Stack prior to error:
              
      ```
      //====
      mouseEvent:2591, Scene$ScenePeerListener (javafx.scene)
      run:409, GlassViewEventHandler$MouseEventNotification (com.sun.javafx.tk.quantum)
      run:299, GlassViewEventHandler$MouseEventNotification (com.sun.javafx.tk.quantum)
      doPrivileged:-1, AccessController (java.security)
      lambda$handleMouseEvent$2:447, GlassViewEventHandler (com.sun.javafx.tk.quantum)
      get:-1, 2067987277 (com.sun.javafx.tk.quantum.GlassViewEventHandler$$Lambda$812)
      runWithoutRenderLock:412, QuantumToolkit (com.sun.javafx.tk.quantum)
      handleMouseEvent:446, GlassViewEventHandler (com.sun.javafx.tk.quantum)
      handleMouseEvent:556, View (com.sun.glass.ui)
      notifyMouse:942, View (com.sun.glass.ui)
      _runLoop:-1, GtkApplication (com.sun.glass.ui.gtk)
      lambda$runLoop$11:277, GtkApplication (com.sun.glass.ui.gtk)
      run:-1, 1159114532 (com.sun.glass.ui.gtk.GtkApplication$$Lambda$115)
      run:834, Thread (java.lang)

      //============================================================================

      Application code call stack:

      ```
      //==
      private void setupStage()
          {

              mLastTitle = mPrimaryStage.getTitle();
              mPrimaryStage.setScene(mScene);
              mPrimaryStage.setTitle("PhotoNoteBook" + MyConstants.TMMARK + " Photo Carousel");
              mPrimaryStage.show();
          }
          
      //===
      ```
      The Above Method is called by:
      ```
      //==
      public PhotoCarousel(ImageContainerCallBack imageContainerCallBack, Stage primaryStage, Scene lastScene, UUID photoNotebookUuid, int imageNumber)
          {
              DEBUG = (MyLogger.getTraceLevel() == MyLogger.TRACELEVELDEBUG);
              MyLogger.Logi(this.getClass(), " - Method: PhotoCarousel",
                      "Message: Starting constructor ", "");


              mImageContainerCallback = imageContainerCallBack;
              mPrimaryStage = primaryStage;
              mLastScene = lastScene;
              mPhotoNotebookUuid = photoNotebookUuid;
              mImageNumber = imageNumber;
              mPhotoNotebookDataList = PhotoNotebookDataList.get();

              setUpScene();
              setupStage();
          }
          
      //==
      ```
       NOTE setupscene() in the above method is a method that creates the scene, and works fine in JAVAFX 11.0.2 -> 11.0.5
      The Above Method is called by:

      ```
      //===
         private void openPhotoCarouselButtonClickHandler()
          {
              mOpenPhotoCarouselButton.setStyle("-fx-background-color:MediumSeaGreen");
              if ((mPhotoNotebookUuid != null) && (photosToWorkWith()))
              {

                  PhotoCarousel photoCarousel = new PhotoCarousel(this,
                          mPrimaryStage, mScene, mPhotoNotebookUuid, 0);

              }
              resetButtonColours();
          }
        
      //===
      ```
      the next code fragment is part of a method that creates buttons and places them on a tool bar. the button described in the fragment uses a lambda to set the button setOnAction variable

      The Above Method is called by:

      ```
      //===
           .
           .
           .
              mOpenPhotoCarouselButton = new Button();
              mOpenPhotoCarouselButton.setOnAction(e -> openPhotoCarouselButtonClickHandler());
              mOpenPhotoCarouselButton.setPrefWidth(buttonWidth);
              mOpenPhotoCarouselButton.setText("Photos");

      .
      .

      //===

      ---------- BEGIN SOURCE ----------
      Approximate test code

      //=================
       public static void main(String[] args)
          {
              // TODO Test that thi
              // s cures the Windows scaling issue

              launch(args);
          }

          @Override
          public void start(Stage primaryStage)
          {
              //hostServices = getHostServices() ;
              primaryStage.initStyle(StageStyle.UNDECORATED);
              primaryStage.setTitle( PHOTO_NOTEBOOK_NAME);
              Image image = new Image("/icon_photonotebook_4_web.png");
              primaryStage.getIcons().add(image);
              EntryScreen entryScreen = new EntryScreen(primaryStage) ;
          }
          
      //====
      public class EntryScreen
      {
       public EntryScreen(Stage primaryStage)
          {
              
              setUpToolBar();
              mBorderPane.setBottom(mToolBar);

              mScene = new Scene(mBorderPane, mScreenWidth, mScreenHeight);
              
              setupStage();
              
          }
          
      //==

       private void setUpToolBar()
          {
              
              mOpenPhotoCarouselButton = new Button();
              mOpenPhotoCarouselButton.setOnAction(e -> openPhotoCarouselButtonClickHandler());
              mOpenPhotoCarouselButton.setPrefWidth(buttonWidth);
              mOpenPhotoCarouselButton.setText("Photos");
              
              mToolBar = new ToolBar();
              mToolBar.getItems().add(mOpenPhotoCarouselButton);
              
         }
         
         //===========================================================
          private void openPhotoCarousel()
          {
              mOpenPhotoNoteCarouselButton.setStyle("-fx-background-color:MediumSeaGreen");
              if ((mPhotoNotebookUuid != null) && (photosToWorkWith()))
              {
                      PhotoCarousel photoCarousel
                              = new PhotoCarousel(mPrimaryStage, mScene);
              }
          }
          //==
           private void setupStage()
          {
              //set the stage

              mPrimaryStage.setScene(mScene);
              mPrimaryStage.setResizable(true);
              mPrimaryStage.setMaximized(true);

              ScreenUtils screenUtils = new ScreenUtils() ;
              double minX = screenUtils.getMinX();
              double minY = screenUtils.getMinY();
              double height = screenUtils.getScreenHeight();
              double width = screenUtils.getScreenWidth();

              mPrimaryStage.setX(minX);
              mPrimaryStage.setY(minY);

              mPrimaryStage.setWidth(width);
              mPrimaryStage.setHeight(height);

              // attach a listener to capture changes to maximise property
             mPrimaryStage.maximizedProperty().addListener(new ChangeListener<Boolean>()
             {
               @Override
               public void changed(ObservableValue<? extends Boolean> prop, Boolean oldValue, Boolean newValue)
               {
               //use a local ScreenUtils as things have changed
                 ScreenUtils screenUtils = new ScreenUtils();
                 double minX = screenUtils.getMinX();
                 double minY = screenUtils.getMinY();
                 double height = screenUtils.getScreenHeight();
                 double width = screenUtils.getScreenWidth();
                 mPrimaryStage.setX(minX);
                 mPrimaryStage.setY(minY);
                 mPrimaryStage.setWidth(width);
                 mPrimaryStage.setHeight(height);
                 mPrimaryStage.setMaximized(true);
                });
              }
              mPrimaryStage.setAlwaysOnTop(false);
              mPrimaryStage.setTitle("PhotoNoteBook" + MyConstants.TMMARK);
              mPrimaryStage.widthProperty().addListener(new ChangeListener<Number>()
              {
                  @Override
                  public void changed(ObservableValue<? extends Number> observableValue, Number number, Number number2)
                  {
                     setCurrentWidthToStage(number2);
                  }
              });

              mPrimaryStage.heightProperty().addListener(new ChangeListener<Number>()
              {
                  @Override
                  public void changed(ObservableValue<? extends Number> observableValue, Number number, Number number2)
                  {
                      setCurrentHeightToStage(number2);
                  }
              });

              mPrimaryStage.show();
              
          }
      }// end class EntryScreen

      //=============================================================
      public class PhotoCarousel
      {
        public PhotoCarousel(Stage primaryStage, Scene lastScene)
          {
              
              mPrimaryStage = primaryStage;
              mLastScene = lastScene;
              
              setUpScene();
              setupStage();
          }
          
      //==
      private void setUpScene()
      {
        Rectangle2D bounds = Screen.getPrimary().getVisualBounds();
        mScreenHeight = bounds.getHeight() - bounds.getMinY();
        mScreenWidth = bounds.getWidth() - bounds.getMinX();

        mImageContainer = new ImageContainer();
        mImageContainer.refreshImage("myimage.png");

        setUpToolBar();

        mBorderpane = new BorderPane();

        mBorderpane.setCenter(mImageContainer.getmMainImageView());

        mBorderpane.setBottom(mToolBar);
        mScene = new Scene(mBorderpane, mScreenWidth, mScreenHeight);
      }
      //==
        private void setUpToolBar()
          {
              double buttonWidth = mScreenUtils.ratioXDimension(MyConstants.BASE_BUTTON_WIDTH);
              mCancelButton = new Button();
              mCancelButton.setOnAction(e -> buttonCancelClick());
              mCancelButton.setPrefWidth(buttonWidth);
              mCancelButton.setText("Back");

          }
          
      //==
          private void buttonCancelClick()
          {
              mPrimaryStage.toFront();
              mPrimaryStage.setScene(mLastScene);
              mPrimaryStage.setTitle(mLastTitle);
              mPrimaryStage.show();
          }
      //===
      private void setupStage()
          {
              mLastTitle = mPrimaryStage.getTitle();
              mPrimaryStage.setScene(mScene);
              mPrimaryStage.setTitle("PhotoNoteBook" + MyConstants.TMMARK + " Photo Carousel");
              mPrimaryStage.show();
          }
      //==

      }//class PhotoCarousel

      /=====================================
      public class ImageContainer
      {
       public ImageContainer(Image imagename)

          {
              mMainImageView = new ImageView();
              mMainImageView.setImage(imagename);
              mMainImageView.setSmooth(true);
              mMainImageView.setPreserveRatio(true);
             
              okUuid = photoNotebookUuid;
            
              setViewport(mMainImageView.getImage());
          }
           //===========================================================
          public ImageView getmMainImageView()
          {
              return mMainImageView;
          }



      ---------- END SOURCE ----------

      FREQUENCY : always


            kcr Kevin Rushforth
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated: