科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件使用 C++ 的托管扩展针对 Windows 窗体编程-从头开始创建 Windows 窗体

使用 C++ 的托管扩展针对 Windows 窗体编程-从头开始创建 Windows 窗体

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

使用 C++ 的托管扩展针对 Windows 窗体编程-从头开始创建 Windows 窗体

作者:Chris Sells 和 Sam Gentile 来源:Microsoft 开发人员网络 2007年10月28日

关键字: 窗体 Windows C++ Linux

  • 评论
  • 分享微博
  • 分享邮件

典型的 Windows 窗体应用程序有至少一个窗体。窗体就是一个窗口,也就是从 Windows 1.0 开始我们所看到的 Microsoft 用户界面单元。通常,Windows 窗体应用程序中的一个窗体是主窗体,意思是它是应用程序的生存周期内可能显示的所有其他窗体的父级或所有者。该窗体是显示主菜单以及工具栏、任务栏等的位置。主窗体结束时,应用程序也退出。

应用程序的主窗体可以是一个简单的消息框、一个对话框、一个 SDI 窗口、一个 MDI 窗口,或者更为复杂的控件,如 Visual Studio .NET 这样的应用程序中具有多个子窗口、工具窗口和浮动工具栏的窗体。

如果您的应用程序极为简单,可以使用充斥在任何窗口化系统中的简朴的消息框来实现它:

#using <mscorlib.dll>
#using <System.dll>
#using <System.Windows.Forms.dll>

void __stdcall WinMain(HINSTANCE hInstance,
             HINSTANCE hPrevInstance,
          long lpCmdLine,
          int nCmdShow)
{
  System::Windows::Forms::MessageBox::Show("Hello, Windows Forms");
}

作为 C++ 程序员,您必定非常熟悉 WinMain 入口点,在托管应用程序中,仍需要该入口点。在我们的第一个 Windows 窗体应用程序中,唯一一行实际的代码调用了 Windows::System::Forms::MessageBox 类的静态 Show 方法,这其实只是调用包含在 Window::Systems::Forms 命名空间 内的 MessageBox 类的静态方法的长写形式。.NET 框架类库中广泛使用了命名空间来将类、结构、枚举等类型分隔为不同的逻辑组。由于有数以千计的 Microsoft 雇员要从事添加 .NET 框架类库的工作,而且有数以百计的第三方组织要扩展该类库,同时有数以百万计的程序员正在尝试学习它,因此这种分隔是非常必要的。没有命名空间,就需要采用各种复杂的约定来唯一地命名各种对象(像现有的 Win32 API 一样)。

命名空间中的类型的定义位于 .NET 程序集 中。程序集是打包为 DLL 或 EXE 的托管类型的容器。#using 指令用于将程序集中的类型应用到您的应用程序中。例如,mscorlibSystem 程序集提供了基本的 .NET 框架类型,如 intstringSystem.Windows.Forms 程序集包含了 Windows 窗体类型。

使用 #using 将程序集应用到应用程序中后,就可以以前面讲到的长写形式引用类型,或者,可以使用标准的 C++ using namespace 语句来省略键入代码的工作:

#using <mscorlib.dll>
#using <System.Windows.Forms.dll>

using namespace System::Windows::Forms;

void __stdcall WinMain(HINSTANCE hInstance,
             HINSTANCE hPrevInstance,
          long lpCmdLine,
          int nCmdShow)
{
  MessageBox::Show("Hello, Windows Forms");
}

因此,虽然这个简单的示例很有效地演示了最基本的 .NET 框架和 C++ 的托管扩展的概念,但它并不能很好地演示典型的 Windows 窗体程序。对于真实的应用程序,将需要一个 Form 类(或从 Form 派生的类)的实例,如下所示:

void __stdcall WinMain(HINSTANCE hInstance,
             HINSTANCE hPrevInstance,
          long lpCmdLine,
          int nCmdShow)
{
  Form* form = new Form();
  ...
}

form 变量引用了托管类型的一个实例。托管对象是由 .NET 框架的公共语言运行库 (CLR) 处理的,它们的生存周期由垃圾回收器控制的,该回收器在一定的时间取消分配内存。因此,C++ 程序员无需显式地删除托管类型,但是同样不能指望在任何特定时刻(如关闭范围时)破坏对象。

创建窗体后,就需要显示它。如果您曾经看过 Windows 窗体的文档,可能已经注意到了 Form 方法 Show,这意味着:

void __stdcall WinMain(HINSTANCE hInstance,
             HINSTANCE hPrevInstance,
          long lpCmdLine,
          int nCmdShow)
{
  Form* form = new Form();
  form->Show(); // This is not what you want to do.
}

虽然上面的代码可以显示窗体,但是必须眼疾手快才可以看到该窗体,这是因为 Show 以无模式的方式显示窗体。这意味着在 Show 将新的窗体显示到屏幕上之后,会立即将控制权返回给 Main 函数,该函数在返回时将退出进程,同时关闭刚刚显示不久的窗体。要以有模式的方式显示窗体,文档建议使用 ShowDialog 函数:

void __stdcall WinMain(HINSTANCE hInstance,
             HINSTANCE hPrevInstance,
          long lpCmdLine,
          int nCmdShow)
{
  Form* form = new Form();
  form->ShowDialog(); // This is not quite what you want to do.
}

虽然这些代码事实上可以显示一个空窗体,并且在用户关闭它之后才会将控制权返回给 Main 函数,但通常您并不会编写这样的代码。相反,您将把一个窗体指定为主窗体,使得应用程序的其他部分可以把它当作主窗体来进行访问。为此,可以将主窗体作为一个参数传递给 Windows 窗体的 Application 对象的 Run 方法:

#using <mscorlib.dll>
#using <System.dll>
#using <System.Windows.Forms.dll>

using namespace System::Windows::Forms;

void __stdcall WinMain(HINSTANCE hInstance,
             HINSTANCE hPrevInstance,
          long lpCmdLine,
          int nCmdShow)
{
  Application::Run(new Form);
}

Application 类的静态 Run 方法将显示主窗体并开始发送 Windows 消息,直到主窗体关闭为止。主窗体关闭后,Run 将返回,让我们的 Main 函数退出,以便结束进程。要实际查看这一过程,可以使用下面的命令行编译这个小小的 Windows 窗体应用程序:

C:\MSDN\MYFIRS~1>cl /clr MyFirstApp.cpp

现在,编译器已经生成了 MyFirstApp.exe,可以执行它了。关闭窗体时,MyFirstApp.exe 将退出,结束您的第一个 Windows 窗体应用程序。

要想增添一些趣味,可以在新窗体上设置一个属性。像 .NET 框架类库中的大多数对象一样,Form 对象有一些可以访问的属性、可以调用的方法和可以处理的事件。可以直接在 Form 类的实例上设置属性,但通常我们不会这么做。相反,每个自定义窗体都是一个派生自 Form 的类,并且会初始化自己的属性,如下所示:

__gc class MyForm : public Form
{
public:
  MyForm()
  {
      Text = "Hello, Windows Forms!";
  }
};

void __stdcall WinMain(HINSTANCE hInstance,
             HINSTANCE hPrevInstance,
          long lpCmdLine,
          int nCmdShow)
{
  Application::Run(new MyForm);
}

在 C++ 的托管扩展中,自定义托管类型是使用 __gc 修饰符声明的。请注意,MyForm 类派生自 Form,然后在构造函数中初始化了它自己的属性。这提供了一个很好的用法模型,如新的 Main 函数中所示,该函数创建了 MyForm 类的一个实例。

但这个窗体仍旧很乏味。除系统提供的特点外,它没有任何交互功能。我们可以通过添加一个按钮来增加一些交互功能,如下所示:

MyForm()
{
  Text = "Hello, Windows Forms!";
  Button* button = new Button();
  button->Text = "Click Me!";
  this->Controls->Add(button);
}

向窗体添加按钮就是创建一个新的 Button 对象,设置我们需要的属性,并将其添加到该窗体所管理的控件列表中。虽然上面的代码会在窗体上产生一个按钮,在单击它后看上去像是被单击了,但并不会发生别的事情,这是因为您还没有处理该按钮的 click 事件。您可以这样来处理该事件:

__gc class MyForm : public Form
{
public:
  MyForm()
  {
    Text = "Hello, Windows Forms!";
    Button* button = new Button();
    button->Text = "Click Me!";
    button->Click += new EventHandler(this, button_click);
    this->Controls->Add(button);
  }

  void button_click(Object* sender, EventArgs* e)
  {
    MessageBox::Show("Ouch!");
  }
};

处理按钮的 Click 事件涉及两项工作。第一项是创建具有适当签名的处理程序方法,我们称其为 button_Click。绝大多数 .NET 框架事件的签名都是一个函数,该函数什么都不返回,但是获取两个参数:一个表示事件的发送方(本例中为按钮)的对象,和一个 System::EventArgs 对象(或者一个从 EventArgs 类派生的对象)的实例。

预订事件所需的第二项内容是在 MyForm 构造函数中使用 += 运算符的行。这种表示法意味着您要向与特定对象上的特定事件有关的所有其他方法的列表中添加一个方法。这要求 EventHandler 委托对象的一个实例。委托是一个类,该类将对事件的调用转换为预订该事件的方法的调用。

请注意,Button 类上的 Click 事件是对 EventHandler 委托的引用,因此,要将自己的方法添加到订户列表中,您还需要创建一个该种类的委托的实例。当然,搞清楚您所感兴趣的所有事件的委托签名,或者通过手动编写代码来将控件添加到窗体上,很快会成为很乏味的事情。幸运的是,这同样可以避免,因为 Visual Studio .NET 2003 中集成了 Windows Forms for C++。

查看本文来源
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章