C# 中部分透明的启动画面

问题描述 投票:0回答:4

我正在尝试为我的应用程序制作一个启动屏幕。我有一个 .PNG 图像,其中有一些部分透明的部分。

我已将表单设为无边框并禁用了控制框。然而,背景颜色引起了问题。

首先我将图像放入图片框中。然后我这样使表单背景透明:

this.BackColor = Color.Magenta;
this.TransparencyKey = Color.Magenta;

这确实有效。屏幕的完全透明部分是透明的,但在部分透明部分可以看到洋红色。

然后我尝试将图像作为表单的背景图像。我尝试使用此代码使表单的背景透明:

private void Form1_Load(object sender, EventArgs e)
{
   this.SetStyle(System.Windows.Forms.ControlStyles.SupportsTransparentBackColor, true);
   this.BackColor = System.Drawing.Color.Transparent;
}

也没有用。背景仍然不透明。 我能做什么?

c# winforms
4个回答
3
投票

为什么是洋红色? 尝试使用白色。 我将背景颜色设置为白色,透明度键设置为白色。 下图中,带有图片的随机框是我的启动项。

Results


3
投票

TransparencyKey
将把表单设置为完全不透明,除了指定的确切颜色的pixels。据我所知,它通过实际定义
WindowRegion
来实现这一点,即基于与颜色匹配的像素的窗口形状 - 这些像素不再是窗口的一部分,可以单击。

听起来你的 PNG 有一个 alpha 层,即透明度级别 0..255,它与背景颜色(洋红色)混合,之后只有纯洋红色像素变得透明。

你可以尝试:

  • 选择一种颜色,例如
    Magenta
    未在您的启动画面中使用,并将其放入您的启动画面 PNG 中,代替完全透明区域作为不透明像素
  • 在窗口显示之前在窗口下捕获桌面位图的副本,并将其放在启动画面下的
    PictureBox
    中。

飞溅的部分透明区域将与背景图像混合,完全透明的区域将匹配

TransparencyKey
并且是透明的。

但是,如果在显示启动画面时桌面的其余部分发生变化,如果启动画面移动等,您将获得视觉假象。

编辑:似乎有一个更简单的解决方案here,无需使用

TransparencyKey


2
投票

您可以使用

layered windows
UpdateLayeredWindow()
Api 来完成它:

protected override CreateParams CreateParams
{
    get
    {
        // Add the layered extended style (WS_EX_LAYERED) to this window
        CreateParams createParam = base.CreateParams;
        createParam.ExStyle = (createParam.ExStyle | APIHelp.WS_EX_LAYERED);
        return createParam;
    }
}

并以您的形式

load event

IntPtr memDc, hBmp, hOldBmp;

private void Form1_Load(object sender, EventArgs e)
{
    APIHelp.BLENDFUNCTION blend;

    //Only works with a 32bpp bitmap
    blend.BlendOp = APIHelp.AC_SRC_OVER;
    //Always 0
    blend.BlendFlags = 0;
    //Set to 255 for per-pixel alpha values
    blend.SourceConstantAlpha = 255;
    //Only works when the bitmap contains an alpha channel
    blend.AlphaFormat = APIHelp.AC_SRC_ALPHA;

    IntPtr screenDc;

    screenDc = APIHelp.GetDC(IntPtr.Zero);

    Bitmap bmp;

    using (bmp = (Bitmap)Bitmap.FromFile(@"C:\.......png")) //the image must be the same size as your form
    {
        memDc = APIHelp.CreateCompatibleDC(screenDc);
        hBmp = bmp.GetHbitmap(Color.FromArgb(0));
        hOldBmp = APIHelp.SelectObject(memDc, hBmp); //memDc is a device context that contains our image
    }

    APIHelp.DeleteDC(screenDc);

    APIHelp.Size newSize;
    APIHelp.Point newLocation;
    APIHelp.Point sourceLocation;

    newLocation.x = this.Location.X;
    newLocation.y = this.Location.Y;

    sourceLocation.x = 0;
    sourceLocation.y = 0;

    newSize.cx = this.Width;
    newSize.cy = this.Height;

    APIHelp.UpdateLayeredWindow(Handle, IntPtr.Zero, ref newLocation, ref newSize, memDc, ref sourceLocation, 
           0, ref blend, APIHelp.ULW_ALPHA);
}

