Cool Excel Magnifying Glass to Zoom the entire Screen !

Jaafar Tribak

Well-known Member
Joined
Dec 5, 2002
Messages
9,619
Office Version
  1. 2016
Platform
  1. Windows
Hi all,

Here is a Magnifying Glass that you can use in Excel :) I am not sure about the usefulness of it in the normal day to day use of Excel but it's cool and was challenging to programme. The actual round Glass is actually a simple XL userorm whose standard styles were changed.

Here is a workbook example : https://www.box.com/shared/c1ujurjhkt

Just point to the round Glass with the mouse and move it around the screen to zoom in. It worked on my machine quite smoothly.

Here is the code that goes in a userform :

Code:
Option Explicit

Private Declare Function StretchBlt Lib "gdi32" _
(ByVal hdc As Long, ByVal X As Long, ByVal Y As Long, _
ByVal nWidth As Long, ByVal nHeight As Long, _
ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, _
ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal dwRop As Long) As Long

Private Declare Function BitBlt Lib "gdi32" _
(ByVal hDestDC As Long, ByVal X As Long, ByVal Y As Long, _
ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, _
ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long

Private Const SRCCOPY = &HCC0020

Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long

Private Declare Function CreateCompatibleBitmap Lib "gdi32" _
(ByVal hdc As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long

Private Declare Function SelectObject Lib "gdi32" _
(ByVal hdc As Long, ByVal hObject As Long) As Long

Private Declare Function DeleteObject Lib "gdi32" _
(ByVal hObject As Long) As Long

Private Declare Function OleCreatePictureIndirect Lib "olepro32.dll" _
(PicDesc As uPicDesc, RefIID As GUID, _
ByVal fPictureOwnsHandle As Long, IPic As IPicture) As Long

Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long

Private Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long

Private lfrmDC As Long

Private Declare Function GetSystemMetrics Lib "user32" _
(ByVal nIndex As Long) As Long

Private Const SM_CXSCREEN = 0
Private Const SM_CYSCREEN = 1

Private Type GUID
    Data1 As Long
    Data2 As Integer
    Data3 As Integer
    Data4(7) As Byte
End Type
Private Type PicBmp
    Size As Long
    Type As Long
    hBmp As Long
    hPal As Long
    Reserved As Long
End Type
Private Type uPicDesc
    Size As Long
    Type As Long
    hPic As Long
    hPal As Long
End Type
Private Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type
Private Type POINTAPI
    Width As Long
    Height As Long
End Type
'________________________________________________________________________
Private Declare Function CreateEllipticRgn Lib "gdi32" _
                          (ByVal X1 As Long, ByVal Y1 As Long, _
                           ByVal X2 As Long, ByVal Y2 As Long) As Long

 Private Declare Function SetWindowRgn Lib "user32" _
                          (ByVal hWnd As Long, ByVal hRgn As Long, _
                           ByVal bRedraw 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

Const GWL_STYLE = (-16)
Const WS_SYSMENU = &H80000
Private Const WS_CAPTION As Long = &HC00000

Private Declare Function DrawMenuBar Lib "user32" _
(ByVal hWnd As Long) As Long
'_________________________________________________________________________

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Private lfrmHwnd As Long

'_________________________________________________________________________


Private Declare Function SendMessage Lib "user32" _
Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, lParam As Any) As Long

Private Declare Sub ReleaseCapture Lib "user32" ()

Private Const WM_NCLBUTTONDOWN = &HA1
Private Const HTCAPTION = 2

Private objCmb As CommandBar



Private Sub UserForm_Initialize()
    Dim lBmp As Long
    Dim IPic As IPicture
    Dim Screen As POINTAPI
    
    'assign the form handle to a module level var
    'will be needed throughout the module
    lfrmHwnd = FindWindow(vbNullString, Me.Caption)
    
    'setup the shape of our form so it looks
    'like a round magnifying glass
    Call FormSetUp(lfrmHwnd)
    
    'get the form dc on which the drawing will be made
    lfrmDC = GetDC(lfrmHwnd)
    
    'get the screen dimensions
    Screen = GetScreenDims
    
    'get a pointer of the screen bitmap
    lBmp = GetScrnBmpHandle(GetDC(0), 0, 0, Screen.Width, Screen.Height)
    
    'create a picture from the bitmap pointer
    Set IPic = GetBitmapPic(lBmp)
    
    'save bitmap to disk
    stdole.SavePicture IPic, (Environ("Temp")) & "\Scr.Bmp"
    'set the form picture to display the bitmap
     Me.Picture = LoadPicture((Environ("Temp")) & "\Scr.Bmp")
    
    'clean up
    Kill (Environ("Temp")) & "\Scr.Bmp"

End Sub


Private Sub UserForm_Activate()

    'the layout event doesn't fire here so refresh form now
    Me.Repaint
   Call UserForm_Layout
   
End Sub


Private Sub UserForm_Layout()

'update the userform background upon moving it
    StretchBlt _
     lfrmDC, 0, 0, Me.Width * 1.5, Me.Height * 1.5, _
     lMemoryDC, Me.Left * 1.5, Me.Top * 1.5, _
     Me.Width, Me.Height, SRCCOPY

End Sub

Private Sub UserForm_MouseDown _
(ByVal Button As Integer, ByVal Shift As Integer, _
ByVal X As Single, ByVal Y As Single)

    'show close menu
    If Button = 2 Then objCmb.ShowPopup

End Sub

Private Sub UserForm_MouseMove _
(ByVal Button As Integer, ByVal Shift As Integer, _
ByVal X As Single, ByVal Y As Single)

    'move the captionless form with the mouse
     If Button = 1 Then
        Call ReleaseCapture
        SendMessage lfrmHwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0
    End If

End Sub

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)

    'safety cleanup
    On Error Resume Next
    DeleteDC lMemoryDC
    CommandBars("GlassPopUp").Delete

End Sub

'****** Supporting functions **********************************


Private Function GetScrnBmpHandle _
(lScrDC As Long, lScrnLeft As Long, lScrnTop As Long, _
lScrnWidth As Long, lScrnHeight As Long) As Long

    Dim lBmp, lOldBmp As Long
    
    'create a temp memory dc on which to copy the current screen shot
    lMemoryDC = CreateCompatibleDC(lScrDC)
    
    'create a bmp
    lBmp = CreateCompatibleBitmap(lScrDC, lScrnWidth, lScrnHeight)
    
    'select the bmp onto the temp dc
    lOldBmp = SelectObject(lMemoryDC, lBmp)
    DeleteObject lBmp
    
    'copy the screen image onto the temp dc
    BitBlt lMemoryDC, 0, 0, lScrnWidth, lScrnHeight, _
    lScrDC, lScrnLeft, lScrnTop, SRCCOPY
    
    'return our bmp pointer
    GetScrnBmpHandle = lBmp

End Function

Private Function GetBitmapPic(ByVal lBmpHandle As Long) As IPicture

Dim r As Long, IPic As IPicture, IID_IDispatch As GUID, Pic As uPicDesc

    'Fill GUID info
    With IID_IDispatch
        .Data1 = &H20400
        .Data4(0) = &HC0
        .Data4(7) = &H46
    End With
    
    'Fill picture info
    With Pic
        .Size = Len(Pic) ' Length of structure
        .Type = 1  ' Type of Picture (bitmap)
        .hPic = lBmpHandle ' Handle to bitmap
        .hPal = 0 ' Handle to palette (may be null)
    End With
    'create the pic
    OleCreatePictureIndirect Pic, IID_IDispatch, 1, IPic
    Set GetBitmapPic = IPic


End Function


Private Function GetScreenDims() As POINTAPI

    'get screen width an height
    Dim r As POINTAPI
    
    With r
        .Width = GetSystemMetrics(SM_CXSCREEN)
        .Height = GetSystemMetrics(SM_CYSCREEN)
    End With
    GetScreenDims = r

End Function


Private Sub FormSetUp(lhwnd As Long)

    Dim lHr, IStyle As Long
    
    'adjust form dims
    Me.Width = 210
    Me.Height = 195
    
    'Create rightclick close menu
    On Error Resume Next
    CommandBars("GlassPopUp").Delete
    Set objCmb = Application.CommandBars.Add(Position:=msoBarPopup)
    With objCmb
        objCmb.Name = "GlassPopUp"
        With .Controls.Add(msoControlButton)
            .Caption = "CloseMe"
            .OnAction = "CloseGlass"
        End With
    End With
    On Error GoTo 0
    'set the mouse pointer so it simulates
    'that of a magnifying glass
    
    Me.MousePointer = fmMousePointerCross
    'make the userform captionless and round
    'so it simulates a magnifying glass
    
    IStyle = GetWindowLong(lhwnd, GWL_STYLE)
    IStyle = IStyle And Not WS_CAPTION 'And WS_THICKFRAME
    SetWindowLong lhwnd, GWL_STYLE, IStyle
    DrawMenuBar lhwnd
    lHr = CreateEllipticRgn(0, 0, Me.Width, Me.Height)
    SetWindowRgn lhwnd, lHr, True

End Sub


Copy the code below in a Standard Module :

Code:
Option Explicit

Public lMemoryDC As Long

Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long

Sub CloseGlass()

    On Error Resume Next
    DeleteDC lMemoryDC
    CommandBars("GlassPopUp").Delete
    Unload UserForm1

End Sub

Sub Bouton1_QuandClic()

    UserForm1.Show

End Sub

One nice touch that i haven't been able to give the magnifying glass is a frame around it so it can be more visible on the screen. Because of the round shape, framing the userform is quite difficult.

I have tested this on XL2003 Win XP French Version. I am hoping it also works for other XL versions.

Regards.
 
Last edited by a moderator:
I'm sure that in an older version of windows - maybe even windows 3.1 - there was a magnifying glass function in the accesibility options. But it didn't work that well with Excel 3, it would crash it quite a lot.

I am using WIN XP and can't get the Magnifying Glass Windows Applet to work in the same fashion. All I get is an amplified horizontal section accross the top of the screen. Is there an option to make this Applet look like a propper round Magnifying Glass ?

Regards.
 
Upvote 0

Excel Facts

Last used cell?
Press Ctrl+End to move to what Excel thinks is the last used cell.
Hi Jaafar

I see this as a continuation of http://www.mrexcel.com/board2/viewtopic.php?t=300146&highlight=

A nice implimentation!! Good job, I did it another way.

You don't actually need to do the
'save bitmap to disk
stdole.SavePicture IPic, (Environ("Temp")) & "\Scr.Bmp"
'set the form picture to display the bitmap
Me.Picture = LoadPicture((Environ("Temp")) & "\Scr.Bmp")

As you are working with the image within Memory which is what you have using the 2 API and getting there DC's to create a DC within memory.

Also (I know you know and may have missed) But Dim lBmp
can be dangerouse in API's, this time it didn't.

Again, good work.
 
Upvote 0
Ivan,

i tried using "Me.Picture.Handle = IPic" instead of saving the Pic to disk and then reloading it from the bmp file but didn't work. It gives me an error.

Also, i am having a hard time giving the round Glass a frame to make it more visible. Any ideas how to frame a round shape as opposed to a rectangular one which is easier.

Thanks for looking into this.

Regards.

Late edit :
Oops ! I see what you meant by not needing to save to and to load the Picture from disk . Using the StretchBlt would have been enough to load it from the temp memory DC. Good observation !
 
Upvote 0
Hi Jaafar

sorry about confusion.

What I meant was you just needed to impliment it a diff way...
you already have to DC's and you have created these via your call to

Private Function GetScrnBmpHandle

which, aside from getting a handle actually cfreates the DC that you use to manipulate via your Layout call.

You have everything there in order to use.

Again, good job, it helped me to look @ mine again.


Code:
Private Sub UserForm_Initialize()
    Dim lBmp As Long
    Dim IPic As IPicture
    Dim Screen As POINTAPI
    Dim lOldBmp As Long
    
    'assign the form handle to a module level var
    'will be needed throughout the module
    lfrmHwnd = FindWindow(vbNullString, Me.Caption)
    
    'setup the shape of our form so it looks
    'like a round magnifying glass
    Call FormSetUp(lfrmHwnd)
       
    'get the form dc on which the drawing will be made
    lfrmDC = GetDC(lfrmHwnd)

    'get the screen dimensions
    Screen = GetScreenDims
        
    '// create a temp memory dc on which to copy the current screen shot
    lMemoryDC = CreateCompatibleDC(GetDC(0))
    'create a bmp
    lBmp = CreateCompatibleBitmap(GetDC(0), Screen.Width, Screen.Height)
    
    'select the bmp onto the temp dc
    lOldBmp = SelectObject(lMemoryDC, lBmp)
    DeleteObject lBmp
    
    'copy the screen image onto the temp dc
    BitBlt lMemoryDC, 0, 0, Screen.Width, Screen.Height, _
        GetDC(0), 0, 0, SRCCOPY

    'create a picture from the bitmap pointer
    'Set IPic = GetBitmapPic(lBmp)
    
    'save bitmap to disk
    'stdole.SavePicture IPic, (Environ("Temp")) & "\Scr.Bmp"
    'set the form picture to display the bitmap
     'Me.Picture = LoadPicture((Environ("Temp")) & "\Scr.Bmp")
    
    'clean up
    'Kill (Environ("Temp")) & Scrn


End Sub

As for the border, you will need to draw these using AngleArc API
I have a little biton this ......
 
Upvote 0
OK, go on gentlemen :)
Nice thread!

