C# Windows 7样式的无边框Dropshadow
短版: 目标:在C语言的无边界WinForm中,一个深沉、黑暗的Windows7 dropshadow#C# Windows 7样式的无边框Dropshadow,c#,.net,winforms,user-interface,windows-7,C#,.net,Winforms,User Interface,Windows 7,短版: 目标:在C语言的无边界WinForm中,一个深沉、黑暗的Windows7 dropshadow# 已知现有解决方案1:使用CreateParams的简单XP风格dropshadow 问题:太弱、太轻、太难看 已知的现有解决方案2:用位图替换表单的GDI 问题:无法使用控件,只能作为启动屏幕使用 本帖的目标:为这个问题找到一个中位数的解决方案,或是一个综合起来更好的解决方案 。 . 长版本: (编辑:我指的是沿着任何windows窗体边框的阴影,如果不清楚的话。) 我知道有一种方法
已知现有解决方案1:使用CreateParams的简单XP风格dropshadow 问题:太弱、太轻、太难看
已知的现有解决方案2:用位图替换表单的GDI 问题:无法使用控件,只能作为启动屏幕使用
本帖的目标:为这个问题找到一个中位数的解决方案,或是一个综合起来更好的解决方案 。 . 长版本: (编辑:我指的是沿着任何windows窗体边框的阴影,如果不清楚的话。) 我知道有一种方法可以在C#中制作XP风格的dropshadows,方法是: C#代码1-简单XP风格的dropshadow(问题:变亮、变弱、变丑) 然而,我正试图找出如何使它们看起来像Windows7中的那样(更深更大的阴影),却找不出最好的方法 我现在创建了一个方法,可以覆盖整个表单GDI,并像启动屏幕一样出现(不是我的): C#代码2:用位图替换表单GDI(问题:无法使用表单控件,难以维护GUI)
public void SetBitmap(Bitmap bitmap, byte opacity)
{
if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
throw new ApplicationException("The bitmap must be 32ppp with alpha-channel.");
// 1. Create a compatible DC with screen;
// 2. Select the bitmap with 32bpp with alpha-channel in the compatible DC;
// 3. Call the UpdateLayeredWindow.
IntPtr screenDc = Win32.GetDC(IntPtr.Zero);
IntPtr memDc = Win32.CreateCompatibleDC(screenDc);
IntPtr hBitmap = IntPtr.Zero;
IntPtr oldBitmap = IntPtr.Zero;
try
{
hBitmap = bitmap.GetHbitmap(Color.FromArgb(0)); // grab a GDI handle from this GDI+ bitmap
oldBitmap = Win32.SelectObject(memDc, hBitmap);
Win32.Size size = new Win32.Size(bitmap.Width, bitmap.Height);
Win32.Point pointSource = new Win32.Point(0, 0);
Win32.Point topPos = new Win32.Point(Left, Top);
Win32.BLENDFUNCTION blend = new Win32.BLENDFUNCTION();
blend.BlendOp = Win32.AC_SRC_OVER;
blend.BlendFlags = 0;
blend.SourceConstantAlpha = opacity;
blend.AlphaFormat = Win32.AC_SRC_ALPHA;
Win32.UpdateLayeredWindow(this.Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, Win32.ULW_ALPHA);
}
finally
{
Win32.ReleaseDC(IntPtr.Zero, screenDc);
if (hBitmap != IntPtr.Zero)
{
Win32.SelectObject(memDc, oldBitmap);
Win32.DeleteObject(hBitmap);
}
Win32.DeleteDC(memDc);
}
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x00080000; // This form has to have the WS_EX_LAYERED extended style
return cp;
}
}
然而,这确实给了我一个完整的32位背景(因为我需要手动添加dropshadow),但是我失去了创建可见表单元素的能力
所以基本上,我试图找出这两种方法之间的中间值。在不丢失其他功能/导致过度重新喷漆要求的情况下,可以给我带来深沉的阴影 好吧,经过大约4个小时的头脑风暴和编码,我终于找到了一个解决方案。基本上,我做了两张表格 表单#1:通过修改和组合8个图像(每个方向4个角渐变+4个线性渐变)创建dropshadow,并使用上面发布的第二个代码将其设置为背景(C#代码2:用位图替换表单GDI)。代码很好地解释了这一点
public partial class Dropshadow : Form
{
public Dropshadow(Form parentForm)
{
/*This bit of code makes the form click-through.
So you can click forms that are below it in z-space */
int wl = GetWindowLong(this.Handle, -20);
wl = wl | 0x80000 | 0x20;
SetWindowLong(this.Handle, -20, wl);
InitializeComponent();
//Makes the start location the same as parent.
this.StartPosition = parentForm.StartPosition;
parentForm.Activated += ParentForm_Activated; //Fires on parent activation to do a this.BringToFront()
this.Deactivate += This_Deactivated; //Toggles a boolean that ensures that ParentForm_Activated does fire when clicking through (this)
parentForm.Closed += ParentForm_Closed; //Closes this when parent closes
parentForm.Move += ParentForm_Move; //Follows movement of parent form
//Draws border with standard bitmap modifications and merging
/* Omitted function to avoid extra confusion */
Bitmap getShadow = DrawBlurBorder(parentForm.ClientSize.Width, parentForm.ClientSize.Height);
/* **This code was featured in the original post:** */
SetBitmap(getShadow, 255); //Sets background as 32-bit image with full alpha.
this.Location = Offset; //Set within DrawBlurBorder creates an offset
}
private void ParentForm_Activated(object o, EventArgs e)
{
/* Sets this form on top when parent form is activated.*/
if (isBringingToFront)
{
/*Hopefully prevents recusion*/
isBringingToFront = false;
return;
}
this.BringToFront();
/* Some special tweaks omitted to avoid confusion */
}
private void This_Deactivated(object o, EventArgs e)
{
/* Prevents recusion. */
isBringingToFront = true;
}
/* Closes this when parent form closes. */
private void ParentForm_Closed(object o, EventArgs e)
{
this.Close();
}
/* Adjust position when parent moves. */
private void ParentForm_Move(object o, EventArgs e)
{
if(o is Form)
this.Location = new Point((o as Form).Location.X + Offset.X, (o as Form).Location.Y + Offset.Y);
}
}
表单#2:这只是在启动时启动dropshadow表单,我还创建了一些接口以允许进一步的集成和灵活性,我省略了这些接口以避免额外的混乱。基本上是确保Dropshadow窗体不会从活动窗体中删除鼠标单击,并且如果Dropshadow窗体位于顶部,也不会强迫用户必须单击按钮两次的方法。谢谢,Coryllu
一个可操作的类是
DrawShadow
创建了一个类似阴影的位图,但还不够完美。
这门课并不完美,但很有效
顺便说一句,我不知道如何在任务栏中隐藏阴影窗体。设置ShowInTaskBar=false
将使表单消失
编辑
我重写了这个类,现在看起来像这样,一个真正的DropShadow
源是
你应该知道的是这个类不考虑<代码>边界半径< /代码>(取而代之的CSS)。
主要财产是- 阴影色
- 沙多夫
- 阴影
- 阴影蔓延
- 阴影模糊
框阴影相同,请参见
这些财产
- 阴影蔓延
- 阴影模糊
- 阴影色
需要手动调用RefreshShadow()
转到你的问题是什么?这里真的不是为你编写解决方案的地方。@Ramhound问题很简单。我希望能在这件事上找到正确的方向。我的问题经过充分研究,尽可能清楚。我只是想知道是否有人知道一种更好的方法来创建Windows 7风格的dropshadow。你能添加一个屏幕截图或所需结果的模型吗?@KevinMcCormick这是我所需的最终结果,但我发布了我是如何完成的。如果你有任何建议,欢迎。我不知道这是否是最好的方法,但我认为这很聪明。这是ShowInTaskbar问题的有趣之处。我似乎没有同样的问题。我会把我的代码挖出来,如果你愿意的话,把它寄给你。这是一个非常古老的代码,所以它没有经过精确的优化。我的版本涉及到更多的内容,我完全忘记了原因:P但下面是我为使代码正常工作所做的所有事情。有些可能是我想做的,但我主要是想把这些都去掉。我创建了一个新项目来测试dropshadow,发现
ShowInTaskBar
很好。现在,困难的部分是绘制阴影位图。我想使用描述的参数。我注意到您绘制阴影时使用的是图像,它是不可更改的。我更新了我的答案,实现了一个真正的DrowShadow。源代码是,我使用图像是因为我不想每次在一个应用程序上使用dropshadow时都增加不必要的处理能力,而这个应用程序将持续使用相同的dropshadow。然而,当我几年前第一次进入WinForms时,这是我自己使用的。我不再使用此代码,因为现在我主要使用WPF。不过,在推进我的原始代码方面做得很好。
public partial class Dropshadow : Form
{
public Dropshadow(Form parentForm)
{
/*This bit of code makes the form click-through.
So you can click forms that are below it in z-space */
int wl = GetWindowLong(this.Handle, -20);
wl = wl | 0x80000 | 0x20;
SetWindowLong(this.Handle, -20, wl);
InitializeComponent();
//Makes the start location the same as parent.
this.StartPosition = parentForm.StartPosition;
parentForm.Activated += ParentForm_Activated; //Fires on parent activation to do a this.BringToFront()
this.Deactivate += This_Deactivated; //Toggles a boolean that ensures that ParentForm_Activated does fire when clicking through (this)
parentForm.Closed += ParentForm_Closed; //Closes this when parent closes
parentForm.Move += ParentForm_Move; //Follows movement of parent form
//Draws border with standard bitmap modifications and merging
/* Omitted function to avoid extra confusion */
Bitmap getShadow = DrawBlurBorder(parentForm.ClientSize.Width, parentForm.ClientSize.Height);
/* **This code was featured in the original post:** */
SetBitmap(getShadow, 255); //Sets background as 32-bit image with full alpha.
this.Location = Offset; //Set within DrawBlurBorder creates an offset
}
private void ParentForm_Activated(object o, EventArgs e)
{
/* Sets this form on top when parent form is activated.*/
if (isBringingToFront)
{
/*Hopefully prevents recusion*/
isBringingToFront = false;
return;
}
this.BringToFront();
/* Some special tweaks omitted to avoid confusion */
}
private void This_Deactivated(object o, EventArgs e)
{
/* Prevents recusion. */
isBringingToFront = true;
}
/* Closes this when parent form closes. */
private void ParentForm_Closed(object o, EventArgs e)
{
this.Close();
}
/* Adjust position when parent moves. */
private void ParentForm_Move(object o, EventArgs e)
{
if(o is Form)
this.Location = new Point((o as Form).Location.X + Offset.X, (o as Form).Location.Y + Offset.Y);
}
}
var f = new Dropshadow(this)
{
BorderRadius = 40,
ShadowColor = Color.Blue
};
f.RefreshShadow();