Transparent Background on Winforms

Transparent background on winforms?

The manner I have used before is to use a wild color (a color no one in their right mind would use) for the BackColor and then set the transparency key to that.

this.BackColor = Color.LimeGreen;
this.TransparencyKey = Color.LimeGreen;

WinForm transparent background text outline have the form background color

You have this problem:

SO70209408A

I've changed the Form's BackColor and TransparencyKey to Fuchsia, and the Label.ForeColor to Gray. Note how the TransparencyKey outlines the text. Here is a good explanation.

The suggested fix - commented above - is to draw the string yourself, Gdi+ way to have a control over the string rendering quality through the TextRenderingHint.SingleBitPerPixelGridFit hinting which provides a better antialiasing for this problem.

// +
// System.Drawing.Text;

private void lbl_Message_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(lbl_Message.BackColor);

using (var sf = new StringFormat())
using (var br = new SolidBrush(lbl_Message.ForeColor))
{
sf.Alignment = sf.LineAlignment = StringAlignment.Center;
e.Graphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
e.Graphics.DrawString(lbl_Message.Text, lbl_Message.Font, br,
lbl_Message.ClientRectangle, sf);
}
}

You'll get:

SO70209408B

How can I set a form to have a transparent background in c#?

Here's a code that may help you achieve what you are trying to do. The following code will make the form transparent but leave the controls visible. If you want to hide the controls as well, I suggest you set the form opacity to 0%

this.BackColor = Color.White;
this.TransparencyKey = Color.White;

Thanks,

I hope this helps :)

Transparent background image for Form - Smooth edge shape for the Form

You can use Layered Windows:

Using a layered window can significantly improve performance and
visual effects for a window that has a complex shape, animates its
shape, or wishes to use alpha blending effects. The system
automatically composes and repaints layered windows and the windows of
underlying applications. As a result, layered windows are rendered
smoothly, without the flickering typical of complex window regions. In
addition, layered windows can be partially translucent, that is,
alpha-blended.

Create layered window in Windows Forms

Here is some code from msdn code gallery which demonstrates creating Layered Windows in Windows Forms. It allows you to create a shaped splash screen and let you to move it by mouse.

Add PerPixelAlphaForm to the project and then it's enough to inherit from this form and call its SelectBitmap and pass your png to the method to create a layered window.

Sample Image

PerPixelAlphaForm.cs

#region Using directives
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
#endregion
namespace CSWinFormLayeredWindow
{
public partial class PerPixelAlphaForm : Form
{
public PerPixelAlphaForm()
{
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.ShowInTaskbar = false;
this.StartPosition = FormStartPosition.CenterScreen;
this.Load += PerPixelAlphaForm_Load;
}

void PerPixelAlphaForm_Load(object sender, EventArgs e)
{
this.TopMost = true;
}
protected override CreateParams CreateParams
{
get
{
// Add the layered extended style (WS_EX_LAYERED) to this window.
CreateParams createParams = base.CreateParams;
if(!DesignMode)
createParams.ExStyle |= WS_EX_LAYERED;
return createParams;
}
}
/// <summary>
/// Let Windows drag this window for us (thinks its hitting the title
/// bar of the window)
/// </summary>
/// <param name="message"></param>
protected override void WndProc(ref Message message)
{
if (message.Msg == WM_NCHITTEST)
{
// Tell Windows that the user is on the title bar (caption)
message.Result = (IntPtr)HTCAPTION;
}
else
{
base.WndProc(ref message);
}
}
/// <summary>
///
/// </summary>
/// <param name="bitmap"></param>
public void SelectBitmap(Bitmap bitmap)
{
SelectBitmap(bitmap, 255);
}
/// <summary>
///
/// </summary>
/// <param name="bitmap">
///
/// </param>
/// <param name="opacity">
/// Specifies an alpha transparency value to be used on the entire source
/// bitmap. The SourceConstantAlpha value is combined with any per-pixel
/// alpha values in the source bitmap. The value ranges from 0 to 255. If
/// you set SourceConstantAlpha to 0, it is assumed that your image is
/// transparent. When you only want to use per-pixel alpha values, set
/// the SourceConstantAlpha value to 255 (opaque).
/// </param>
public void SelectBitmap(Bitmap bitmap, int opacity)
{
// Does this bitmap contain an alpha channel?
if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
{
throw new ApplicationException("The bitmap must be 32bpp with alpha-channel.");
}

// Get device contexts
IntPtr screenDc = GetDC(IntPtr.Zero);
IntPtr memDc = CreateCompatibleDC(screenDc);
IntPtr hBitmap = IntPtr.Zero;
IntPtr hOldBitmap = IntPtr.Zero;

try
{
// Get handle to the new bitmap and select it into the current
// device context.
hBitmap = bitmap.GetHbitmap(Color.FromArgb(0));
hOldBitmap = SelectObject(memDc, hBitmap);

// Set parameters for layered window update.
Size newSize = new Size(bitmap.Width, bitmap.Height);
Point sourceLocation = new Point(0, 0);
Point newLocation = new Point(this.Left, this.Top);
BLENDFUNCTION blend = new BLENDFUNCTION();
blend.BlendOp = AC_SRC_OVER;
blend.BlendFlags = 0;
blend.SourceConstantAlpha = (byte)opacity;
blend.AlphaFormat = AC_SRC_ALPHA;

// Update the window.
UpdateLayeredWindow(
this.Handle, // Handle to the layered window
screenDc, // Handle to the screen DC
ref newLocation, // New screen position of the layered window
ref newSize, // New size of the layered window
memDc, // Handle to the layered window surface DC
ref sourceLocation, // Location of the layer in the DC
0, // Color key of the layered window
ref blend, // Transparency of the layered window
ULW_ALPHA // Use blend as the blend function
);
}
finally
{
// Release device context.
ReleaseDC(IntPtr.Zero, screenDc);
if (hBitmap != IntPtr.Zero)
{
SelectObject(memDc, hOldBitmap);
DeleteObject(hBitmap);
}
DeleteDC(memDc);
}
}
#region Native Methods and Structures

const Int32 WS_EX_LAYERED = 0x80000;
const Int32 HTCAPTION = 0x02;
const Int32 WM_NCHITTEST = 0x84;
const Int32 ULW_ALPHA = 0x02;
const byte AC_SRC_OVER = 0x00;
const byte AC_SRC_ALPHA = 0x01;

[StructLayout(LayoutKind.Sequential)]
struct Point
{
public Int32 x;
public Int32 y;

public Point(Int32 x, Int32 y)
{ this.x = x; this.y = y; }
}

[StructLayout(LayoutKind.Sequential)]
struct Size
{
public Int32 cx;
public Int32 cy;

public Size(Int32 cx, Int32 cy)
{ this.cx = cx; this.cy = cy; }
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct ARGB
{
public byte Blue;
public byte Green;
public byte Red;
public byte Alpha;
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct BLENDFUNCTION
{
public byte BlendOp;
public byte BlendFlags;
public byte SourceConstantAlpha;
public byte AlphaFormat;
}

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst,
ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc,
Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags);

[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr CreateCompatibleDC(IntPtr hDC);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr GetDC(IntPtr hWnd);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool DeleteDC(IntPtr hdc);

[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);

[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool DeleteObject(IntPtr hObject);

#endregion
}
}

SplashScreen.cs

public partial class Form4 : CSWinFormLayeredWindow.PerPixelAlphaForm
{
public Form4()
{
InitializeComponent();
this.SelectBitmap(Properties.Resources.splash);
}
}

Note

The original answer was based on turning double buffer off and overriding OnPaintBackground and drawing the image without calling base method. The answer had a known issue; while the form was moveless it was working well but if form was moving or the window behind the form was changed the window was not updating. You can see previous code in revisions. The current edit which is completely based on an MSDN code doesn't have any known issue.

How to make transparent background to ListBox?

What you can do should be something like:

Say, we want to create a transparent list box named TansparentListBox. So we need to derive a new class from the ListBox control, set some control styles to make it double buffered, prevent painting the background, and to say that we will do the painting ourselves:

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.ComponentModel;

[ToolboxBitmap(typeof(ListBox)),
DesignerCategory("")]
public class TransparentListBox : ListBox
{

public TransparentListBox() : base()
{
SetStyle(
ControlStyles.Opaque |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.ResizeRedraw |
ControlStyles.UserPaint |
ControlStyles.OptimizedDoubleBuffer, true);
DrawMode = DrawMode.OwnerDrawFixed;
}
//...

Now we need to override both the OnPaint and OnDrawItem events to do the drawing. The DrawThemeParentBackground function is required to copy the parent's background, just the region of our control. Also we have a new member, the SelectionBackColor property, the background color of the selected items:

    //...
public Color SelectionBackColor { get; set; } = Color.DarkOrange;

[DllImport("uxtheme", ExactSpelling = true)]
private extern static int DrawThemeParentBackground(
IntPtr hWnd,
IntPtr hdc,
ref Rectangle pRect
);

protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics;
var rec = ClientRectangle;

IntPtr hdc = g.GetHdc();
DrawThemeParentBackground(this.Handle, hdc, ref rec);
g.ReleaseHdc(hdc);

using (Region reg = new Region(e.ClipRectangle))
{
if (Items.Count > 0)
{
for (int i = 0; i < Items.Count; i++)
{
rec = GetItemRectangle(i);

if (e.ClipRectangle.IntersectsWith(rec))
{
if ((SelectionMode == SelectionMode.One && SelectedIndex == i) ||
(SelectionMode == SelectionMode.MultiSimple && SelectedIndices.Contains(i)) ||
(SelectionMode == SelectionMode.MultiExtended && SelectedIndices.Contains(i)))
OnDrawItem(new DrawItemEventArgs(g, Font, rec, i, DrawItemState.Selected, ForeColor, BackColor));
else
OnDrawItem(new DrawItemEventArgs(g, Font, rec, i, DrawItemState.Default, ForeColor, BackColor));

reg.Complement(rec);
}
}
}
}
}

protected override void OnDrawItem(DrawItemEventArgs e)
{
if (e.Index < 0) return;

var rec = e.Bounds;
var g = e.Graphics;

g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;

if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
using (SolidBrush sb = new SolidBrush(SelectionBackColor))
g.FillRectangle(sb, rec);

using (SolidBrush sb = new SolidBrush(ForeColor))
using (StringFormat sf = new StringFormat { Alignment = StringAlignment.Near, LineAlignment = StringAlignment.Center })
g.DrawString(GetItemText(Items[e.Index]), Font, sb, rec, sf);
}
//...

The hard part is done. To finish up, the drawing should be refreshed on occurrence of certain events, otherwise it will be a visual chaos:

    //...
protected override void OnSelectedIndexChanged(EventArgs e)
{
base.OnSelectedIndexChanged(e);
Invalidate();
}

protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
Invalidate();
}

protected override void OnMouseWheel(MouseEventArgs e)
{
base.OnMouseWheel(e);
Invalidate();
}
//...

Also, a refresh is required when using both, the vertical and horizontal scroll bars. Doing that is possible by overriding the WndProc since the ListBox control does not have any scroll events.

    //...
private const int WM_KILLFOCUS = 0x8;
private const int WM_VSCROLL = 0x115;
private const int WM_HSCROLL = 0x114;

protected override void WndProc(ref Message m)
{
if (m.Msg != WM_KILLFOCUS &&
(m.Msg == WM_HSCROLL || m.Msg == WM_VSCROLL))
Invalidate();
base.WndProc(ref m);
}
}

That's it. Puzzle up, rebuild and try.

TransparentListBox

C# Windows Forms semi-opacity

OP: If there is any other language / environment in which I can deal with
this problem, of course I am ready to try it.

So in addition to Windows Forms solutions, I'll share a WPF solution as well (which is a better framework to satisfy this requirement):