another two cents:
I suppose you are using a circular magnfier because of the "look"? A rectangle would be more effective to my sense: so why not make it an oval-almost-rectangle to combine nice look with utility?

have a nice play with this :LOL:
Erik
 
Upvote 0
Ivan. Actually, i didn't even need to have the "GetBitmapPic" function either as i am working with a memory picture :) . And yes. I looked at the "Arc" API and it is the one I was missing. Again, thanks for the tips.

Erik.

I suppose you are using a circular magnfier because of the "look"? A rectangle would be more effective to my sense: so why not make it an oval-almost-rectangle to combine nice look with utility?
I thought, a round Magnifier was more intuitive. Also, by making it round , we code more and we learn more which is the purpose of me getting into this in the first place :)

Regards.
 
Upvote 0
Hi Jaafar

have a play around with

Private Const PS_SOLID = 0
Private Const PS_DASH As Long = 1
Private Const PS_DOT As Long = 2
Private Const PS_DASHDOT As Long = 3
Private Const PS_DASHDOTDOT As Long = 4
Private Const PS_JOIN_BEVEL As Long = &H1000
Private Const PS_JOIN_MASK As Long = &HF000
Private Const PS_JOIN_MITER As Long = &H2000
Private Const PS_JOIN_ROUND As Long = &H0

