12
votes

I tried setting the opacity of my form to 50%, and then drawing a string on it. It seems that the string I draw on it also has an opacity of 50%. How would I draw a non transparent string , but let the form background show through 50%?

Would also be willing to do this in WPF if it is possible, but I would need explicit instructions or an example project as I have never done it before.

To clarify, I want the form background to be a black 80% opaque to what is underneath, and then I want to draw text, etc.. on it and have it appear 100% opaque.

7

7 Answers

19
votes

This is very easily done in WPF:

  1. Set WindowStyle="None" on the Window (note: this is required, you cannot have Transparency and the standard windows chrome)
  2. Set AllowsTransparency="True" on the Window
  3. Set a Background on the Window using a brush with transparency, such as Background="#AAFFFFFF"

Here's a quick sample:

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
Height="300" Width="300" AllowsTransparency="True" Background="#AAFFFFFF" WindowStyle="None">
<Grid>
    <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="20" FontWeight="Bold">Hello World!</TextBlock>
</Grid>

Now obviously, since you've disabled the standard Windows chrome, you will need to supply your own button to close/minimize/maximize/drag the window. You can do this pretty easily yourself or you could look into purchasing something like Blendables which comes with a "Chromeless Window" control that you could use.

1
votes

One workaround that comes to mind is to use two windows overlaid on top of one another. Render the "bottom" window at 50% opacity and then owner draw your text to a window overlaid on top of the other one. If you're doing lable-type displays this might be simple but might get complicated quickly if you need a lot of user input which might then need to get filtered down through to your "main" or "bottom" window.

So, i got it to work, but it's a little squirrelly. The two window solution seemed promissing until i discovered that .Net or Win32 does some weird auto parenting thing when you even implicitly refer to it. Probably has to do with the way the messages are pumped though. The main parent holds the application message pump and int guess is implicitly the parent...

i tried a bunch of workarounds but this timer thing below worked the best. In any case, it might be a clue as to doing it better...


// the "main" or transparent window. Notice it just sets and runs the timer
using System;
using System.Windows.Forms;
namespace TransparencyPlusNottransparentTest
{
    public partial class FormMain : Form
    {
        public FormMain()
        {
            InitializeComponent();
        }

    private void timer1_Tick(object sender, EventArgs e)
    {
        Program.ShowNontransparency();
    }
}

}

// the "top" or not transparent window. Notice it does owner draw on // transparent background. The design-time settings are also sans border etc. using System.Drawing; using System.Windows.Forms;

namespace TransparencyPlusNottransparentTest { public partial class FormTop : Form { public FormTop() { InitializeComponent(); BackColor = Color.Firebrick; TransparencyKey = Color.Firebrick; }

    private void FormTop_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.DrawString("Hello Whirrled!", new Font("Tahoma", 14f), Brushes.Black, 10f, 10f );
    }
}

}

// The control of this whole spiel. It instantiates both windows, // sets the main as the main app window and hosts the public // hacky method to force the non-transparent window to show up on top // and offset so it doesn't obscure the top of the main window. using System; using System.Drawing; using System.Windows.Forms;

namespace TransparencyPlusNottransparentTest { static class Program { private static FormMain _formMain; private static FormTop _formTop; private const int XY_OFFSET = 30;

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        _formTop = new FormTop();
        _formTop.Show(null);

        _formMain = new FormMain();

        Application.Run(_formMain);
    }

    public static void ShowNontransparency()
    {
        _formTop.Location = 
            new Point(
            _formMain.Location.X + XY_OFFSET, 
            _formMain.Location.Y + XY_OFFSET);

        _formTop.BringToFront();
    }
}

}

0
votes

in the ControlStyles enumeration MSDN there is a value called SupportsTransparentBackColor. In your form contructor run this:

SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.SupportsTransparentBackColor, true);

then you can set the background color to Color.Transparent.

Hope this helps.

0
votes

Use TransparencyKey to render the window as transparent. Create an empty panel with the background color of your and give it the desired opacity.

Then create all your children in a separate container/panel (itself a sibling to the translucent panel created above), and have it not render a background at all.

This should give you the effect of a translucent background but visible controls.

0
votes

In winforms, MSDN says this:

The Opacity property enables you to specify a level of transparency for the form and its controls. When this property is set to a value less than 100 percent (1.00), the entire form, including borders, is made more transparent.

So, any child controls of the form that you set opacity on will have their opacity changed. If you want to achieve different levels of opacity on individual controls, you'll have to switch to WPF.

0
votes

I assume that this is a WinForms project, though you said you’d be willing to try WPF.

Lemme switch to my lateral thinking cap: Any particular reason you couldn’t just fake it? As in, make a bitmap in PhotoShop Elements or Paint Shop Pro or some such that you will set as the entire background of the WinForm, and you simply draw the partially transparent area over which the controls will be placed right on that bitmap?