在无边框窗体上使用 windows 动画
Use windows animations on borderless form
最近我(主要是出于好奇)制作了一个无边框表格。在制作了我自己的包含标题和三个按钮(最小化、最大化和关闭)的标题栏之后,就像每个普通的 Windows 程序一样。我也为这些按钮制作了代码(只要问你是否想看代码)。
但是,我注意到没有动画。我的意思是,例如如果我单击最小化按钮,没有动画,程序会立即消失(它不会关闭,按钮有效,但没有动画)。在所有情况下都会发生这种情况:当我打开程序时它立即出现,当我关闭它时它立即消失。
是否有某种方法可以使用标准 Windows 程序使用的这些动画?
似乎无法在无边框窗体上实现动画效果。但是,有两种可能的解决方法。
在最小化或恢复之前将 FormBorderStyle
设置回 Sizable,然后再设置回 none。
请改用 AnimateWindow
函数。动画往往发生在 window 当前所在的位置。这些函数可以应用于任何 Control
,而不仅仅是顶级 windows.
下面是一些示例代码:
class FormA : Form {
private const int WM_SYSCOMMAND = 0x0112;
private const int SC_MINIMIZE = 0xF020;
private const int SC_RESTORE = 0xF120;
protected override void WndProc(ref Message m) {
switch (m.Msg) {
case WM_SYSCOMMAND:
int command = m.WParam.ToInt32();
if (command == SC_RESTORE) {
this.FormBorderStyle = FormBorderStyle.Sizable;
this.ControlBox = true;
}
break;
}
base.WndProc(ref m);
}
}
[DllImport("user32.dll")]
static extern bool AnimateWindow(IntPtr hwnd, int dwTime, int dwFlags);
private const int AW_VER_POSITIVE = 0x00000004;
private const int AW_VER_NEGATIVE = 0x00000008;
private const int AW_SLIDE = 0x00040000;
private const int AW_HIDE = 0x00010000;
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Form f = new FormA();
f.ControlBox = false;
f.FormBorderStyle = FormBorderStyle.None;
bool isMinimizing = false;
var mb = new Button { Text = "Min" };
mb.Click += delegate {
isMinimizing = true;
f.FormBorderStyle = FormBorderStyle.Sizable;
f.ControlBox = true;
f.WindowState = FormWindowState.Minimized;
f.FormBorderStyle = FormBorderStyle.None;
isMinimizing = false;
//AnimateWindow(f.Handle, 300, AW_SLIDE | AW_VER_POSITIVE | AW_HIDE);
};
f.SizeChanged += delegate {
if (isMinimizing)
return;
if (f.WindowState != FormWindowState.Minimized)
f.FormBorderStyle = FormBorderStyle.None;
};
f.Controls.Add(mb);
Application.Run(f);
}
我知道一年多以前有人问过这个问题,但我遇到了同样的问题并找到了一个非常好的解决方案。
查看 Github 上的 this 回购协议。
将 FormBase.cs 和 Native.cs 添加到您的项目。
您所要做的基本上就是创建一个表单,f.e。 Main.cs 并从 FormBase
派生
Main.cs
public Main()
{
InitializeComponent();
// Redraw gripper on resize
this.SetStyle(ControlStyles.ResizeRedraw, true);
// Ability to minimize/restore the form with animation
this.FormBorderStyle = FormBorderStyle.Sizable;
}
// Draw the gripper on the bottom right corner
protected override void OnPaint(PaintEventArgs e)
{
Rectangle rc = new Rectangle(this.ClientSize.Width - cGrip, this.ClientSize.Height - cGrip, cGrip, cGrip);
ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc);
rc = new Rectangle(0, 0, this.ClientSize.Width, cCaption);
e.Graphics.FillRectangle(Brushes.DarkBlue, rc);
SizeGripStyle = SizeGripStyle.Hide;
}
// Override WndProc to add resize ability -> Cursor
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x84)
{ // Trap WM_NCHITTEST
Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
pos = this.PointToClient(pos);
if (pos.X >= this.ClientSize.Width - cGrip && pos.Y >= this.ClientSize.Height - cGrip)
{
m.Result = (IntPtr)17; // HTBOTTOMRIGHT
return;
}
}
base.WndProc(ref m);
}
我还删除了 FormBase.cs 中的第 147 行,因为我的表单有圆边
//SetWindowRegion(m.HWnd, 0, 0, pos.cx, pos.cy);
最近我(主要是出于好奇)制作了一个无边框表格。在制作了我自己的包含标题和三个按钮(最小化、最大化和关闭)的标题栏之后,就像每个普通的 Windows 程序一样。我也为这些按钮制作了代码(只要问你是否想看代码)。
但是,我注意到没有动画。我的意思是,例如如果我单击最小化按钮,没有动画,程序会立即消失(它不会关闭,按钮有效,但没有动画)。在所有情况下都会发生这种情况:当我打开程序时它立即出现,当我关闭它时它立即消失。
是否有某种方法可以使用标准 Windows 程序使用的这些动画?
似乎无法在无边框窗体上实现动画效果。但是,有两种可能的解决方法。
在最小化或恢复之前将
FormBorderStyle
设置回 Sizable,然后再设置回 none。请改用
AnimateWindow
函数。动画往往发生在 window 当前所在的位置。这些函数可以应用于任何Control
,而不仅仅是顶级 windows.
下面是一些示例代码:
class FormA : Form {
private const int WM_SYSCOMMAND = 0x0112;
private const int SC_MINIMIZE = 0xF020;
private const int SC_RESTORE = 0xF120;
protected override void WndProc(ref Message m) {
switch (m.Msg) {
case WM_SYSCOMMAND:
int command = m.WParam.ToInt32();
if (command == SC_RESTORE) {
this.FormBorderStyle = FormBorderStyle.Sizable;
this.ControlBox = true;
}
break;
}
base.WndProc(ref m);
}
}
[DllImport("user32.dll")]
static extern bool AnimateWindow(IntPtr hwnd, int dwTime, int dwFlags);
private const int AW_VER_POSITIVE = 0x00000004;
private const int AW_VER_NEGATIVE = 0x00000008;
private const int AW_SLIDE = 0x00040000;
private const int AW_HIDE = 0x00010000;
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Form f = new FormA();
f.ControlBox = false;
f.FormBorderStyle = FormBorderStyle.None;
bool isMinimizing = false;
var mb = new Button { Text = "Min" };
mb.Click += delegate {
isMinimizing = true;
f.FormBorderStyle = FormBorderStyle.Sizable;
f.ControlBox = true;
f.WindowState = FormWindowState.Minimized;
f.FormBorderStyle = FormBorderStyle.None;
isMinimizing = false;
//AnimateWindow(f.Handle, 300, AW_SLIDE | AW_VER_POSITIVE | AW_HIDE);
};
f.SizeChanged += delegate {
if (isMinimizing)
return;
if (f.WindowState != FormWindowState.Minimized)
f.FormBorderStyle = FormBorderStyle.None;
};
f.Controls.Add(mb);
Application.Run(f);
}
我知道一年多以前有人问过这个问题,但我遇到了同样的问题并找到了一个非常好的解决方案。
查看 Github 上的 this 回购协议。
将 FormBase.cs 和 Native.cs 添加到您的项目。
您所要做的基本上就是创建一个表单,f.e。 Main.cs 并从 FormBase
派生Main.cs
public Main()
{
InitializeComponent();
// Redraw gripper on resize
this.SetStyle(ControlStyles.ResizeRedraw, true);
// Ability to minimize/restore the form with animation
this.FormBorderStyle = FormBorderStyle.Sizable;
}
// Draw the gripper on the bottom right corner
protected override void OnPaint(PaintEventArgs e)
{
Rectangle rc = new Rectangle(this.ClientSize.Width - cGrip, this.ClientSize.Height - cGrip, cGrip, cGrip);
ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc);
rc = new Rectangle(0, 0, this.ClientSize.Width, cCaption);
e.Graphics.FillRectangle(Brushes.DarkBlue, rc);
SizeGripStyle = SizeGripStyle.Hide;
}
// Override WndProc to add resize ability -> Cursor
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x84)
{ // Trap WM_NCHITTEST
Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
pos = this.PointToClient(pos);
if (pos.X >= this.ClientSize.Width - cGrip && pos.Y >= this.ClientSize.Height - cGrip)
{
m.Result = (IntPtr)17; // HTBOTTOMRIGHT
return;
}
}
base.WndProc(ref m);
}
我还删除了 FormBase.cs 中的第 147 行,因为我的表单有圆边
//SetWindowRegion(m.HWnd, 0, 0, pos.cx, pos.cy);