2

Re: JavaFX Anchorpane and Tab resize and erasure of underlying screen elements

After reading Stack Overflow postings -

here: JavaFX Panel inside Panel auto resizing

and here: Resize JavaFX tab when double click

I was able to get the JavaFX code shown below to resize a tab to its maxium AnchorPane allowable size; the if() block worked. But on the else block execution the underlying pane (main stage's scene) gets erased/clipped by the Tab minimization. I have looked for many hours and tried various things to refresh the main stage's screen but all UI elements are still not shown. I could reload the stage as from the program startup but all the the user data on the erased screen would have to be saved, etc.

I thought about refreshing, repainting, etc., but I really don't know what to do in this case. Like I said, I search thoroughly for this information (esp. various stack overflow postings.)

Thanks for your comments.

if (mouseEvent.getClickCount() == 2) {

  if (!isTabMaximized) {

    TabPane tabPane = (TabPane) namespace.get("tabPane");
    AnchorPane applAnchorPane = 
         (AnchorPane) namespace.get("applAnchorPane");

    applAnchorPane.getChildren().forEach( node -> {

      System.out.println("Node: " + node.getId());
     });

    applAnchorPane.setLeftAnchor(tabPane, 0.0d);
    applAnchorPane.setTopAnchor(tabPane, 0.0d);
    applAnchorPane.setRightAnchor(tabPane, 0.0d);
    applAnchorPane.setBottomAnchor(tabPane, 0.0d);

    applAnchorPane.getChildren().setAll(tabPane);

    isTabMaximized = true;

  }else {

    TabPane tabPane = (TabPane) namespace.get("tabPane");
    AnchorPane applAnchorPane = 
       (AnchorPane) namespace.get("applAnchorPane");

    applAnchorPane.setLeftAnchor(tabPane, 0.0d);
    applAnchorPane.setTopAnchor(tabPane, 495.0d);
    applAnchorPane.setRightAnchor(tabPane, 0.0d);
    applAnchorPane.setBottomAnchor(tabPane, 0.0d);


    //not used commented out --> 
    // applAnchorPane.getChildren().setAll(tabPane);

    isTabMaximized = false;

    applAnchorPane.toBack();
    applAnchorPane.getChildren().forEach( node -> {
      node.toFront();
      System.out.println("Node: " + node.getId());
      node.setVisible(true);
    });

  }

}


My console output from println() in the if():

Node: mainFlowPane

My console output from println() in the else:

Node: tabPane

My fxml has the following structure (before the TabPane maximize):

AnchorPane

FlowPane - named mainFlowPane

  • HBox - contained in FlowPane

  • GridPane - contained in FlowPane

  • TabPane - contained in FlowPane, named tabPane

The FlowPane/name does not get printed in the else output to console, just the TabPane/name

It seems like the following has happened: My fxml has the following structure (after the TabPane minimized):

AnchorPane

  • TabPane - contained in FlowPane, named tabPane

I debugged the code again and the FlowPane looks like it still exists. But I get the following exception when I try to printout the FlowPane Node fx:id's :

Node: null Exception in thread "JavaFX Application Thread" java.util.ConcurrentModificationException

Here is my stacktrace:

Node: null
Exception in thread "JavaFX Application Thread" java.util.ConcurrentModificationException
    at com.sun.javafx.collections.VetoableListDecorator$VetoableIteratorDecorator.checkForComodification(VetoableListDecorator.java:714)
    at com.sun.javafx.collections.VetoableListDecorator$VetoableIteratorDecorator.hasNext(VetoableListDecorator.java:682)
    at java.lang.Iterable.forEach(Iterable.java:74)
    at wordcounterfxapp.WordCounterFXApp$4.handle(WordCounterFXApp.java:963)
    at wordcounterfxapp.WordCounterFXApp$4.handle(WordCounterFXApp.java:897)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Scene$ClickGenerator.postProcess(Scene.java:3470)
    at javafx.scene.Scene$ClickGenerator.access$8100(Scene.java:3398)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3766)
    at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:380)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:294)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:416)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:415)
    at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
    at com.sun.glass.ui.View.notifyMouse(View.java:937)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
    at java.lang.Thread.run(Thread.java:745)
Deleting directory C:\NetBeans\workspace8_0\WordCounterFXApp\dist\run2084430703
jfxsa-run:
BUILD SUCCESSFUL (total time: 13 seconds)


I found that I had omitted the fx:id's from the FlowPane's HBox and GridPane: once I added these the exception goes away. Now my output is the following:

jfx-project-run:

Executing

C:\NetBeans\workspace8_0\WordCounterFXApp\dist\run923058183\WordCounterFXApp.jar using platform C:\Program Files\Java\jdk1.8.0_101\jre/bin/java

Before TabPane maximized - Node: applAnchorPane

Before TabPane maximized - Node: mainFlowPane

Before TabPane maximized - Node: flowPaneHBox

Before TabPane maximized - Node: flowPaneGridPane

Before TabPane maximized - Node: tabPane

After TabPane minimized - Node: applAnchorPane

After TabPane minimized - Node: tabPane

After TabPane minimized - Node: mainFlowPane

After TabPane minimized - Node: flowPaneHBox

After TabPane minimized - Node: flowPaneGridPane

Deleting directory C:\NetBeans\workspace8_0\WordCounterFXApp\dist\run923058183

jfxsa-run:

BUILD SUCCESSFUL (total time: 10 seconds)

This printout shows that the FlowPane with its child Nodes are pushed below the TabPane?

So, this might show what's going on. That the FlowPane might be outside of the visible region. At this point I don't know how to fix it however...


10/26/2016

To wrap up this debugging exercise...

The problem: JavaFX AnchorPane and Tab resize and erasure of underlying screen elements

