screen v form coordinates (1 Viewer)

CJ_London

Super Moderator
Staff member
Local time
Today, 08:11
Joined
Feb 19, 2013
Messages
16,610
I’m trying to line up a form against the left side of a control of another form.

To position it I’m using the form.move method and to line it up perfectly the value for left needs to be 6800 twips in this example. This figure will vary depending on the location of the lower form on the windows screen – so I need to calculate it, which is where I am having the problem.

There are a number of variables in play.

To determine the position of the control on the lower form is simply ctrl.left which is a twips value

To determine the position of the lower form on the desktop I have two options. I can use the form windowleft property (in twips) to determine its location in respect to the access window, plus rect.left value using the getwindowrec function on the access window which returns a screen coordinates value and then use pixelstotwips to convert this value to twips.

Or I can determine the rect.left value using the getwindowrec function which returns a screen coordinates value and then use pixelstotwips to convert this value to twips of the form in relation to the screen.
For completeness, the access window is maximised

References:
Windowsleft:
https://msdn.microsoft.com/en-us/library/office/aa663055(v=office.11).aspx
Getwindowrec: https://msdn.microsoft.com/en-us/library/windows/desktop/ms633519(v=vs.85).aspx
Pixelstotwips – calculates to 1440/96=15 twips per pixel:
Code:
 Private Function PixelsToTwips(ByVal X As Long, ByVal Y As Long) As POINT
 Dim ScreenDC As LongPtr
 
     ScreenDC = GetDC(0)
     PixelsToTwips.X = X / GetDeviceCaps(ScreenDC, LOGPIXELSX) * TWIPSPERINCH
     PixelsToTwips.Y = Y / GetDeviceCaps(ScreenDC, LOGPIXELSY) * TWIPSPERINCH
     ReleaseDC 0, ScreenDC
 
 End Function
 
 Private Function TwipsToPixels(ByVal X As Long, ByVal Y As Long) As POINT
 Dim ScreenDC As LongPtr
 
     ScreenDC = GetDC(0)
     TwipsToPixels.X = X / TWIPSPERINCH * GetDeviceCaps(ScreenDC, LOGPIXELSX)
     TwipsToPixels.Y = Y / TWIPSPERINCH * GetDeviceCaps(ScreenDC, LOGPIXELSY)
     ReleaseDC 0, ScreenDC
 
 End Function
The code I’m using is
Code:
Private Function WinTopLeft(frm As Form, ctrl As Object) As POINT
Dim FormWR As RECT
Dim offset As POINT
Dim AccessWR As RECT
Dim POS As POINT



GetWindowRect frm.hwnd, FormWR
GetWindowRect Application.hWndAccessApp, AccessWR
GetCursorPos POS
offset = TwipsToPixels(ctrl.left, ctrl.top)
Debug.Print POS.X; AccessWR.left; FormWR.left; ctrl.left; offset.X; frm.WindowLeft
Code:
 [FONT=Tahoma]DoCmd.OpenForm "form2"
Forms!form2.Move 6800 'target twips to line up
'work with p&p to determine calculation[/FONT]
 [FONT=Tahoma]
End Function
[/FONT]
The results I get from the debug is
POS.X..AccessWR.left…FormWR.left…ctrl.left…offset.X…frm.WindowLeft
672......-8……..............357….........….4545……303………..2100

So the calculation:
1. (AccessWR.left*15)+ frm.WindowLeft+ ctrl.left=(-8*15)+2100+4545=6525
2. ((AccessWR.left+FormWR.left)*15)+ ctrl.left=((-8+357)*15)+4545=9780

Neither are particularly close to the target value of 6800.


I would have expected the frm.WindowsLeft value to be equivalent to the FormWR.Left value but there is a big difference - 2100/15=140 v 357 reported. and the FormWR.Left value seems to be the suspect.


I've also converted the ctrl.left to screen coordinates (303) which when added to FormWR.Left and AccessWR.left closely approximates to the mouse position returned from getcursorPOS - I triggered the code from a mouseclick as close to the left of the control as I could to give me a guide of what was required.

I had wondered if the pixeltotwips conversion was calculating correctly, but it is a standard function I am using elsewhere without issue - and just to check I went online to confirm it was reading the screen correctly.

Any thoughts?
 

CJ_London

Super Moderator
Staff member
Local time
Today, 08:11
Joined
Feb 19, 2013
Messages
16,610
Thanks Stopher - I've see that before but hadn't thought about using it in this situation - it works just on using the windowleft/top etc properties which are all twip units - but when I use the equivalent (in the first of my examples calculations), there is a 135 twip/9 pixel difference.

I'll look at Markk's code in more detail, but has given me a thought - perhaps it is to do with the thickness of the window border

Edit - yes, it is, changed the form border to none and it lines up perfectly. Just need to find the value for that!

Thanks for getting me to think ion another direction!
 

gemma-the-husky

Super Moderator
Staff member
Local time
Today, 08:11
Joined
Sep 12, 2006
Messages
15,641
I think forms hold values for outer window and inner window positioning to take into account the borders. Will that help?
 

CJ_London

Super Moderator
Staff member
Local time
Today, 08:11
Joined
Feb 19, 2013
Messages
16,610
That was the route I ended up going down.

The calculation needs to take into account borderstyle, recordselectors and scrollbars and I ended up with this

Forms!form2.Move frm.WindowLeft + ctrl.left + IIf(hasParent(frm), 0, Choose(frm.BorderStyle + 1, 0, 45, 150, 45)) + Abs(frm.RecordSelectors * 255)

It means I've hardcoded the widths for borders and recordselectors, but I guess I can fix that if it becomes a problem

Thanks for all the comments, I shall consider this thread solved
 

jdraw

Super Moderator
Staff member
Local time
Today, 03:11
Joined
Jan 23, 2006
Messages
15,379
CJ,

The attached demo database was posted by the author on a different forum in response
to attempts to position form(s) precisely. I did not have anything to do with its creation.

You may get some ideas/options for it.
Just passing it on in hopes it may help.
 

Attachments

  • Move_Form.zip
    406.9 KB · Views: 191
Last edited:

CJ_London

Super Moderator
Staff member
Local time
Today, 08:11
Joined
Feb 19, 2013
Messages
16,610
Thanks JDraw - the problem was to determine the XY coordinates of the control top left - the example requires you to type in the coordinates. I have solved that with hardcoding the border width which was causing the problem.

But the example is interesting for its use of class modules, so I'm going to take a closer look, it might be more appropriate than passing the form object as I am at the moment or using screen.activeform
 

Users who are viewing this thread

Top Bottom