13

I've got a problem that maybe is caused by a lack of understanding in some principles of wether the Netbeans Platform(7.1.2) or JavaFX 2. I wanted to add a JFXPanel with a very simple Scene to a Swing JPanel that is a child of a TopComponent. I achieved this by the following code:

 public accexTopComponent() {
    initComponents();
    setName(Bundle.CTL_accexTopComponent());
    setToolTipText(Bundle.HINT_accexTopComponent());
    putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.TRUE);



    //Begin of my code
    myFX = new JFXPanel(); //myFX is a static JFXPanel
    Platform.runLater(new Runnable() {

        @Override
        public void run() {

            myFX.setScene(new Scene(ButtonBuilder.create().minHeight(40.0).minWidth(40.0).build()));

        }
    });

      jPanel1.add(myFX);



}

This compiles without a problem and a JavaFX Button is displayed when i show the TopComponent for the very first time. But as soon as the component is hidden and shown again, the JavaFX Button disappears while the other children still are visible.

Why does the JavaFX content disappear?

Edit:

I now include the source of the whole TopComponent. I guess that's all you need to test it for yourself. I didn't change any other file.

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package de.jeed.nbgan.accexplorer;

import java.awt.Color;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.control.ButtonBuilder;
import javafx.scene.text.TextBuilder;
import javafx.scene.web.WebView;
import javafx.scene.web.WebViewBuilder;
import org.netbeans.api.settings.ConvertAsProperties;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.windows.TopComponent;
import org.openide.util.NbBundle.Messages;

/**
 * Top component which displays something.
 */
@ConvertAsProperties(dtd = "-//de.jeed.nbgan.accexplorer//accex//EN",
autostore = false)
@TopComponent.Description(preferredID = "accexTopComponent",
//iconBase="SET/PATH/TO/ICON/HERE", 
persistenceType = TopComponent.PERSISTENCE_ALWAYS)
@TopComponent.Registration(mode = "explorer", openAtStartup = true)
@ActionID(category = "Window", id = "de.jeed.nbgan.accexplorer.accexTopComponent")
@ActionReference(path = "Menu/Window" /*
 * , position = 333
 */)
@TopComponent.OpenActionRegistration(displayName = "#CTL_accexAction",
preferredID = "accexTopComponent")
@Messages({
    "CTL_accexAction=accex",
    "CTL_accexTopComponent=Konten-Explorer",
    "HINT_accexTopComponent=Durchsuchen von Abteilungen und Konten"
})
public final class accexTopComponent extends TopComponent {

    static JFXPanel myFX;

    public accexTopComponent() {
        initComponents();
        setName(Bundle.CTL_accexTopComponent());
        setToolTipText(Bundle.HINT_accexTopComponent());
        putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.TRUE);
        myFX = new JFXPanel();
        Platform.runLater(new Runnable() {

            @Override
            public void run() {

                myFX.setScene(new                            Scene(ButtonBuilder.create().minHeight(40.0).minWidth(40.0).build()));

        }
    });

      jPanel1.add(myFX);


}

/**
 * This method is called from within the constructor to initialize the form.
 * WARNING: Do NOT modify this code. The content of this method is always
 * regenerated by the Form Editor.
 */
// <editor-fold defaultstate="collapsed" desc="Generated Code">                          
private void initComponents() {

    jPanel1 = new javax.swing.JPanel();

    jPanel1.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED));
    jPanel1.setLayout(new java.awt.GridBagLayout());

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
    this.setLayout(layout);
    layout.setHorizontalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
            .addGap(54, 54, 54)
            .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, 193, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addContainerGap(153, Short.MAX_VALUE))
    );
    layout.setVerticalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
            .addGap(33, 33, 33)
            .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, 193, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addContainerGap(74, Short.MAX_VALUE))
    );
}// </editor-fold>                        
// Variables declaration - do not modify                     
private javax.swing.JPanel jPanel1;
// End of variables declaration                   