Private Declare Function CreatePen _
Lib "gdi32" ( _
ByVal nPenStyle As Long, _
ByVal nWidth As Long, _
ByVal crColor As Long) _
As Long

changing diff values etc


Code:
Private Sub UserForm_Layout()
    Dim lOffSet As Long

    Let lOffSet = 4
    'update the userform background upon moving it
    StretchBlt _
        lfrmDC, 0, 0, Me.Width * 1.5, Me.Height * 1.5, _
        lMemoryDC, Me.Left * 1.5, Me.Top * 1.5, _
        Me.Width, Me.Height, SRCCOPY
    
    hRPen = CreatePen(PS_JOIN_BEVEL, 2, vbBlack)
    'Select our pen into the form's device context and delete the old pen
    DeleteObject SelectObject(hdc, hRPen)
    
    Arc hdc, 0, 0, _
        Me.Width - (Me.Width - Me.InsideWidth), _
        Me.Height - (Me.Height - Me.InsideHeight), _
        360, 0, 360, 0
   
    hRPen = CreatePen(PS_JOIN_BEVEL, 2, vbBlack + 128)
    'Select our pen into the form's device context and delete the old pen
    DeleteObject SelectObject(hdc, hRPen)
    
    Arc hdc, lOffSet, lOffSet, _
        Me.Width - (Me.Width - Me.InsideWidth) - lOffSet, _
        Me.Height - (Me.Height - Me.InsideHeight) - lOffSet, _
        360, 0, 360, 0