The analysis: On TabPane minimization, the JavaFx UI does not render my FlowPane properly with its 3 nodes of structure:

AnchorPane

FlowPane - named mainFlowPane

  • HBox - contained in FlowPane

  • GridPane - contained in FlowPane

  • TabPane - contained in FlowPane, named tabPane

On TabPane maximization, the UI relocates the TabPane Node from within the FlowPane to under the AnchorPane. On minimization the following Node hierachy results:

AnchorPane

  • TabPane - contained in FlowPane, named tabPane

FlowPane - named mainFlowPane

  • HBox - contained in FlowPane

  • GridPane - contained in FlowPane

Thus, the JavaFx UI places the TabPane as shown. And, thus, the FlowPane with its Node elements are pushed out of UI stage/scene visual display. Why does the UI do this, rather than relocate/minimize the display, and not move the TabPane Node???

The solution:

I found a solution, with adding two lines of code at end of the else block:

flowPane.getChildren().add(tabPane);

applAnchorPane.getChildren().add(flowPane);

I have done some investigation so the UI should be fixed for now. I am now able to do both maximize and minimize a TabPane with is associated Tab Nodes. As far as I can tell, the JavaFx Node hierarchy is now the same after a min/max Tab as the Node structure was before these 2 operations. The problem was probably not a coding issue. Should JavaFx UI render things the way it does, to re-order the various nodes? I could not find any documentation for this in about 5-7 hours of research. Hopefully, my notes about this will help others in a similar situation.

Thanks to Blip/StackExchange commentor, I was able to debug this issue to a successful outcome. Hat's off to Blip! Thanks so much for your help.

Community
  • 1
  • 1
Seattle JD
  • 21
  • 7
  • Did you get any kind of error or exception? – Blip Oct 26 '16 at 07:35
  • Thanks for your response. No, I did not get either an error or exception. – Seattle JD Oct 26 '16 at 07:48
  • how are you running the program? are you using an ide? – Blip Oct 26 '16 at 07:52
  • I'm using NetBeans, latest Dev. version. I updated the IDE – Seattle JD Oct 26 '16 at 07:57
  • in the last month or so – Seattle JD Oct 26 '16 at 07:57
  • in the console window see if there is any error or exception shown – Blip Oct 26 '16 at 08:01
  • Like I said, none are shown. – Seattle JD Oct 26 '16 at 08:05
  • jfx-project-run: Executing C:\NetBeans\workspace8_0\WordCounterFXApp\dist\run1167502575\WordCounterFXApp.jar using platform C:\Program Files\Java\jdk1.8.0_101\jre/bin/java Deleting directory C:\NetBeans\workspace8_0\WordCounterFXApp\dist\run1167502575 jfxsa-run: BUILD SUCCESSFUL (total time: 42 seconds) – Seattle JD Oct 26 '16 at 08:07
  • The attached console is what's output. – Seattle JD Oct 26 '16 at 08:07
  • ok. but does anything extra gets printed when you want to resize by double clicking the maximized tabPane – Blip Oct 26 '16 at 08:25
  • No, nothing extra is printed. – Seattle JD Oct 26 '16 at 08:32
  • Also I tried the following (java 8): – Seattle JD Oct 26 '16 at 08:44
  • applAnchorPane.toBack(); /* Is the issue is z-order problem? - No*/ applAnchorPane.getChildren().forEach( node -> node.setVisible(true) – Seattle JD Oct 26 '16 at 09:05
  • And nothing is displayed in the erased area of the app – Seattle JD Oct 26 '16 at 09:06
  • I would suggest to add a `printLn` inside the body of the `else` and check whether this is getting printed in the console or not. If it gets written then the else is executing otherwise the else is not executing. Also you could add break points in the else loop and then run the program in debug. This will help you the peep into the instances and their propertied. – Blip Oct 26 '16 at 09:34
  • did you try what I suggested? – Blip Oct 26 '16 at 09:42
  • Yes, I did. I have added notes in body. Looks like my FlowPane is missing. It contained a couple of Node's before the TabPane. In the else block the AnchorPane only prints out the TabPane as a child not the missing FlowPane container. The FXML structure is highlighted. The FlowPane is totally gone, it's fx:id is not printed. – Seattle JD Oct 26 '16 at 10:23
  • please edit your code that you have posted as to where and how you have added the printlns – Blip Oct 26 '16 at 10:31
  • The println 's are in the logic above and discussed in the accompanying notes. – Seattle JD Oct 26 '16 at 10:34
  • post the complete stacktrace – Blip Oct 26 '16 at 10:46
  • post the code how you got this exception – Blip Oct 26 '16 at 10:53
  • I found the problem that caused the stacktrace. The fx:id 's for the FlowPane's Node's were missing. See the notes after the stacktrace. The FlowPane is pushed below the TabPane after the Tab minimization takes place. This describes the problem, maybe, and the println's output show the resulting structure. I don't quite know how to fix this however. I would have thought that the underlying rendering would have placed the TabPane to its original place in the Node heirachy. – Seattle JD Oct 26 '16 at 11:37
  • is the node hierarchy `AnchorPane` contains `FlowPane` contains `HBox`, `GridPane` and `TabPane` initially? Also does the `AnchorPane` have any Bounds set to it? – Blip Oct 26 '16 at 11:41
  • Blip - thanks for helping/shadowing me with this problem. I found a solution, with adding two lines of code at end of the else block: ->>> flowPane.getChildren().add(tabPane); ->>>> applAnchorPane.getChildren().add(flowPane); I will still do some investigation but the UI should be fixed for now. Thanks for your questions. They proved to be helpful in debugging this issue. Have a wonderful day! - JD from Seattle – Seattle JD Oct 26 '16 at 11:53

0 Answers0