@Override
public void componentOpened() {
    // TODO add custom code on component opening
}

@Override
public void componentClosed() {
    // TODO add custom code on component closing
}

void writeProperties(java.util.Properties p) {
    // better to version settings since initial version as advocated at
    // http://wiki.apidesign.org/wiki/PropertyFiles
    p.setProperty("version", "1.0");
    // TODO store your settings
}

void readProperties(java.util.Properties p) {
    String version = p.getProperty("version");
    // TODO read your settings according to their version
}
}

In my case, this TopComponent is part of a Component called AccountExplorer which references JavaFX and is referenced by a plain NB Platform Application.

dajood
  • 3,758
  • 9
  • 46
  • 68
  • I tried to reproduce your issue using netbeans 7.1 and JavaFX 2.1. All components reappear as expected. Post an SSCCE, please. – pmoule May 19 '12 at 11:17
  • Thanks for the effort. See my project [here](https://rapidshare.com/files/894496305/FinancialEngineer.7z) – dajood May 19 '12 at 12:02
  • Sorry, no project download links, please. To get others involved and make it more attractive to help, post an [SSCCE](http://pscode.org/sscce.html). – pmoule May 19 '12 at 12:24
  • I hope the now attached source + short explanation is what you mean :) – dajood May 20 '12 at 18:03

3 Answers3

22

Try this:

Platform.setImplicitExit(false);
Tiago
  • 2,871
  • 4
  • 23
  • 39
Cedric
  • 236
  • 2
  • 2
4

We experience the same problem. Based on the following threads we assume that once the panel is no longer visible the JavaFX Platform automatically exits because all JavaFX gui elements are not visible anymore.

This assumption is based on information from:
https://forums.oracle.com/forums/thread.jspa?messageID=10287328 and
https://forums.oracle.com/forums/thread.jspa?threadID=2390971

A first try in our environnment is to add a dummy JFXPanel somewhere in the code and leave it there untill your program exits seems to work.

Second try on your code also works:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package de.jeed.nbgan.accexplorer;

import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.geometry.Rectangle2D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ButtonBuilder;
import javafx.scene.paint.Color;
import javafx.stage.Modality;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import org.netbeans.api.settings.ConvertAsProperties;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.windows.TopComponent;
import org.openide.util.NbBundle.Messages;

/**
 * Top component which displays something.
 */
@ConvertAsProperties(dtd = "-//de.jeed.nbgan.accexplorer//accex//EN",
autostore = false)
@TopComponent.Description(preferredID = "accexTopComponent",
//iconBase="SET/PATH/TO/ICON/HERE", 
persistenceType = TopComponent.PERSISTENCE_ALWAYS)
@TopComponent.Registration(mode = "explorer", openAtStartup = true)
@ActionID(category = "Window", id = "de.jeed.nbgan.accexplorer.accexTopComponent")
@ActionReference(path = "Menu/Window" /*
 * , position = 333
 */)
@TopComponent.OpenActionRegistration(displayName = "#CTL_accexAction",
preferredID = "accexTopComponent")
@Messages({
    "CTL_accexAction=accex",
    "CTL_accexTopComponent=Konten-Explorer",
    "HINT_accexTopComponent=Durchsuchen von Abteilungen und Konten"
})
public final class accexTopComponent extends TopComponent {

    static JFXPanel myFX;
    static JFXPanel myDummyFXtoKeepJavaFxRunning;

    public accexTopComponent() {
        initComponents();
        setName(Bundle.CTL_accexTopComponent());
        setToolTipText(Bundle.HINT_accexTopComponent());
        putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.TRUE);
        myFX = new JFXPanel();
        myDummyFXtoKeepJavaFxRunning = new JFXPanel();
        Platform.runLater(new Runnable() {

            @Override
            public void run() {
                // Actual FX code that will be hidden/shown
                myFX.setScene(new Scene(ButtonBuilder.create().minHeight(40.0).minWidth(40.0).build()));

                // Workaround
                Stage dummyPopup = new Stage();
                dummyPopup.initModality(Modality.NONE);
                // set as utility so no iconification occurs
                dummyPopup.initStyle(StageStyle.UTILITY);
                // set opacity so the window cannot be seen
                dummyPopup.setOpacity(0d);
                // not necessary, but this will move the dummy stage off the screen
                final Screen screen = Screen.getPrimary();
                final Rectangle2D bounds = screen.getVisualBounds();
                dummyPopup.setX(bounds.getMaxX());
                dummyPopup.setY(bounds.getMaxY());
                // create/add a transparent scene
                final Group root = new Group();
                dummyPopup.setScene(new Scene(root, 1d, 1d, Color.TRANSPARENT));
                // show the dummy stage
                dummyPopup.show();

                // size back to scene size
                dummyPopup.sizeToScene();   

                // if you centered it before hiding
                //dummyPopup.centerOnScreen();      
            }
        });

        jPanel1.add(myFX);
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jPanel1 = new javax.swing.JPanel();

        jPanel1.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED));
        jPanel1.setLayout(new java.awt.GridBagLayout());

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(54, 54, 54)
                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, 193, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(153, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(33, 33, 33)
                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, 193, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(74, Short.MAX_VALUE))
        );
    }// </editor-fold>                        
    // Variables declaration - do not modify                     
    private javax.swing.JPanel jPanel1;
    // End of variables declaration                   

    @Override
    public void componentOpened() {
        // TODO add custom code on component opening
    }

    @Override
    public void componentClosed() {
        // TODO add custom code on component closing
    }

    void writeProperties(java.util.Properties p) {
        // better to version settings since initial version as advocated at
        // http://wiki.apidesign.org/wiki/PropertyFiles
        p.setProperty("version", "1.0");
        // TODO store your settings
    }

    void readProperties(java.util.Properties p) {
        String version = p.getProperty("version");
        // TODO read your settings according to their version
    }
}
Escay
  • 294
  • 1
  • 10
  • 1
    I had no hope anymore. Thank you a lot, that's really a great help for me. – dajood May 25 '12 at 15:19
  • 7
    The real fix should be in javaFX 2.2 See http://javafx-jira.kenai.com/browse/RT-15011 One should be using Platform.setImplicitExit(boolean implicitExit). – Escay May 29 '12 at 08:06