End Sub
 
Upvote 0
Thanks Ivan for your guidance.

I have encapsulated the code in a Class module for easy use. I have called the Class : "frmMagnifier" .

Here is a Workbook Example: http://www.savefile.com/files/1183137

In order to benefit from the IntelliSense feature of the VBE, I have made this Class act as an Implementation of another custom Class called "ImpMagnifier" so that as you key in the letters to set the Properties & Methods of the Magnifier Class, all of its Members showup behaving just like normal native XL/VBA Objects/Classes.Hence, although the code is contained inside the UserForm none of the native members of the userform showup.

We can now easily set the following Properties for the Magnifier :

Shape- Width- Height- FrameStyle- FrameColor- FrameWidth- ZoomFactor- MousePointer.

Here is the code which is contained in 3 Modules : The UserForm, the Implement Class and a Standard Module to run the Glass.

Place this in a Class Module: ("ImpMagnifier")

Code:
' ************   Implement Class Signature ******************
'_________________________________________________________________

Option Explicit

Const PS_DOT = 2
Const PS_SOLID = 0

Public Enum MagShape ' note that the Enum Keyword
                     ' doesn't work in XL97 !!!!!!!!!!
    Rectangular
    elliptic
    
End Enum

Public Enum MagFrameStyle

    dot = PS_DOT
    Solid = PS_SOLID
    