类API帮助:

class APIHelp
{
    public const Int32 WS_EX_LAYERED = 524288;
    public const Int32 ULW_ALPHA = 2;
    public const byte AC_SRC_OVER = 0;
    public const byte AC_SRC_ALPHA = 1;

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

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

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

    [StructLayout(LayoutKind.Sequential)]
    public struct BLENDFUNCTION
    {
        public Byte BlendOp;
        public Byte BlendFlags;
        public Byte SourceConstantAlpha;
        public Byte AlphaFormat;
    }

    [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst,
       ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pptSrc, uint crKey,
       [In] ref BLENDFUNCTION pblend, uint dwFlags);


    [DllImport("gdi32.dll", EntryPoint = "CreateCompatibleDC", SetLastError = true)]
    public static extern IntPtr CreateCompatibleDC([In] IntPtr hdc);

    [DllImport("gdi32.dll", EntryPoint = "SelectObject")]
    public static extern IntPtr SelectObject([In] IntPtr hdc, [In] IntPtr hgdiobj);

    [DllImport("user32.dll")]
    public static extern IntPtr GetDC(IntPtr hWnd);

    [DllImport("gdi32.dll", EntryPoint = "DeleteDC")]
    public static extern bool DeleteDC([In] IntPtr hdc);

    [DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool DeleteObject([In] IntPtr hObject);
}

当表单关闭时释放资源:

APIHelp.SelectObject(memDc, hOldBmp);
APIHelp.DeleteObject(hBmp);
APIHelp.DeleteDC(memDc);

0
投票

大家好,这里是更新的代码。 我添加了代码的缺失部分,将其从启动屏幕转换为表单 1-计时器更新表单图像 调整 2 个图像大小以匹配表单大小 3-当表单上没有背面图像时自定义绘制 4-在更新后的图像上绘制控件以显示所有具有更新状态的控件 5-WndProc 用于拖动表单并调整其大小

但是这段代码需要一些内存管理来减少内存使用 如果有人知道如何做,请更新此代码

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

namespace Amro_Omran
{
    public partial class Form2 : Form
    {
        IntPtr memDc, hBmp, hOldBmp;
        Bitmap backgroundBmp;
        Timer refreshTimer;

        public Form2()
        {
            InitializeComponent();
            this.FormBorderStyle = FormBorderStyle.None; // Remove the form border
            InitializeTimer();
            this.Load += Form2_Load;
        }

        const Int32 HTCAPTION = 0x02; // Identifier for the window title bar
        const Int32 WM_NCHITTEST = 0x84;

        protected override void WndProc(ref Message message)
        {
            if (message.Msg == WM_NCHITTEST)
            {
                // Inform Windows that the user is on the title bar (to allow dragging)
                message.Result = (IntPtr)HTCAPTION;
            }
            else
            {
                base.WndProc(ref message);
            }
        }

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams createParam = base.CreateParams;
                createParam.ExStyle |= APIHelp.WS_EX_LAYERED; // Set the window as a layered window for transparency
                return createParam;
            }
        }

        private void Form2_Load(object sender, EventArgs e)
        {
            SetupBackgroundImage();
            DrawControlsOnBackground();
            ApplyTransparency();
        }

        private void InitializeTimer()
        {
            refreshTimer = new Timer();
            refreshTimer.Interval = 500; // Refresh every 0.5 seconds
            refreshTimer.Tick += (s, e) => { UpdateBackground(); };
            refreshTimer.Start();
        }

        private void SetupBackgroundImage()
        {
            // Dispose of any existing background image to avoid memory leaks
            if (backgroundBmp != null)
            {
                backgroundBmp.Dispose();
            }

            if (this.BackgroundImage != null)
            {
                // Use the form's current background, resizing it to fit the form
                backgroundBmp = ResizeImage(new Bitmap(this.BackgroundImage), this.Width, this.Height);
            }
            else
            {
                // Create a transparent background with a specified color if no image is present
                backgroundBmp = new Bitmap(this.Width, this.Height);
                using (Graphics g = Graphics.FromImage(backgroundBmp))
                {
                    g.Clear(Color.FromArgb(128, 0, 0, 0)); // Transparent background
                    using (Pen borderPen = new Pen(Color.Black, 2))
                    {
                        g.DrawRectangle(borderPen, 0, 0, this.Width - 1, this.Height - 1); // Draw a border
                    }
                }
            }
        }

