Modal Dialogs with Transparent Backgrounds

Published 28 April 08 05:20 PM

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!

Filed under: , ,

Comments

# Chris Lockwood said on April 29, 2008 3:43 AM:

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!

# Renaud Bompuis said on April 29, 2008 5:54 AM:

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.

# Khuzema said on April 29, 2008 1:01 PM:

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

# Khuzema said on April 29, 2008 1:05 PM:

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

# robcooper said on April 29, 2008 1:28 PM:

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

# Mike said on April 30, 2008 10:09 AM:

Thanks guys, this is exactly what I needed.

# Toffee said on April 30, 2008 10:32 PM:

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?

# Renaud Bompuis said on May 1, 2008 5:00 AM:

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.

# Joe Dowski said on May 1, 2008 12:49 PM:

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.

# robcooper said on May 1, 2008 1:24 PM:

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

# robcooper said on May 1, 2008 1:36 PM:

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

# JoeOxfordCT said on May 1, 2008 2:10 PM:

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

# robcooper said on May 1, 2008 2:47 PM:

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

# Renaud Bompuis said on May 2, 2008 7:51 AM:

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).

# Thomas Wortig said on May 4, 2008 11:00 AM:

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?

# Thomas Wortig said on May 4, 2008 11:04 AM:

Never mind, found it myself.

The modal-property did the trick.

Sorry for posting prematurely ...

# robcooper said on May 4, 2008 7:50 PM:

Thanks Renaud - I'll check that out.

Thomas - thanks for the feedback! Glad you got it working.

# Jose Cardona said on May 5, 2008 7:54 AM:

Hello!  Please don’t forget the Microsoft Access Project (.ADP) developers.  In addition, MS Access Project don’t recognize the data type bigint when connect to MS SQL Server 2005.  Thanks for read this and remember us!  We feel a little orphaned.

# Joe said on May 5, 2008 2:38 PM:

Hi Rob,

I've implement the effect on one form but I'm getting some users where when they call the form, (I'll call it Form1) that opens the frmTransparent up, Form1 is behind frmTransparent and greyed out along with everything else on the screen.  It's weird because they don't get this all the time.....In fact I was having trouble believing it until I saw it happen with my own eyes on another user's machine.....it's not everytime...just sometimes.  In my example Form1 has both Popup & Modal properties set to yes.

# robcooper said on May 5, 2008 4:42 PM:

Hi Joe,

Does the frmTransparent form have the Popup property set to Yes?

# Access Team Blog said on May 5, 2008 8:47 PM:

Renaud posted some comments to the previous post about transparency forms and made some really cool enhancements

New Comments to this post are disabled

About robcooper

Rob Cooper is a Test Lead at Microsoft working on Microsoft Access. He started at Microsoft in 1998 working in Access product support in Charlotte, NC and then moved to Redmond to join the test team in 2001. For Access 2007, Rob worked on the new Grouping Pane for Reports, and security features such as Database Encryption and Disabled Mode. He is also a co-author on Expert Access 2007 Programming and Access 2007 VBA Programmer's Reference, both published by Wrox. Rob also spends time on www.utteraccess.com reading and answering questions.
Page view tracker