B4J Question How to get the screen coords of a node?

jmon

Well-Known Member
Licensed User
Longtime User
Hi,

I'm trying to get the screen coordinates of a node. It works ok, but when I put that control in a tab, the coordinates I get don't include the offset of the position of the tab in the window.

How to do it? is there another way than the one I am doing?
Is there a way to get the node's parents and loop through them to get each's position?

I have included an example of how much I have done so far.
Thanks

jmon.
 

Attachments

  • testGetScreenCoords.zip
    1.7 KB · Views: 240

Daestrum

Expert
Licensed User
Longtime User
There is getLocalToSceneTransform the description sounds like it may give you the figures you want.
It returns a Transform object, which appears to hold the x, y, z, scale and rotations relative to the scene.
 
Upvote 0

jmon

Well-Known Member
Licensed User
Longtime User
Where exactly in the code is the problem?
Sorry, my post wasn't clear enought.

This example I provided is supposed to change the child position from one button to the other when clicking on the "Switch Position" button. As you will see, the child window is correctly positioned under the "button1" because the button1 is children of the root. The child window doesn't position itself correctly under the button2, because the button 2 is children of another control. You will see that in that case the child window positions itself where it believes the button2 is, not taking into account the offset of the tab control.

This is the part of the code that doesn't work properly:
B4X:
Sub setWindowPosition
    Dim SceneX, SceneY As Double
    Dim joStage, joScene As JavaObject
    joStage = MainForm.RootPane   
    joScene = joStage.RunMethod("getScene",Null)
    SceneX = joScene.RunMethod("getX", Null)
    SceneY = joScene.RunMethod("getY", Null)
   
   
    ChildForm.WindowLeft = MainForm.WindowLeft + CurrentButton.Left + SceneX
    ChildForm.WindowWidth = MainForm.Width
    ChildForm.WindowTop = MainForm.WindowTop + CurrentButton.Top + SceneY + CurrentButton.PrefHeight
End Sub

What works here is:
- the position of the window is correct
- the offset of the scene inside the window is correct
- the position of the button inside the scene is correct, only for button1, but not for button2

I've done some research, and what I may have to do is to use the "parent" property of the node, and loop through all the parents of the button2 and add their left position. Is that what I should do?

There is getLocalToSceneTransform the description sounds like it may give you the figures you want.
It returns a Transform object, which appears to hold the x, y, z, scale and rotations relative to the scene.

Thanks for that, I will try to implement that. But it looks like it returns the bouding box rather that the position in the scene?


Thank you both for your help.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Check this code:
B4X:
Sub setWindowPosition
   Dim TopLeft() As Int = GetScreenPosition(CurrentButton)
   Log("Top = " & TopLeft(0))
   Log("Left = " & TopLeft(1))
   ChildForm.WindowLeft = MainForm.WindowLeft + TopLeft(1)
   ChildForm.WindowWidth = MainForm.Width
   ChildForm.WindowTop = MainForm.WindowTop + TopLeft(0)
End Sub

Sub GetScreenPosition(n As Node) As Int()
   Dim t, l As Int
   Dim jo As JavaObject = n
   Do While True
     t = t + n.Top
     l = l + n.Left
     jo = jo.RunMethod("getParent", Null)
     If jo.IsInitialized = False Then Exit
     n = jo
   Loop
   Return Array As Int(t, l)
End Sub
 
Upvote 0

jmon

Well-Known Member
Licensed User
Longtime User
Check this code:
...

Thanks a lot, it works! But I still had to add the scene offset inside the stage for it to work properly:
B4X:
Sub setWindowPosition
    Dim SceneX, SceneY As Double
    Dim joStage, joScene As JavaObject
    joStage = MainForm.RootPane   
    joScene = joStage.RunMethod("getScene",Null)
    SceneX = joScene.RunMethod("getX", Null)
    SceneY = joScene.RunMethod("getY", Null)

  Dim TopLeft() As Int = GetScreenPosition(CurrentButton)
  Log("Top = " & TopLeft(0))
  Log("Left = " & TopLeft(1))
  ChildForm.WindowLeft = MainForm.WindowLeft + TopLeft(1) + SceneX
  ChildForm.WindowWidth = MainForm.Width
  ChildForm.WindowTop = MainForm.WindowTop + TopLeft(0) + SceneY