End Enum



' **** defining the ImpMagnifier properties and methods ! ******

Public Property Let Height(ByVal vNewValue As Double)

End Property


Public Property Let ZoomFactor(ByVal vNewValue As Double)

End Property


Public Property Let Width(ByVal vNewValue As Double)

End Property




Public Property Let FrameStyle(ByVal vNewValue As MagFrameStyle)

End Property


Public Property Let FrameColor(ByVal vNewValue As Long)

End Property

Public Property Let MousePointer(ByVal vNewValue As fmMousePointer)

End Property


Public Property Let Shape(ByVal vNewValue As MagShape)

End Property


Public Property Let FrameWidth(ByVal vNewValue As Double)

End Property

Public Sub ShowMe()


End Sub

Place the code below in the UserForm Module ( "frmMagnifier")

Code:
Option Explicit


Implements ImpMagnifier 'this is so that the form module can
                        'implement the ImpMagnifier class interface !!!

'module level vars to store the actual ImpMagnifier properties
Private P_MagShape As MagShape
Private P_FrameStyle As MagFrameStyle
Private P_FrameColor As Long
Private P_FrameWidth As Double
Private P_Width As Double
Private P_Height As Double
Private P_ZoomFactor As Double
Private P_MousePointer As fmMousePointer

Private Type Rect
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

Private tRect As Rect

Private Type POINTAPI
    Width As Long
    Height As Long
End Type


'________________________________________________________________________
Private Declare Function DrawEdge Lib "user32" _
(ByVal hdc As Long, qrc As Rect, ByVal edge As Long, ByVal grfFlags As Long) As Long

Const BF_RECT = &HF
Const BDR_SUNKENOUTER = &H2
Const BDR_RAISEDINNER = &H4
Const EDGE_ETCHED = (BDR_SUNKENOUTER Or BDR_RAISEDINNER)

Private Declare Function CreatePen Lib "gdi32" _
(ByVal nPenStyle As Long, ByVal nWidth As Long, ByVal crColor As Long) As Long
Private Declare Function Arc Lib "gdi32" (ByVal hdc As Long, ByVal X1 As Long, _
ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long, _
ByVal X3 As Long, ByVal Y3 As Long, ByVal X4 As Long, ByVal Y4 As Long) As Long

'________________________________________________________________________

Private Declare Function StretchBlt Lib "gdi32" _
(ByVal hdc As Long, ByVal x As Long, ByVal y As Long, _
ByVal nWidth As Long, ByVal nHeight As Long, _
ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, _
ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal dwRop As Long) As Long

Private Declare Function BitBlt Lib "gdi32" _
(ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, _
ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, _
ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long

Private Const SRCCOPY = &HCC0020
'________________________________________________________________________

Private Declare Function SelectObject Lib "gdi32" _
(ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" _
(ByVal hObject As Long) As Long

'________________________________________________________________________
Private Declare Function CreateCompatibleBitmap Lib "gdi32" _
(ByVal hdc As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long

Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long

Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long

Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long

Private lfrmDC As Long
Private lbmp As Long
Private lMemoryDC As Long

'________________________________________________________________________
Private Declare Function CreateEllipticRgn Lib "gdi32" _
                          (ByVal X1 As Long, ByVal Y1 As Long, _
                           ByVal X2 As Long, ByVal Y2 As Long) As Long

Private Declare Function SetWindowRgn Lib "user32" _
                          (ByVal hwnd As Long, ByVal hRgn As Long, _
                           ByVal bRedraw As Long) As Long
                           
Private Declare Function GetClientRect Lib "user32" _
(ByVal hwnd As Long, lpRect As Rect) As Long
                           
'_________________________________________________________________________

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

Private Declare Function DrawMenuBar Lib "user32" _
(ByVal hwnd 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

Const GWL_STYLE = (-16)
Const WS_SYSMENU = &H80000
Private Const WS_CAPTION As Long = &HC00000

'_________________________________________________________________________

Private Declare Function GetSystemMetrics Lib "user32" _
(ByVal nIndex As Long) As Long
Private Const SM_CXSCREEN = 0
Private Const SM_CYSCREEN = 1

'_________________________________________________________________________

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Private lfrmHwnd As Long
'_________________________________________________________________________

Private Declare Function SendMessage Lib "user32" _
Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, lParam As Any) As Long

Private Declare Sub ReleaseCapture Lib "user32" ()

Private Const WM_NCLBUTTONDOWN = &HA1
Private Const HTCAPTION = 2
'_________________________________________________________________________

Private Declare Function LockWindowUpdate Lib "user32" (ByVal hwndLock As Long) As Long
'_________________________________________________________________________


Private objCmb As CommandBar


Private Sub UserForm_Initialize()

    Dim lbmp As Long
    Dim IPic As IPicture
    Dim Screen As POINTAPI
    
    'assign the form handle to a module level var
    'will be needed throughout the module
    lfrmHwnd = FindWindow(vbNullString, Me.Caption)

    'get the form dc on which the drawing will be made
    lfrmDC = GetDC(lfrmHwnd)

    'get the screen dimensions
    Screen = GetScreenDims
    
    'prevent screen flickering of the form when
    'calling the following procedures: "GetScrnBmpHandle" & "FormSetUp"
    LockWindowUpdate lfrmHwnd

    'get a pointer of the screen bitmap
    lbmp = GetScrnBmpHandle(GetDC(0), 0, 0, Screen.Width, Screen.Height)


End Sub


Private Sub UserForm_Activate()
    
    'format our form
    Call FormSetUp(lfrmHwnd)
    
    'setting up the form is done so unlock the form window
    LockWindowUpdate 0
    
    'the layout event doesn't fire here so refresh form now
    Call UserForm_Layout
    Me.Repaint

End Sub


Private Sub UserForm_Layout()

    Dim lhr As Long
    
    ' set up defaults
    If P_ZoomFactor = 0 Then P_ZoomFactor = 1.5
    
    'update the userform background upon moving it
    StretchBlt _
    lfrmDC, 0, 0, Me.Width * P_ZoomFactor, Me.Height * P_ZoomFactor, _
    lMemoryDC, Me.Left * P_ZoomFactor, Me.Top * P_ZoomFactor, _
    Me.Width, Me.Height, SRCCOPY
    
    GetClientRect lfrmHwnd, tRect
    
    'define the form shapes now
    With tRect
        If P_MagShape = elliptic Then
            lhr = CreateEllipticRgn(0, 0, .Right - .Left, .Bottom - .Top)
            SetWindowRgn lfrmHwnd, lhr, True
        Else
            DrawEdge lfrmDC, tRect, EDGE_ETCHED, BF_RECT
        End If
        Arc lfrmDC, .Left, .Top, .Right - .Left - 5, .Bottom - .Top - 5, _
        .Right - .Left, .Right - .Left, .Bottom - .Top, .Bottom - .Top
    End With

End Sub

Private Sub UserForm_MouseDown _
(ByVal Button As Integer, ByVal Shift As Integer, _
ByVal x As Single, ByVal y As Single)

    'if form right-clicked show close menu
    If Button = 2 Then objCmb.ShowPopup

End Sub

Private Sub UserForm_MouseMove _
(ByVal Button As Integer, ByVal Shift As Integer, _
ByVal x As Single, ByVal y As Single)

    'move the captionless form with the mouse
     If Button = 1 Then
        Call ReleaseCapture
        SendMessage lfrmHwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0
    End If

End Sub

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)

    'safety cleanup
    On Error Resume Next
    DeleteDC lMemoryDC
    DeleteObject lbmp
    CommandBars("GlassPopUp").Delete

End Sub

'****** Supporting functions **********************************


Private Function GetScrnBmpHandle _
(lScrDC As Long, lScrnLeft As Long, lScrnTop As Long, _
lScrnWidth As Long, lScrnHeight As Long) As Long

    'create a temp memory dc on which to copy the current screen shot
    lMemoryDC = CreateCompatibleDC(lScrDC)
    
    'create a bmp
    lbmp = CreateCompatibleBitmap(lScrDC, lScrnWidth, lScrnHeight)
    
    'select the bmp onto the temp dc
'    lOldBmp = SelectObject(lMemoryDC, lBmp)
    DeleteObject SelectObject(lMemoryDC, lbmp)


    'copy the screen image onto the temp dc
    BitBlt lMemoryDC, 0, 0, lScrnWidth, lScrnHeight, _
    lScrDC, lScrnLeft, lScrnTop, SRCCOPY
    'return our bmp pointer
    GetScrnBmpHandle = lbmp

End Function


Private Function GetScreenDims() As POINTAPI

    'get screen width an height
    Dim r As POINTAPI
    
    With r
        .Width = GetSystemMetrics(SM_CXSCREEN)
        .Height = GetSystemMetrics(SM_CYSCREEN)
    End With
    
    GetScreenDims = r

End Function


Private Sub FormSetUp(lhwnd As Long)

    Dim lhr, IStyle, hRPen As Long
    
    'set form size default parameters
    If P_Width = 0 Then P_Width = 100
    If P_Height = 0 Then P_Height = 100

    Me.Width = P_Width
    Me.Height = P_Height
    
    'set the mouse pointer so it simulates
    'that of a magnifying glass
    Me.MousePointer = P_MousePointer
    
    'make the userform captionless and round
    'so it simulates a magnifying glass
    IStyle = GetWindowLong(lhwnd, GWL_STYLE)
    IStyle = IStyle And Not WS_CAPTION 'And WS_THICKFRAME
    SetWindowLong lhwnd, GWL_STYLE, IStyle
    DrawMenuBar lhwnd

    hRPen = CreatePen(P_FrameStyle, P_FrameWidth, P_FrameColor)
    DeleteObject SelectObject(lfrmDC, hRPen)

    'Create rightclick close menu
    On Error Resume Next
    CommandBars("GlassPopUp").Delete
    Set objCmb = Application.CommandBars.Add(Position:=msoBarPopup)
    With objCmb
        objCmb.Name = "GlassPopUp"
        With .Controls.Add(msoControlButton)
            .Caption = "CloseMe"
            .OnAction = "CloseGlass"
        End With
    End With

End Sub

'******* setting the Implement Class "ImpMagnifier" Properties **********

Private Property Let ImpMagnifier_Width(ByVal RHS As Double)

    P_Width = RHS

End Property

Private Property Let ImpMagnifier_Height(ByVal RHS As Double)

    P_Height = RHS

End Property

Private Property Let ImpMagnifier_ZoomFactor(ByVal RHS As Double)

    P_ZoomFactor = RHS

End Property

Private Property Let ImpMagnifier_Shape(ByVal RHS As MagShape)

    P_MagShape = RHS

End Property

Private Property Let ImpMagnifier_FrameStyle(ByVal RHS As MagFrameStyle)

    P_FrameStyle = RHS

End Property

Private Property Let ImpMagnifier_FrameColor(ByVal RHS As Long)

    P_FrameColor = RHS

End Property

Private Property Let ImpMagnifier_FrameWidth(ByVal RHS As Double)

    P_FrameWidth = RHS

End Property

Private Property Let ImpMagnifier_MousePointer(ByVal RHS As fmMousePointer)

    P_MousePointer = RHS

End Property

Private Sub ImpMagnifier_ShowMe()

    Me.Show

End Sub


...and place this in a Standard Module to Call the Glass Class :

Code:
Option Explicit

Private Magnifier As ImpMagnifier

Sub CloseGlass() 'OnClick procedure.
                 ' has to be in a Standard Module !
   Unload Magnifier

End Sub


Sub Test()

    Set Magnifier = New frmMagnifier
    
    ' use the  IntelliSense feature of the VBE.
    ' As you key in the letters,all the members of
    ' the Implement Class "ImpMagnifier" show up
    With Magnifier
        .FrameColor = vbGreen
        .FrameWidth = 3
        .FrameStyle = dot
        .Height = 150
        .Width = 150
        .MousePointer = fmMousePointerCross
        .ZoomFactor = 1.5
        .Shape = elliptic
        .ShowMe
    End With
    
End Sub


Note that I am using the Enum Keyword . I believe it wasn't introduced until XL2000 !

Tested in XL 2003 French version only.

Regards.
 
Upvote 0

Forum statistics

Threads
1,214,935
Messages
6,122,337
Members
449,077
Latest member
Jocksteriom

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top