如何:创建非矩形 Windows 窗体

更新:2007 年 11 月

以前,创建非矩形窗体是一个既费时又费人力的过程,其中涉及到 API 调用和大量的编程工作。现在,这已经不成问题了。

说明:

此过程涉及到大量的相关硬件的图形处理,因此,根据现有的内存和图形卡,计算机的执行也有所不同。当应用程序涉及到自定义绘图时,在为用户部署该应用程序之前,应始终在不同的显示视频卡上进行测试,以确保良好的性能。

创建非矩形窗体的过程有两个要素:创建成形的窗体,并编写某些编程逻辑的代码以允许移动和关闭窗体。第二个步骤是必要的,因为自定义形状的窗体没有标题栏,并且它本身不具有任何功能,例如在屏幕中移动窗体以及关闭窗体的能力。因此,编写重现这些功能的代码是非常必要的。有关创建非矩形形状的两个窗体和控件的更多信息,请参见 如何:创建特定形状的 Windows 窗体

创建非矩形窗体的过程包含三个步骤:

  • 创建一个作为窗体图面的位图。(一种有效的方式是,您可以从矩形中“裁剪掉”所需的窗体形状。)

  • 创建 Windows 应用程序项目,将其属性设置为移除标题栏并使用位图作为窗体背景。

  • 输入重新创建标题栏所提供功能的代码,例如移动和关闭窗体。

说明:

显示的对话框和菜单命令可能会与“帮助”中的描述不同,具体取决于您的当前设置或版本。若要更改设置,请在“工具”菜单上选择“导入和导出设置”。有关更多信息,请参见 Visual Studio 设置

创建特定形状的窗体

  1. 创建一个非矩形的单色位图,其背景则使用另一种颜色。使用您喜欢的任何绘图程序。所绘制的形状最终将成为您的窗体,因此请确保该形状足够大,以满足使用的需求。

    说明:

    请选择便于记忆的背景色,例如蓝色,因为这对于后面的操作是非常重要的。

  2. 在 Visual Studio 中创建一个新的 Windows 应用程序项目。有关更多信息,请参见如何:创建 Windows 应用程序项目

  3. 在“属性”窗口中:

    • FormBorderStyle 属性设置为 None

      此属性从窗体中移除标题栏。(它同时移除标题栏所提供的功能,包括关闭和移动窗体的能力。不过,以下代码中解决了这种不足。)

    • 将窗体的 BackgroundImage 属性设置为先前创建的位图文件。不必将文件添加到项目系统中;这将在指定该文件作为背景图像时自动完成。

      此属性将该位图图像设置为窗体的背景。(当与以下指定的 TransparencyKey 属性前后使用时,此属性将定义窗体的形状。)

    • TransparencyKey 属性设置为位图文件的背景色。

      此属性告诉应用程序窗体中的哪些部分需要设置为透明。

      说明:

      如果监视器的颜色深度设置大于 24 位,则不管 TransparencyKey 属性是如何设置的,窗体的非透明部分都会产生显示问题。若要避免出现这种问题,请确保“显示”控制面板中的监视器颜色深度的设置小于 24 位。当开发具有这种透明功能的应用程序时,请牢记应使您的用户意识到此问题。

编写关闭窗体的代码

  1. 将一个 Button 控件添加到窗体中。有关更多信息,请参见 如何:向 Windows 窗体添加控件

  2. 添加代码,使用户可通过调用 Close 方法关闭该窗体。

    下面的示例显示如何添加一个按钮,单击该按钮将关闭窗体。

    Private Sub Button1_Click(ByVal sender As System.Object, _
       ByVal e As System.EventArgs) Handles Button1.Click
       Me.Close()
    End Sub
    
    private void button1_Click(object sender, System.EventArgs e)
    {
       this.Close();
    }
    
    C# 说明:

    请确保添加启用事件处理程序的代码。使用以下示例中的代码,它类似于以下内容:

    this.Button1.Click += new System.EventHandler(this.button1_Click);
    

