我正在尝试为我的应用程序制作一个启动屏幕。我有一个 .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;
}
也没有用。背景仍然不透明。 我能做什么?
为什么是洋红色? 尝试使用白色。 我将背景颜色设置为白色,透明度键设置为白色。 下图中,带有图片的随机框是我的启动项。
TransparencyKey
将把表单设置为完全不透明,除了指定的确切颜色的pixels。据我所知,它通过实际定义 WindowRegion
来实现这一点,即基于与颜色匹配的像素的窗口形状 - 这些像素不再是窗口的一部分,可以单击。
听起来你的 PNG 有一个 alpha 层,即透明度级别 0..255,它与背景颜色(洋红色)混合,之后只有纯洋红色像素变得透明。
你可以尝试:
Magenta
未在您的启动画面中使用,并将其放入您的启动画面 PNG 中,代替完全透明区域作为不透明像素PictureBox
中。飞溅的部分透明区域将与背景图像混合,完全透明的区域将匹配
TransparencyKey
并且是透明的。
但是,如果在显示启动画面时桌面的其余部分发生变化,如果启动画面移动等,您将获得视觉假象。
编辑:似乎有一个更简单的解决方案here,无需使用
TransparencyKey
您可以使用
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);
大家好,这里是更新的代码。 我添加了代码的缺失部分,将其从启动屏幕转换为表单 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);
}
}
}