Here is a much better version of the previous API based solution.
The code now works more accuratly and gives a Scroll Direction choice as well.
Workbook example.
Code in a standard module :
Code:'// Written by Jaafar Tribak on 28/07/10 '// API based code that enables to scroll the '// text in a Worksheet Cell giving it the visual '// effect of a "Stock Ticker". '// '// Results accuracy may be affected by the '// current Zoom factor. Option Explicit Private Type POINTAPI x As Long y As Long End Type Private Type RECT Left As Long Top As Long Right As Long Bottom As Long End Type Private Declare Function FindWindow Lib "user32.dll" _ Alias "FindWindowA" _ (ByVal lpClassName As String, _ ByVal lpWindowName As String) As Long Private Declare Function FindWindowEx Lib "user32.dll" _ Alias "FindWindowExA" _ (ByVal hWnd1 As Long, _ ByVal hWnd2 As Long, _ ByVal lpsz1 As String, _ ByVal lpsz2 As String) As Long Private Declare Function GetDeviceCaps Lib "gdi32" ( _ ByVal hdc As Long, _ ByVal nIndex As Long) As Long Private Declare Function GetDC Lib "user32" _ (ByVal hwnd As Long) As Long Private Declare Function ReleaseDC Lib "user32" ( _ ByVal hwnd As Long, _ ByVal hdc As Long) As Long 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 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 Declare Function ScreenToClient Lib "user32" ( _ ByVal hwnd As Long, _ lpPoint As POINTAPI) As Long Private Const SRCCOPY As Long = &HCC0020 Private Const LOGPIXELSX As Long = 88 Private Const LOGPIXELSY As Long = 90 Private Const POINTSPERINCH As Long = 72 Private tPrevRect As RECT Private oTargetCell As Range Private bStop As Boolean Private bRangeRectHasChanged As Boolean Private vNumberFormat As String Private vHorzAlignment As Long Private lMemoryDC As Long Private lWBHwnd As Long Private i As Long Public Sub StartScrolling() '//Scroll the text in Cell B4 from Right to Left. Call ScrollCell(Range("B4"), 0.01, True) End Sub Public Sub StopScrolling() '// Set flg to exit the loop. bStop = True i = 0 '//Reset this flag. bRangeRectHasChanged = False '//Reset Cell's settings. oTargetCell.NumberFormat = vNumberFormat oTargetCell.HorizontalAlignment = vHorzAlignment End Sub Private Sub TakeCellSnapShot(Target As Range) Dim lDC As Long Dim lXLDeskhwnd As Long Dim lBmp As Long '//Get the workbook Wnd hwnd. lXLDeskhwnd = _ FindWindowEx(FindWindow("XLMAIN", Application.Caption) _ , 0, "XLDESK", vbNullString) lWBHwnd = FindWindowEx _ (lXLDeskhwnd, 0, "EXCEL7", vbNullString) '//Get the Wbk window DC. lDC = GetDC(lWBHwnd) '//Create a memory DC. lMemoryDC = CreateCompatibleDC(lDC) '//Get the target cell metrics in pixels. tPrevRect = GetRangeRect(ByVal Target) With tPrevRect '//create a compatible Bmp the same size as the target cell. lBmp = CreateCompatibleBitmap _ (lDC, (.Right - 1 - .Left), (.Bottom - .Top)) '//Select the Bmp onto our mem DC. DeleteObject SelectObject(lMemoryDC, lBmp) '//Copy the target cell image onto the Mem DC. BitBlt lMemoryDC, 0, 0, (.Right - .Left), (.Bottom - .Top), _ lDC, .Left, .Top, SRCCOPY End With '//CleanUp. ReleaseDC 0, lDC ReleaseDC lMemoryDC, 0 End Sub Private Sub ScrollCell _ (ByVal Target As Range, ByVal Delay As Single, _ Optional ByVal RightToLeft As Boolean) '//Make sure the target range is one Cell. If Target.Cells.Count > 1 Then Exit Sub bStop = False '//Store the target cell for later use. Set oTargetCell = Target '//Unselect the target cell to avoid the selection borders. If ActiveCell.Address = _ Target.Address Then oTargetCell.Offset(1).Select If Not bRangeRectHasChanged Then vHorzAlignment = Target.HorizontalAlignment Target.HorizontalAlignment = xlLeft End If '//copy the target cell image onto memory. Call TakeCellSnapShot(Target) If Not bRangeRectHasChanged Then vNumberFormat = Target.NumberFormat Target.NumberFormat = ";;;" '//call the text scrolling routine. Call UpdateCell(Target, Delay, RightToLeft) End If End Sub Private Sub UpdateCell _ (ByVal Target As Range, ByVal Delay As Single, _ Optional ByVal RightToLeft As Boolean) Dim lDC As Long '//store the Wbk window DC. lDC = GetDC(lWBHwnd) '//Scroll the Target Cell Text. Do '//Do nothing if not on the target sheet. If ActiveSheet Is oTargetCell.Parent Then '//Update the tPrevRect Struct if the Target Cell '//screen location/size have changed. If tPrevRect.Left <> GetRangeRect(Target).Left Or _ tPrevRect.Top <> GetRangeRect(Target).Top Or _ tPrevRect.Right <> GetRangeRect(Target).Right Or _ tPrevRect.Bottom <> GetRangeRect(Target).Bottom Then bRangeRectHasChanged = True tPrevRect = GetRangeRect(Target) Target.NumberFormat = vNumberFormat ScrollCell oTargetCell, Delay Target.NumberFormat = ";;;" End If '//do the actual text scrolling here. With tPrevRect If RightToLeft Then BitBlt lDC, .Left + 1, .Top, (.Right - .Left), _ (.Bottom - .Top), _ lMemoryDC, i - (.Right - .Left), 0, SRCCOPY Else BitBlt lDC, .Left, .Top, (.Right - .Left), _ .Bottom - .Top, _ lMemoryDC, (.Right - .Left) - i, 0, SRCCOPY End If If i >= (.Right - .Left) * 2 Then i = 0 End With i = i + 1 SetDelay Delay 'Secs. End If DoEvents Loop Until bStop ReleaseDC 0, lDC End Sub '//=============================== '// Other Supporting routines... '//=============================== Private Function ScreenDPI(bVert As Boolean) As Long Static lDPI(1), lDC If lDPI(0) = 0 Then lDC = GetDC(0) lDPI(0) = GetDeviceCaps(lDC, LOGPIXELSX) lDPI(1) = GetDeviceCaps(lDC, LOGPIXELSY) lDC = ReleaseDC(0, lDC) End If ScreenDPI = lDPI(Abs(bVert)) End Function Private Function PTtoPX _ (Points As Single, bVert As Boolean) As Long PTtoPX = Points * ScreenDPI(bVert) / POINTSPERINCH End Function Private Function GetRangeRect(ByVal rng As Range) As RECT Dim tPt1 As POINTAPI Dim tPt2 As POINTAPI Dim OWnd As Window On Error Resume Next Set OWnd = rng.Parent.Parent.Windows(1) With rng GetRangeRect.Left = _ PTtoPX(.Left * OWnd.Zoom / 100, 0) _ + OWnd.PointsToScreenPixelsX(0) GetRangeRect.Top = _ PTtoPX(.Top * OWnd.Zoom / 100, 1) _ + OWnd.PointsToScreenPixelsY(0) GetRangeRect.Right = _ PTtoPX(.Width * OWnd.Zoom / 100, 0) _ + GetRangeRect.Left GetRangeRect.Bottom = _ PTtoPX(.Height * OWnd.Zoom / 100, 1) _ + GetRangeRect.Top End With With GetRangeRect tPt1.x = .Left tPt1.y = .Top tPt2.x = .Right tPt2.y = .Bottom ScreenToClient lWBHwnd, tPt1 ScreenToClient lWBHwnd, tPt2 .Left = tPt1.x + 2 .Top = tPt1.y .Right = tPt2.x - 2 .Bottom = tPt2.y End With End Function Private Sub SetDelay(TimeOut As Single) Dim t As Single t = Timer Do DoEvents Loop Until Timer - t >= TimeOut End Sub
One annoying limitation is when the worksheet zoom is less than 75 the the text precision may be dimished.
Apologies, I didn't provide any information on my OS and software version, I'm using MS Excel 2016 (16.0.4927.1000) 32-bit
Option Explicit
Private Type POINTAPI
x As Long
y As Long
End Type
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
#If VBA7 Then
Private Declare PtrSafe Function GetDeviceCaps Lib "gdi32" (ByVal hDc As LongPtr, ByVal nIndex As Long) As Long
Private Declare PtrSafe Function GetDC Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
Private Declare PtrSafe Function ReleaseDC Lib "user32" (ByVal hwnd As LongPtr, ByVal hDc As LongPtr) As Long
Private Declare PtrSafe Function CreateCompatibleDC Lib "gdi32" (ByVal hDc As LongPtr) As LongPtr
Private Declare PtrSafe Function CreateCompatibleBitmap Lib "gdi32" (ByVal hDc As LongPtr, ByVal nWidth As Long, ByVal nHeight As Long) As LongPtr
Private Declare PtrSafe Function SelectObject Lib "gdi32" (ByVal hDc As LongPtr, ByVal hObject As LongPtr) As LongPtr
Private Declare PtrSafe Function DeleteObject Lib "gdi32" (ByVal hObject As LongPtr) As LongPtr
Private Declare PtrSafe Function BitBlt Lib "gdi32" (ByVal hDestDC As LongPtr, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As LongPtr, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr
Private hMemoryDC As LongPtr
#Else
Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal hDc As Long, ByVal nIndex As Long) As Long
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hDc As Long) As Long
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 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 Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Declare Function GetActiveWindow Lib "user32" () As Long
Private hMemoryDC As Long
#End If
Private Const SRCCOPY As Long = &HCC0020
Private Const LOGPIXELSX As Long = 88
Private Const LOGPIXELSY As Long = 90
Private Const POINTSPERINCH As Long = 72
Private tCellRect As RECT
Private oTargetCell As Range
Private bScrolling As Boolean
Private bRangeRectHasChanged As Boolean
Private vNumberFormat As String
Private vHorzAlignment As Long
Private xOffset As Long
Public Sub StartScrolling()
'//Scroll the text in Cell B4 from Right to Left.
Call ScrollCell(TargetCell:=Range("B4"), Delay:=0.5, RightToLeft:=True)
End Sub
Public Sub StopScrolling()
bScrolling = False
bRangeRectHasChanged = False
xOffset = 0
DeleteObject hMemoryDC
If Not oTargetCell Is Nothing Then
oTargetCell.NumberFormat = vNumberFormat
oTargetCell.HorizontalAlignment = vHorzAlignment
End If
End Sub
Private Sub ScrollCell(ByVal TargetCell As Range, ByVal Delay As Single, Optional ByVal RightToLeft As Boolean = True)
Application.OnTime Now, "'ScrollCellNow " & Chr$(34) & TargetCell.Address & Chr$(34) & "," & Delay & "," & RightToLeft & "'"
End Sub
Sub ScrollCellNow(ByVal TargetCellAddr As String, ByVal Delay As Single, ByVal RightToLeft As Boolean)
If bScrolling = False Then
If Range(TargetCellAddr).Cells.Count > 1 Then Exit Sub
bScrolling = True
Set oTargetCell = Range(TargetCellAddr)
If ActiveCell.Address = oTargetCell.Address Then oTargetCell.Offset(2).Select
Sleep 150
If Not bRangeRectHasChanged Then
vHorzAlignment = oTargetCell.HorizontalAlignment
oTargetCell.HorizontalAlignment = xlLeft
End If
Call TakeCellSnapShot(oTargetCell)
If Not bRangeRectHasChanged Then
vNumberFormat = oTargetCell.NumberFormat
oTargetCell.NumberFormat = ";;;"
Call UpdateCell(oTargetCell, Delay, RightToLeft)
End If
End If
End Sub
Private Sub TakeCellSnapShot(ByVal Target As Range)
#If VBA7 Then
Dim hDc As LongPtr, hBmp As LongPtr
#Else
Dim hDc As Long, hBmp As Long
#End If
tCellRect = GetRangeRect(ByVal Target)
hDc = GetDC(0)
hMemoryDC = CreateCompatibleDC(hDc)
With tCellRect
hBmp = CreateCompatibleBitmap(hDc, (.Right - .Left), (.Bottom - .Top))
DeleteObject SelectObject(hMemoryDC, hBmp)
BitBlt hMemoryDC, 0, 0, (.Right - .Left), (.Bottom - .Top), _
hDc, .Left, .Top, SRCCOPY
End With
ReleaseDC 0, hDc
DeleteObject hBmp
End Sub
Private Sub UpdateCell(ByVal Target As Range, ByVal Delay As Single, Optional ByVal RightToLeft As Boolean = True)
#If VBA7 Then
Dim hDc As LongPtr
#Else
Dim hDc As Long
#End If
hDc = GetDC(0)
Do
With tCellRect
If ActiveSheet Is oTargetCell.Parent And IsCellVisible(oTargetCell) And GetActiveWindow = Application.hwnd Then
If tCellRect.Left <> GetRangeRect(oTargetCell).Left Or _
.Top <> GetRangeRect(oTargetCell).Top Or _
.Right <> GetRangeRect(oTargetCell).Right Or _
.Bottom <> GetRangeRect(oTargetCell).Bottom Then
bRangeRectHasChanged = True
tCellRect = GetRangeRect(oTargetCell)
oTargetCell.NumberFormat = vNumberFormat
ScrollCell oTargetCell, Delay, RightToLeft
oTargetCell.NumberFormat = ";;;"
End If
If RightToLeft Then
BitBlt hDc, .Left, .Top, (.Right - .Left), _
(.Bottom - .Top), _
hMemoryDC, xOffset - (.Right - .Left), 0, SRCCOPY
Else
BitBlt hDc, .Left, .Top, (.Right - .Left), _
.Bottom - .Top, _
hMemoryDC, (.Right - .Left) - xOffset, 0, SRCCOPY
End If
If xOffset >= (.Right - .Left) * 2 Then xOffset = 0
xOffset = xOffset + 1
SetDelay Delay 'Secs.
End If
End With
DoEvents
Loop Until bScrolling = False
ReleaseDC 0, hDc
End Sub
Private Function ScreenDPI(ByVal bVert As Boolean) As Long
Static lDPI(1), hDc
If lDPI(0) = 0 Then
hDc = GetDC(0)
lDPI(0) = GetDeviceCaps(hDc, LOGPIXELSX)
lDPI(1) = GetDeviceCaps(hDc, LOGPIXELSY)
hDc = ReleaseDC(0, hDc)
End If
ScreenDPI = lDPI(Abs(bVert))
End Function
Private Function PTtoPX(ByVal Points As Single, ByVal bVert As Boolean) As Long
PTtoPX = Points * ScreenDPI(bVert) / POINTSPERINCH
End Function
Private Function GetRangeRect(ByVal Obj As Object) As RECT
Dim oPane As Pane
Set oPane = ThisWorkbook.Windows(1).ActivePane
With Obj
GetRangeRect.Left = oPane.PointsToScreenPixelsX(.Left)
GetRangeRect.Top = oPane.PointsToScreenPixelsY(.Top)
GetRangeRect.Right = oPane.PointsToScreenPixelsX(.Left + .Width - 2)
GetRangeRect.Bottom = oPane.PointsToScreenPixelsY(.Top + .Height)
End With
End Function
Private Function IsCellVisible(ByVal Cell As Range) As Boolean
With Cell
IsCellVisible = .Left >= ActiveWindow.VisibleRange.Left And .Top >= ActiveWindow.VisibleRange.Top
End With
End Function
Private Sub SetDelay(ByVal TimeOut As Single)
Dim t As Single
t = Timer
Do
DoEvents
Loop Until Timer - t >= TimeOut / 100
End Sub
Option Explicit
Private Type POINTAPI
x As Long
y As Long
End Type
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
#If VBA7 Then
Private Declare PtrSafe Function GetDeviceCaps Lib "gdi32" (ByVal hDc As LongPtr, ByVal nIndex As Long) As Long
Private Declare PtrSafe Function GetDC Lib "user32" (ByVal hWnd As LongPtr) As LongPtr
Private Declare PtrSafe Function ReleaseDC Lib "user32" (ByVal hWnd As LongPtr, ByVal hDc As LongPtr) As Long
Private Declare PtrSafe Function CreateCompatibleDC Lib "gdi32" (ByVal hDc As LongPtr) As LongPtr
Private Declare PtrSafe Function CreateCompatibleBitmap Lib "gdi32" (ByVal hDc As LongPtr, ByVal nWidth As Long, ByVal nHeight As Long) As LongPtr
Private Declare PtrSafe Function SelectObject Lib "gdi32" (ByVal hDc As LongPtr, ByVal hObject As LongPtr) As LongPtr
Private Declare PtrSafe Function DeleteObject Lib "gdi32" (ByVal hObject As LongPtr) As LongPtr
Private Declare PtrSafe Function BitBlt Lib "gdi32" (ByVal hDestDC As LongPtr, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As LongPtr, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr
Private Declare PtrSafe Function GlobalAddAtom Lib "kernel32" Alias "GlobalAddAtomA" (ByVal lpString As String) As Integer
Private Declare PtrSafe Function GlobalGetAtomName Lib "kernel32" Alias "GlobalGetAtomNameA" (ByVal nAtom As Integer, ByVal lpBuffer As String, ByVal nSize As Long) As Long
Private Declare PtrSafe Function GlobalDeleteAtom Lib "kernel32" (ByVal nAtom As Integer) As Integer
Private Declare PtrSafe Function SetProp Lib "user32" Alias "SetPropA" (ByVal hWnd As LongPtr, ByVal lpString As String, ByVal hData As LongPtr) As Long
Private Declare PtrSafe Function GetProp Lib "user32" Alias "GetPropA" (ByVal hWnd As LongPtr, ByVal lpString As String) As LongPtr
Private Declare PtrSafe Function RemoveProp Lib "user32" Alias "RemovePropA" (ByVal hWnd As LongPtr, ByVal lpString As String) As LongPtr
Private hMemoryDC As LongPtr
#Else
Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal hDc As Long, ByVal nIndex As Long) As Long
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hDc As Long) As Long
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 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 Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Declare Function GetActiveWindow Lib "user32" () As Long
Private Declare Function GlobalAddAtom Lib "kernel32" Alias "GlobalAddAtomA" (ByVal lpString As String) As Integer
Private Declare Function GlobalGetAtomName Lib "kernel32" Alias "GlobalGetAtomNameA" (ByVal nAtom As Integer, ByVal lpBuffer As String, ByVal nSize As Long) As Long
Private Declare Function GlobalDeleteAtom Lib "kernel32" (ByVal nAtom As Integer) As Integer
Private Declare Function SetProp Lib "user32" Alias "SetPropA" (ByVal hWnd As Long, ByVal lpString As String, ByVal hData As Long) As Long
Private Declare Function GetProp Lib "user32" Alias "GetPropA" (ByVal hWnd As Long, ByVal lpString As String) As Long
Private Declare Function RemoveProp Lib "user32" Alias "RemovePropA" (ByVal hWnd As Long, ByVal lpString As String) As Long
Private hMemoryDC As Long
#End If
Private Const SRCCOPY As Long = &HCC0020
Private Const LOGPIXELSX As Long = 88
Private Const LOGPIXELSY As Long = 90
Private Const POINTSPERINCH As Long = 72
Private tCellRect As RECT
Private oTargetCell As Range
Private bScrolling As Boolean
Private bRangeRectHasChanged As Boolean
Private sNumberFormat As String
Private lHorzAlignment As Long
Private lXOffset As Long
Public Sub StartScrolling()
'//Scroll the text in Cell B4 from Right to Left.
Call scrollCell(TargetCell:=Range("B4"), Delay:=0.5, RightToLeft:=True)
End Sub
Public Sub StopScrolling()
Call Auto_Close
End Sub
Private Sub scrollCell(ByVal TargetCell As Range, ByVal Delay As Single, Optional ByVal RightToLeft As Boolean = True)
Application.OnTime Now, "'ScrollCellNow " & Chr$(34) & TargetCell.Address & Chr$(34) & "," & Delay & "," & RightToLeft & "'"
End Sub
Sub ScrollCellNow(ByVal TargetCellAddr As String, ByVal Delay As Single, ByVal RightToLeft As Boolean)
Dim iAtom_ID As Integer
If bScrolling = False Then
If Range(TargetCellAddr).Cells.Count > 1 Then Exit Sub
bScrolling = True
Set oTargetCell = Range(TargetCellAddr)
iAtom_ID = GlobalAddAtom(oTargetCell.Address)
SetProp Application.hWnd, "CellAddress", iAtom_ID
If ActiveCell.Address = oTargetCell.Address Then oTargetCell.Offset(2).Select
Sleep 150
If Not bRangeRectHasChanged Then
lHorzAlignment = oTargetCell.HorizontalAlignment
iAtom_ID = GlobalAddAtom(CStr(oTargetCell.HorizontalAlignment))
SetProp Application.hWnd, "HorzAlignment", iAtom_ID
oTargetCell.HorizontalAlignment = xlLeft
End If
Call TakeCellSnapShot(oTargetCell)
If Not bRangeRectHasChanged Then
sNumberFormat = oTargetCell.NumberFormat
iAtom_ID = GlobalAddAtom(oTargetCell.NumberFormat)
SetProp Application.hWnd, "NumberFormat", iAtom_ID
oTargetCell.NumberFormat = ";;;"
Call UpdateCell(oTargetCell, Delay, RightToLeft)
End If
End If
End Sub
Private Sub TakeCellSnapShot(ByVal target As Range)
#If VBA7 Then
Dim hDc As LongPtr, hBmp As LongPtr
#Else
Dim hDc As Long, hBmp As Long
#End If
tCellRect = GetRangeRect(ByVal target)
hDc = GetDC(0)
hMemoryDC = CreateCompatibleDC(hDc)
With tCellRect
hBmp = CreateCompatibleBitmap(hDc, (.Right - .Left), (.Bottom - .Top))
DeleteObject SelectObject(hMemoryDC, hBmp)
BitBlt hMemoryDC, 0, 0, (.Right - .Left), (.Bottom - .Top), _
hDc, .Left, .Top, SRCCOPY
End With
ReleaseDC 0, hDc
DeleteObject hBmp
End Sub
Private Sub UpdateCell(ByVal target As Range, ByVal Delay As Single, Optional ByVal RightToLeft As Boolean = True)
#If VBA7 Then
Dim hDc As LongPtr
#Else
Dim hDc As Long
#End If
hDc = GetDC(0)
Do
With tCellRect
If ActiveSheet Is oTargetCell.Parent And IsCellVisible(oTargetCell) And GetActiveWindow = Application.hWnd Then
If tCellRect.Left <> GetRangeRect(oTargetCell).Left Or _
.Top <> GetRangeRect(oTargetCell).Top Or _
.Right <> GetRangeRect(oTargetCell).Right Or _
.Bottom <> GetRangeRect(oTargetCell).Bottom Then
bRangeRectHasChanged = True
tCellRect = GetRangeRect(oTargetCell)
oTargetCell.NumberFormat = sNumberFormat
scrollCell oTargetCell, Delay, RightToLeft
oTargetCell.NumberFormat = ";;;"
End If
If RightToLeft Then
BitBlt hDc, .Left, .Top, (.Right - .Left), _
(.Bottom - .Top), _
hMemoryDC, lXOffset - (.Right - .Left), 0, SRCCOPY
Else
BitBlt hDc, .Left, .Top, (.Right - .Left), _
.Bottom - .Top, _
hMemoryDC, (.Right - .Left) - lXOffset, 0, SRCCOPY
End If
If lXOffset >= (.Right - .Left) * 2 Then lXOffset = 0
lXOffset = lXOffset + 1
SetDelay Delay 'Secs.
End If
End With
DoEvents
Loop Until bScrolling = False
ReleaseDC 0, hDc
End Sub
Private Function ScreenDPI(ByVal bVert As Boolean) As Long
Static lDPI(1), hDc
If lDPI(0) = 0 Then
hDc = GetDC(0)
lDPI(0) = GetDeviceCaps(hDc, LOGPIXELSX)
lDPI(1) = GetDeviceCaps(hDc, LOGPIXELSY)
hDc = ReleaseDC(0, hDc)
End If
ScreenDPI = lDPI(Abs(bVert))
End Function
Private Function PTtoPX(ByVal Points As Single, ByVal bVert As Boolean) As Long
PTtoPX = Points * ScreenDPI(bVert) / POINTSPERINCH
End Function
Private Function GetRangeRect(ByVal Obj As Object) As RECT
Dim oPane As Pane
Set oPane = ThisWorkbook.Windows(1).ActivePane
With Obj
GetRangeRect.Left = oPane.PointsToScreenPixelsX(.Left)
GetRangeRect.Top = oPane.PointsToScreenPixelsY(.Top)
GetRangeRect.Right = oPane.PointsToScreenPixelsX(.Left + .Width - 2)
GetRangeRect.Bottom = oPane.PointsToScreenPixelsY(.Top + .Height)
End With
End Function
Private Function IsCellVisible(ByVal Cell As Range) As Boolean
With Cell
IsCellVisible = .Left >= ActiveWindow.VisibleRange.Left And .Top >= ActiveWindow.VisibleRange.Top
End With
End Function
Private Sub SetDelay(ByVal TimeOut As Single)
Dim t As Single
t = Timer
Do
DoEvents
Loop Until Timer - t >= TimeOut / 100
End Sub
Private Sub Auto_Close()
Dim Atom_ID As Integer, lRet As Long, sBuffer As String * 256
Dim sRangeAddr As String, sNumberFormat As String, lHorzAlignment As Long
bScrolling = False
bRangeRectHasChanged = False
lXOffset = 0
DeleteObject hMemoryDC
If GetProp(Application.hWnd, "CellAddress") Then
Atom_ID = CInt(GetProp(Application.hWnd, "CellAddress"))
lRet = GlobalGetAtomName(Atom_ID, sBuffer, Len(sBuffer))
sRangeAddr = Left(sBuffer, lRet)
Atom_ID = CInt(GetProp(Application.hWnd, "NumberFormat"))
lRet = GlobalGetAtomName(Atom_ID, sBuffer, Len(sBuffer))
sNumberFormat = Left(sBuffer, lRet)
Atom_ID = CInt(GetProp(Application.hWnd, "HorzAlignment"))
lRet = GlobalGetAtomName(Atom_ID, sBuffer, Len(sBuffer))
lHorzAlignment = CLng(Left(sBuffer, lRet))
Range(sRangeAddr).NumberFormat = sNumberFormat
Range(sRangeAddr).HorizontalAlignment = lHorzAlignment
RemoveProp Application.hWnd, "CellAddress"
RemoveProp Application.hWnd, "NumberFormat"
RemoveProp Application.hWnd, "HorzAlignment"
End If
End Sub
Thank you!! I had no idea you could get the marquee effect that smooth, all the other examples I’ve saw were pretty clunky but this is great. A fair bit I need to learn before I understand how this works but thank you for your time and replies Jaafar!This is an update of the above code that takes into account the scenario where the user might close the workbook without first stopping the scrolling .
Workbook Update
In a Standard Module:
VBA Code:Option Explicit Private Type POINTAPI x As Long y As Long End Type Private Type RECT Left As Long Top As Long Right As Long Bottom As Long End Type #If VBA7 Then Private Declare PtrSafe Function GetDeviceCaps Lib "gdi32" (ByVal hDc As LongPtr, ByVal nIndex As Long) As Long Private Declare PtrSafe Function GetDC Lib "user32" (ByVal hWnd As LongPtr) As LongPtr Private Declare PtrSafe Function ReleaseDC Lib "user32" (ByVal hWnd As LongPtr, ByVal hDc As LongPtr) As Long Private Declare PtrSafe Function CreateCompatibleDC Lib "gdi32" (ByVal hDc As LongPtr) As LongPtr Private Declare PtrSafe Function CreateCompatibleBitmap Lib "gdi32" (ByVal hDc As LongPtr, ByVal nWidth As Long, ByVal nHeight As Long) As LongPtr Private Declare PtrSafe Function SelectObject Lib "gdi32" (ByVal hDc As LongPtr, ByVal hObject As LongPtr) As LongPtr Private Declare PtrSafe Function DeleteObject Lib "gdi32" (ByVal hObject As LongPtr) As LongPtr Private Declare PtrSafe Function BitBlt Lib "gdi32" (ByVal hDestDC As LongPtr, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As LongPtr, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Private Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr Private Declare PtrSafe Function GlobalAddAtom Lib "kernel32" Alias "GlobalAddAtomA" (ByVal lpString As String) As Integer Private Declare PtrSafe Function GlobalGetAtomName Lib "kernel32" Alias "GlobalGetAtomNameA" (ByVal nAtom As Integer, ByVal lpBuffer As String, ByVal nSize As Long) As Long Private Declare PtrSafe Function GlobalDeleteAtom Lib "kernel32" (ByVal nAtom As Integer) As Integer Private Declare PtrSafe Function SetProp Lib "user32" Alias "SetPropA" (ByVal hWnd As LongPtr, ByVal lpString As String, ByVal hData As LongPtr) As Long Private Declare PtrSafe Function GetProp Lib "user32" Alias "GetPropA" (ByVal hWnd As LongPtr, ByVal lpString As String) As LongPtr Private Declare PtrSafe Function RemoveProp Lib "user32" Alias "RemovePropA" (ByVal hWnd As LongPtr, ByVal lpString As String) As LongPtr Private hMemoryDC As LongPtr #Else Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal hDc As Long, ByVal nIndex As Long) As Long Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hDc As Long) As Long 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 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 Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Private Declare Function GetActiveWindow Lib "user32" () As Long Private Declare Function GlobalAddAtom Lib "kernel32" Alias "GlobalAddAtomA" (ByVal lpString As String) As Integer Private Declare Function GlobalGetAtomName Lib "kernel32" Alias "GlobalGetAtomNameA" (ByVal nAtom As Integer, ByVal lpBuffer As String, ByVal nSize As Long) As Long Private Declare Function GlobalDeleteAtom Lib "kernel32" (ByVal nAtom As Integer) As Integer Private Declare Function SetProp Lib "user32" Alias "SetPropA" (ByVal hWnd As Long, ByVal lpString As String, ByVal hData As Long) As Long Private Declare Function GetProp Lib "user32" Alias "GetPropA" (ByVal hWnd As Long, ByVal lpString As String) As Long Private Declare Function RemoveProp Lib "user32" Alias "RemovePropA" (ByVal hWnd As Long, ByVal lpString As String) As Long Private hMemoryDC As Long #End If Private Const SRCCOPY As Long = &HCC0020 Private Const LOGPIXELSX As Long = 88 Private Const LOGPIXELSY As Long = 90 Private Const POINTSPERINCH As Long = 72 Private tCellRect As RECT Private oTargetCell As Range Private bScrolling As Boolean Private bRangeRectHasChanged As Boolean Private sNumberFormat As String Private lHorzAlignment As Long Private lXOffset As Long Public Sub StartScrolling() '//Scroll the text in Cell B4 from Right to Left. Call scrollCell(TargetCell:=Range("B4"), Delay:=0.5, RightToLeft:=True) End Sub Public Sub StopScrolling() Call Auto_Close End Sub Private Sub scrollCell(ByVal TargetCell As Range, ByVal Delay As Single, Optional ByVal RightToLeft As Boolean = True) Application.OnTime Now, "'ScrollCellNow " & Chr$(34) & TargetCell.Address & Chr$(34) & "," & Delay & "," & RightToLeft & "'" End Sub Sub ScrollCellNow(ByVal TargetCellAddr As String, ByVal Delay As Single, ByVal RightToLeft As Boolean) Dim iAtom_ID As Integer If bScrolling = False Then If Range(TargetCellAddr).Cells.Count > 1 Then Exit Sub bScrolling = True Set oTargetCell = Range(TargetCellAddr) iAtom_ID = GlobalAddAtom(oTargetCell.Address) SetProp Application.hWnd, "CellAddress", iAtom_ID If ActiveCell.Address = oTargetCell.Address Then oTargetCell.Offset(2).Select Sleep 150 If Not bRangeRectHasChanged Then lHorzAlignment = oTargetCell.HorizontalAlignment iAtom_ID = GlobalAddAtom(CStr(oTargetCell.HorizontalAlignment)) SetProp Application.hWnd, "HorzAlignment", iAtom_ID oTargetCell.HorizontalAlignment = xlLeft End If Call TakeCellSnapShot(oTargetCell) If Not bRangeRectHasChanged Then sNumberFormat = oTargetCell.NumberFormat iAtom_ID = GlobalAddAtom(oTargetCell.NumberFormat) SetProp Application.hWnd, "NumberFormat", iAtom_ID oTargetCell.NumberFormat = ";;;" Call UpdateCell(oTargetCell, Delay, RightToLeft) End If End If End Sub Private Sub TakeCellSnapShot(ByVal target As Range) #If VBA7 Then Dim hDc As LongPtr, hBmp As LongPtr #Else Dim hDc As Long, hBmp As Long #End If tCellRect = GetRangeRect(ByVal target) hDc = GetDC(0) hMemoryDC = CreateCompatibleDC(hDc) With tCellRect hBmp = CreateCompatibleBitmap(hDc, (.Right - .Left), (.Bottom - .Top)) DeleteObject SelectObject(hMemoryDC, hBmp) BitBlt hMemoryDC, 0, 0, (.Right - .Left), (.Bottom - .Top), _ hDc, .Left, .Top, SRCCOPY End With ReleaseDC 0, hDc DeleteObject hBmp End Sub Private Sub UpdateCell(ByVal target As Range, ByVal Delay As Single, Optional ByVal RightToLeft As Boolean = True) #If VBA7 Then Dim hDc As LongPtr #Else Dim hDc As Long #End If hDc = GetDC(0) Do With tCellRect If ActiveSheet Is oTargetCell.Parent And IsCellVisible(oTargetCell) And GetActiveWindow = Application.hWnd Then If tCellRect.Left <> GetRangeRect(oTargetCell).Left Or _ .Top <> GetRangeRect(oTargetCell).Top Or _ .Right <> GetRangeRect(oTargetCell).Right Or _ .Bottom <> GetRangeRect(oTargetCell).Bottom Then bRangeRectHasChanged = True tCellRect = GetRangeRect(oTargetCell) oTargetCell.NumberFormat = sNumberFormat scrollCell oTargetCell, Delay, RightToLeft oTargetCell.NumberFormat = ";;;" End If If RightToLeft Then BitBlt hDc, .Left, .Top, (.Right - .Left), _ (.Bottom - .Top), _ hMemoryDC, lXOffset - (.Right - .Left), 0, SRCCOPY Else BitBlt hDc, .Left, .Top, (.Right - .Left), _ .Bottom - .Top, _ hMemoryDC, (.Right - .Left) - lXOffset, 0, SRCCOPY End If If lXOffset >= (.Right - .Left) * 2 Then lXOffset = 0 lXOffset = lXOffset + 1 SetDelay Delay 'Secs. End If End With DoEvents Loop Until bScrolling = False ReleaseDC 0, hDc End Sub Private Function ScreenDPI(ByVal bVert As Boolean) As Long Static lDPI(1), hDc If lDPI(0) = 0 Then hDc = GetDC(0) lDPI(0) = GetDeviceCaps(hDc, LOGPIXELSX) lDPI(1) = GetDeviceCaps(hDc, LOGPIXELSY) hDc = ReleaseDC(0, hDc) End If ScreenDPI = lDPI(Abs(bVert)) End Function Private Function PTtoPX(ByVal Points As Single, ByVal bVert As Boolean) As Long PTtoPX = Points * ScreenDPI(bVert) / POINTSPERINCH End Function Private Function GetRangeRect(ByVal Obj As Object) As RECT Dim oPane As Pane Set oPane = ThisWorkbook.Windows(1).ActivePane With Obj GetRangeRect.Left = oPane.PointsToScreenPixelsX(.Left) GetRangeRect.Top = oPane.PointsToScreenPixelsY(.Top) GetRangeRect.Right = oPane.PointsToScreenPixelsX(.Left + .Width - 2) GetRangeRect.Bottom = oPane.PointsToScreenPixelsY(.Top + .Height) End With End Function Private Function IsCellVisible(ByVal Cell As Range) As Boolean With Cell IsCellVisible = .Left >= ActiveWindow.VisibleRange.Left And .Top >= ActiveWindow.VisibleRange.Top End With End Function Private Sub SetDelay(ByVal TimeOut As Single) Dim t As Single t = Timer Do DoEvents Loop Until Timer - t >= TimeOut / 100 End Sub Private Sub Auto_Close() Dim Atom_ID As Integer, lRet As Long, sBuffer As String * 256 Dim sRangeAddr As String, sNumberFormat As String, lHorzAlignment As Long bScrolling = False bRangeRectHasChanged = False lXOffset = 0 DeleteObject hMemoryDC If GetProp(Application.hWnd, "CellAddress") Then Atom_ID = CInt(GetProp(Application.hWnd, "CellAddress")) lRet = GlobalGetAtomName(Atom_ID, sBuffer, Len(sBuffer)) sRangeAddr = Left(sBuffer, lRet) Atom_ID = CInt(GetProp(Application.hWnd, "NumberFormat")) lRet = GlobalGetAtomName(Atom_ID, sBuffer, Len(sBuffer)) sNumberFormat = Left(sBuffer, lRet) Atom_ID = CInt(GetProp(Application.hWnd, "HorzAlignment")) lRet = GlobalGetAtomName(Atom_ID, sBuffer, Len(sBuffer)) lHorzAlignment = CLng(Left(sBuffer, lRet)) Range(sRangeAddr).NumberFormat = sNumberFormat Range(sRangeAddr).HorizontalAlignment = lHorzAlignment RemoveProp Application.hWnd, "CellAddress" RemoveProp Application.hWnd, "NumberFormat" RemoveProp Application.hWnd, "HorzAlignment" End If End Sub
Hi @Jaafar TribakThis is an update of the above code that takes into account the scenario where the user might close the workbook without first stopping the scrolling .
Workbook Update
In a Standard Module:
VBA Code:Option Explicit Private Type POINTAPI x As Long y As Long End Type Private Type RECT Left As Long Top As Long Right As Long Bottom As Long End Type #If VBA7 Then Private Declare PtrSafe Function GetDeviceCaps Lib "gdi32" (ByVal hDc As LongPtr, ByVal nIndex As Long) As Long Private Declare PtrSafe Function GetDC Lib "user32" (ByVal hWnd As LongPtr) As LongPtr Private Declare PtrSafe Function ReleaseDC Lib "user32" (ByVal hWnd As LongPtr, ByVal hDc As LongPtr) As Long Private Declare PtrSafe Function CreateCompatibleDC Lib "gdi32" (ByVal hDc As LongPtr) As LongPtr Private Declare PtrSafe Function CreateCompatibleBitmap Lib "gdi32" (ByVal hDc As LongPtr, ByVal nWidth As Long, ByVal nHeight As Long) As LongPtr Private Declare PtrSafe Function SelectObject Lib "gdi32" (ByVal hDc As LongPtr, ByVal hObject As LongPtr) As LongPtr Private Declare PtrSafe Function DeleteObject Lib "gdi32" (ByVal hObject As LongPtr) As LongPtr Private Declare PtrSafe Function BitBlt Lib "gdi32" (ByVal hDestDC As LongPtr, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As LongPtr, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Private Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr Private Declare PtrSafe Function GlobalAddAtom Lib "kernel32" Alias "GlobalAddAtomA" (ByVal lpString As String) As Integer Private Declare PtrSafe Function GlobalGetAtomName Lib "kernel32" Alias "GlobalGetAtomNameA" (ByVal nAtom As Integer, ByVal lpBuffer As String, ByVal nSize As Long) As Long Private Declare PtrSafe Function GlobalDeleteAtom Lib "kernel32" (ByVal nAtom As Integer) As Integer Private Declare PtrSafe Function SetProp Lib "user32" Alias "SetPropA" (ByVal hWnd As LongPtr, ByVal lpString As String, ByVal hData As LongPtr) As Long Private Declare PtrSafe Function GetProp Lib "user32" Alias "GetPropA" (ByVal hWnd As LongPtr, ByVal lpString As String) As LongPtr Private Declare PtrSafe Function RemoveProp Lib "user32" Alias "RemovePropA" (ByVal hWnd As LongPtr, ByVal lpString As String) As LongPtr Private hMemoryDC As LongPtr #Else Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal hDc As Long, ByVal nIndex As Long) As Long Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hDc As Long) As Long 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 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 Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Private Declare Function GetActiveWindow Lib "user32" () As Long Private Declare Function GlobalAddAtom Lib "kernel32" Alias "GlobalAddAtomA" (ByVal lpString As String) As Integer Private Declare Function GlobalGetAtomName Lib "kernel32" Alias "GlobalGetAtomNameA" (ByVal nAtom As Integer, ByVal lpBuffer As String, ByVal nSize As Long) As Long Private Declare Function GlobalDeleteAtom Lib "kernel32" (ByVal nAtom As Integer) As Integer Private Declare Function SetProp Lib "user32" Alias "SetPropA" (ByVal hWnd As Long, ByVal lpString As String, ByVal hData As Long) As Long Private Declare Function GetProp Lib "user32" Alias "GetPropA" (ByVal hWnd As Long, ByVal lpString As String) As Long Private Declare Function RemoveProp Lib "user32" Alias "RemovePropA" (ByVal hWnd As Long, ByVal lpString As String) As Long Private hMemoryDC As Long #End If Private Const SRCCOPY As Long = &HCC0020 Private Const LOGPIXELSX As Long = 88 Private Const LOGPIXELSY As Long = 90 Private Const POINTSPERINCH As Long = 72 Private tCellRect As RECT Private oTargetCell As Range Private bScrolling As Boolean Private bRangeRectHasChanged As Boolean Private sNumberFormat As String Private lHorzAlignment As Long Private lXOffset As Long Public Sub StartScrolling() '//Scroll the text in Cell B4 from Right to Left. Call scrollCell(TargetCell:=Range("B4"), Delay:=0.5, RightToLeft:=True) End Sub Public Sub StopScrolling() Call Auto_Close End Sub Private Sub scrollCell(ByVal TargetCell As Range, ByVal Delay As Single, Optional ByVal RightToLeft As Boolean = True) Application.OnTime Now, "'ScrollCellNow " & Chr$(34) & TargetCell.Address & Chr$(34) & "," & Delay & "," & RightToLeft & "'" End Sub Sub ScrollCellNow(ByVal TargetCellAddr As String, ByVal Delay As Single, ByVal RightToLeft As Boolean) Dim iAtom_ID As Integer If bScrolling = False Then If Range(TargetCellAddr).Cells.Count > 1 Then Exit Sub bScrolling = True Set oTargetCell = Range(TargetCellAddr) iAtom_ID = GlobalAddAtom(oTargetCell.Address) SetProp Application.hWnd, "CellAddress", iAtom_ID If ActiveCell.Address = oTargetCell.Address Then oTargetCell.Offset(2).Select Sleep 150 If Not bRangeRectHasChanged Then lHorzAlignment = oTargetCell.HorizontalAlignment iAtom_ID = GlobalAddAtom(CStr(oTargetCell.HorizontalAlignment)) SetProp Application.hWnd, "HorzAlignment", iAtom_ID oTargetCell.HorizontalAlignment = xlLeft End If Call TakeCellSnapShot(oTargetCell) If Not bRangeRectHasChanged Then sNumberFormat = oTargetCell.NumberFormat iAtom_ID = GlobalAddAtom(oTargetCell.NumberFormat) SetProp Application.hWnd, "NumberFormat", iAtom_ID oTargetCell.NumberFormat = ";;;" Call UpdateCell(oTargetCell, Delay, RightToLeft) End If End If End Sub Private Sub TakeCellSnapShot(ByVal target As Range) #If VBA7 Then Dim hDc As LongPtr, hBmp As LongPtr #Else Dim hDc As Long, hBmp As Long #End If tCellRect = GetRangeRect(ByVal target) hDc = GetDC(0) hMemoryDC = CreateCompatibleDC(hDc) With tCellRect hBmp = CreateCompatibleBitmap(hDc, (.Right - .Left), (.Bottom - .Top)) DeleteObject SelectObject(hMemoryDC, hBmp) BitBlt hMemoryDC, 0, 0, (.Right - .Left), (.Bottom - .Top), _ hDc, .Left, .Top, SRCCOPY End With ReleaseDC 0, hDc DeleteObject hBmp End Sub Private Sub UpdateCell(ByVal target As Range, ByVal Delay As Single, Optional ByVal RightToLeft As Boolean = True) #If VBA7 Then Dim hDc As LongPtr #Else Dim hDc As Long #End If hDc = GetDC(0) Do With tCellRect If ActiveSheet Is oTargetCell.Parent And IsCellVisible(oTargetCell) And GetActiveWindow = Application.hWnd Then If tCellRect.Left <> GetRangeRect(oTargetCell).Left Or _ .Top <> GetRangeRect(oTargetCell).Top Or _ .Right <> GetRangeRect(oTargetCell).Right Or _ .Bottom <> GetRangeRect(oTargetCell).Bottom Then bRangeRectHasChanged = True tCellRect = GetRangeRect(oTargetCell) oTargetCell.NumberFormat = sNumberFormat scrollCell oTargetCell, Delay, RightToLeft oTargetCell.NumberFormat = ";;;" End If If RightToLeft Then BitBlt hDc, .Left, .Top, (.Right - .Left), _ (.Bottom - .Top), _ hMemoryDC, lXOffset - (.Right - .Left), 0, SRCCOPY Else BitBlt hDc, .Left, .Top, (.Right - .Left), _ .Bottom - .Top, _ hMemoryDC, (.Right - .Left) - lXOffset, 0, SRCCOPY End If If lXOffset >= (.Right - .Left) * 2 Then lXOffset = 0 lXOffset = lXOffset + 1 SetDelay Delay 'Secs. End If End With DoEvents Loop Until bScrolling = False ReleaseDC 0, hDc End Sub Private Function ScreenDPI(ByVal bVert As Boolean) As Long Static lDPI(1), hDc If lDPI(0) = 0 Then hDc = GetDC(0) lDPI(0) = GetDeviceCaps(hDc, LOGPIXELSX) lDPI(1) = GetDeviceCaps(hDc, LOGPIXELSY) hDc = ReleaseDC(0, hDc) End If ScreenDPI = lDPI(Abs(bVert)) End Function Private Function PTtoPX(ByVal Points As Single, ByVal bVert As Boolean) As Long PTtoPX = Points * ScreenDPI(bVert) / POINTSPERINCH End Function Private Function GetRangeRect(ByVal Obj As Object) As RECT Dim oPane As Pane Set oPane = ThisWorkbook.Windows(1).ActivePane With Obj GetRangeRect.Left = oPane.PointsToScreenPixelsX(.Left) GetRangeRect.Top = oPane.PointsToScreenPixelsY(.Top) GetRangeRect.Right = oPane.PointsToScreenPixelsX(.Left + .Width - 2) GetRangeRect.Bottom = oPane.PointsToScreenPixelsY(.Top + .Height) End With End Function Private Function IsCellVisible(ByVal Cell As Range) As Boolean With Cell IsCellVisible = .Left >= ActiveWindow.VisibleRange.Left And .Top >= ActiveWindow.VisibleRange.Top End With End Function Private Sub SetDelay(ByVal TimeOut As Single) Dim t As Single t = Timer Do DoEvents Loop Until Timer - t >= TimeOut / 100 End Sub Private Sub Auto_Close() Dim Atom_ID As Integer, lRet As Long, sBuffer As String * 256 Dim sRangeAddr As String, sNumberFormat As String, lHorzAlignment As Long bScrolling = False bRangeRectHasChanged = False lXOffset = 0 DeleteObject hMemoryDC If GetProp(Application.hWnd, "CellAddress") Then Atom_ID = CInt(GetProp(Application.hWnd, "CellAddress")) lRet = GlobalGetAtomName(Atom_ID, sBuffer, Len(sBuffer)) sRangeAddr = Left(sBuffer, lRet) Atom_ID = CInt(GetProp(Application.hWnd, "NumberFormat")) lRet = GlobalGetAtomName(Atom_ID, sBuffer, Len(sBuffer)) sNumberFormat = Left(sBuffer, lRet) Atom_ID = CInt(GetProp(Application.hWnd, "HorzAlignment")) lRet = GlobalGetAtomName(Atom_ID, sBuffer, Len(sBuffer)) lHorzAlignment = CLng(Left(sBuffer, lRet)) Range(sRangeAddr).NumberFormat = sNumberFormat Range(sRangeAddr).HorizontalAlignment = lHorzAlignment RemoveProp Application.hWnd, "CellAddress" RemoveProp Application.hWnd, "NumberFormat" RemoveProp Application.hWnd, "HorzAlignment" End If End Sub
I am afraid, I know nothing about excel for Mac ...AFAIK, you cannot use Windows API calls on a Mac.Hi @Jaafar Tribak
The party seems to have ended but its never too late . Unfortunately I moved away from windows and this doesn't seem to work on Excel for Mac, is it possible you have a version that will work onExcel for Mac?
Thanks
Thanks for getting back with a response, appreciate it.I am afraid, I know nothing about excel for Mac ...AFAIK, you cannot use Windows API calls on a Mac.