【发布时间】:2019-01-25 16:32:51
【问题描述】:
背景:
你好。我目前正在尝试在 Windows 窗体中为学校项目制作自定义平面样式窗口。这个想法是使用这个窗口作为基础并创建其他继承自它的窗口。我想要实现的风格类似于 Visual Studio 2017 本身(深色主题)。我正在尝试向窗口添加功能,例如:
- 双击顶部面板可最大化窗口(完成)。
- 用顶部面板拖动窗口(完成)。
- 焦点/取消焦点时边框颜色变化(完成)。
当试图通过拖动边框来调整窗口大小时,问题就出现了。
我有什么:
这是window 的图片。
表单有 2 个面板:
- 顶部面板:作为窗口图标、窗口名称标签和 3 个按钮(最小化、最大化和关闭)。
- 主面板:它是一个空面板,这是窗口内容所在的位置。
表单有 1px 的内边距(变色边框,稍后会出现)
问题:
我发现这个答案似乎可以解决我的问题:https://stackoverflow.com/a/32261547/70345 但是当我尝试实现它时,它并不能完全起作用。人们似乎做的是在表单周围绘制矩形,并在 WndProc 函数中检测光标是否悬停在它们上方:
protected override void OnPaint(PaintEventArgs e) // you can safely omit this method if you want
{
e.Graphics.FillRectangle(Brushes.Green, Top);
e.Graphics.FillRectangle(Brushes.Green, Left);
e.Graphics.FillRectangle(Brushes.Green, Right);
e.Graphics.FillRectangle(Brushes.Green, Bottom);
}
private const int
HTLEFT = 10,
HTRIGHT = 11,
HTTOP = 12,
HTTOPLEFT = 13,
HTTOPRIGHT = 14,
HTBOTTOM = 15,
HTBOTTOMLEFT = 16,
HTBOTTOMRIGHT = 17;
const int _ = 10; // you can rename this variable if you like
Rectangle Top { get { return new Rectangle(0, 0, this.ClientSize.Width, _); } }
Rectangle Left { get { return new Rectangle(0, 0, _, this.ClientSize.Height); } }
Rectangle Bottom { get { return new Rectangle(0, this.ClientSize.Height - _, this.ClientSize.Width, _); } }
Rectangle Right { get { return new Rectangle(this.ClientSize.Width - _, 0, _, this.ClientSize.Height); } }
Rectangle TopLeft { get { return new Rectangle(0, 0, _, _); } }
Rectangle TopRight { get { return new Rectangle(this.ClientSize.Width - _, 0, _, _); } }
Rectangle BottomLeft { get { return new Rectangle(0, this.ClientSize.Height - _, _, _); } }
Rectangle BottomRight { get { return new Rectangle(this.ClientSize.Width - _, this.ClientSize.Height - _, _, _); } }
protected override void WndProc(ref Message message)
{
base.WndProc(ref message);
if (message.Msg == 0x84) // WM_NCHITTEST
{
var cursor = this.PointToClient(Cursor.Position);
if (TopLeft.Contains(cursor)) message.Result = (IntPtr)HTTOPLEFT;
else if (TopRight.Contains(cursor)) message.Result = (IntPtr)HTTOPRIGHT;
else if (BottomLeft.Contains(cursor)) message.Result = (IntPtr)HTBOTTOMLEFT;
else if (BottomRight.Contains(cursor)) message.Result = (IntPtr)HTBOTTOMRIGHT;
else if (Top.Contains(cursor)) message.Result = (IntPtr)HTTOP;
else if (Left.Contains(cursor)) message.Result = (IntPtr)HTLEFT;
else if (Right.Contains(cursor)) message.Result = (IntPtr)HTRIGHT;
else if (Bottom.Contains(cursor)) message.Result = (IntPtr)HTBOTTOM;
}
}}
但是当我这样做时,矩形被绘制在面板后面,所以即使我将矩形的大小(“_”变量)设置为 10 像素或 20 像素,我可以单击以调整窗口大小的区域始终是 1 像素(因为表单填充)。
我还尝试使用某种叠加层并在那里绘制矩形:https://www.codeproject.com/Articles/26071/Draw-Over-WinForms-Controls
但我遇到了同样的问题。
我需要什么:
我需要以某种方式在面板前面绘制矩形,这样我就可以有更大的区域来调整表单的大小。我在编程方面不是很有经验,所以我愿意接受任何建议和改进。也欢迎其他解决方案。
这是我的表格:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace BaseWindow
{
public partial class BaseWindowForm : Form
{
public BaseWindowForm()
{
InitializeComponent();
}
#region draggable window
private bool windowDragging = false;
private Point startPoint = new Point(0, 0);
private void TopPanel_MouseDown(object sender, MouseEventArgs e)
{
windowDragging = true; // _dragging is your variable flag
startPoint = new Point(e.X, e.Y);
}
private void TopPanel_MouseUp(object sender, MouseEventArgs e)
{
windowDragging = false;
}
private void TopPanel_MouseMove(object sender, MouseEventArgs e)
{
if (windowDragging)
{
Point p = PointToScreen(e.Location);
Location = new Point(p.X - this.startPoint.X, p.Y - this.startPoint.Y);
}
}
#endregion
#region border color focus
private void BaseWindowForm_Activated(object sender, EventArgs e)
{
this.BackColor = Color.FromArgb(0, 122, 204);
}
private void BaseWindowForm_Deactivate(object sender, EventArgs e)
{
this.BackColor = Color.FromArgb(63, 63, 70);
}
#endregion
#region maximize/minimize
private void BaseWindowForm_Maximize(object sender, EventArgs e)
{
if (this.WindowState == FormWindowState.Normal)
{
this.WindowState = FormWindowState.Maximized;
}
else if (this.WindowState == FormWindowState.Maximized)
{
this.WindowState = FormWindowState.Normal;
}
}
private void ButtonMinimize_Click(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Minimized;
}
#endregion
private const int
HTLEFT = 10,
HTRIGHT = 11,
HTTOP = 12,
HTTOPLEFT = 13,
HTTOPRIGHT = 14,
HTBOTTOM = 15,
HTBOTTOMLEFT = 16,
HTBOTTOMRIGHT = 17;
const int _ = 10; // you can rename this variable if you like
Rectangle Top { get { return new Rectangle(0, 0, this.ClientSize.Width, _); } }
Rectangle Left { get { return new Rectangle(0, 0, _, this.ClientSize.Height); } }
Rectangle Bottom { get { return new Rectangle(0, this.ClientSize.Height - _, this.ClientSize.Width, _); } }
Rectangle Right { get { return new Rectangle(this.ClientSize.Width - _, 0, _, this.ClientSize.Height); } }
Rectangle TopLeft { get { return new Rectangle(0, 0, _, _); } }
Rectangle TopRight { get { return new Rectangle(this.ClientSize.Width - _, 0, _, _); } }
Rectangle BottomLeft { get { return new Rectangle(0, this.ClientSize.Height - _, _, _); } }
Rectangle BottomRight { get { return new Rectangle(this.ClientSize.Width - _, this.ClientSize.Height - _, _, _); } }
protected override void WndProc(ref Message message)
{
base.WndProc(ref message);
if (message.Msg == 0x84) // WM_NCHITTEST
{
var cursor = this.PointToClient(Cursor.Position);
if (TopLeft.Contains(cursor)) message.Result = (IntPtr)HTTOPLEFT;
else if (TopRight.Contains(cursor)) message.Result = (IntPtr)HTTOPRIGHT;
else if (BottomLeft.Contains(cursor)) message.Result = (IntPtr)HTBOTTOMLEFT;
else if (BottomRight.Contains(cursor)) message.Result = (IntPtr)HTBOTTOMRIGHT;
else if (Top.Contains(cursor)) message.Result = (IntPtr)HTTOP;
else if (Left.Contains(cursor)) message.Result = (IntPtr)HTLEFT;
else if (Right.Contains(cursor)) message.Result = (IntPtr)HTRIGHT;
else if (Bottom.Contains(cursor)) message.Result = (IntPtr)HTBOTTOM;
}
}
}
}
如果您需要更多详细信息,可以在此处下载源代码:https://github.com/RndmDud/FormBaseWindow
【问题讨论】: