Welcome to MSDN Blogs Sign in | Join | Help

Microsoft Access Team Blog

Get product announcements, tips and tricks, and news directly from the team @ Microsoft.
Follow up to Transparency Forms

Renaud posted some comments to the previous post about transparency forms and made some really cool enhancements to the code, along with a note about using a class module to make it easier to use. This is how I use transparency forms in my own implementations so let's update the post to show how you can do this with a class. I've incorporated Renaud's changes to the API code which adds the following functionality:

  • Disable transparency when Access is running under Remote Desktop
  • Cover the entire screen or just the Access window

The class module shown here will make this easier to use by adding properties and methods that:

  • Control the opacity
  • Set the back color of the lightbox form
  • Display the lightbox form

Here's how you can create this functionality using a class module. Incidentally, class modules are one of my favorite features in VBA. They're really great for this sort of thing.

Create the LightboxForm class

The bulk of the work is going to be done in a new class module called LightboxForm. The class will subclass the Access Form object using the WithEvents keyword so that we can handle the Form_Resize event directly in the LightboxForm class.

Declarations

Start by adding the API declarations as before. There are a few new ones this time as well: IsZoomed, GetWindowRect, and MoveWindow. Also shown here are the private data, constants, and types.

' API declarations, types, and constants
Private Declare Function IsZoomed Lib "user32" (ByVal hWnd As Long) As Long

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 Declare Function GetWindowRect Lib "user32" _
   (ByVal hWnd As Long, _
    rectangle As RECT) As Long

Private 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 Long

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

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

' Access event property string
Private Const CON_EVENT_PROC As String = "[Event Procedure]"

' name of the lightbox form
Private Const CON_LIGHTBOX_FORM As String = "frmLightbox"

' Private data
Private m_sngOpacity         As Single
Private m_lngBackColor       As Long
Private WithEvents m_objForm As Form

Helper Routines

There is one helper routine in the class to add the event hook. Access forms, reports, and controls will not respond to events unless the event property is set to the string "[Event Procedure]". This routine sets the event property for a given form to this string.

Private Sub AddEventHook(strEventProperty As String)
    m_objForm.Properties(strEventProperty) = CON_EVENT_PROC
End Sub

Properties

The LightboxForm class makes transparency a little easier and more flexible by adding properties for opacity and back color. There's also a property which determines whether Access is running under Remote Desktop.

Public Property Get OpenInRemoteDesktop() As Boolean
    OpenInRemoteDesktop = (Environ$("SESSIONNAME") Like "RDP*")
End Property

Public Property Get Opacity() As Single
    Opacity = m_sngOpacity
End Property

Public Property Let Opacity(sngOpacity As Single)
    ' make sure opacity is between 0 and 1
    If (sngOpacity < 0 Or sngOpacity > 1) Then
        Err.Raise vbObjectError + 513, TypeName(Me), "Invalid value for opacity"
        Exit Property
    End If
    m_sngOpacity = sngOpacity
End Property

Public Property Get BackColor() As Long
    BackColor = m_lngBackColor
End Property

Public Property Let BackColor(lngBackColor As Long)
    m_lngBackColor = lngBackColor
End Property

Form Property

The Form property of the LightboxForm class is the property which binds frmLightbox to the LightboxForm class. This property ensures that the form is in the correct state by setting other properties such as ScrollBars, RecordSelectors, and NavigationButtons. It also changes the color of the Detail section to enable different colors to be used for the transparency.

Public Property Get Form() As Form
    Set Form = m_objForm
End Property

Public Property Set Form(objForm As Form)
    ' make sure there is a valid object
    If (objForm Is Nothing) Then
        Err.Raise vbObjectError + 514, TypeName(Me), "Form object is Nothing"
        Exit Property
    End If
    Set m_objForm = objForm
    ' hook the Resize event
    AddEventHook "OnResize"
    ' set properties of the form
    m_objForm.RecordSelectors = False
    m_objForm.NavigationButtons = False
    m_objForm.ScrollBars = 0  ' Neither
    m_objForm.Section(acDetail).BackColor = m_lngBackColor

End Property

Show Method

The Show method in the class is used to display the frmLightbox form.

Public Sub Show()
    On Error GoTo ShowErrorHandler
    With DoCmd
        .Echo False
        .OpenForm CON_LIGHTBOX_FORM
    End With

ShowExit:
    DoCmd.Echo True
    Exit Sub

