自定义窗体标题栏

This commit is contained in:
蓝点lilac
2021-03-14 05:08:55 +08:00
parent 37910682d8
commit eaa0704170
4 changed files with 292 additions and 57 deletions

View File

@@ -0,0 +1,35 @@
namespace BluePointLilac.Controls
{
public static class HitTestMessage
{
/// <summary>光标移动或鼠标按下、释放时的消息</summary>
public const int WM_NCHITTEST = 0x84;
/// <summary>鼠标击中位置</summary>
public enum HitTest : int
{
Error = -2,
Transparent = -1,
Nowhere = 0,
Client = 1,
TitleBar = 2,
SysMenu = 3,
Size = 4,
GrowBox = 5,
Hscroll = 6,
Vscroll = 7,
MinButton = 8,
MaxButton = 9,
Left = 10,
Right = 11,
Top = 12,
TopLeft = 13,
TopRight = 14,
Bottom = 15,
BottomLeft = 16,
BottomRight = 17,
Border = 18,
Close = 20,
Help = 21
}
}
}

View File

@@ -0,0 +1,232 @@
using BluePointLilac.Methods;
using System;
using System.Drawing;
using System.Windows.Forms;
namespace BluePointLilac.Controls
{
public class MyBorderForm : Form
{
public MyBorderForm()
{
this.HelpBox = false;
//无边框窗体最大化不覆盖任务栏
this.MaximizedBounds = Screen.PrimaryScreen.WorkingArea;
this.FormBorderStyle = FormBorderStyle.None;
this.InitializeComponents();
}
public new Icon Icon
{
get => base.Icon;
set
{
base.Icon = value;
picIcon.Image = value.ToBitmap().ResizeImage(picIcon.Size);
}
}
public new string Text
{
get => base.Text;
set
{
lblTilte.Text = base.Text = value;
SetTitleLeft();
}
}
public new bool MaximizeBox
{
get => lblMax.Visible;
set => lblMax.Visible = value;
}
public new bool MinimizeBox
{
get => lblMin.Visible;
set => lblMin.Visible = value;
}
public bool CloseBox
{
get => lblClose.Visible;
set => lblClose.Visible = value;
}
public bool HelpBox
{
get => lblHelp.Visible;
set => lblHelp.Visible = value;
}
public new bool ShowIcon
{
get => picIcon.Visible;
set
{
picIcon.Visible = value;
SetTitleLeft();
}
}
public Color TitleBarBackColor
{
get => pnlTitleBar.BackColor;
set => pnlTitleBar.BackColor = value;
}
public Color TitleForeColor
{
get => lblTilte.ForeColor;
set => lblTilte.ForeColor = value;
}
private bool centerTitle;
public bool CenterTitle
{
get => centerTitle;
set
{
centerTitle = value;
SetTitleLeft();
}
}
readonly Panel pnlTitleBar = new Panel
{
BackColor = Color.White,
Dock = DockStyle.Top,
Height = 30.DpiZoom()
};
readonly FlowLayoutPanel flpControls = new FlowLayoutPanel
{
FlowDirection = FlowDirection.RightToLeft,
AutoSizeMode = AutoSizeMode.GrowAndShrink,
Font = new Font("Marlett", 11F),
Anchor = AnchorStyles.Right,
AutoSize = true,
Top = 0
};
readonly Label lblHelp = new Label { Text = "s" };
readonly Label lblMin = new Label { Text = "0" };
readonly Label lblMax = new Label { Text = "1" };
readonly Label lblClose = new Label { Text = "r" };
readonly Label[] lblBorders = new Label[]
{
new Label { Cursor = Cursors.SizeWE, Dock = DockStyle.Left },
new Label { Cursor = Cursors.SizeWE, Dock = DockStyle.Right },
new Label { Cursor = Cursors.SizeNS, Dock = DockStyle.Top },
new Label { Cursor = Cursors.SizeNS, Dock = DockStyle.Bottom }
};
readonly PictureBox picIcon = new PictureBox
{
Location = new Point(8, 8).DpiZoom(),
Size = new Size(16, 16).DpiZoom(),
Enabled = false
};
readonly Label lblTilte = new Label
{
Location = new Point(26, 8).DpiZoom(),
Font = new Font(SystemFonts.CaptionFont.FontFamily, 9F),
AutoSize = true
};
/// <summary>无边框窗体放缩窗体和移动窗体</summary>
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if(m.Msg == HitTestMessage.WM_NCHITTEST && this.WindowState == FormWindowState.Normal)
{
Point point = PointToClient(Cursor.Position);
int x = point.X;
int y = point.Y;
HitTestMessage.HitTest res = 0;
if(x <= 5)
{
if(y <= 5) res = HitTestMessage.HitTest.TopLeft;
else if(y >= ClientSize.Height - 5) res = HitTestMessage.HitTest.BottomLeft;
else res = HitTestMessage.HitTest.Left;
}
else if(x >= ClientSize.Width - 5)
{
if(y <= 5) res = HitTestMessage.HitTest.TopRight;
else if(y >= ClientSize.Height - 5) res = HitTestMessage.HitTest.BottomRight;
else res = HitTestMessage.HitTest.Right;
}
else if(y <= 5) res = HitTestMessage.HitTest.Top;
else if(y >= ClientSize.Height - 5) res = HitTestMessage.HitTest.Bottom;
m.Result = (IntPtr)res;
}
}
/// <summary>最小化后点击任务栏图标还原窗口</summary>
protected override CreateParams CreateParams
{
get
{
CreateParams p = base.CreateParams;
p.Style |= 0x20000;//WS_MINIMIZEBOX
return p;
}
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
lblMax.Text = this.WindowState == FormWindowState.Normal ? "1" : "2";
SetTitleLeft();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
SetTitleLeft();
}
private void SetMaxOrNormal()
{
if(this.WindowState == FormWindowState.Normal)
{
this.WindowState = FormWindowState.Maximized;
}
else
{
this.WindowState = FormWindowState.Normal;
}
}
private void SetTitleLeft()
{
if(CenterTitle) lblTilte.Left = (pnlTitleBar.Width - lblTilte.Width) / 2;
else if(ShowIcon) lblTilte.Left = 26.DpiZoom();
else lblTilte.Left = 4.DpiZoom();
}
private void InitializeComponents()
{
this.Controls.Add(pnlTitleBar);
this.ControlAdded += (sender, e) => pnlTitleBar.SendToBack();
foreach(Label label in lblBorders)
{
label.Parent = this;
label.Enabled = false;
label.Size = new Size(1, 1);
label.BackColor = Color.FromArgb(85, 145, 215);
this.ControlAdded += (sender, e) => label.SendToBack();
}
lblTilte.SetEnabled(false);
pnlTitleBar.CanMoveForm();
pnlTitleBar.Controls.AddRange(new Control[] { flpControls, picIcon, lblTilte });
flpControls.Left = pnlTitleBar.Width;
flpControls.SizeChanged += (sender, e) => this.MinimumSize = new Size(flpControls.Width + 2, pnlTitleBar.Height + 2);
foreach(Label label in new[] { lblClose, lblMax, lblMin, lblHelp })
{
label.Parent = flpControls;
label.Margin = new Padding(0);
label.Size = new Size(32, 30).DpiZoom();
label.TextAlign = ContentAlignment.MiddleCenter;
label.MouseLeave += (sender, e) => label.BackColor = pnlTitleBar.BackColor;
label.MouseEnter += (sender, e) => label.BackColor = Color.FromArgb(213, 225, 242);
label.MouseDown += (sender, e) => label.BackColor = Color.FromArgb(163, 189, 227);
}
lblClose.MouseClick += (sender, e) => { if(e.Button == MouseButtons.Left) this.Close(); };
lblMin.MouseClick += (sender, e) => { if(e.Button == MouseButtons.Left) this.WindowState = FormWindowState.Minimized; };
lblMax.MouseClick += (sender, e) => { if(e.Button == MouseButtons.Left) this.SetMaxOrNormal(); };
pnlTitleBar.MouseDoubleClick += (sender, e) => { if(e.Button == MouseButtons.Left) this.SetMaxOrNormal(); };
lblHelp.Click += (sender, e) => this.OnHelpButtonClicked(null);
}
}
}

