Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Westi on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

ms access form with just close x 1

Status
Not open for further replies.

patriciaxxx

Programmer
Jan 30, 2012
277
GB
These are the form settings:
Close Button = Yes
ControlBox = Yes
BorderStyle = Dialog
MaxMinBitton = None

The above setting gives me the Close button (X) but also the form ControlBox.

If I change the settings to:

Close Button = Yes
ControlBox = No
BorderStyle = Dialog
MaxMinBitton = None

Both the Close button (X) and the form ControlBox, infact all buttons, are removed.
I would like to display the close button (X) only and none of the forms other buttons / controls.

Does anyone know how this could be achieved, maybe using API and the forms handle or something?
 
I cannot replicate your problem. If I do your original settings, I get an X only at the top of the form only. I do not get the min max buttons. In fact if I make the form PopUp or set the border to dialog it gets rid of the min/max buttons. What version of Access?
 
Hello MajP

> What version of Access

2003

> I get an X only at the top of the form only

You don’t also have the control box menu on the left of the form?

I want to have nothing on the left of the form except the caption.

And on the right of the form only an X



 
I think you are misinterpreting the "Control Box". The control box is the box that holds the min, max, and X. Are you talking the navigation pane?
 
Patricia, I'm afraid that the close button is a subset of the control box. The MS Access documentation is pretty clear: "Setting the ControlBox property to False also removes the Minimize, Maximize, and Close buttons on a form
 
My Access documentation says: “The ControlBox Property Specifies whether a form has a Control menu in Form view” and “Setting the ControlBox property to No also removes the Minimize, Maximize, and Close buttons on a form”

The Control menu is on the left of the form.

The buttons are on the right of the form.

I want to have nothing on the left of the form except the caption.

And on the right of the form only an X

I have seen code that uses API calls to manipulate the form buttons on the right but I need to remove the Control menu on the left and have the Caption begin on the far left instead and also just a close X on the right (using the first group of settings I posted).

If no one can do it this way round then perhaps someone can achieve it in the following way (using the second group of settings I posted).

If I set the forms ControlBox value to false it gives me what I need on the left but of course also removes all the buttons on the right so using the second group of settings I would need to add the close X button on the right.
 
>I have seen code that uses API calls to manipulate the form buttons

Sure. And there are API calls to manipulate the Control Box (system menu, in fact) as well - the trouble is that, because of the low-level window class template used to build the window, you cannot disable the system menu without disabling the form buttons. But, you say, I have seen windows where this is the case. And you'd be correct - but those windows are built from a different template (specifically the dialog window class). And Access really doesn't give you the ability change which template is used to create it's windows.

This is, in fact, very hard to do ...
 
Hello strongm

I understand that you are very experienced at coding so if you tell me its not possible then I accept that’s the end of it.

On the subject of code I’ve seen I wonder if you could come up with a workaround... let me explain.

I can remember playing around with some button / system menu API code which would actually move the item (button or system menu) according to which you set, off the form, which affectively meant it wasn’t there, well it was I suppose just not on the form where it should be.

My point is perhaps this kind of manipulation could be the answer using it in such a way as to move the system menu off the form leaving the caption aligned to the far left in its place.

I surely can’t remember where I found the code it was a long time ago and sadly don’t have it now but I definitely have seen and used it.

Or, perhaps you can think of another way to use manipulation and tricks to achieve what I am trying.
 
I understand that you are very experienced at coding so if you tell me its not possible then I accept that’s the end of it
I am not saying it is not possible, I am saying I cannot recreate this problem. The behavior you desired appears to work fine and is the default behavior

Or, perhaps you can think of another way to use manipulation and tricks to achieve what I am trying.
I am using 2010 and I can only achieve what you are trying. I cannot get it to replicate your problem. If I make it dialog popup I only get an X even if min max buttons is yes. Maybe the behavior is different in 2003, which is possible. I have no way to test that.

