Solved

Doc 2 forms together

Posted on 2006-06-09
16
313 Views
Last Modified: 2007-12-19
I have created a form that displays data that is linked to a permission table. If the permission table lists the current user as a "Manager" then it will also open another popup that contains the menu buttons and other controls. It works fine but I would like to dock the two forms together so I looked up the following question and found some code that I thought would help. http://www.experts-http://www.experts-exchange.com/Databases/MS_Access/Q_21462025.html?query=set+as+form&topics=39
I've created the class module and copied the two subs into my application, then I tried using the following commands but they don't work as I thought they should. frmMainMenu is set up to Auto Centre so it correctly centres itself on the screen. The menu frmAdminMenu should, I thought, position itself at the top of frmMainMenu, instead it positions itself at the top of the screen over the top of the main Access Menu. Can anyone tell me what I need to do to make it work?
            Dim FormA As Form
            Dim FormB As Form
            Set FormB = [Forms]![frmMainMenu]
            Set FormA = [Forms]![frmAdminMenu]
            Call AlignTops(FormA, FormB)
 Rob
0
Comment
Question by:Rob4077
  • 9
  • 7
16 Comments
 

Author Comment

by:Rob4077
Comment Utility
Actually, I just realised it seems to align the bottom of one form with the top of the other with little regard for it's alignment from the left. What I would like is for it to position FormA (the frmAdminMenu) over the top left of FormB (the two top lefts on top of one another. Is that possible?
0
 
LVL 58

Expert Comment

by:harfang
Comment Utility
Hello Rob4077

I didn't find AlignTops() in the question {http:/Q_21462025.html}. So I can't really help there. Perhaps your form is set as popup?

You might also want to read this MS reference if you are trying to align forms on screen:
ACC2000: How to Get the Right and Down Measurements of a Form
http://support.microsoft.com/kb/q210141/

Cheers!
(°v°)
0
 

Author Comment

by:Rob4077
Comment Utility
Thanks for the tip Markus,
I will have a read and try to figure it out. I will leave the question open until I do, just in case I need more help.

The link I referred to has two subs associated with it as follows. I used the one that seemed to suit me.


 Often times, it's necessary to open forms in specified locations and size them to a custom size. Windows API are the most convenient way of doing this, but the converting between the different coordinate systems can be a pain.

      Download clFormWindows.Bas

    This Class Module hides the API functions and provides generic methods to move and size your forms. The class, once imported in your application, can be used in in a couple of ways.

    1. To align the tops of two forms (at the position of the topmost form):

'********** Code Start ************
Public Sub AlignTops(ByRef frmA As Form, ByRef frmB As Form)
  Dim fwA As New clFormWindow, fwB As New clFormWindow
  fwA.hwnd = frmA.hwnd
  fwB.hwnd = frmB.hwnd
  If fwA.Top < fwB.Top Then
    fwB.Top = fwA.Top
  Else
    fwA.Top = fwB.Top
  End If
 
  Set fwA = Nothing
  Set fwB = Nothing
End Sub
'********** Code End  ************
    2. To move a form to the top right corner of the Access window:

'********** Code Start ************
Public Sub MoveToTopRight(ByVal strFormName As String)
  Dim fwForm As New clFormWindow
  Const SMALL_OFFSET = 5  'Used to position window slightly _
                      away from the Access MDI window border _
                          in order to avoid appearance of the Access _
                          window vertical scroll bar.
  With fwForm
    .hwnd = Forms(strFormName).hwnd
    .Top = .Parent.Top
    .Left = .Parent.Width - .Width - SMALL_OFFSET
  End With
  Set fwForm = Nothing
End Sub
'********** Code End ************
0
 
LVL 58

Expert Comment

by:harfang
Comment Utility
Rob4077

Again, your link contains nothing of the sort, and no link to a downloadable class module. You must have mixed up your cut-and-paste.

Anyway, based on the code above, something like this might do it:

Public Sub StackOnTop(ByRef frmA As Form, ByRef frmB As Form)
  Dim fwA As New clFormWindow, fwB As New clFormWindow
  fwA.hwnd = frmA.hwnd
  fwB.hwnd = frmB.hwnd

  fwB.Left = fwA.Left
  fwB.Top = fwA.Top - fwB.Height

  Set fwA = Nothing
  Set fwB = Nothing
End Sub

Good luck
(°v°)
0
 

Author Comment

