Modal Dialogs with Transparent Backgrounds

If you've taken a look at some web sites recently, you may have noticed an effect where items (usually images or videos) are brought to the foreground using an effect called a lightbox. The effect is used to dim (or sometimes lighten) the background of the active window while bringing another window to the foreground. The window in the foreground appears to have more prominence because the windows in the background have been dimmed or made transparent. Our friend Tim uses this on his site to display images of sports cards and it looks pretty cool.

Windows Vista uses this effect in a security feature called User Account Control. This feature provides prompts when launching a process with elevated privilege. In order to draw attention to the prompt, the desktop and other windows are dimmed which makes the elevation prompt stand out. Vista also places the machine in a "sandbox" of sorts so that you cannot interact with other portions of the UI. The solution presented here does not do this. Users will still be able to switch to other applications running at the time.

Now let's say that you want to do something like this to draw attention to a form in Access. There are a few places in an application where this might be interesting. For example:

  • Login dialog
  • Image viewer
  • About dialog
  • User entry screen
  • On screen help

As you can see, almost any case where you might use a modal form in an Access application might be a good candidate to add a lightbox effect. That said - the effect could feel a bit heavy handed after a while so you might not use it for all modal forms, but certainly for those that are more important than others.

You can add this effect to your Access applications with another form by adding transparency on the form window using the SetLayeredWindowAttributes and SetWindowLong Windows API functions. To start, create a new dialog form with the Modal property set to Yes. I used a Login type form called frmLogin as shown below:

LoginForm

