B4J Question To dip or not to dip - 4k display question

jroriz

Active Member
Licensed User
I have a project that works by reading and showing graphics on the screen from ordinary windows.

Everything was fine until I bought a 4K monitor. Everything is out of position, and I can't solve this problem.

I attached a project trying to replicate my scenario.

Download the project here: https://1drv.ms/f/s!ArdqlgJhFnmYkiHuImTcA5_GVX89

Result in my good old 21 inch display:
result1.PNG


4K display result:

result4k.PNG


Entire project:
B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600

    #AdditionalJar: jna-5.2.0
    #AdditionalJar: jna-platform-5.2.0
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    
    Dim OriginX, OriginY As Int
    Dim SecondForm As Form
    Dim img As ImageView
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1

    ' I read graphical elements from ordinary Windows forms wich i get by window name
    ' Mainform will play this part. See Scanwindow sub
    MainForm.RootPane.LoadLayout("main")
    MainForm.Title = "Window that I need to scan some graphical elements"
    MainForm.Show
    
    MainForm.AlwaysOnTop = True
    
    ScanWindow    ' as if mainform does not belong to the project
    
    img.Initialize("")
    
    SecondForm.Initialize("", 300,300)
    SecondForm.RootPane.AddNode(img,0,0,SecondForm.Width, SecondForm.Height)
    
    SecondForm.WindowLeft = OriginX + 300
    SecondForm.WindowTop = OriginY + 300
    SecondForm.Title = "Second"
    
    SecondForm.BackColor = fx.Colors.Blue
    
    SecondForm.AlwaysOnTop = True

End Sub

Sub Capture(x As Int, y As Int, width As Int, height As Int) As B4XBitmap

    Dim c3po As AWTRobot

    c3po.ScreenCurrentRectangleSetAsArbitrary(x, y, width, height)
    Return BytesToImage(c3po.ScreenCaptureAsByteArray)

End Sub

Public Sub BytesToImage(bytes() As Byte) As B4XBitmap
    Dim In As InputStream
    In.InitializeFromBytesArray(bytes, 0, bytes.Length)

    Dim bmpret As Image
    bmpret.Initialize2(In)

    Return bmpret
End Sub


Sub ScanWindow
    
    Dim wu As JavaObject
    
    wu.InitializeStatic("com.sun.jna.platform.WindowUtils")

    ' I need a list cause I scan several windows
    Dim Ls As List = wu.RunMethod("getAllWindows",Array(True))

    Dim tit As String

    For Each JO As JavaObject In Ls
        tit = JO.RunMethod("getTitle",Null)
        
        If tit = "Window that I need to scan some graphical elements" Then

                Dim awtrect As JavaObject = JO.RunMethod("getLocAndSize", Null)
                
                OriginX = awtrect.GetField("x")
                OriginY = awtrect.GetField("y")
                Log("Form found")
                Return

        End If
        
    Next

End Sub

Sub MainForm_CloseRequest (EventData As Event)
    
    SecondForm.Close

End Sub



'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub

Sub Button1_Click
    Dim bmp As B4XBitmap
    bmp = Capture(OriginX + 100, OriginY + 100, 300, 300)
    img.SetImage(bmp)

    SecondForm.Show

End Sub
 
Last edited:

emexes

Well-Known Member
Licensed User
I am guessing that OriginX and OriginY are already in screen-coordinate scale and don't need to be put through DipToCurrent().
B4X:
SecondForm.WindowLeft = DipToCurrent(OriginX) + 300dip
SecondForm.WindowTop = DipToCurrent(OriginY) + 300dip
B4X:
Dim awtrect As JavaObject = JO.RunMethod("getLocAndSize", Null)
OriginX = awtrect.GetField("x")
OriginY = awtrect.GetField("y")
B4X:
bmp = Capture(DipToCurrent(OriginX) + 100dip, DipToCurrent(OriginY) + 100dip, 300dip, 300dip)
so delete the four DipToCurrent() calls and give it a run.
 

jroriz