1

I got stuck on the same problem: I do have the problem not only with the top component ... but also with my modal dialog windows. On some OSs they seem to work at first (Windows) on others the dialogs start as a black, empty boxes (linux). In some dialogs (under Windows) while working with the dialog (typically after clicking buttons) the dialog also gets empty (typically after the sixth click or so???). When moving the mouse (without clicking) over the buttons they reappear (but not the rest)

I also have the effect (at least under windows) that minimizing and restoring the main window results in an empty window.

But: (!!!!!) I found out that resizing the main window or the dialogs with the mouse brings back the content!!!! So I assume your assumption with prelimanary death can't be the reason (why should it come back then).

For the Dialogs I found a solution: Make the scene of the window a class member so you can access it later in the following repaint() method:

  /**
   * force repaint by re-setting the scene
   * This solves a repainting bug in JavaFx 1.8.05
   */
  private void repaint(){
    setScene(null);
    Platform.runLater(new Runnable() {
      @Override
      public void run() {
        setScene(scene);
      }
    });
  }

In a Dialog I use repaint() just before showModal() and at the end of every button event --> works fine :-) But I havn't found a event where I can call repaint() after minimization for the main window. Now a new mystical but a solution: If I place repaint() just before show() for the MainWindow it all works fine. I have no idea why...

But I definitely think it's all about a bug in JavaFX which hopefully will be fixed in the next version.

Best regards

Ingo

Ingo
  • 605
  • 6
  • 10