'InValidateRect' API not working as expected !


R

RAFAAJ2000

here is a workbook demo:

Demo


Ok. Let me explain.

I have an Excel worksheet with a Source Cell and a Target Cell.

Via GDI API functions, I draw a temporary gradient fill over the source cell
which happens to be cell "D6".

then, I make a transparent copy of the temp gradient fill drawn over the
source cell and place the copy (ie the transparent gradient fill) over the
target cell which happens to be cell "D9".


Ultimatly, my goal is to have only the target cell with its transparent
gradient and get rid of the source gradient.

I am using the InValidateRect to erase the temp fill located over the source
cell by passing to the function the application hwnd and the exact Rect value
of the source cell (measured in screen pixels) .This is according to the API
tutorial. YET ,when called, InValidateRect either doesn't do anything
at all or redraw the entire screen instead of redrawing the source cell rect
only as expected.

Any help would be much appreciated.

Jaafar.
 
Ad

Advertisements

Ad

Advertisements

P

Peter T

Yes I see what you mean about InvalidateRect. At first I assumed the problem
was because you are doing everything to the desktop window, so sending say
the workbook window will obviously throw all the dimensions out.

I reworked your main routine and considerably simplified it, so as to paint
the gradient to the top left corner of app window and the blend to the
workbook window. Note SourceCell is not needed at all, indeed if
Source/Target row/col sizes are not same the results would be wrong.

' additional declarations
Private Declare Function GetWindowRect Lib "user32.dll" ( _
ByVal hwnd As Long, _
ByRef lpRect As RECT) As Long
Private Declare Function GetClientRect Lib "user32.dll" ( _
ByVal hwnd As Long, _
ByRef lpRect As RECT) As Long

Sub Test1()
MakeTransparentGradientCopyOfCell2 ActiveSheet.Range("d9")
End Sub

Sub MakeTransparentGradientCopyOfCell2(ByRef TargetCell As Range)
Dim BF As BLENDFUNCTION, lBF As Long
Dim vert(2) As TRIVERTEX
Dim gRect As GRADIENT_RECT

Dim tTargetCellRect As RECT
Dim hWndApp As Long, hdcApp As Long
Dim hWndXL7 As Long, hdcXL7 As Long
Dim rctXL7 As RECT, rctXL7inside As RECT
Dim bdr As Long

hWndApp = Application.hwnd
hWndXL7 = FindWindowEx( _
FindWindowEx(hWndApp, 0, "XLDESK", vbNullString), _
0&, "EXCEL7", vbNullString)

Call GetWindowRect(hWndXL7, rctXL7)
Call GetClientRect(hWndXL7, rctXL7inside)

' need to get the coordinates of the "inside" top-left
With rctXL7
' window border
bdr = (.Right - .Left - rctXL7inside.Right) / 2
rctXL7inside.Left = .Left + bdr

' window caption
bdr = (.Bottom - .Top - rctXL7inside.Bottom - bdr)
rctXL7inside.Top = .Top + bdr
End With

tTargetCellRect = GetCellRect(TargetCell)

With tTargetCellRect
tSourceCellRect.Left = 0
tSourceCellRect.Right = .Right - .Left
tSourceCellRect.Top = 0
tSourceCellRect.Bottom = .Bottom - .Top
End With

With tTargetCellRect
.Left = .Left - rctXL7inside.Left
.Right = .Right - rctXL7inside.Left
.Top = .Top - rctXL7inside.Top
.Bottom = .Bottom - rctXL7inside.Top
End With

' from Pink
With vert(1)
.x = tSourceCellRect.Left
.y = tSourceCellRect.Top
.Red = LongToUShort(&HFF00&)
.Green = 0
.Blue = LongToUShort(&HFF00&)
.Alpha = 0
End With

'to White
With vert(2)
.x = tSourceCellRect.Right
.y = tSourceCellRect.Bottom
.Red = LongToUShort(&HFF00&)
.Green = LongToUShort(&HFF00&)
.Blue = LongToUShort(&HFF00&)
.Alpha = 0
End With

' btw, no need to do those LongToUShort's,
' simply assign rgb(blue) to .red and rgb(red) to .blue

gRect.UpperLeft = 0
gRect.LowerRight = 1

hdcApp = GetDC(hWndApp)
hdcXL7 = GetDC(hWndXL7)

' paint the gradient to top-left of app-window
GradientFillRect hdcApp, vert(1), 2, gRect, 1, GRADIENT_FILL_RECT_H

With BF
.BlendOp = AC_SRC_OVER
.BlendFlags = 0
.SourceConstantAlpha = 110
.AlphaFormat = 0
End With

RtlMoveMemory lBF, BF, 4
'RedrawSourceCell

' paint the blend to the EXCEL7 window
With tSourceCellRect
AlphaBlend hdcXL7, _
tTargetCellRect.Left, tTargetCellRect.Top, _
(.Right - .Left), (.Bottom - .Top), _
hdcApp, .Left, .Top, _
.Right - .Left, .Bottom - .Top, lBF
End With

ReleaseDC hWndApp, hdcApp
ReleaseDC hWndXL7, hdcXL7

End Sub


I expected to be able to do this -

' note the "As Any"
Private Declare Function InvalidateRect _
Lib "user32" (ByVal hwnd As Long, _
lpRect As Any, ByVal bErase As Long) As Long

InvalidateRect Application.hwnd, ByVal 0&, 1

But it doesn't seem to work as expected, not sure why.

There's probably a simple reason. If not, other ways would be to paint the
gradient over say a temporary shape, then delete or hide the shape. (would
need to change the position and window of the gradient). I suspect though it
should be possible to paint the gradient to a 'virtual' window, possibly
with CreateCompatibleDC and maybe CreateCompatibleBitmap and SelectObject.
But that would take rather more than a few minutes to look into.

I hope you are not intending this for Excel 2007, which supports transparent
gradient fill formats (in a shape sized to the cell).

Regards,
Peter T



RAFAAJ2000 said:
here is a workbook demo:

Demo


Ok. Let me explain.

I have an Excel worksheet with a Source Cell and a Target Cell.

Via GDI API functions, I draw a temporary gradient fill over the source
cell
which happens to be cell "D6".

then, I make a transparent copy of the temp gradient fill drawn over the
source cell and place the copy (ie the transparent gradient fill) over the
target cell which happens to be cell "D9".


Ultimatly, my goal is to have only the target cell with its transparent
gradient and get rid of the source gradient.

I am using the InValidateRect to erase the temp fill located over the
source
cell by passing to the function the application hwnd and the exact Rect
value
of the source cell (measured in screen pixels) .This is according to the
API
tutorial. YET ,when called, InValidateRect either doesn't do
anything
at all or redraw the entire screen instead of redrawing the source cell
rect
only as expected.

Any help would be much appreciated.

Jaafar.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top