        private void DrawControlsOnBackground()
        {
            // Draw all form controls onto the background image
            using (Graphics g = Graphics.FromImage(backgroundBmp))
            {
                foreach (Control ctrl in Controls)
                {
                    Bitmap controlBmp = new Bitmap(ctrl.Width, ctrl.Height);
                    ctrl.DrawToBitmap(controlBmp, new Rectangle(0, 0, ctrl.Width, ctrl.Height));
                    g.DrawImage(controlBmp, ctrl.Location);
                    controlBmp.Dispose();
                }
            }
        }

        private void ApplyTransparency()
        {
            // Set the transparency blend function parameters
            APIHelp.BLENDFUNCTION blend = new APIHelp.BLENDFUNCTION
            {
                BlendOp = APIHelp.AC_SRC_OVER,
                BlendFlags = 0,
                SourceConstantAlpha = 255,
                AlphaFormat = APIHelp.AC_SRC_ALPHA
            };

            // Apply the transparent layer to the form window
            IntPtr screenDc = APIHelp.GetDC(IntPtr.Zero);
            memDc = APIHelp.CreateCompatibleDC(screenDc);
            hBmp = backgroundBmp.GetHbitmap(Color.FromArgb(0));
            hOldBmp = APIHelp.SelectObject(memDc, hBmp);
            APIHelp.DeleteDC(screenDc);

            APIHelp.Size newSize = new APIHelp.Size { cx = this.Width, cy = this.Height };
            APIHelp.Point newLocation = new APIHelp.Point { x = this.Location.X, y = this.Location.Y };
            APIHelp.Point sourceLocation = new APIHelp.Point { x = 0, y = 0 };

            APIHelp.UpdateLayeredWindow(this.Handle, IntPtr.Zero, ref newLocation, ref newSize, memDc, ref sourceLocation, 0, ref blend, APIHelp.ULW_ALPHA);
        }

        private void UpdateBackground()
        {
            SetupBackgroundImage();
            DrawControlsOnBackground();
            ApplyTransparency();
        }

        protected override void OnFormClosed(FormClosedEventArgs e)
        {
            // Clean up resources when the form is closed
            APIHelp.SelectObject(memDc, hOldBmp);
            APIHelp.DeleteObject(hBmp);
            APIHelp.DeleteDC(memDc);
            backgroundBmp.Dispose();
            refreshTimer.Dispose();
            base.OnFormClosed(e);
        }

        // Method to resize an image to the specified width and height
        private Bitmap ResizeImage(Image img, int width, int height)
        {
            Bitmap newImage = new Bitmap(width, height);
            using (Graphics g = Graphics.FromImage(newImage))
            {
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                g.DrawImage(img, 0, 0, width, height);
            }
            return newImage;
        }

        // APIHelper class for layered window and GDI operations
        public class APIHelp
        {
            public const int WS_EX_LAYERED = 0x80000; // Extended window style for layered windows
            public const int ULW_ALPHA = 0x02; // Flag for per-pixel alpha blending
            public const byte AC_SRC_OVER = 0x00; // Blend operation flag
            public const byte AC_SRC_ALPHA = 0x01; // Alpha format flag

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

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

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

            [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
            public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pptSrc, uint crKey, [In] ref BLENDFUNCTION pblend, uint dwFlags);

            [DllImport("gdi32.dll", SetLastError = true)]
            public static extern IntPtr CreateCompatibleDC(IntPtr hdc);

            [DllImport("gdi32.dll", EntryPoint = "SelectObject")]
            public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);

            [DllImport("user32.dll")]
            public static extern IntPtr GetDC(IntPtr hWnd);

            [DllImport("gdi32.dll", EntryPoint = "DeleteDC")]
            public static extern bool DeleteDC(IntPtr hdc);

            [DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
            public static extern bool DeleteObject(IntPtr hObject);
        }
    }
}


© www.soinside.com 2019 - 2024. All rights reserved.