by:Rob4077
Comment Utility
Sorry to have wasted your time. The correct link is as follows: http://www.experts-exchange.com/Databases/MS_Access/Q_20831121.html?query=dock+forms&topics=39
I tried your code (in fact I was experimenting with it when I got your e-mail and changed it to the followeing: ) and it's doing something strange (to me at least).

   fwA.hWnd = FrmA.hWnd
    fwB.hWnd = FrmB.hWnd
    fwB.Left = fwA.Left
    fwB.Top = fwA.Top + fwB.Height
Stop
    Set fwA = Nothing
    Set fwB = Nothing

When I pause execution and hover my mouse over the values (at the stop) it comes up with the following values:
fwB.Left = 6
fwA.Left = 6
fwB.Top = 94
fwA.Top = 12
fwB.Height = 108

When I went to school 12 + 108 used to equal 120 not 94. In answer to an earlier comment of yours, Form B is a popup (so it will always be in view). I have no idea why it's doing that.
0
 
LVL 58

Expert Comment

by:harfang
Comment Utility
Rob4077

The code from mvps.org is not very professional, in many ways. It will works with normal forms, but  not with popups. There is some rather heavy confusion between the various metrics...

For example, when your code is stopped, try this in the immediate pane:

    fwB.Top = fwB.Top   ' funny, no?

The difference you observe (26 pixel) is probably the size of the title + menu bar area at the top.

Let me write a better class module. I'll get back to you on this.

(°v°)
0
 
LVL 58

Accepted Solution

by:
harfang earned 500 total points
Comment Utility
Rob4077,

I have something for you. This would be a replacement for the  faulty class module you had found. It works a little differently, though.

You cannot directly write to the .Top or .Left properties, but there is a global MoveSize method instead. This method is compatible with DoCmd.MoveSize, by the way.

For popup forms, the coordinates are normally relative to the desktop, not to the Access window. The module implements a flag, .Relative, which can be set to True for those forms. For other forms, the setting is true and cannot be changed.

There are two or three exemples in the explanations at the top of the module.

I hope this works better for your case, enjoy!

'-------------------------------------------------------------------------------
' Class Module  claFormWindow
' Copyright     Markus Fischer, Geneva, 2006
' Author        Markus G Fischer - www.harfang.ch (°v°)
' Created       Jun-2006
' Distribution  free if proper credit given
'-------------------------------------------------------------------------------
'
' Purpose
' ¯¯¯¯¯¯¯
' Provides the missing WindowTop and WindowLeft properties of forms, and
' implements a MoveSize that does not require the form to have the focus.
'
' Also allows relative metrics to be used for PopUp forms, which are normally
' relative to the desktop.
'
' Usage
' ¯¯¯¯¯
' Create an instance of this class module and pass a form object:
'
'   Dim objFW As New claFormWindow
'   Set objFW.Form = Forms!frmAnyForm
'
'   Properties:
'       Form (Form, set to initialize)
'       Left, Top, Width, Height: metrics in twips (Long, read only)
'
'   Methods:
'       MoveSize [Right], [Down], [Width], [Height]
'       (all arguments optional, in twips)
'
'   Note:
'       Me.Form.WindowWidth == Me.Width
'       Me.Form WindowHeight == Me.Height
'
' Example
' ¯¯¯¯¯¯¯
'   Dim oA As claFormWindow
'   Dim oB As claFormWindow
'
'   Set oA = Forms!frmCustomers
'   Set oB = Forms!fmodInfo   ' popup
'   oB.Relative = True
'
'   ' move the popup to the left of the normal form
'   oB.MoveSize oA.Left - oB.Width, oA.Top
'
' Used on a form module
' ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
'   Public Window As claFormWindow
'
'   Private Sub Form_Load()
'       Set Me.Window = New claFormWindow
'       Set Me.Window.Form = Me
'   End sub
'
'   Private Sub Form_Close()
'       Set Me.Window = Nothing
'   End Sub
'
' You could then use for example:
'   Debug.Pring Forms!frmCustomers!Window.Top
'   With Me.Window
'       .MoveSize , .Top + 60
'   End With
'   Debug.Print Me.WindowHeight, Me.Window.Height
'   etc...
'
' Warning:
' ¯¯¯¯¯¯¯¯
' There is no error handling at all
'
'-------------------------------------------------------------------------------
Option Compare Database
Option Explicit

Public Form             As Form     ' the form object
Dim mlngTwipsPerPixelX  As Long     ' depends on screen resolution
Dim mlngTwipsPerPixelY  As Long     ' " vertically

Dim mlngTop             As Long     ' in pixel
Dim mlngLeft            As Long     ' "
Dim mlngWidth           As Long     ' "
Dim mlngHeight          As Long     ' "

