C# Windows 窗体半透明

Posted

技术标签:

【中文标题】C# Windows 窗体半透明【英文标题】:C# Windows Forms semi-opacity 【发布时间】:2018-12-03 08:41:05 【问题描述】:

我已经阅读了很多关于 C# 中 Windows 窗体的不透明度/透明度的主题,但这不是我想要的效果。我希望Form 是 100% 透明的,但 Panel 的透明度是可调节的,并且透明效果被转移到 Form 后面的元素(Windows 桌面、Web 浏览器等)。所附照片显示了我想要获得的效果(我在图形程序中制作它们)。我会很感激你的帮助。

【问题讨论】:

每个面板都可以是由Form1 拥有的***无边框FormForm1 具有与其背景颜色相同的透明度键,并且那些拥有的表单具有不透明度。 这个想法看起来不错,但不幸的是它不起作用。我不知道我是否理解得很好。我这样做是为了设置 Form1.IsMdiContainer = true 和 Form1.TransparencyKey = Color.FromArgb(171, 171, 171) (当 Form 为 MdiContainer 时等于背景颜色)。不幸的是,这并没有给出预期的结果,因为 Form1 不透明。我不知道 Form1 是 IsMdiContainer 时透明度是否不起作用。除非我做了 Form1 拥有的 Form2,否则 Form2 参数 Opacity 不会改变 Form2 的透明度。 拥有的表单与 MDIchildren 不同。它们不是以所有者形式托管的。他们只是在所有者表格之上。你应该把它们放在一起。 您的另一个选择是使用layered windows。这样,您可以在运行时创建半透明图像并将其设置为表单的背景图像。但是您的表单将不会收到任何绘制事件,因此在此类表单上托管控件毫无意义(但是您可以通过某种方式使这些控件正常工作)。 根据你这里的评论→OP:如果有其他语言/环境可以处理>这个问题,我当然准备试试。 i> 我建议你使用WPF 【参考方案1】:

面板没有 opacity 属性。为了使面板透明,您应该使用这样的自定义面板...

Imports System.ComponentModel

Partial Public Class C_PANEL
Inherits Panel
Private Const WS_EX_TRANSPARENT As Integer = &H20

Public Sub NewP()
    SetStyle(ControlStyles.Opaque, True)
End Sub

Public Sub NewP(con As IContainer)
    con.Add(Me)
End Sub

Private iopacity As Integer = 50
<DefaultValue(50)>

Public Property Opacity() As Integer
    Get
        Return Me.iopacity
    End Get

    Set(value As Integer)
        If Value < 0 OrElse Value > 100 Then
            Throw New ArgumentException("value must be between 0 and 100")
        End If
        Me.iopacity = Value
    End Set
End Property

Protected Overrides ReadOnly Property CreateParams() _
          As CreateParams
    Get
        Dim cpar As CreateParams = MyBase.CreateParams
        cpar.ExStyle = cpar.ExStyle Or WS_EX_TRANSPARENT
        Return cpar
    End Get
End Property

Protected Overrides Sub OnPaint(e As PaintEventArgs)
    Using brush = New SolidBrush(Color.FromArgb(Me.Opacity _
          * 255 / 100, Me.BackColor))
        e.Graphics.FillRectangle(brush, Me.ClientRectangle)
    End Using
    MyBase.OnPaint(e)
End Sub

End Class

创建此控件后,您可以将此面板添加到表单中,并可以根据您的设置设置不透明度。

并且表单有自己的 opacity 属性,可以轻松设置。

【讨论】:

问题标记为 C#,而不是 VB。 您可以使用 carlosag 转换器将此代码转换为 c# 代码。我认为这个想法足以解决问题而不是代码.. ;) 没错,问题是关于 C#,而不是 VB,但没关系,因为我在 C# 中看到了相同的解决方案,但它并没有像我想要的那样工作。使用此解决方案,透明度仅适用于本地,仅适用于 Form 上的元素。整个 Panel 对桌面不透明。下面我附上这个解决方案的外观。 link “问题是关于 C#,而不是 VB”@grzenio_l,你的问题围绕着操纵 WinForm 控件来达到预期的效果。用于实现该解决方案的 .Net 语言应该是无关紧要的。为什么你会选择限制获得解决方案的可能性只是为了强加个人偏好? 我将使用哪种语言并不重要。我正在学习使用 C# 语言,因为我有使用 C 和 C++ 编写微控制器的经验,而 C# 最接近这种语言。如果有其他语言/环境我可以处理这个问题,当然我准备尝试一下,虽然VB语言的语法对我来说不是很清楚,我宁愿避免。【参考方案2】:

OP: 如果有其他语言/环境我可以处理 这个问题,我当然准备试试了。

所以除了 Windows Forms 解决方案之外,我还会分享一个 WPF 解决方案(这是一个更好的框架来满足这个要求):

Windows 窗体 - 拥有的窗体 Windows 窗体 - 分层窗口 WPF - 透明表单和控制不透明度

Windows 窗体 - 拥有的窗体

作为一个选项,您可以使用自有表单。

每个面板都可以是主窗体拥有的***无边框窗体。主窗体具有与其背景颜色相同的透明度键,而那些拥有的窗体具有不透明度。这样,您应该处理主表单的移动并同时移动拥有的表单:

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 窗体 - 分层窗口

作为一个选项,您可以使用Layered Windows。

这样您可以在运行时创建半透明图像并将其设置为表单的背景图像。但是您的表单不会收到任何绘制事件,因此在此类表单上托管控件是没有意义的(但是它们正在工作并且您可以以某种方式强制这些控件重新绘制)。

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 - 具有不透明度的透明表单和控件

满足此类 UI 要求的更好框架是 WPF。

为此,您可以将窗口的Background 设置为Transparent,将WindowStyle 设置为None,并将AllowTransparency 设置为True。同样对于每个控件,您可以简单地设置Opacity 值:

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

【讨论】:

非常感谢您的帮助,您给了我很多有用的信息。对于我的项目,我不需要使用控件(按钮、文本框),因此“Windows 窗体 - 分层 Windows”解决方案可能很好。我已经尝试过这个解决方案并且效果很好,但是当我下班回家时我会对其进行更多测试。我也会尝试“WPF”。不幸的是,我的评分没有足够的声誉被包括在内。 不客气。不用担心,通过提出好问题或分享好答案,您将获得更多声誉。 和 *** 一样,我们周围有一些不可见的反对者! 我认为不仅在***上:P 好的,@RezaAghaei,我知道这是一篇旧帖子。我使用 PixelPerAlpha 版本来显示我的启动画面。如何使用该表单的标签来显示一些进展?我的意思是显示一个标签并能够从主窗体更改其文本。怎么重画?!您在回答中这么说!

以上是关于C# Windows 窗体半透明的主要内容,如果未能解决你的问题,请参考以下文章

在具有一些控件的 Windows 窗体上绘制半透明覆盖图像

如何在C#中画半透明的圆?

delphi 怎样绘制半透明窗体,只让窗体背景半透明,而窗体里面的控件 不透明

求助,关于Qt的窗口半透明,窗口上的空间不透明

一个用UpdateLayeredWindow实现窗体半透明的delphi的代码

QT主窗体半透明实现