编写移动窗体的代码(可选)

  1. 创建一个在拖动窗体时使窗体移动的过程。输入类似于下文显示的代码来创建新的 Point 对象。这将作为计算如何移动窗体时的变量。isMouseDown 字段用于跟踪用户是否按下了鼠标按钮。该窗体应只在用户按下鼠标按钮时才移动。

    Private mouseOffset As Point
    Private isMouseDown As Boolean = False
    
    private Point mouseOffset;
    private bool isMouseDown = false;
    
  2. 为窗体的 MouseDown 事件创建一个事件处理程序。在处理程序中添加代码,使用户可以在窗体上的任意位置单击以拖动窗体。有关创建事件处理程序的详细信息,请参见 如何:使用设计器创建事件处理程序

    输入类似于下文显示的代码,以根据鼠标指针的当前位置,将坐标分配给 mouseOffset 变量。在以下代码中,请注意偏移位置是使用有关边框大小 (FrameBorderSize.Width) 和标题栏高度 (CaptionHeight) 的系统信息进行计算的。在测试偏移位置时必须考虑这些因素,因为某些测量结果是使用工作区得出的,而另一些测量结果是使用屏幕坐标得出的。因此,偏移位置等于边框宽度加上标题高度,再加上窗体工作区的偏移位置。

    Private Sub Form1_MouseDown(ByVal sender As Object, _
        ByVal e As MouseEventArgs) Handles MyBase.MouseDown
        Dim xOffset As Integer
        Dim yOffset As Integer
    
        If e.Button = MouseButtons.Left Then
            xOffset = -e.X - SystemInformation.FrameBorderSize.Width
            yOffset = -e.Y - SystemInformation.CaptionHeight - _
                    SystemInformation.FrameBorderSize.Height
            mouseOffset = New Point(xOffset, yOffset)
            isMouseDown = True
        End If
    End Sub
    
    private void Form1_MouseDown(object sender, 
        System.Windows.Forms.MouseEventArgs e)
    {
        int xOffset;
        int yOffset;
    
        if (e.Button == MouseButtons.Left) 
        {
            xOffset = -e.X - SystemInformation.FrameBorderSize.Width;
            yOffset = -e.Y - SystemInformation.CaptionHeight - 
                SystemInformation.FrameBorderSize.Height;
            mouseOffset = new Point(xOffset, yOffset);
            isMouseDown = true;
        }    
    }
    
    C# 说明:

    请确保添加启用事件处理程序的代码。使用以下示例中的代码,它类似于以下内容:

    this.MouseDown += new
       System.Windows.Forms.MouseEventHandler
       (this.Form1_MouseDown);
    
  3. 为窗体的 MouseMove 事件创建一个事件处理程序。

    输入类似以下内容的代码。单击鼠标左键并且拖动鼠标时,窗体的 Location 属性将设置为新的位置。

    Private Sub Form1_MouseMove(ByVal sender As Object, _
        ByVal e As MouseEventArgs) Handles MyBase.MouseMove
        If isMouseDown Then
            Dim mousePos As Point = Control.MousePosition
            mousePos.Offset(mouseOffset.X, mouseOffset.Y)
            Location = mousePos
        End If
    End Sub
    
    private void Form1_MouseMove(object sender, 
        System.Windows.Forms.MouseEventArgs e)
    {
        if (isMouseDown) 
        {
            Point mousePos = Control.MousePosition;
            mousePos.Offset(mouseOffset.X, mouseOffset.Y);
            Location = mousePos;
        }
    }
    
    C# 说明:

    请确保添加启用事件处理程序的代码。使用以下示例中的代码,它类似于以下内容:

    this.MouseMove += new
       System.Windows.Forms.MouseEventHandler
       (this.Form1_MouseMove);
    
  4. 为窗体的 MouseUp 事件创建一个事件处理程序。输入类似以下内容的代码。

    Private Sub Form1_MouseUp(ByVal sender As Object, _
        ByVal e As MouseEventArgs) Handles MyBase.MouseUp
        ' Changes the isMouseDown field so that the form does
        ' not move unless the user is pressing the left mouse button.
        If e.Button = MouseButtons.Left Then
            isMouseDown = False
        End If
    End Sub
    
    private void Form1_MouseUp(object sender, 
        System.Windows.Forms.MouseEventArgs e)
    {
        // Changes the isMouseDown field so that the form does
        // not move unless the user is pressing the left mouse button.
        if (e.Button == MouseButtons.Left) 
        {
            isMouseDown = false;
        }
    }
    

请参见

任务

如何:创建特定形状的 Windows 窗体

如何:创建透明 Windows 窗体

参考

Windows 窗体概述