Active Member
Licensed User
I am guessing that OriginX and OriginY are already in screen-coordinate scale and don't need to be put through DipToCurrent().
B4X:
SecondForm.WindowLeft = DipToCurrent(OriginX) + 300dip
SecondForm.WindowTop = DipToCurrent(OriginY) + 300dip
B4X:
Dim awtrect As JavaObject = JO.RunMethod("getLocAndSize", Null)
OriginX = awtrect.GetField("x")
OriginY = awtrect.GetField("y")
B4X:
bmp = Capture(DipToCurrent(OriginX) + 100dip, DipToCurrent(OriginY) + 100dip, 300dip, 300dip)
so delete the four DipToCurrent() calls and give it a run.
Nice try but the result was the same.
 

emexes

Well-Known Member
Licensed User
Having said that, could you try the following Logs? Because if:
Nice try but the result was the same.
then that would imply that DipToCurrent() has no effect, which... hmm...
B4X:
SecondForm.WindowLeft = DipToCurrent(OriginX) + 300dip
SecondForm.WindowTop = DipToCurrent(OriginY) + 300dip
Log("OriginX = " & OriginX)
Log("OriginY = " & OriginY)
Log(DipToCurrent(OriginX))
Log("300dip = " & 300dip)
B4X:
bmp = Capture(DipToCurrent(OriginX) + 100dip, DipToCurrent(OriginY) + 100dip, 300dip, 300dip)
Log("OriginX = " & OriginX)
Log("OriginY = " & OriginY)
Log(DipToCurrent(OriginX))
Log("100dip = " & 100dip)
Log(DipToCurrent(OriginX) + 100dip)
Log("300dip = " & 300dip)
 

emexes

Well-Known Member
Licensed User
Just out of interest: is there a reason for not using the regular graphics operations, eg:
B4X:
Dim bb As B4XBitmap = MainForm.RootPane.Snapshot    'grab entire content of pane (not including window borders)
img.SetImage(bb.Crop(92dip, 70dip, 300dip, 300dip))    'and copy cropped part to ImageView on second form
other than the grab only being from within the full window pane rather than from the entire screen?
 

Erel

Administrator
Staff member
Licensed User
dip in B4J always equals 1.

JavaFX takes care of handling the scale for you.

I haven't checked your project. Make sure to test it with Java 11 as it better handles higher scales.
 

jroriz

Active Member
Licensed User
Having said that, could you try the following Logs? Because if:

then that would imply that DipToCurrent() has no effect, which... hmm...
B4X:
SecondForm.WindowLeft = DipToCurrent(OriginX) + 300dip
SecondForm.WindowTop = DipToCurrent(OriginY) + 300dip
Log("OriginX = " & OriginX)
Log("OriginY = " & OriginY)
Log(DipToCurrent(OriginX))
Log("300dip = " & 300dip)
B4X:
bmp = Capture(DipToCurrent(OriginX) + 100dip, DipToCurrent(OriginY) + 100dip, 300dip, 300dip)
Log("OriginX = " & OriginX)
Log("OriginY = " & OriginY)
Log(DipToCurrent(OriginX))
Log("100dip = " & 100dip)
Log(DipToCurrent(OriginX) + 100dip)
Log("300dip = " & 300dip)
As said by Erel in post 7, dip is always 1 in B7J.
 

jroriz

Active Member
Licensed User
Just out of interest: is there a reason for not using the regular graphics operations, eg:
B4X:
Dim bb As B4XBitmap = MainForm.RootPane.Snapshot    'grab entire content of pane (not including window borders)
img.SetImage(bb.Crop(92dip, 70dip, 300dip, 300dip))    'and copy cropped part to ImageView on second form
other than the grab only being from within the full window pane rather than from the entire screen?
Because I'm grabbing small portions of windows that do not belong to my project, they are ordinary windows from other applications.
 

jroriz

Active Member
Licensed User
dip in B4J always equals 1.

JavaFX takes care of handling the scale for you.

I haven't checked your project. Make sure to test it with Java 11 as it better handles higher scales.
Changed to java java 11.0.1 (java 11.0.4 raises the error "module not found: javafx.swing").
Now the compiled jar does not run animore. Running from the IDE works, both in debug and release mode.
dip in B4J always equals 1.

JavaFX takes care of handling the scale for you.

I haven't checked your project. Make sure to test it with Java 11 as it better handles higher scales.
Changed to java 11.0.1 (java 11.0.4 raises the error "module not found: javafx.swing").
Now the compiled jar does not run anymore. Does not show any error, just nothing happens. I have tryed a default new project, and the same happens: the compiled jar does not work, only if I run from the IDE.
 
Top