ShowErrorHandler:
    If (Err = 2501) Then
        Resume ShowExit
    Else
        ' return to the error
        Resume
    End If
End Sub

Resize Event

In the previous post, we used the Resize event of the form to set the opacity. Since we're handling this event from the LightboxForm class, we'll add this code here. This code also includes Renaud's updates to enable you to choose whether to cover the entire screen or just the Access window. I've modified this only slightly to maximize the lightbox form if the Access window is maximized (as determined by the IsZoomed API). If Access is not maximized, then we'll position the lightbox form to cover the Access window using the MoveWindow API.

Private Sub m_objForm_Resize()

    Dim lngStyle As Long
    Dim r        As RECT

    ' disable screen updates
    m_objForm.Painting = False

    ' If the Access window is maximized, then maximize the lightbox form.
    ' If the Access window is not maximized, then
    ' position the lightbox form so that it covers the Access window

    If IsZoomed(hWndAccessApp()) Then
        DoCmd.Maximize
    Else
        GetWindowRect Application.hWndAccessApp(), r
        MoveWindow m_objForm.hWnd, r.x1, r.y1, (r.x2 - r.x1), (r.y2 - r.y1), True
    End If

    ' get the current window style, then set transparency
    lngStyle = GetWindowLong(m_objForm.hWnd, GWL_EXSTYLE)
    SetWindowLong m_objForm.hWnd, GWL_EXSTYLE, lngStyle Or WS_EX_LAYERED
    SetLayeredWindowAttributes m_objForm.hWnd, 0, (m_sngOpacity * 255), LWA_ALPHA

    ' enable screen updates
    m_objForm.Painting = True

End Sub

Initialization

Lastly, there are a couple defaults we want to set in the class for opacity and back color:

Private Sub Class_Initialize()
    m_sngOpacity = 1         ' initialize opacity to 100% (not transparent)
    m_lngBackColor = vbBlack ' initialize back color to black
End Sub

Create supporting module

Since we're wrapping most of the functionality in a class module, we need an instance of the class. To do this, create a new standard module with the following code:

Private m_objLightbox As LightboxForm

Public Property Get LightboxForm() As LightboxForm
    If (m_objLightbox Is Nothing) Then
        Set m_objLightbox = New LightboxForm
    End If
    Set LightboxForm = m_objLightbox
End Property

To interact with the instance of the LightboxForm class, you'll use this LightboxForm property in the standard module.

Create the Lightbox form

We'll start this time by creating the lightbox form. This is the form that we'll use to display the transparency. Create a new form called frmLightbox and set the following properties:

  • AutoCenter = Yes
  • Popup = Yes
  • BorderStyle = None

The other properties and the back color are managed in the class.

Next, add the following code to the Open event of frmLightbox. This will "bind" the form to the class by setting the Form property of the class.

Private Sub Form_Open(Cancel As Integer)
    ' if the form is open in a remote desktop window, then
    ' cancel the lightbox form effect
    If (LightboxForm.OpenInRemoteDesktop) Then
        Cancel = True
        Exit Sub
    End If

    ' bind the lightbox form class
    Set LightboxForm.Form = Me
End Sub

Create the Login form

The last thing to do before we try this out is to create the login form. You can create a straight forward dialog form as was created in the previous post. This time however, we've modified the code in the Load and Unload events to use the LightboxForm property created in the previous step.

Create another form called frmLogin as described in the previous post. Add the following code to this form.

Private Sub Form_Load() 
    LightboxForm.BackColor = vbBlue
    LightboxForm.Opacity = 0.5
    LightboxForm.Show
End Sub

Private Sub Form_Unload(Cancel As Integer)
    If (Not LightboxForm.Form Is Nothing) Then
        If (CurrentProject.AllForms(LightboxForm.Form.Name).IsLoaded) Then
            DoCmd.Close acForm, LightboxForm.Form.Name, acSaveNo
        End If
    End If
End Sub

Try it out

Try this out by opening the Login dialog. Play around with different values for the .Opacity property and .BackColor property of the class. Here's a screen shot showing a green lightbox with 50% opacity:

TransparencyFormFollowUp

Many thanks to Renaud for extending the code and for a great post!

Posted: Monday, May 05, 2008 5:47 PM by robcooper
Filed under: , ,

Comments

Opa-Horst said:

Very need indeed, but doesn’t seem to work properly on my system (XP).

The login form seems to sit behind the lightbox form and seems not to be active. I can type information in the login box, but the buttons don’t work. Can you help?