View File

@@ -5,18 +5,18 @@ using System.Windows.Forms;
namespace BluePointLilac.Controls
{
public class MyMainForm : Form
public class MyMainForm : MyBorderForm
{
public MyMainForm()
{
this.Text = Application.ProductName;
this.MinimumSize = this.Size = new Size(866, 649).DpiZoom();
this.StartPosition = FormStartPosition.CenterScreen;
this.MinimumSize = this.Size = new Size(866, 642).DpiZoom();
this.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
this.Controls.AddRange(new Control[] { MainBody, SideBar, StatusBar, ToolBar });
SideBar.Resize += (sender, e) => MainBody.Width = ClientSize.Width - SideBar.Width;
SideBar.Resize += (sender, e) => this.OnResize(null);
ToolBar.CanMoveForm();
StatusBar.CanMoveForm();
this.CenterToScreen();
}
protected MyToolBar ToolBar = new MyToolBar();
@@ -30,7 +30,7 @@ namespace BluePointLilac.Controls
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
MainBody.Width = ClientSize.Width - SideBar.Width;
MainBody.Width = ClientSize.Width - SideBar.Width - 2;
}
}
}

View File

@@ -15,60 +15,28 @@ namespace BluePointLilac.Controls
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch(m.Msg)
if(m.Msg == HitTestMessage.WM_NCHITTEST && this.WindowState == FormWindowState.Normal)
{
case WM_NCHITTEST:
IntPtr hNowhere = new IntPtr((int)HitTest.Nowhere);
HitTest value = (HitTest)m.Result;
switch(value)
{
case HitTest.Top:
case HitTest.Bottom:
if(!VerticalResizable) m.Result = hNowhere;
break;
case HitTest.Left:
case HitTest.Right:
if(!HorizontalResizable) m.Result = hNowhere;
break;
case HitTest.TopLeft:
case HitTest.TopRight:
case HitTest.BottomLeft:
case HitTest.BottomRight:
if(!VerticalResizable || !HorizontalResizable) m.Result = hNowhere;
break;
}
break;
IntPtr hNowhere = new IntPtr((int)HitTestMessage.HitTest.Nowhere);
HitTestMessage.HitTest value = (HitTestMessage.HitTest)m.Result;
switch(value)
{
case HitTestMessage.HitTest.Top:
case HitTestMessage.HitTest.Bottom:
if(!VerticalResizable) m.Result = hNowhere;
break;
case HitTestMessage.HitTest.Left:
case HitTestMessage.HitTest.Right:
if(!HorizontalResizable) m.Result = hNowhere;
break;
case HitTestMessage.HitTest.TopLeft:
case HitTestMessage.HitTest.TopRight:
case HitTestMessage.HitTest.BottomLeft:
case HitTestMessage.HitTest.BottomRight:
if(!VerticalResizable || !HorizontalResizable) m.Result = hNowhere;
break;
}
}
}
/// <summary>光标移动或鼠标按下、释放时的消息</summary>
private const int WM_NCHITTEST = 0x84;
/// <summary>鼠标击中位置</summary>
private enum HitTest : int
{
Error = -2,
Transparent = -1,
Nowhere = 0,
Client = 1,
TitleBar = 2,
SysMenu = 3,
Size = 4,
GrowBox = 5,
Hscroll = 6,
Vscroll = 7,
MinButton = 8,
MaxButton = 9,
Left = 10,
Right = 11,
Top = 12,
TopLeft = 13,
TopRight = 14,
Bottom = 15,
BottomLeft = 16,
BottomRight = 17,
Border = 18,
Close = 20,
Help = 21
}
}
}