Any Trick to Use Opacity on a Panel in Visual Studio Window Form

How can I set the opacity or transparency of a Panel in WinForms?

Yes, opacity can only work on top-level windows. It uses a hardware feature of the video adapter, that doesn't support child windows, like Panel. The only top-level Control derived class in Winforms is Form.

Several of the 'pure' Winform controls, the ones that do their own painting instead of letting a native Windows control do the job, do however support a transparent BackColor. Panel is one of them. It uses a trick, it asks the Parent to draw itself to produce the background pixels. One side-effect of this trick is that overlapping controls doesn't work, you only see the parent pixels, not the overlapped controls.

This sample form shows it at work:

public partial class Form1 : Form {
public Form1() {
InitializeComponent();
this.BackColor = Color.White;
panel1.BackColor = Color.FromArgb(25, Color.Black);
}
protected override void OnPaint(PaintEventArgs e) {
e.Graphics.DrawLine(Pens.Yellow, 0, 0, 100, 100);
}
}

If that's not good enough then you need to consider stacking forms on top of each other. Like this.

Notable perhaps is that this restriction is lifted in Windows 8. It no longer uses the video adapter overlay feature and DWM (aka Aero) cannot be turned off anymore. Which makes opacity/transparency on child windows easy to implement. Relying on this is of course future-music for a while to come. Windows 7 will be the next XP :)

C# Transparency Isn't Affecting Panel

The first link that @Reza Aghaei sent me worked!

Here it is: https://stackoverflow.com/a/32402532/6804700

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:

enter image description here

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

enter image description here

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:

enter image description here

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

Creating semi-transparent panels/controls. Is there a foolproof way?

I have done a few tests now.

You are mixiing several problems into one, so let's take them apart:

  • No WebBrowser is written in C# using Winforms. So this is no reason why this must be possible.

  • Your button almost certainly is not in the Form's Controls collection. You need to either script it to be or use a little UI trick (*) to place it over another Control without adding it to it.

  • When you scroll you will see whatever the scrolling control report as its surface.

Here are two screenshots:

This is after startup:

screenshot1

..and this is after I scrolled a little to the right:

screenshot1

I have use this code to make sure the Z-order is right:

button1.Parent = this;
panel1.BringToFront();
button1.BringToFront();
seeThroughPanel1.BringToFront();

Note how the the space of the button is spared; this shows how the old surface is being used.

To work around this you would have to get at the current Form surfacse (maybe by Control.DrawToBitmap) and then use the right part of that to paint your 'semi-transparent' panel. Of course it would have to hide before you capture the form's current surface.

Of all terrible ideas I have had, this seems to be one of the worst..

* The trick is to move it over the container with the keyboard, not the mouse; with this trick it just moves without chnging its parent container. Also useful for placing a Control on top of the tabs of a TabControl... But I was too lazy for that, so I coded it..

Show a Label with semi-transparent BackColor above other controls?

To have a transparent label control, you can override the OnPaint method and draw all controls that intersects with label, at last draw the background and text of the label.

Also when moving your picture boxes, don't forget to call the Invalidate() method of the transparent label.

Screenshot

enter image description here

Sample Implementation

public class TransparentLabel : Label
{
public TransparentLabel()
{
this.transparentBackColor = Color.Blue;
this.opacity = 50;
this.BackColor = Color.Transparent;
}
protected override void OnPaint(PaintEventArgs e)
{
if (Parent != null)
{
using (var bmp = new Bitmap(Parent.Width, Parent.Height))
{
Parent.Controls.Cast<Control>()
.Where(c => Parent.Controls.GetChildIndex(c) > Parent.Controls.GetChildIndex(this))
.Where(c => c.Bounds.IntersectsWith(this.Bounds))
.OrderByDescending(c => Parent.Controls.GetChildIndex(c))
.ToList()
.ForEach(c => c.DrawToBitmap(bmp, c.Bounds));

e.Graphics.DrawImage(bmp, -Left, -Top);
using (var b = new SolidBrush(Color.FromArgb(this.Opacity, this.TransparentBackColor)))
{
e.Graphics.FillRectangle(b, this.ClientRectangle);
}
e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
TextRenderer.DrawText(e.Graphics, this.Text, this.Font, this.ClientRectangle, this.ForeColor, Color.Transparent);
}
}
}

private int opacity;
public int Opacity
{
get { return opacity; }
set
{
if (value >= 0 && value <= 255)
opacity = value;
this.Invalidate();
}
}

public Color transparentBackColor;
public Color TransparentBackColor
{
get { return transparentBackColor; }
set
{
transparentBackColor = value;
this.Invalidate();
}
}

[Browsable(false)]
public override Color BackColor
{
get
{
return Color.Transparent;
}
set
{
base.BackColor = Color.Transparent;
}
}
}