# May 5, 2008 10:10 PM

Renaud Bompuis said:

Hi Rob,

I'll have a hard time one-upping this now :-)

# May 5, 2008 11:20 PM

Edwin Blancovitch said:

HEy guys this is great, i was wondering how to acomplish this, but you have come with a solution.

I was wondering, can ypu make this in an downloadable example.

It will be great to have such coded already implemented.

You guys talk about renaud's class and Rob Cooper Love for class modules . . .

Can you just create and publish it here, so we can all bennefit.

What do you say?

# May 6, 2008 10:47 AM

María said:

Hi Rob, Thanks for sharing with us your great work !!, i´ve just implemented in a new project that I am working on..

By the way I post a code problem in the Wrox Forum, Do you have the opprotunity to read it ??

Thanks again .

Maria

# May 6, 2008 11:24 AM

robcooper said:

Opa-Horst: Make sure that the frmLogin form has the Popup and Modal properties set to Yes.

Renaud: :) Thanks for your comments in the previous post!

Edwin: Good suggestion! I'll see if this is something we can do.

Maria: Thanks - glad to hear you'll be able to take advantage of this! I read the question in the Wrox forum and will try to respond through there.

Rob

# May 6, 2008 12:39 PM

David said:

Yes, an example mdb would be helpful because I get an error in the line:

Private m_objLightbox As LightboxForm

no matter what version of Access I use.

# May 6, 2008 3:55 PM

Opa-Horst said:

Thanks Rob, login form wasn’t set to pop-up, changed it and it works beautifully now! Will apply it to my current project. Really great!

# May 6, 2008 4:37 PM

robcooper said:

Opa-Horst: Thanks for the feedback!

David: What is the error you are seeing?

# May 6, 2008 8:41 PM

Renaud Bompuis said:

For anyone interested, I have included Rob's code and made some minor improvements to my sample databases.

You an get them from my blog, just click on my name above.

Thanks again Rob for sharing this with us, it was enlightening :-)

# May 7, 2008 3:48 AM

Vladimir Cvajniga said:

Can this trick be implemented in the next version of Access so that no coding is needed?

# May 7, 2008 2:16 PM

Vladimir Cvajniga said:

Access 2007: Is there any function to highlight current row in continuous form? I'm talking about form with conditionally formatted fields, ie. not just a datasheet.

# May 8, 2008 3:57 AM

Renaud Bompuis said:

To Vladimir: you should have a look at some of the forums and websites like AccessMonster and the sites from the Access MVP (just search for it, there are a few interesting web sites).

I'm not giving links here because it seems the comments don't get through.

There is not -to my knowledge- any function to highlight the current row in a continuous form. There are a few tricks that can work using a textbox behind the other controls and conditional formatting to change its backcolor for the current record.

Have a look at  Stephen Lebans' website.

# May 8, 2008 8:55 AM

Renaud Bompuis said:

To Vladimir again: after experimenting a bit I got row highlighting working in a way that's simple and probably nicer than the usual stuff I've seen.

In your continuous form, add a Panel and call it Highlighter, make it fit the size of the area to highlight (the size of the Detail section in the form). Send the Panel behind the other controls.

Add the following to your Form's code (supposing that ID is the Unique ID field of your record):

Dim currentId As Variant

Private Sub Form_Current()

   currentId = ID

End Sub

Add the following code to the Detail section's OnPaint event:

Private Sub Detail_Paint()

   If (ID = currentId) Then

       Highlighter.BackColor = vbYellow

   Else

       Highlighter.BackColor = vbWhite

   End If

End Sub

If anyone is interested I will make a post on this with a sample database.

# May 8, 2008 10:30 AM

Edwin Blancovitch said:

Reneaud, and Vladimir.

Reneaud, you said, :"Add a panel", what do you meant by a panel, i think you meant a textbox, correct?

I have been trying with a lot of coding for the current row highlight, and i have seen the code of stephens , by the way great implementation.

I was using lebans solution until this new verssion of access, the problem was that new verssion uses a different image format, than old verssions of access.

I personally contacted stephen and he told me to use other solutions because his was outdated.

Well, i started looking and in utter access i found a great solution, working with just a textbox(one by each color) and changing the expression inside the text box, and using a block character to fill the textbox.

It just works, and is great, very light solution, the only problem is that it takes a lot of textboxes to acomplish what we need.

