-
Bug
-
Resolution: Unresolved
-
P4
-
9, jfx14
-
x86_64
-
windows_10
ADDITIONAL SYSTEM INFORMATION :
Windows 10, AdoptOpenJDK 11.0.6+10, JavaFX 14.0.1
A DESCRIPTION OF THE PROBLEM :
Node.toFront() never causes Parent to set the flag that marks its viewOrderChildren dirty.
Thus, after a Node.toFront() call when a previously higher-indexed sibling has an equal nonzero viewOrder, the Node still renders behind the now lower-indexed sibling.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Set equal nonzero ViewOrders on two sibling Nodes and lay them out overlapping.
Display them.
Call Node.toFront() on the sibling at the lower children index, which moves it to a higher children index than the sibling.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The Node at the higher children index should render in front of the sibling Node that still has an equal nonzero ViewOrder.
From javadoc of method Node.viewOrderProperty():
"If two children have the same viewOrder, the parent will traverse them in the order they appear in the parent's children list."
The code in method Parent.computeViewOrderChildren() produces a render order consistent with that javadoc. The problem is that the flag to call computeViewOrderChildren() does not get set upon calling Node.toFront().
ACTUAL -
The Node at the higher children index still renders behind its sibling Node.
---------- BEGIN SOURCE ----------
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.ListChangeListener;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
/**
* Demonstrates the bug in which {@code Parent.children} fails to set the flag to recompute
* {@code Parent.viewOrderChildren} when {@link Node#toFront()} changes the children order
* while children have nonzero {@link Node#viewOrderProperty()}.
**/
public class NodeToFrontBugDemo extends Application {
@Override
public void start( final Stage primaryStage ) throws Exception {
final CheckBox workaroundCheckBox = new CheckBox( "Apply bug workaround after toFront()" );
workaroundCheckBox.setLayoutX( 200 );
workaroundCheckBox.setLayoutY( 300 );
final Button button1 = new Button();
button1.setViewOrder( -1 );
button1.setOnAction( __ -> {
button1.toFront();
if( workaroundCheckBox.isSelected() ) {
// Temporarily change node's view order, then change it back.
// This causes a call to Parent.markViewOrderChildrenDirty().
button1.setViewOrder( 0 );
button1.setViewOrder( -1 );
}
} );
final Button button2 = new Button();
button2.setViewOrder( -1 );
button2.setOnAction( __ -> {
button2.toFront();
if( workaroundCheckBox.isSelected() ) {
// Temporarily change node's view order, then change it back.
// This causes a call to Parent.markViewOrderChildrenDirty().
button2.setViewOrder( 0 );
button2.setViewOrder( -1 );
}
} );
final Pane pane = new Pane( workaroundCheckBox, button1, button2 );
final Runnable button1TextUpdater = () -> button1.setText(
"Click to bring to front. Children index: "
+ pane.getChildren().indexOf( button1 ) + ", viewOrder: " + button1.getViewOrder() );
button1TextUpdater.run();
pane.getChildrenUnmodifiable().addListener( (ListChangeListener<Node>) __ -> button1TextUpdater.run() );
button1.viewOrderProperty().addListener( ( __, ___, ____ ) -> button1TextUpdater.run() );
final Runnable button2TextUpdater = () -> button2.setText(
"Click to bring to front. Children index: "
+ pane.getChildren().indexOf( button2 ) + ", viewOrder: " + button2.getViewOrder() );
button2TextUpdater.run();
pane.getChildrenUnmodifiable().addListener( (ListChangeListener<Node>) __ -> button2TextUpdater.run() );
button1.viewOrderProperty().addListener( ( __, ___, ____ ) -> button2TextUpdater.run() );
primaryStage.setTitle( "Node.toFront() with nonzero viewOrder bug demo" );
primaryStage.setScene( new Scene( pane, 600, 500 ) );
primaryStage.show();
Platform.runLater( () -> {
button1.setLayoutX( 100 );
button1.setLayoutY( 200 );
button2.setLayoutX( 100 + 0.5 * button1.getLayoutBounds().getWidth() );
button2.setLayoutY( 200 + 0.5 * button1.getLayoutBounds().getHeight() );
} );
}
public static void main( final String[] args ) {
launch( args );
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
After Node.toFront(), temporarily change the Node's ViewOrder and then change it back to what you want, which causes a call to Parent.markViewOrderChildrenDirty(). You cannot call that method directly because it is private API.
FREQUENCY : always
Windows 10, AdoptOpenJDK 11.0.6+10, JavaFX 14.0.1
A DESCRIPTION OF THE PROBLEM :
Node.toFront() never causes Parent to set the flag that marks its viewOrderChildren dirty.
Thus, after a Node.toFront() call when a previously higher-indexed sibling has an equal nonzero viewOrder, the Node still renders behind the now lower-indexed sibling.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Set equal nonzero ViewOrders on two sibling Nodes and lay them out overlapping.
Display them.
Call Node.toFront() on the sibling at the lower children index, which moves it to a higher children index than the sibling.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The Node at the higher children index should render in front of the sibling Node that still has an equal nonzero ViewOrder.
From javadoc of method Node.viewOrderProperty():
"If two children have the same viewOrder, the parent will traverse them in the order they appear in the parent's children list."
The code in method Parent.computeViewOrderChildren() produces a render order consistent with that javadoc. The problem is that the flag to call computeViewOrderChildren() does not get set upon calling Node.toFront().
ACTUAL -
The Node at the higher children index still renders behind its sibling Node.
---------- BEGIN SOURCE ----------
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.ListChangeListener;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
/**
* Demonstrates the bug in which {@code Parent.children} fails to set the flag to recompute
* {@code Parent.viewOrderChildren} when {@link Node#toFront()} changes the children order
* while children have nonzero {@link Node#viewOrderProperty()}.
**/
public class NodeToFrontBugDemo extends Application {
@Override
public void start( final Stage primaryStage ) throws Exception {
final CheckBox workaroundCheckBox = new CheckBox( "Apply bug workaround after toFront()" );
workaroundCheckBox.setLayoutX( 200 );
workaroundCheckBox.setLayoutY( 300 );
final Button button1 = new Button();
button1.setViewOrder( -1 );
button1.setOnAction( __ -> {
button1.toFront();
if( workaroundCheckBox.isSelected() ) {
// Temporarily change node's view order, then change it back.
// This causes a call to Parent.markViewOrderChildrenDirty().
button1.setViewOrder( 0 );
button1.setViewOrder( -1 );
}
} );
final Button button2 = new Button();
button2.setViewOrder( -1 );
button2.setOnAction( __ -> {
button2.toFront();
if( workaroundCheckBox.isSelected() ) {
// Temporarily change node's view order, then change it back.
// This causes a call to Parent.markViewOrderChildrenDirty().
button2.setViewOrder( 0 );
button2.setViewOrder( -1 );
}
} );
final Pane pane = new Pane( workaroundCheckBox, button1, button2 );
final Runnable button1TextUpdater = () -> button1.setText(
"Click to bring to front. Children index: "
+ pane.getChildren().indexOf( button1 ) + ", viewOrder: " + button1.getViewOrder() );
button1TextUpdater.run();
pane.getChildrenUnmodifiable().addListener( (ListChangeListener<Node>) __ -> button1TextUpdater.run() );
button1.viewOrderProperty().addListener( ( __, ___, ____ ) -> button1TextUpdater.run() );
final Runnable button2TextUpdater = () -> button2.setText(
"Click to bring to front. Children index: "
+ pane.getChildren().indexOf( button2 ) + ", viewOrder: " + button2.getViewOrder() );
button2TextUpdater.run();
pane.getChildrenUnmodifiable().addListener( (ListChangeListener<Node>) __ -> button2TextUpdater.run() );
button1.viewOrderProperty().addListener( ( __, ___, ____ ) -> button2TextUpdater.run() );
primaryStage.setTitle( "Node.toFront() with nonzero viewOrder bug demo" );
primaryStage.setScene( new Scene( pane, 600, 500 ) );
primaryStage.show();
Platform.runLater( () -> {
button1.setLayoutX( 100 );
button1.setLayoutY( 200 );
button2.setLayoutX( 100 + 0.5 * button1.getLayoutBounds().getWidth() );
button2.setLayoutY( 200 + 0.5 * button1.getLayoutBounds().getHeight() );
} );
}
public static void main( final String[] args ) {
launch( args );
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
After Node.toFront(), temporarily change the Node's ViewOrder and then change it back to what you want, which causes a call to Parent.markViewOrderChildrenDirty(). You cannot call that method directly because it is private API.
FREQUENCY : always