Change position of acDialog form

M

MacDermott

My client asked for functionality which would let his users save the
position of a form, so that the next time it's opened (on that system), it
returns to the saved position. I achieved this using the GetWindowPlacement
and SetWindowPlacement API calls.
That worked fine, until my client noticed that if the form being
repositioned (this occurs in the OnLoad event) has been opened acDialog, it
loses this property.
I haven't even been able to figure out a way to tell whether the form is
opened acDialog.

Any ideas?
TIA
 
J

Jon Lewis

What may be happening here is that normally the SetWindowsPlacement call
will position the form relative to the main Access window but if the form is
opened acDialog then the form will be positioned relative to the Screen.

If a form is opened acDialog then it's presumably done with Docmd.OpenForm,
so you can use the OpenArgs parameter to indicate this. Then your Form's On
Load event can check the OpenArgs value and adjust the SetWindowPlacement
call accordingly to take into account the Access window position in the
acDialog case.

HTH
Jon
 
M

MacDermott

Thank you so much for your input on this, Jon!

Perhaps I didn't explain the problem properly:
When I open a form with acDialog (yes, I'm using DoCmd.OpenForm), the
form placement is correct.
The problem is that after it has been repositioned, it's no longer modal;
although it's pop-up (always remains displayed as the top layer),
the user can work in the form below it.
The whole point of opening it acDialog was to prevent the user from
working in the other form until this one is closed.

Any ideas?
TIA
 
J

Jon Lewis

Sorry - I misunderstood. I can't reproduce the problem though. I'm opening
frm2 from a Command Button on frm1:

On Error GoTo Err_Command0_Click
DoCmd.OpenForm "frm2", , , , , acDialog
MsgBox "frm2 closed!"
Exit_Command0_Click:
Exit Sub
Err_Command0_Click:
MsgBox Err.Description
Resume Exit_Command0_Click

This is what's in frm2 On Load:

Dim WinEst As WINDOWPLACEMENT
Dim rtn As Long
Dim rct As RECT
Dim rct2 As RECT

rtn = GetWindowPlacement(Me.hwnd, WinEst)
rct = WinEst.rcNormalPosition
rct2.Bottom = (rct.Bottom - rct.Top) + 10
rct2.Left = 10
rct2.Right = (rct.Right - rct.Left) + 10
rct2.Top = 10

WinEst.Length = Len(WinEst)
WinEst.showCmd = SW_SHOWNORMAL
WinEst.rcNormalPosition = rct2

rtn = SetWindowPlacement(Me.hwnd, WinEst)

frm2's Modularity is preserved and the MsgBox from frm1 Command0 On Click
doesn't appear until after frm2 is closed.

Is this similar to what you are doing or do you have something else going on
to affect frm2's window mode? You mentioned "if the form ... has been
opened acDialog". Is it opened acWindowNormal sometimes? Could it be
already open (maybe hidden) when the OpenForm acDialog command is executed?

Jon
 
M

MacDermott

Try this:
Put a second command button on frm1 - have it pop up some sort of
msgbox.
Now click Command0 to open frm2.
Go back and click the second button on frm1.
I get a msgbox in this scenario - do you?
In contrast, if I delete (or comment out) the code that changes the position
of frm2,
frm1 can't get the focus after frm2 has been opened.

Can you reproduce this?

TIA!
 
J

Jon Lewis

No but............

I was using Access 2007 (albeit mdb file format). Just opened the file in
Access 2000 and yes I get what you get - very strange. It loses it's Modal
state but the code (at least from the calling procedure) is still suspended
i.e. my "frm2 closed" message doesn't appear until I close frm2.

I added Me.Modal = True to the end of frm2's On Load procedure and that
seems to bring back the Modal state.

Why A2K7 & A2k should be different must be down to version differences in
how the Access Forms (as windows) are subclassed. I doubt you'll get to the
bottom of what's going on although you could try different api calls (maybe
SetWindowPos or MoveWindow) to see if the effect is the same.

Hopefully the extra Me.Modal = True will work for you as code is definitely
suspended in the calling procedure anyway and re-setting the Modal state
should replicate acDialog elsewhere.

HTH

Jon
 
M

MacDermott

Thanks so much for your help on this, Jon!
The insight about the behavior changing with Access version may be
enough for my client...

I've been using Access 2003 (mdb, of course).

So here's the next aspect of the problem:

This application has over 100 forms, and I would estimate at least several
dozen of them use this position tracking.
I'm not sure how many of them are opened with acDialog - I know it's a
mix.
(My client does the basic development - I only get called in when he
gets stuck...)
I'm not even sure but what some forms are sometimes opened acDialog,
sometimes not.
So I've written a generic procedure which he can call with just a single
line of code.
To implement your suggestion of adding Me.Modal = True, it would be
great if I could somehow figure out programmatically whether the form had
been opened with acDialog. Clearly, even though the behavior is a lot like
having both Modal and Popup true, normally opening a window with acDialog
doesn't set those properties...

TIA!

(I may also try using some of those other API calls...)
 
M

MacDermott

Just to let you know -
MoveWindow did the trick!
Guess it's the old Keep It Simple principle -
MoveWindow doesn't give you any options of changing windowstate.

Thanks again for all your help!
Turtle
 
J

Jon Lewis

Does this help:

Private Const GWL_EXSTYLE = (-20)
Private Const WS_EX_MDICHILD = &H40
Private Const GWL_STYLE = (-16)
Private Const GW_OWNER = 4

Private Declare Function GetWindow Lib "user32" _
(ByVal hwnd As Long, ByVal wCmd As Long) As Long


Private Const WS_DISABLED = &H8000000
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
(ByVal hwnd As Long, ByVal nIndex As Long) As Long


This is the generally accepted way of testing modularity and it returns
False under these circumstances:

Private Function IsWindowModal(hwnd As Long) As Boolean
Dim hwndOwner As Long
hwndOwner = GetWindow(hwnd, GW_OWNER)
If hwndOwner Then
IsWindowModal = (GetWindowLong(hwndOwner, GWL_STYLE) _
And WS_DISABLED)
End If
End Function


However this one returns True.


Public Function IsModal(ByVal lHwnd As Long) As Boolean
Dim lWinstyle As Long
lWinstyle = GetWindowLong(lHwnd, GWL_EXSTYLE)
If (lWinstyle And WS_EX_MDICHILD) Then
IsModal = False
Else
IsModal = True
End If

End Function


How reliable it is I don't know because it seems to be relating modularity
just to whether a window is a MDICHILD but it does seem to work . Using
OpenArgs as below would be totally reliable or use IsModal if you want. By
the way MoveWindow doesn't remove modularity so maybe you could just use
that.

To open frm2:
DoCmd.OpenForm "frm2", , , , , acDialog, "Dialog"
In frm2's Load Event:
PosWindow Me
In a Standard Module
Sub PosWindow(frm As Form)
Dim WinEst As WINDOWPLACEMENT
Dim rtn As Long
Dim rct As RECT
Dim rct2 As RECT
rtn = GetWindowPlacement(frm.hWnd, WinEst)
rct = WinEst.rcNormalPosition
rct2.Bottom = (rct.Bottom - rct.Top) + 10
rct2.Left = 10
rct2.Right = (rct.Right - rct.Left) + 10
rct2.Top = 10
WinEst.Length = Len(WinEst)
WinEst.showCmd = SW_SHOWNORMAL
WinEst.rcNormalPosition = rct2
rtn = SetWindowPlacement(frm.hWnd, WinEst)
If frm.OpenArgs = "Dialog" Then
frm.Modal = True
End If
End Sub

Jon
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top