简体   繁体   English

如何调整平面窗口的大小?

[英]How can I make a flat window resizable?

Background: 背景:

Hello. 你好。 I'm currently trying to make a custom flat style window in Windows Forms for a school project. 我目前正在尝试在Windows窗体中为学校项目创建自定义平面样式窗口。 The idea is to use this window as a base and create other windows that inherit from it. 想法是使用此窗口作为基础并创建从其继承的其他窗口。 The style I'm trying to achieve is similar to that of Visual Studio 2017 itself (Dark theme). 我试图实现的样式类似于Visual Studio 2017本身的样式(深色主题)。 I'm trying to add functionality to the window, like: 我正在尝试向窗口添加功能,例如:

  • Double clicking on the top panel maximizes the window (Done). 双击顶部面板将最大化窗口(完成)。
  • Dragging the window wit the top panel (Done). 用顶部面板拖动窗口(完成)。
  • Color changing border when focus/unfocus (Done). 聚焦/未聚焦(完成)时颜色改变边界。

The problem comes when trying to make the window resizable by dragging the borders. 尝试通过拖动边框使窗口可调整大小时出现问题。

What I have: 我有的:

Here's an image of the window . 这是窗户的图像。

The form has 2 panels: 该表格有2个面板:

  • The top panel: It as a window icon, a label for the name of the window, and 3 buttons (minimize, maximize, and close). 顶部面板:它是一个窗口图标,一个窗口名称标签和3个按钮(最小化,最大化和关闭)。
  • Main panel: It is an empty panel, this is where the content of the window will be. 主面板:这是一个空面板,这是窗口内容所在的位置。

The form has a 1px padding (the color changing border, this will come up later) 表单具有1px的填充(颜色变化的边框,稍后会出现)

The problem: 问题:

I found this answer that seemed to solve my problem: https://stackoverflow.com/a/32261547/70345 but when I try to implement it doesn't work entirely. 我找到了似乎可以解决我问题的答案: https : //stackoverflow.com/a/32261547/70345,但是当我尝试实现它时,并不能完全解决问题。 What people seem to do is draw rectangles around the form and detect in the WndProc function if the cursor hovers over them: 人们似乎要做的是在窗体周围绘制矩形,并在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;
    }
}}

But when I do that, the rectangles are drawn behind the panels, so even if I set the rectangle's size (the "_" variable) to 10px or 20px, the area where I can click to resize the window is always 1px (because of the form padding). 但是,当我这样做时,矩形是在面板后面绘制的,因此即使我将矩形的大小(“ _”变量)设置为10px或20px,我可以单击以调整窗口大小的区域始终为1px(因为表格填充)。

I also tried using some sort of overlay and draw the rectanges there: https://www.codeproject.com/Articles/26071/Draw-Over-WinForms-Controls 我也尝试过使用某种叠加层并在其中绘制矩形: https ://www.codeproject.com/Articles/26071/Draw-Over-WinForms-Controls

But I had the same problem. 但是我有同样的问题。

What I need: 我需要的:

I need to somehow draw the rectangles in front of the panels so I can have a bigger area to resize the form. 我需要以某种方式在面板前面绘制矩形,以便可以有更大的区域来调整表单大小。 I'm not very experienced in programming so I'm open to any sugestions and improvements. 我在编程方面不是很有经验,所以我愿意接受任何建议和改进。 Alternate solutions are also welcome. 也欢迎其他解决方案。

This is my form: 这是我的表格:

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;
            }
        }
    }
}

If you need more details you can download the source code here: https://github.com/RndmDud/FormBaseWindow 如果您需要更多详细信息,可以在此处下载源代码: https : //github.com/RndmDud/FormBaseWindow

you can increase form padding (set it to ex: 2,2,2,2) Please check :( Can't resize a borderless winform from top because of a docked panel ) 您可以增加表格填充(将其设置为ex:2,2,2,2),请检查:( 由于面板停靠,无法从顶部调整无边界winform的大小

Edit: 编辑:

as in the same link as @Outman suggested to change the boarder color: 与@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);
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM