JDK-8107810 : There is no way to obtain node coordinates on the screen
  • Type: Bug
  • Component: javafx
  • Sub-Component: graphics
  • Affected Version: fx1.2.1
  • Priority: P3
  • Status: Resolved
  • Resolution: Duplicate
  • Submitted: 2009-08-31
  • Updated: 2015-06-16
  • Resolved: 2010-02-03
Related Reports
Blocks :  
Duplicate :  
Description
The existing way to obtain screen coordinates does not return correct results for a node. According to the documentation, node coordinates can be got in the following way:

onScreenX = node.scene.stage.x + node.scene.x + node.localToScene(node.boundsInLocal).minX;
onScreenY = node.scene.stage.y + node.scene.y + node.localToScene(node.boundsInLocal).minY;

This approach returns incorrect results. In the sample, there is a Button control on the scene. When clicking the Run button, the following calculation results (obtained using the above clauses) of the stage, scene and Button object coordinates are posted to the console window:

Stage  location on screen: 428.0, 337.0
Scene  location on screen: 428.0, 337.0
javafx.scene.control.Button location on screen: 426.6, 335.6

After that, by using the SwingButton object placed on the scene and the getTopLevelAWTComponent function, screen coordinates of the AWT\Swing top-level object (from which the stage object is created) are calculated and printed. Here are the results:

javax.swing.JFrame location on screen: 428.0, 337.0

Note that screen coordinates of the JFrame top left corner are equivalent to the stage top left corner coordinates. However, according to the printed coordinates of the Button object, it is placed more to the top and to the left than the JFrame top left corner. It is absolutely obvious that this is not true. We need a way to find out the real screen coordinates of a node. 


[NodeLocationOnScreen.fx]

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.ext.swing.*;
import java.awt.Component;

var button = Button {translateY: 0;   width: 150; text: "MyButton"; };
var swingButton = SwingButton {translateY: 100; width: 150; text: "MySwingButton"; };

function PrintNodeLocationOnScreen(node: Node)
{
	var scene = node.scene;
	var stage = scene.stage;
										
	var sceneOnStageX = scene.x;
	var sceneOnStageY = scene.y;
		
	var nodeOnSceneX = node.localToScene(node.boundsInLocal).minX;
	var nodeOnSceneY = node.localToScene(node.boundsInLocal).minY;
		
	var stageOnScreenX = stage.x;
	var stageOnScreenY = stage.y;
	var sceneOnScreenX = stageOnScreenX + sceneOnStageX;
	var sceneOnScreenY = stageOnScreenY + sceneOnStageY;
	var nodeOnScreenX = sceneOnScreenX + nodeOnSceneX;
	var nodeOnScreenY = sceneOnScreenY + nodeOnSceneX;
				
	println("Stage  location on screen: {stageOnScreenX}, {stageOnScreenY}");
	println("Scene  location on screen: {sceneOnScreenX}, {sceneOnScreenY}");
	println("{node.getClass().getName()} location on screen: {nodeOnScreenX}, {nodeOnScreenY}");

}

function getTopLevelAWTComponent(node: SwingComponent): Component
{
	var c: Component = node.getJComponent();
	while(true)
	{
		var parent: Component = c.getParent();
		if (parent == null)
			break;
		c = parent;
	}

	return c;
}

Stage
{
	title: "Node location on screen"
	scene: Scene
	{
		content:
		[
			button,
			swingButton,
			Button
			{
				translateY: 200;
				translateX: 200;
				text: "Run";
				action: function(): Void
				{
					PrintNodeLocationOnScreen(button);

					var topLevelAWTComponent = getTopLevelAWTComponent(swingButton);
					var topLevelAWTComponentScreenX = topLevelAWTComponent.getLocationOnScreen().getX();
					var topLevelAWTComponentScreenY = topLevelAWTComponent.getLocationOnScreen().getY();
					
					println("{topLevelAWTComponent.getClass().getName()} location on screen: {topLevelAWTComponentScreenX}, {topLevelAWTComponentScreenY}");
					println("");
				}				
			}
		]
	}
}
Comments
This functionality exists in 1.3 now that RT-3215 is fixed. It could be made easier -- see RT-3290 -- but it is now possible.
03-02-2010