Vladimir, did you were able to make the ribbon work, or to just enable the old command bars in your solution, we just left that conversation somewhere in space.

Will like to know what happened?

# May 8, 2008 11:31 AM

Vladimir Cvajniga said:

Edwin: Still trying to get it to work. There's a bug in A2007: when I open 2002 MDB I can see my CommandBar - that's what I need; but when I save the MDB as ACDDB the CommandBar disappears - I can see other CommandBars instead. :-(

# May 8, 2008 2:18 PM

Vladimir Cvajniga said:

Renaud Bompuis: I use that trick in my A97 projects. But it can't be done with different colors for different fields and/or with fields with conditional formatting.

Current status:

http://img140.imagevenue.com/img.php?image=71850_CurrentRow-current_status_122_653lo.jpg

This is what I get when I use "the trick":

http://img109.imagevenue.com/img.php?image=71925_CurrentRow-what_I_get_122_1042lo.jpg

This is what I really need:

http://img239.imagevenue.com/img.php?image=72102_CurrentRow-what_I_need_122_79lo.jpg

# May 8, 2008 2:47 PM

Renaud Bompuis said:

To Vladimir and Edwin: I'm sorry, I just realised that I used the wrong terminology. By Panel I meant Rectlangle (*not* a TextBox).

From your screenshots it seems that you want to add a shade to all the fields for the current row rather than just highlight it in a single colour.

It's probably possible to go through each control during the Detail_Paint() and calculate its backcolor to add a darker shade but I'm not sure how well it would work.

If I have a bit of time I'll try to make a blog post and a sample database this week-end on that subject.

# May 8, 2008 7:28 PM

Vladimir Cvajniga said:

Renaud Bompuis "From your screenshots it seems that you want to add a shade to all the fields for the current row rather than just highlight it in a single colour."

Yes, you've got the idea!

P.S. I think that "What's new in Access 2007" was talking about highligthing of current row, but now I realised that it was meant for datasheets only. :-(

I'm really disappointed...

# May 9, 2008 6:41 AM

Vladimir Cvajniga said:

Renaud Bompuis: I'd appreciate if new record in continuous form was graphically distinguished as well. Maybe different grade of shade or something like that.

# May 9, 2008 6:45 AM

Phillip Kocmoud said:

This creates a great effect, but I'm stuck on the following problem:

The LightboxForm can still take the focus, when clicked on. Even though the login form is in the foreground and set as modal and popup.

If I Alt-f4 to close the LightboxForm, the login form comes to the foreground again and functions normailly as a modal form.

Is there a way to make the LightboxForm focus disabled?

# May 9, 2008 12:34 PM

Renaud Bompuis said:

@Phillip: this should not happen. Make sure that the frmLightBox has its modal property set to "No".

Whenever you use the transaprency layer you have to make sure that it's in a scenario where it's opened from a popup modal dialog box like the login form in the example.

The transparency layer is just a normal form so if you open it from non-modal forms it will be clickable and may end-up at the top of other windows.

If this still happens to you I would suggest adding a property to the LightBoxForm such as OpeningForm where you keep a reference to the form that opened the layer (such as the Login form in the example).

Add some code to the OnFocus event for the frmLightBox to move back the focus to that OpeningForm.

It shouldn't be necessary though.

Another thing that usually cause problems is to open modal forms from other modal forms: there should never be more than one modal form open at any time.

# May 9, 2008 10:03 PM

Phillip Kocmoud said:

Thank you Renaud!

It turned out to be caused by calling it from an separate open modal form.

# May 12, 2008 10:49 AM

Edwin Blancovitch said:

I think you are the appropriate guys so i can ask this question.

If you reads posts from Vladimir and others . . . you will see need n code from access to do things that are needed in a program such as access.

Access community really needs not only to highlight the current row, also need to create conditional formatting rows based on more than 3 conditions, and maybe also use icons.

If you guys do not fix a solution people just start to see other products like external grids and stuff not necessarily. . .

I used to have code from www.lebans.com to highlight the current row in datasheet or continuous form, also to highlight the row based on some conditions, (the access embed conditional format only supports 3)

lebans created a solution for this, but now is outdated, I think you guys can revise the api's and create a new solution(maybe give it to Microsoft :-) )

The thing is that if you look into excel you have a great conditional formatting options even with icons and all that stuff, but that doesn’t exist for excel.

What do you say, can you guys do it?

# May 12, 2008 12:27 PM
New Comments to this post are disabled
Page view tracker