GDI form transparency problem

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


Answer this question

GDI form transparency problem

  • purplehaze

    The last sample i posted works for me when i do a little test. Doesn't it work on you side

    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.


  • bigshiny90

    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.



  • Abahay

    I played around with it myself and if I understand you right: Use the Form's TransparencyKey property to render its background completely transparent. If the background image has the same color for its background then you should see the image rendered on the nothingness of space, mwahahahaha! If you're trying to kill the border and title bar then you're gonna need to combine form shaping with the transparency key.

  • Yao-Jie Tang - MSFT

    As I said above, there is no transparecy key. The problem with using a transparency key is that it only provides on/off transparency, rather than full alpha transparency. My method is to not draw the background at all, which means that there is no background color to be set to transparent.

    So you can more accurately see the problem, here's the VS.2005 sample project linked to above.

  • David Smitty


    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);
    }
    }




  • laboremus

    That didn't do it. I still have the same issue.

  • Gn0MiCK

    No. The problem with the form opacity is that it makes everything transparent. The effect I'm trying to create is just the background being transparent. This, apparently, will be an easy effect to achieve with the WPF, but currently appears to be quite difficult. But it seems like there should be some way of surmounting my problem.

  • mjj0000

    I am still a little unclear as to what you're trying to accomplish. If it's simple transparency, Form has an Opacity property. Is this a watermarking What do you mean it works the first time

    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.


  • ViLiO

    I apologize for not being more specific. The effect I'm trying to acheive is a semi-transparent form overlayed on the desktop, a la many OS X applications. I'm doing this by overriding the OnPaintBackground call, and not drawing anything for that. The result is (for the first draw) a nicely composited image, but I can't figure out how to, in subsequent draws, clear the application from the screen before it redraws, essentially compositing the new draw on top of the previous ones. The effect is that transparent images get darker and darker, and text is drawn again on top the old text.

    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.

  • Tiduske

    Hi. instead of:

    ...
    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.


  • sbonomi

    I'm not using a transparency key. In fact, my form doesn't display anything; everything is drawn to the screen using GDI. Using the transparency key method allows for only 2bit transparency (AFAIK), while this method allows for alpha transparency. I've tried clearing the buffer using Color.Transparent, btu that (as far as I can tell) doesn't do anything.

  • cab15

    You are fully redrawing the whole Image. It is better to only redraw what is needed, i geus you will keep the correct transparency if you do that.

    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 );
    }
    }
    }




  • curious george2

    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



  • 喬伊

    I've made a sample application to show the problem I'm having, and what I'm trying to do. It can be downloaded here.

    Once loaded, try typing (backspace clears). You will see that upon each refresh the new paint get overlayed over the old one.

  • GDI form transparency problem