Dim mlngMDIhWnd         As Long     ' MDIClient window ("inside" Access)
Dim mlngMDI_Left        As Long     ' relative to destop, in pixel
Dim mlngMDI_Top         As Long     ' "

Dim mfPopupRelative     As Boolean  ' force popup metrics to relative

Private Type RECT_Type              ' used by the WinAPI calls
   Left As Long
   Top As Long
   Right As Long
   Bottom As Long
End Type

' obtain a window's rectangle
Private Declare Function GetWindowRect Lib "user32" _
    (ByVal hWnd As Long, lpRect As RECT_Type) As Long

' move a window and repaint
Private Declare Function MoveWindow Lib "user32" _
    (ByVal hWnd As Long, ByVal x As Long, ByVal Y As Long, _
    ByVal nWidth As Long, ByVal nHeight As Long, _
    ByVal bRepaint As Long) As Long

' find a window (used to find MDIClient)
Private Declare Function FindWindowExA Lib "user32" _
    (ByVal hWnd1 As Long, ByVal hWnd2 As Long, _
    ByVal lpsz1 As String, ByVal lpsz2 As String) As Long

' used for the logical screen resolution (twips per pixel)
Private Declare Function GetDC Lib "user32" _
    (ByVal hWnd As Long) As Long
Private Declare Function ReleaseDC Lib "user32" _
    (ByVal hWnd As Long, ByVal hDC As Long) As Long
Private Declare Function GetDeviceCaps Lib "gdi32" _
    (ByVal hDC As Long, ByVal nIndex As Long) As Long

' Relative is always true for normal forms, can be changed for popups
Property Get Relative() As Boolean
    Relative = Not Form.PopUp Or mfPopupRelative
End Property
Property Let Relative(pfNew As Boolean)
    mfPopupRelative = Form.PopUp And pfNew
End Property

' Optain the coordinates of the form
Private Sub GetMetrics()
   
    Dim FormRect    As RECT_Type    ' the form's rectangle
    Dim MDIClient   As RECT_Type    ' the container rectangle

    GetWindowRect Form.hWnd, FormRect
    With FormRect
        mlngTop = .Top
        mlngLeft = .Left
        mlngWidth = (.Right - .Left)
        mlngHeight = (.Bottom - .Top)
    End With

    If Me.Relative Then   ' always for normal forms
   
        GetWindowRect mlngMDIhWnd, MDIClient
        mlngMDI_Left = MDIClient.Left
        mlngMDI_Top = MDIClient.Top
       
        mlngLeft = mlngLeft - mlngMDI_Left - 2
        mlngTop = mlngTop - mlngMDI_Top - 2
       
    End If
End Sub

' Compatible with DoCmd.MoveSize
Public Sub MoveSize _
    (Optional Right, Optional Down, Optional Width, Optional Height)
   
    GetMetrics
    ' manage empty arguments and units conversions
    If IsMissing(Right) _
        Then Right = mlngLeft _
        Else Right = Right / mlngTwipsPerPixelX
    If IsMissing(Down) _
        Then Down = mlngTop _
        Else Down = Down / mlngTwipsPerPixelY
    If IsMissing(Width) _
        Then Width = mlngWidth _
        Else Width = Width / mlngTwipsPerPixelX
    If IsMissing(Height) _
        Then Height = mlngHeight _
        Else Height = Height / mlngTwipsPerPixelY
   
    ' special case for relative popups
    If mfPopupRelative Then
        Right = Right + mlngMDI_Left + 2
        Down = Down + mlngMDI_Top + 2
    End If
   
    MoveWindow Form.hWnd, Right, Down, Width, Height, True
   
End Sub

' Read metrics in Twips (Access compatible)
'
Property Get Top() As Long
    GetMetrics
    Top = mlngTop * mlngTwipsPerPixelY
End Property
Property Get Left() As Long
    GetMetrics
    Left = mlngLeft * mlngTwipsPerPixelX
End Property
Property Get Width() As Long
    GetMetrics
    Width = mlngWidth * mlngTwipsPerPixelX
End Property
Property Get Height() As Long
    GetMetrics
    Height = mlngHeight * mlngTwipsPerPixelY
End Property

' Get logical screen resolution
Private Sub Class_Initialize()

    Dim hDC As Long

    hDC = GetDC(0)
    mlngTwipsPerPixelX = 1440 / GetDeviceCaps(hDC, 88)   ' log X
    mlngTwipsPerPixelY = 1440 / GetDeviceCaps(hDC, 90)   ' log Y
    ReleaseDC 0, hDC
    mlngMDIhWnd = FindWindowExA(Application.hWndAccessApp, 0&, "MDIClient", "")
   