If this is actually a real problem with earlier versions of Access and it can be modified with an API call I would look here
Most of these solutions are no longer relevant, because many of these modifications have been incorporated into newer versions of Access such as Rich Text and Image rendering.

Could you simply get rid of the control box and build a custom control box on the form? Or build OK, Cancel buttons.
 
Hello MajP

You’ve quoted me on my last post which was in reply to strongm.

I do accept that you can’t recreate my problem because you’re using a later version of Access.

I am now curious about the code I mention in my last post to strongm and my suggestion in that post as to a workaround.

Sorry for any confusion.

 
>would actually move the item

It is certainly the case with some custom forms, where the form buttons are actually controls, that this could be done. However, the 'buttons' on an Access form title bar are not real buttons at all, they are simply bitmaps painted into place - and there's no easy way to get a handle to them and have them paint elsewhere.

I'd guess we can hide them some other way, by painting over them or something - but they'd still be clickable.
 
Yes, painting over them but still being able to click on them wouldn’t be a good workaround. Actually, along those lines I’ve just found a way of doing a similar thing with the system menu which removes the icon but still the menu behind the icon is clickable and even worst the caption aligns left of where the icon ends and not far left to the edge of the form, again no good.

I guess all that’s left to do now is to give up gracefully and accept that we won’t be solving this one and of course to thank you for your help and insight, as ever much appreciated.
 
majp - Patricia is equating the ControlBox with the application/window icon that appears on the left of the titlebar which, when clicked, displays the system menu. She wants to eliminate that icon, but leave the close button available.
 
Actually, Patricia, I may have a cunning(ish) idea. Won't get a chance to try it until tomorrow, though.
 
I shall wait with baited breath in anticipation for what is to come.

Thank you
 
Right, I have a proof of concept working in VB. Just need to port it into Access and see if it works properly there. Note that it is fairly dodgy code, in that we need to get down to some low-level window constructors, and the way Access maintains forms may prevent the technique working.
 
Yup, Access does some fairly heavy subclassing of the windows that represent forms, which made this slightly tricky. So there are a number of assumed prerequisites for this to work (and it is a bit of a hack)

1) The Form consists only of a Detail section (no headers and/or footers). Place some controls on it as you like. Bound or unbound.
2) The Form in question is called "Form2"
2) Following settings for the Form
[ul]
[li]popup: no[/li]
[li]border style: none[/li]
[li]scroll bars : neither (probably not critical for the example)[/li]
[/ul]​

Ok. Add a VBA module, and copy'n'paste the following code:

Code:
[blue]Option Compare Database
Option Explicit

Private Type DLGTEMPLATE
    style As Long
    dwExtendedStyle As Long
    cdit As Integer
    x As Integer
    y As Integer
    cx As Integer
    cy As Integer
End Type

Private Type dlg
    dlgtemp As DLGTEMPLATE
    menu As Long
    classname As String
    title As String
End Type

Private Declare Function CreateDialogIndirectParam Lib "user32.dll" Alias "CreateDialogIndirectParamW" (ByVal hInstance As Long, ByRef lpTemplate As DLGTEMPLATE, ByVal hWndParent As Long, ByVal lpDialogFunc As Long, ByVal lParamInit As Long) As Long
'Private Declare Function EndDialog Lib "user32.dll" (ByVal hDlg As Long, ByVal nResult As Long) As Long
Private Declare Function DestroyWindow Lib "user32.dll" (ByVal hwnd As Long) As Long
Private Declare Function SetWindowText Lib "user32.dll" Alias "SetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String) As Long
Public Declare Function SetParent Lib "user32.dll" (ByVal hWndChild As Long, ByVal hWndNewParent As Long) As Long

Public Declare Function GetWindowLong Lib "user32.dll" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Public Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Public Const GWL_STYLE As Long = -16
Public Const GWL_EXSTYLE As Long = -20

