【问题标题】:How can I make a flat window resizable?如何使平面窗口可调整大小?
【发布时间】: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

【问题讨论】:

    标签: c# winforms


    【解决方案1】:

    您可以增加表单填充(将其设置为 ex: 2,2,2,2) 请检查:(Can't resize a borderless winform from top because of a docked panel)

    编辑:

    在与@Outman 建议更改边框颜色相同的链接中:

            protected override void OnPaintBackground(PaintEventArgs e)
        {
            base.OnPaintBackground(e);            //comment this out to prevent default painting 
            using (SolidBrush brush = new SolidBrush(Color.FromArgb(45, 45, 48))) //any color you like  }
            {
                e.Graphics.FillRectangle(brush, e.ClipRectangle);
            }
        }
    

    【讨论】:

      猜你喜欢
      • 2011-07-09
      • 2011-08-18
      • 2020-08-14
      • 1970-01-01
      • 1970-01-01
      • 2023-03-24
      • 2011-10-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多