  • Windows Forms - Owned Forms
  • Windows Forms - Layered Windows
  • WPF - Transparent Form and Control Opacity

Windows Forms - Owned Forms

As an option you can use Owned Forms.

Each of the panels can be a top-level border-less Form owned by the main form. The main has a transparency key equal to its back color and those owned forms has opacity. This way you should handle moving of the main form and move the owned forms as well:

Sample Image

public partial class MyOwnerForm : Form
{
public MyOwnerForm()
{
InitializeComponent();
this.BackColor = Color.Magenta;
this.TransparencyKey = Color.Magenta;
this.StartPosition = FormStartPosition.Manual;
this.DesktopLocation = new Point(100, 100);
this.ClientSize = new Size(330, 330);
}
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
CreateForm(1, new Point(10, 10), new Size(150, 150)).Show();
CreateForm(0.75, new Point(170, 10), new Size(150, 150)).Show();
CreateForm(0.50, new Point(10, 170), new Size(150, 150)).Show();
CreateForm(0.25, new Point(170, 170), new Size(150, 150)).Show();
}
protected override void OnMove(EventArgs e)
{
base.OnMove(e);
if(OwnedForms.Length>0)
{
var p = PointToScreen(new Point(10, 10));
var dx = p.X - OwnedForms[0].Location.X;
var dy = p.Y - OwnedForms[0].Location.Y;
foreach (var f in OwnedForms)
f.Location= new Point(f.Location.X+dx, f.Location.Y+dy);
}
}
Form CreateForm(double opacity, Point location, Size size)
{
var f = new Form();
f.FormBorderStyle = FormBorderStyle.None;
f.BackColor = Color.Lime;
f.Opacity = opacity;
f.StartPosition = FormStartPosition.Manual;
f.DesktopLocation = PointToScreen(location);
f.ClientSize = size;
f.Owner = this;
f.ShowInTaskbar = false;
return f;
}
}

Windows Forms - Layered Windows

As an option you can use Layered Windows.

This way you can create the semi transparent image at run-time and set it as background image of your form. But your form will not receive any paint event and so hosting control on such form is pointless (however they are working and you somehow can force those control repaint).

Sample Image

public partial class MyLayeredForm : PerPixelAlphaForm
{
public MyLayeredForm()
{
InitializeComponent();
var bm = new Bitmap(230, 230);
using (var g = Graphics.FromImage(bm))
{
using (var b = new SolidBrush(Color.FromArgb(255, Color.Lime)))
g.FillRectangle(b, 10, 10, 100, 100);
using (var b = new SolidBrush(Color.FromArgb(255 * 75 / 100, Color.Lime)))
g.FillRectangle(b, 120, 10, 100, 100);
using (var b = new SolidBrush(Color.FromArgb(255 * 50 / 100, Color.Lime)))
g.FillRectangle(b, 10, 120, 100, 100);
using (var b = new SolidBrush(Color.FromArgb(255 * 25 / 100, Color.Lime)))
g.FillRectangle(b, 120, 120, 100, 100);
}
this.SelectBitmap(bm);
}
}

WPF - Transparent Form and Controls having Opacity

A better framework to satisfy such UI requirement is WPF.

To do so, you can set Background of window to Transparent and WindowStyle to None and set AllowTransparency to True. Also for each control you can simply set Opacity value:

Sample Image

<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="261.154" Width="232.923"
Background="Transparent" AllowsTransparency="True"
WindowStyle="None" WindowStartupLocation="CenterScreen">
<Grid Margin="0,0,0,0">
<Grid HorizontalAlignment="Left" Height="100"
Margin="10,10,0,0" VerticalAlignment="Top"
Width="100" Background="Lime" Opacity="1"/>
<Grid HorizontalAlignment="Left" Height="100"
Margin="120,10,0,0" VerticalAlignment="Top"
Width="100" Background="Lime" Opacity="0.75"
Grid.ColumnSpan="2"/>
<Grid HorizontalAlignment="Left" Height="100"
Margin="10,120,0,0" VerticalAlignment="Top"
Width="100" Background="Lime" Opacity="0.50"/>
<Grid HorizontalAlignment="Left" Height="100"
Margin="120,120,0,0" VerticalAlignment="Top"
Width="100" Background="Lime" Opacity="0.25"
Grid.ColumnSpan="2"/>
</Grid>
</Window>


Related Topics



Leave a reply



Submit