Next, create a new form called frmTransparent where we will set transparency so that you can see through it. To set the appearance that the form is being dimmed, change the following properties of frmTransparent.

  1. Set the BackColor property of the Detail section to black (#000000 in Access 2007)
  2. Set the BorderStyle property of the form to None to remove the border.
  3. Set the RecordSelectors property to No
  4. Lastly, set the Popup property to Yes.

Now that the forms are created, it's time to add some code. Start by creating a new module called Module1. In the module, add the following code:

Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
  (ByVal hwnd As Long, _
   ByVal nIndex As Long) As Long

Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
  (ByVal hwnd As Long, _
   ByVal nIndex As Long, _
   ByVal dwNewLong As Long) As Long

Private Declare Function SetLayeredWindowAttributes Lib "user32" _
  (ByVal hwnd As Long, _
   ByVal crKey As Long, _
   ByVal bAlpha As Byte, _
   ByVal dwFlags As Long) As Long

Private Const LWA_ALPHA     As Long = &H2
Private Const GWL_EXSTYLE   As Long = -20
Private Const WS_EX_LAYERED As Long = &H80000

Public Sub SetFormOpacity(frm As Form, sngOpacity As Single)
    Dim lngStyle As Long

    ' get the current window style, then set transparency
    lngStyle = GetWindowLong(frm.hwnd, GWL_EXSTYLE)
    SetWindowLong frm.hwnd, GWL_EXSTYLE, lngStyle Or WS_EX_LAYERED
    SetLayeredWindowAttributes frm.hwnd, 0, (sngOpacity * 255), LWA_ALPHA
End Sub

Next, in the code behind the frmTransparent form, add the following code to the Resize event of the form. Using this code in the Resize event seems to reduce some of the flicker seen with other events such as Open and Load.

Private Sub Form_Resize()
    Me.Painting = False
    DoCmd.Maximize
    SetFormOpacity Me, 0.7
    Me.Painting = True
End Sub

Now, add the following code to the Load and Unload events of the login dialog form. This will open the transparent form when the dialog form opens, and close it when the dialog form closes.

Private Const CON_TRANSPARENT_FORM As String = "frmTransparent"

Private Sub Form_Load()
    With DoCmd
        .Echo False
        .OpenForm CON_TRANSPARENT_FORM
        .Echo True
    End With
End Sub

Private Sub Form_Unload(Cancel As Integer)
    If (CurrentProject.AllForms(CON_TRANSPARENT_FORM).IsLoaded) Then
        DoCmd.Close acForm, CON_TRANSPARENT_FORM
    End If
End Sub

To test this, open the login dialog form which will subsequently open the transparent form. The transparency form appears dimmed which makes the login form stand out.

TransparencyForm

With the API functions created, there are some ways you might extend this in the future. For example, try experimenting with a background color other than #000000, or different values of opacity.

Enjoy!

Office Blogs Comments

Comments: (20) Collapse

  • I really like this, and surprisingly easy to implement. However in my dual monitor set-up I get some odd behaviour, when I view the project on my primary screen the transparency form displays on my secondary monitor... Strange!

  • To Chris and others:

    On the frmTransparent form, also set:

    - Auto Center to true (avoids issues with mutliple monitors)

    - ScrollBars to none (otherwise a portion of the screen remains visible at the bottom in some cases) Nice and great effect!

    Thanks Rob.

  • Its really useful tip and really easy to implement with awesome effect. Renaud - Thanks for AutoCenter/Scrollbar tip I was facing the same issue with multi-monitor. keep more of this coming... regards

  • Renaud - you can add to list Navigation button also which should be no

  • Thanks to Renaud and Khuzema for the tips on setting additional properties of the form. Glad to hear you are enjoying this!

  • Thanks guys, this is exactly what I needed.

  • The effect works great, but I was wandering if anyone has a method for only creating the lightbox effect within the Access program window instead of the whole screen?

  • To Toffee: Add a new module and copy-paste the following into it: '-------------------------

    Type RECT x1 As Long y1 As Long x2 As Long y2 As Long

    End Type Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, rectangle As RECT) As Boolean

    Declare Function MoveWindow Lib "user32" (ByVal hwnd As Long, ByVal x As Long, ByVal y As Long, ByVal width As Long, ByVal height As Long, ByVal repaint As Boolean) As Boolean

    '------------------------- Now change the frmTransparent's Resize event: Private Sub Form_Resize() Me.Painting = False Dim r As RECT GetWindowRect Application.hWndAccessApp, r MoveWindow Me.hwnd, r.x1, r.y1, (r.x2 - r.x1), (r.y2 - r.y1), True SetFormOpacity Me, 0.7 Me.Painting = True

    End Sub Make sure the frmTransparent settings are:

    --> AutoCenter: No <--!!

    - Default View: Single Form

    - BorderStyle: none

    - ScrollBars: neither

    - Record Selector: No

    - Navigation Buttons: No The frmTransparent should now open to cover the main Access window only.

    Works fine on multiple monitors and even if the main form is partially outside the desktop. One thing to be careful with this effect is that if your application is accessible through Remote Desktop, the RDP clients may not support transparency and will instead see an opaque window.

    You can use the following to detect if you're running in a Remote Terminal Desktop client: left(Environ$("SESSIONNAME"), 3) = "RDP" If this is true, then don't show the frmTransparent form.

  • Hi, I love the effect. However, what values do I need to adjust to change the level of transparency in my form ? I'd like to lighten it up a bit. Thanks again very much for the tip ! J.

  • Joe, To change the transparency level, change the value passed to SetFormOpacity from 0.7 to something smaller. I've tried 0.5 (50% opacity) and it looks pretty cool as well. Hope this helps,

    Rob

  • Renaud Your follow up post to this is really great! I tend to use a class module for my own implementation so I'm working on a follow up to this where I'm encapsulting the new code into a class to make it easier to use. Rob

  • Rob, I apologize for being thick headed but I can't find where you're setting the forms opacity to 0.7, nevermind changing it to 0.5....? Sorry... Joe

  • Hi Joe, No worries - it is called from the Form_Resize event of frmTransparent: Private Sub Form_Resize() Me.Painting = False DoCmd.Maximize SetFormOpacity Me, 0.5 Me.Painting = True End Sub Rob

  • thanks Rob.

    I did a sample database showing off the concept.

    My post on this is on blog (just click my name aboce this comment to get to the article) It would be nice to see your own improvements of this by making it a class helper. Strangely enough, Mark Miller talked about that kind of stuff (What makes great UI) on the last show of DotNetRocks.

    Check it out it's both interesting and funny (look up dotnetrocks, show #338).

  • Thx Rob, great concept. However, testing it I ran into the problem (perhaps caused by my relative inexperience, so bear with me):

    When I click on the dimmed area around the lightbox form frmTransparent gets the focus pushing the foreground form into the background, which makes it non-responsive. How to prevent this?

1 2  Next >
Comments

Comments: (loading) Collapse