End Sub

Sub GetScreenPosition(n As Node) As Int()
  Dim t, l As Int
  Dim jo As JavaObject = n
  Do While True
    t = t + n.Top
    l = l + n.Left
    jo = jo.RunMethod("getParent", Null)
    If jo.IsInitialized = False Then Exit
    n = jo
  Loop
  Return Array As Int(t, l)
End Sub

Maybe that's because I'm on windows 7. The scene offset is equal to the taskbar of the window for the X value and the window's edges for the Y value.

Thanks a lot!
 
Upvote 0

ThRuST

Well-Known Member
Licensed User
Longtime User
I need this solution myself and it's year 2019. This is what happened

Any clues?

B4J Version: 7.51
Java Version: 8
Parsing code. (0.38s)
Building folders structure. (0.01s)
Compiling code. (0.22s)
Compiling layouts code. (0.01s)
Organizing libraries. (0.00s)
Compiling generated Java code. Error
B4J line: 27949
Log(GetScreenPosition(MSTextFieldGoogleSearch))
javac 1.8.0_191
src\athena\duologic\se\main.java:33471: error: no suitable method found for NumberToString(int[])
anywheresoftware.b4a.keywords.Common.Log(BA.NumberToString(_getscreenposition((anywheresoftware.b4j.objects.NodeWrapper.ConcreteNodeWrapper) anywheresoftware.b4a.AbsObjectWrapper.ConvertToWrapper(new anywheresoftware.b4j.objects.NodeWrapper.ConcreteNodeWrapper(), (javafx.scene.Node)(_mstextfieldgooglesearch.getObject())))));
^
method BA.NumberToString(double) is not applicable
(argument mismatch; int[] cannot be converted to double)
method BA.NumberToString(float) is not applicable
(argument mismatch; int[] cannot be converted to float)
method BA.NumberToString(int) is not applicable
(argument mismatch; int[] cannot be converted to int)
method BA.NumberToString(long) is not applicable
(argument mismatch; int[] cannot be converted to long)
method BA.NumberToString(Number) is not applicable
(argument mismatch; int[] cannot be converted to Number)
1 error
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Looks like you’re trying to log an array and Log does not do that for you. Has nothing todo (with this error) with GetScreenPosition not working
 
Upvote 0

ThRuST

Well-Known Member
Licensed User
Longtime User
Ok that's embarrassing, but how about this. I am trying to locate the screen position of a text field.
Strange that not the full name of MSTextFieldGoogleSearch is showing up in the log. I should get my brain together and considder jAWTRobot lib on this.

B4X:
Private GetPos As Int
    GetPos = GetScreenPosition (MSTextFieldGoogleSearch)

B4X:
Sub GetScreenPosition(n As Node) As Int()
    Dim t2, l As Int
    Dim jo As JavaObject = n
    Do While True
        t2 = t2 + n.Top
        l = l + n.Left
        jo = jo.RunMethod("getParent", Null)
        If jo.IsInitialized = False Then Exit
        n = jo
    Loop
    Return Array As Int(t, l)
End Sub

Log
B4J Version: 7.51
Java Version: 8
Parsing code. (0.41s)
Building folders structure. (0.01s)
Compiling code. (0.22s)
Compiling layouts code. (0.01s)
Organizing libraries. (0.00s)
Compiling generated Java code. Error
B4J line: 27949
GetPos = GetScreenPosition (MSTextFieldGoogleSear
javac 1.8.0_191
src\athena\duologic\se\main.java:33474: error: incompatible types: int[] cannot be converted to int
_getpos = (int)(_getscreenposition((anywheresoftware.b4j.objects.NodeWrapper.ConcreteNodeWrapper) anywheresoftware.b4a.AbsObjectWrapper.ConvertToWrapper(new anywheresoftware.b4j.objects.NodeWrapper.ConcreteNodeWrapper(), (javafx.scene.Node)(_mstextfieldgooglesearch.getObject()))));
^
1 error
 
Upvote 0

ThRuST

Well-Known Member
Licensed User
Longtime User
An option would be to use AWTRobot.RobotMouseCurrentLocation(x,y) if I could just put the mouse at the position of the text field..

I need to get the position related to the screen, not from the pane.
 
Upvote 0
Top