I'm trying to draw a transparent form using GDI, by overiding the OnPaint and OnPaintBackground event handlers. This technique works well enough on the first draw,and it produces a nice result, however, on subsequent draws, it works less spectacularly. For some reason, the screen is never cleared, and when it redraws the new things are composited ontop the previous draws, making the transparent images darker and darker. Here is the contents of
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = null;
Assembly assembly = Assembly.GetExecutingAssembly();
Point point = new Point(400,400);
backBuffer = new Bitmap(Screen.GetWorkingArea(point).Width, Screen.GetWorkingArea(point).Height);
g = Graphics.FromImage(backBuffer);
g.Clear(Color.Transparent);
Stream imageStream = assembly.GetManifestResourceStream("program.background.png");
g.DrawImage(new Bitmap(imageStream), backgroundPicture.Location.X, backgroundPicture.Location.Y,
backgroundPicture.Width, backgroundPicture.Height);
if(linkType!=null)g.DrawImage(linkType, linkTypePictureRect);
g.DrawString(searchLabel.Text,new Font("Microsoft Sans Serif",14),Brushes.Black,searchLabelRect,
StringFormat.GenericTypographic);
g.Dispose();
e.Graphics.DrawImageUnscaled(backBuffer, 0, 0);
}
Can anyone tell me how I can fix this problem

GDI form transparency problem
leonste
Once loaded, try typing (backspace clears). You will see that upon each refresh the new paint get overlayed over the old one.
vbnewcomer
A little example i wrote out of the head, so there could be some error but you'll get the point:
protected override void OnPaint(PaintEventArgs e)
{
Assembly assembly = Assembly.GetExecutingAssembly();
Point point = new Point(400,400);
Bitmap backBuffer = new Bitmap(Screen.GetWorkingArea(point).Width, Screen.GetWorkingArea(point).Height);
using( Graphics g = Graphics.FromImage( backBuffer ) )
using( Stream imageStream = assembly.GetManifestResourceStream( "program.background.png" ) )
{
g.DrawImage(new Bitmap(imageStream), backgroundPicture.Location.X, backgroundPicture.Location.Y,
backgroundPicture.Width, backgroundPicture.Height);
if(linkType!=null)
{
g.DrawImage(linkType, linkTypePictureRect);
}
g.DrawString(searchLabel.Text,new Font("Microsoft Sans Serif",14),Brushes.Black,searchLabelRect,
StringFormat.GenericTypographic);
g.Flush( FlushIntention.Flush );
using(Bitmap toDraw = backBuffer.Clone( e.ClipRectangle, backBuffer.PixelFormat ))
{
e.Graphics.DrawImageUnscaled(backBuffer, e.ClipRectangle.Location );
}
}
}
Vramin
patti_
Ok. So it seems the problem is that you want to clear the backbuffer, but if you clear the backbuffer it'll paint a big square on your transparent form. You tried Clearing to Transparent but that Color has no meaning in this context.
To get what you're looking for I think this sample I devised might help.
It's not really well written I just threw it up quickly to verify my suggestion. If you clear the back buffer to the TransparencyKey of the form everything should be really happy :)
Public Class Form1
Public Sub New()
' This call is required by the Windows Form Designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me.BackColor = Color.Magenta
Me.TransparencyKey = Color.Magenta
End Sub
Private textDrawLocation As New Point(50, 75)
Private userText As New System.Text.StringBuilder()
Private myFont As New Font("Times New Roman", 36, FontStyle.Italic, GraphicsUnit.Point)
Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
Select Case e.KeyCode
Case Keys.Back
Me.userText.Remove(0, Me.userText.Length)
Me.Invalidate()
Case Is >= Keys.D0
Me.userText.Append(ChrW(e.KeyCode))
Me.Invalidate()
Case Else
'Not sure what to do at this point
End Select
End Sub
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
e.Graphics.Clear(Me.TransparencyKey)
e.Graphics.DrawString(Me.userText.ToString(), Me.myFont, Brushes.Green, Me.textDrawLocation)
End Sub
End Class
ckellner
So you can more accurately see the problem, here's the VS.2005 sample project linked to above.
David_A.
As for optimization, I have not spent much time on making it run better, trying to just get this to work and moving from there.
Incidentally, how do you get syntax highlighting in this forum I can't seem to find the option.
swatts777
You should not repaint pieces that don't ask for a repaint, when you paint transparency over transparency it will get darker and darker. But not only for this reason you should only paint what is needed, it is also better for the preformance.
BartVN
PAULL
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.Clear( TransparencyKey );
Assembly assembly = Assembly.GetExecutingAssembly();
Point point = new Point(400,400);
backBuffer = new Bitmap(Screen.GetWorkingArea(point).Width, Screen.GetWorkingArea(point).Height);
using(Graphics g = Graphics.FromImage(backBuffer) )
using(Stream imageStream = assembly.GetManifestResourceStream("program.background.png"))
{
g.Clear( TransparencyKey );
g.DrawImage(new Bitmap(imageStream), backgroundPicture.Location.X, backgroundPicture.Location.Y,
backgroundPicture.Width, backgroundPicture.Height);
if(linkType!=null)
{
g.DrawImage(linkType, linkTypePictureRect);
}
g.DrawString(searchLabel.Text,new Font("Microsoft Sans Serif",14),Brushes.Black,searchLabelRect,
StringFormat.GenericTypographic);
g.Flush( FlushIntention.Flush );
e.Graphics.DrawImageUnscaled(backBuffer, 0, 0);
}
}
umler
Odin_dark
Pete Sheill MSFT
...
Graphics g = null;
g = Graphics.FromImage(backBuffer);
g.Clear(Color.Transparent);
...
try:
...
Graphics g = e.Graphics;
g = Graphics.FromImage(backBuffer);
g.Clear(Color.Transparent);
...
this will get the graphics used to paint so you'll be clearing the area on which you want to draw the image first.
wilf
As a side note your code strikes me as inefficient. I thing you can cache the background image, font, and/or back buffer. Drawing code is tight. You probably want to test the tradeoff between generation promotion and repeated allocations.
If nothing else your code could stand some refactoring, documentation, and vertical whitespace.
Anyway, if you could describe more fully the exact effect you're aiming for we might better be able to help you produce it.
Akusei
Not sure myself. Would not the Form's Opacity property be a more concise tool for this
See:
http://msdn2.microsoft.com/en-us/library/system.windows.forms.form.opacity.aspx
I'm not sure of the nature of transparency on OS X. I mean I've seen it and it's fantastic but I don't know what granularity you expect.