How to create a partially transparent panel in c# windows application

You need to use: Aero desktop experience and you can find info in: Create Special Effects With The Desktop Window Manager

    using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace FixedFormWithAeroGlass
{
public class Form1 : Form
{
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct DWM_BLURBEHIND
{
public uint dwFlags;
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
public bool fEnable;
public IntPtr hRegionBlur;
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
public bool fTransitionOnMaximized;

public const uint DWM_BB_ENABLE = 0x00000001;
public const uint DWM_BB_BLURREGION = 0x00000002;
public const uint DWM_BB_TRANSITIONONMAXIMIZED = 0x00000004;
}

[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct RECT
{
public int left, top, right, bottom;

public RECT(int left, int top, int right, int bottom)
{
this.left = left; this.top = top;
this.right = right; this.bottom = bottom;
}
}

[System.Runtime.InteropServices.DllImport("dwmapi.dll", PreserveSig = false)]
public static extern int DwmEnableBlurBehindWindow(System.IntPtr hWnd, ref DWM_BLURBEHIND pBlurBehind);

public const int DWM_BB_ENABLE = 0x1;
public const int DWM_BB_BLURREGION = 0x2;
public const int DWM_BB_TRANSITIONONMAXIMIZED = 0x4;

private System.ComponentModel.IContainer components = null;

public Form1()
{
InitializeComponent();

FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
}

#region Windows Form Designer generated code

private void InitializeComponent()
{
this.SuspendLayout();
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(470, 342);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Name = "Form1";
this.ResumeLayout(false);

}

#endregion

protected override void OnPaintBackground(PaintEventArgs e)
{
base.OnPaintBackground(e);

e.Graphics.Clear(BackColor);
using (Brush b = new SolidBrush(Color.FromArgb(196, Color.Black)))
e.Graphics.FillRectangle(b, ClientRectangle);
}

protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);

DWM_BLURBEHIND dbb;
dbb.fEnable = true;
dbb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;

using (Graphics g = CreateGraphics())
dbb.hRegionBlur = new Region(new Rectangle(0, 0, Width, Height)).GetHrgn(g);

dbb.fTransitionOnMaximized = false;

DwmEnableBlurBehindWindow(this.Handle, ref dbb);
}

protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
}
}

and an example of a window with controls

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace AddingControlsInAeroStyleForm
{
public class Form1 : Form
{
[System.Runtime.InteropServices.DllImport("dwmapi.dll", PreserveSig = false)]
public static extern void DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMargins);

[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct MARGINS
{
public int Left, Right, Top, Bottom;

public MARGINS(int left, int top, int right, int bottom)
{
Left = left;
Top = top;
Right = right;
Bottom = bottom;
}

public MARGINS(int margin)
{
Left = margin;
Top = margin;
Right = margin;
Bottom = margin;
}
}

private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Button button1;

/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;

public Form1()
{
InitializeComponent();

MARGINS margins = new MARGINS(-1);

DwmExtendFrameIntoClientArea(this.Handle, ref margins);
}

private void Form1_Load(object sender, EventArgs e)
{
this.TransparencyKey = Color.FromArgb(255, Color.Black);
panel1.BackColor = Color.FromArgb(255, Color.Black);

}

/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}

#region Windows Form Designer generated code

/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.panel1 = new System.Windows.Forms.Panel();
this.button1 = new System.Windows.Forms.Button();
this.panel1.SuspendLayout();
this.SuspendLayout();
//
// panel1
//
this.panel1.Controls.Add(this.button1);
this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel1.Location = new System.Drawing.Point(0, 0);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(374, 303);
this.panel1.TabIndex = 0;
//
// button1
//
this.button1.FlatAppearance.BorderSize = 0;
this.button1.Location = new System.Drawing.Point(202, 23);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(125, 70);
this.button1.TabIndex = 0;
this.button1.UseVisualStyleBackColor = true;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(374, 303);
this.Controls.Add(this.panel1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.panel1.ResumeLayout(false);
this.ResumeLayout(false);

}

#endregion

}
}


Related Topics



Leave a reply



Submit