Groups | Blog | Home
all groups > dotnet drawing api > july 2004 >

dotnet drawing api : Autoscroll and background Painting



news.microsoft.com
7/12/2004 10:36:56 AM
I am painting a gradient background on a sizeable form. We are setting the
autoscroll margins so that the form scrolls when needed. However, when this
is done, if the user clicks on the scroll bar and drags it, then the
gradient doesn't paint correctly. Nothing I have tried seems to paint this
newly exposed region correctly with proper blend of the gradient.

Here is what I tried initially and is a good example of it not painting
properly when scrolled:

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

Dim HB As System.Drawing.Drawing2D.LinearGradientBrush

Dim r As Rectangle

r = Me.ClientRectangle

HB = New System.Drawing.Drawing2D.LinearGradientBrush(r, Color.White,
Color.LightSteelBlue, Drawing2D.LinearGradientMode.Vertical)

e.Graphics.FillRectangle(HB, r)

HB.Dispose()

End Sub

Then I tried creating an image and retrieving the rectangle that corresponds
to the clipped region without succuss:

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

Dim HB As System.Drawing.Drawing2D.LinearGradientBrush

Dim r As Rectangle

Dim img As Bitmap

Dim g As Graphics

r = Me.ClientRectangle

img = New Bitmap(Me.Width, Me.Height)

g = Graphics.FromImage(img)

HB = New System.Drawing.Drawing2D.LinearGradientBrush(r, Color.White,
Color.LightSteelBlue, Drawing2D.LinearGradientMode.Vertical)

g.FillRectangle(HB, r)

e.Graphics.DrawImage(img, e.ClipRectangle, e.ClipRectangle,
GraphicsUnit.Pixel)

g.Dispose()

HB.Dispose()

End Sub

Does anyone see where I have gone wrong or have the solution that I am
looking for?

Thanks, Brian



Bob Powell [MVP]
7/12/2004 7:43:26 PM
You need to remember that the autoscroll function is providing you with a
window onto a virtual client area that is larger than the visible area of
the page. You have to compensate for this and the position of the scroll
bars in any painting you do.

I suspect that the area you want to fill is really the size of the
auto-scroll minimum sizes so you might do something like this to create the
brush...

dim cr as new Rectangle(0,0,me.AutoScrollMinSize.Width,
Me.AutoScrollMinSize.Height)
HB = New System.Drawing.Drawing2D.LinearGradientBrush(cr,
Color.White,Color.LightSteelBlue, Drawing2D.LinearGradientMode.Vertical)

Now you can compensate for the scroll positions

dim mx as new Matrix(1,0,0,me.AutoScrollPosition.X, me.AutoScrollPosition.Y)
e.Graphics.Transform=mx
e.Graphics.FillRectangle(HB,cr)

this can be used in the Paint or OnPaintBackground override.

--
Bob Powell [MVP]
Visual C#, System.Drawing

The Image Transition Library wraps up and LED style instrumentation is
available in the June of Well Formed for C# or VB programmers
http://www.bobpowell.net/currentissue.htm

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/gdiplus_faq.htm

The GDI+ FAQ RSS feed: http://www.bobpowell.net/faqfeed.xml
Windows Forms Tips and Tricks RSS: http://www.bobpowell.net/tipstricks.xml
Bob's Blog: http://bobpowelldotnet.blogspot.com/atom.xml






[quoted text, click to view]

news.microsoft.com
7/13/2004 8:04:02 AM
Thanks for the code snippet. That did the trick. However, that brought up a
couple other interesting "features". It appears that any controls that have
their back color set to transparent are now taking the upper left visible
corner of the form for their backcolor regardless of the size of the form
and regardless if scrollbars are needed or not. This seems to be because of
the matrix that is applied to the graphic object's transform. I was able to
mix the code snippet you provided and some things that I was trying
previously and come up with a workaround:

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
Dim HB As System.Drawing.Drawing2D.LinearGradientBrush
Dim cr As New Rectangle(0, 0, 0, 0)
Dim NeedsImage As Boolean

If Me.Width <= Me.AutoScrollMinSize.Width Then
cr.Width = Me.AutoScrollMinSize.Width
NeedsImage = True
Else
cr.Width = Me.Width
End If

If Me.Height <= Me.AutoScrollMinSize.Height Then
cr.Height = Me.AutoScrollMinSize.Height
NeedsImage = True
Else
cr.Height = Me.Height
End If

HB = New System.Drawing.Drawing2D.LinearGradientBrush(cr,
Color.WhiteSmoke, Color.Orange, Drawing2D.LinearGradientMode.Vertical)

If NeedsImage = True Then
Dim img As New Bitmap(cr.Width, cr.Height)
Dim g As Graphics
Dim mx As New System.Drawing.Drawing2D.Matrix(1, 0, 0, 1,
Me.AutoScrollPosition.X, Me.AutoScrollPosition.Y)

g = Graphics.FromImage(img)
g.Transform = mx
g.FillRectangle(HB, cr)
e.Graphics.DrawImage(img, e.ClipRectangle, e.ClipRectangle,
GraphicsUnit.Pixel)
img.Dispose()
g.Dispose()
Else
e.Graphics.FillRectangle(HB, cr)
End If

HB.Dispose()


End Sub


This seems to work but with a little bit of flicker at times, even with
doublebuffering set. My questions now would be:
1. Are their any other drawbacks to this solution.
2. Is there a way to "change" the graphics object to what it was before the
new transform was set. I tried a couple things that were unsuccesful. It
seems to me
that once the matrix has been applied to the graphics object, it throws
something out of sync when the controls start painting.

news.microsoft.com
7/13/2004 9:19:08 AM
After messing with this a little more, I have found what may be a much
better solution. Here is what I have come up with. This seems to take care
of the
window offset without causing a problem with other controls that are set
with a transparent background.

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
Dim HB As System.Drawing.Drawing2D.LinearGradientBrush
Dim cr As New Rectangle(0, 0, 0, 0)
Dim NeedsImage As Boolean

If Me.Width <= Me.AutoScrollMinSize.Width Then
cr.Width = Me.AutoScrollMinSize.Width
NeedsImage = True
Else
cr.Width = Me.Width
End If

If Me.Height <= Me.AutoScrollMinSize.Height Then
cr.Height = Me.AutoScrollMinSize.Height
NeedsImage = True
Else
cr.Height = Me.Height
End If

HB = New System.Drawing.Drawing2D.LinearGradientBrush(cr,
Color.WhiteSmoke, Color.Orange, Drawing2D.LinearGradientMode.Vertical)

e.Graphics.TranslateTransform(Me.AutoScrollPosition.X,
Me.AutoScrollPosition.Y)

e.Graphics.FillRectangle(HB, cr)

HB.Dispose()

End Sub


Thanks,
Brian

AddThis Social Bookmark Button