' Window styles. Probably don't need all of these.
Public Const WS_CHILD As Long = &H40000000
Public Const WS_POPUP As Long = &H80000000
Public Const WS_SYSMENU As Long = &H80000
Public Const WS_BORDER As Long = &H800000
Public Const WS_DISABLED As Long = &H8000000
Private Const WS_VISIBLE As Long = &H10000000
Private Const WS_CAPTION As Long = &HC00000
Public Const WS_POPUPWINDOW As Long = (WS_POPUP Or WS_BORDER Or WS_SYSMENU)

Public Const WS_EX_NOPARENTNOTIFY As Long = &H4&
Private Const WS_EX_APPWINDOW As Long = &H40000
Private Const WS_EX_CONTROLPARENT As Long = &H10000 ' Don't need

Public Declare Function GetWindowRect Lib "user32.dll" (ByVal hwnd As Long, ByRef lpRect As RECT) As Long
Public Declare Function AdjustWindowRect Lib "user32.dll" (ByRef lpRect As RECT, ByVal dwStyle As Long, ByVal bMenu As Long) As Long
Public Declare Function MoveWindow Lib "user32.dll" (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

Public Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

Private Const WM_SYSCOMMAND As Long = &H112
Private Const SC_CLOSE As Long = &HF060&

Private Const WM_INITDIALOG As Long = &H110
Private Const DS_MODALFRAME As Long = &H80


Public Function MakeDialog(hwnd As Long, Optional strTitle As String = "") As Long
    Dim hWndDlg As Long
    Dim d As dlg
    d.dlgtemp.style = DS_MODALFRAME + WS_VISIBLE + WS_CAPTION + WS_SYSMENU
    d.dlgtemp.dwExtendedStyle = WS_EX_APPWINDOW + WS_EX_CONTROLPARENT
    d.dlgtemp.cdit = 0
    d.dlgtemp.x = 100
    d.dlgtemp.y = 100
    d.dlgtemp.cx = 200
    d.dlgtemp.cy = 200
    d.menu = 0
    d.title = ""
    d.classname = ""

    hWndDlg = CreateDialogIndirectParam(0, d.dlgtemp, hwnd, AddressOf DlgFunc, 0)
    If strTitle <> "" Then SetWindowText hWndDlg, strTitle
    MakeDialog = hWndDlg

End Function

Public Function DlgFunc(ByVal hWndDlg As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Select Case uMsg
        Case WM_INITDIALOG
            DlgFunc = True
        Case WM_SYSCOMMAND
            If wParam = SC_CLOSE Then
                DoCmd.Close acForm, "Form2" ' We may get leaks here becasue of the way Access has heavily subclassed the Form
                'EndDialog hwndDlg, 0& ' for modal dialogs
                DestroyWindow hWndDlg
                DlgFunc = True
            End If
        Case Else
            DlgFunc = False
    End Select
End Function[/blue]

Then add a VBA UserForm, add a commandbutton, and copy'npaste in this code:

Code:
[blue]Option Compare Database
Option Explicit

Private Sub CommandButton1_Click()
    Dim hwnd As Long
    Dim CurrentStyle As Long
    Dim CurrentExStyle As Long
    Dim FormRect As RECT
    Dim DlgRect As RECT
    Dim hWndMyDialog As Long
    
    hWndMyDialog = MakeDialog(hWndAccessApp, "Example") ' create an empty dialog window
    
    DoCmd.OpenForm "Form2", acNormal
    hwnd = Forms("Form2").hwnd
    MoveWindow hwnd, 0, 0, Forms("Form2").Width \ 15 + 32, Forms("Form2").Section(0).Height \ 15 + 32, False 'approximation
    GetWindowRect hwnd, FormRect
    DlgRect = FormRect

    AdjustWindowRect DlgRect, GetWindowLong(Application.hWndAccessApp, GWL_STYLE), False

    MoveWindow hwnd, 0, 0, FormRect.Right - FormRect.Left, FormRect.Bottom - FormRect.Top, False
    MoveWindow hWndMyDialog, FormRect.Left, FormRect.Top, DlgRect.Right - DlgRect.Left, DlgRect.Bottom - DlgRect.Top, True
    
    CurrentStyle = GetWindowLong(hwnd, GWL_STYLE)
    CurrentStyle = CurrentStyle Or WS_CHILD
    If CurrentStyle And WS_POPUP Then CurrentStyle = CurrentStyle Xor WS_POPUP
    If CurrentStyle And WS_DISABLED Then CurrentStyle = CurrentStyle Xor WS_DISABLED
    SetWindowLong hwnd, GWL_STYLE, CurrentStyle
    
    CurrentExStyle = GetWindowLong(hwnd, GWL_EXSTYLE)
    If Not CurrentExStyle And WS_EX_NOPARENTNOTIFY Then CurrentExStyle = CurrentExStyle Or WS_EX_NOPARENTNOTIFY
    CurrentExStyle = CurrentExStyle And Not WS_EX_NOPARENTNOTIFY
    SetWindowLong hwnd, GWL_EXSTYLE, CurrentExStyle
    
    SetParent hwnd, hWndMyDialog
   
End Sub[/blue]


Run the UserForm, and click the commandbutton

Note that this is NOT production quality code. And playing with message queues and messing about with a form's parent is pretty hacky, and likely to explode Access if anything goes slightly awry. You have been warned ...
 
There may be an easier way if this is a simple form, and you do not plan to do this for all the forms. For example your are wanting this for a log-in or splash screen. This requires little code for something like that, but would have to be unbounded for other forms. Unlikely to be worth it in that case unless you are into building unbound forms.
2rwnuqu.png
 
strongm

A very intriguing and clever piece of coding which works for me, thank you.

MajP

I not sure I can achieve your example in Access 2002 / 2003?

With regard to the code I referred to earlier in this thread which I used to manipulate the window buttons and system menu, I’ve found it, but in trying it now it only seems to work on the main Access application window calling it like so

Code:
Call DisableFormClose(Application.hWndAccessApp)

When I try to use it for a form nothing happens calling it like so

Code:
Call DisableFormClose(Me.hwnd)

Here is the code any ideas what I’m doing wrong?

Code:
Option Compare Database

Private Const FFBYPOSITION = &H400
Private Const FFREMOVEWHAT = &H1000
Private Declare Function DrawMenuBar Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long
Private Declare Function GetSystemMenu Lib "user32" (ByVal hwnd As Long, _
                ByVal bRevert As Long) As Long
                   
Private Declare Function RemoveMenu Lib "user32" (ByVal hMenu As Long, _
                ByVal nPosition As Long, ByVal wFlags As Long) As Long

Public Function DisableFormClose(fhWnd)
   ' This Function will disable a Forms' Title Bar Close button [X]
   ' and it will hide the close menu item from within the Title Bar
   ' Control Box.
   Dim MItem As Long
   Dim MItemCount As Long
   ' Get the Handle to the form's system menu
   MItem = GetSystemMenu(fhWnd, 0)
   
   If MItem Then
       
      ' Obtain the number of items in the menu
       MItemCount = GetMenuItemCount(MItem)
     
      ' Get rid of the system menu Close menu item.
      ' The last item on the menu is MItemCount - 1
       Call RemoveMenu(MItem, MItemCount - 1, FFREMOVEWHAT Or FFBYPOSITION)
    
      ' Get rid of the system menu separator line
       Call RemoveMenu(MItem, MItemCount - 2, FFREMOVEWHAT Or FFBYPOSITION)
     
      ' Force a redraw of the menu. This
      ' refreshes the titlebar, Dimming the X
      ' to indicate it is disabled.
      Call DrawMenuBar(fhWnd)
   End If
End Function
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top