End Sub

Private Sub Class_Terminate()
    Set Form = Nothing
End Sub

'-------------------------------------------------------------------------------


(°v°)
0
 

Author Comment

by:Rob4077
Comment Utility
Markus,

Thank you very much for your kind provison of this extensive code!!! Unfortunately I am in and out over the next few days and won't have time to study it properly and see how to use it in  my application. If you don't mind I will leave the question open in case I have any more questions - be assured you have the points and if my questions are especially technical or difficult I will raise a new question.

Thanks Again

Rob  
0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

Author Comment

by:Rob4077
Comment Utility
Markus,
Sorry it's taken so long to get back to this but I've had a number of other jobs to attend to.

I've just tried the code but since use of class modules is totally new to me, I had a bit of trouble getting it to do what I wanted. I think I have figured it out but thought I'd just show you what I'm doing to confirm I am doing it the most appropriate way. Basically I want the popup menu called frmAdminMenu to sit on top of the top left hand corner of my form frmMainMenu so I have loaded your code in the On Current event of my frmMainMenu. The code that I have installed is as follows. It seems to work perfectly:

    Dim objFW As New claFormWindow  
    Dim objBW As New claFormWindow
   
    Set objFW.Form = Forms!frmAdminMenu ' the popup I want to have sit on top
    objFW.Relative = True
   
    Set objBW.Form = Forms!frmMainMenu   'the main menu
    objFW.MoveSize objBW.Left, objBW.Top
0
 
LVL 58

Expert Comment

by:harfang
Comment Utility
Rob,

You use the module exactly as planned. There would be other ways to keep the class module open in the form's module, but as there is no "Form_Move" event, you could not very well use it anyway.

I'm glad it worked, feel free to explain a bit more about the usage of frmAdminMenu or ask other questions if something is still unclear.

Cheers!
(°v°)
0
 

Author Comment

by:Rob4077
Comment Utility
Markus, thank you very much for your help yet again! Your understanding of MS Access is brilliant and your generosity in helping as much as you do is very much appreciated!

Regards,
Rob
0
 

Author Comment

by:Rob4077
Comment Utility
Actually Markus, if it's not too late, I do have one more quesiton. Which event would I use to detect when the user drags one of the forms to another location - that way I can re-position the other form accordingly?
0
 
LVL 58

Expert Comment

by:harfang
Comment Utility
Actually, I was expecting it. Or rather, I was surprised it hadn't turned up.

The bad news is that there no such event. I have tried some mouse events, but these are not fired when dragging the title bar. I suppose it's possible to create a fake title bar using the form header, so that the header's mouse events could be used... but you would have to reprogram the entire window moving.

As for more WinAPI calls, I wouldn't know. My limited knowledge of those was barely enough for the module above, but I have never played with windows events, so I'm not up to that task – if it's even possible in VB...

I will look into it a bit more, but don't hold your breath.

Cheers!
(°v°)
0
 

Author Comment

by:Rob4077
Comment Utility
Thanks for your ongoing interest. Don't waste good time on it. I will tie it to an event that happens when the user switches focus to another form. The fix will be slightly delayed until they change focus but that shouldn't be a problem.
0
 
LVL 58

Expert Comment

by:harfang
Comment Utility
Rob4077,

I tried to play with the windows messages and a technique known as subclassing to trap the form move event, but was unsuccessful. I usually ended up with a total crash or an application freeze-up. It seems to be possible in plain VB or VB.net, but I could not find an example that works with Access VBA.

Cheers, and good luck with your project!
(°v°)
0
 

Author Comment

by:Rob4077
Comment Utility
Thanks again for your ongoing help. The application is going well anyway so this missing feature will not be an issue. I really appreciate your support.
0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

When you are entering numbers in a speadsheet, and don't remember what 6×7 is, you just type “=6*7" instead. It works in every cell! This is not so in Access. To enter the elusive 42 in a text box, you have to find a calculator, and then copy the re…
I see at least one EE question a week that pertains to using temporary tables in MS Access.  But surprisingly, I was unable to find a single article devoted solely to this topic. I don’t intend to describe all of the uses of temporary tables in t…
Familiarize people with the process of utilizing SQL Server stored procedures from within Microsoft Access. Microsoft Access is a very powerful client/server development tool. One of the SQL Server objects that you can interact with from within Micr…
In Microsoft Access, learn the trick to repeating sub-report headings at the top of each page. The problem with sub-reports and headings: Add a dummy group to the sub report using the expression =1: Set the “Repeat Section” property of the dummy…

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now