WinForm:怎么创建一个Form的
又是新生入学,想起去年毕业后也是差不多这个时候开始学习WinForm
从刚开始的拖拉控件照抄DEMO,到后来的学习别人的源码,到后来的参与项目,到后来修改别人的BUG,到后来指导新生开始学习WinForm
在这个标签里,我也记录一下自已得到的一些C、C++的知识吧,或者C相比于C#来说,更能让我们明白创建一个WINDOWS程序
先来一个经典的例子:创建一个窗体(代码源自于windows程序设计)
WINFORM是:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
}
Application.Run(new Form1());
而经典C++呢?
#include <windows.h>
#include "sysmets.c"
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
//是不是也感觉这个函数名很熟。。。。。。。
int WINAPI WinMain(HINSTANCE
hInstance,HINSTANCE hPrevinstance,PSTR szCmdLine,int iCmdShow)
{
static TCHAR szAppName[]
=TEXT("HelloWin");
HWND hwnd;
MSG msg;
WNDCLASS wndClass; //以下,是创建一个窗体的属性,这在孙鑫老师的教程里就已详细的描述
wndClass.style=CS_HREDRAW|CS_VREDRAW;
wndClass.lpfnWndProc=WndProc;
wndClass.cbClsExtra=0;
wndClass.cbWndExtra=0;
wndClass.hInstance=hInstance;
wndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
wndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
wndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.lpszMenuName=NULL;
wndClass.lpszClassName=szAppName;
//注册一个窗体内
if(!RegisterClass(&wndClass))
{
MessageBox(NULL,TEXT("This program
requires windows NT!"),szAppName,MB_ICONERROR);
return 0;
}
//成功后则可以分配内存了。。。。
hwnd =CreateWindow(szAppName,
//window class name
TEXT("The Hello Program"),
//window caption
WS_OVERLAPPEDWINDOW,
//Window style
CW_USEDEFAULT,
//INITIAL X Position
CW_USEDEFAULT,
//INITIAL X Position
CW_USEDEFAULT,
//INITIAL X Position
CW_USEDEFAULT,
//INITIAL X Position
NULL,
//Parent window handle
NULL,
//window menu handle
NULL,
// program instance handle
NULL
//creaion parameters
);
//接着就是ShowWindow,是不是可以理解相当于我们一句new Form,则是C#帮我们做了以上的事情
//而此时才是.show()
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
//接下来这一段,则是在C#里未曾见过的,老的WIN32
CODER应该很熟,这里也即是WINDOWS的消息循环机制,除非是退出,否则GetMessage永选返回大于0的数
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd,UINT
message,WPARAM wParam,LPARAM LParam)
{
static int cxChar,cxCaps,cyChar;
int i;
PAINTSTRUCT ps;
TCHAR szBuffer[10];
TEXTMETRIC tm;
HDC hdc;
//PAINTSTRUCT ps;
RECT rect;
switch(message)
{
case WM_CREATE:
PlaySound(TEXT("helloWin.wav"),NULL,SND_FILENAME|SND_ASYNC);
hdc=GetDC(hwnd);
GetTextMetrics(hdc,&tm);
//调用系统,获取默认字体
cxChar=tm.tmAveCharWidth;
cyChar=tm.tmHeight+tm.tmExternalLeading;
//将高度包括间距,还有宽度保存起来
ReleaseDC(hwnd,hdc);
return 0;
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps);
GetClientRect(hwnd,&rect);
DrawText(hdc,TEXT("Hello,windows
98"),-1,&rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
EndPaint(hwnd,&ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0); 此时才是返回0
return 0;
}
return
DefWindowProc(hwnd,message,wParam,LParam);
}
这是一个很简单的窗体,代码源于windows程序设计第五版,在这里,你是否感觉C#的方便呢,帮我们做了太多事,这C80行代码==c#2行,可却让我们有的新手迷茫起来?或许你也问过这问题.为什么两行代码就可以做SHOW一个窗体了,创建一个窗体必须要有什么,通过上面的一些API函数,你应该清楚了点吧啦。。。
在刘小石 BLUEDOG先生的博客中有这么一段:
仔细来看看到底在Application.Run中发生了什么?
public static void Run(Form
mainForm){ Application.ThreadContext.FromCurrent().RunMessageLoop(-1, new ApplicationContext(mainForm));} |
可以看到实际上调用了Application内部定义的类ThreadContext的RunMessageLoop方法,而ApplicationContext是有关应用程序线程的上下文信息,而RunMessageLoop调用了下面的内部方法:
private void RunMessageLoopInner(int reason, ApplicationContext
context)
这个函数很长,我们只列出其中有关的部分(代码有删节)
if (reason == -1)
{
this.applicationContext = context;
this.applicationContext.ThreadExit += new EventHandler(this.OnAppThreadExit);
if (this.applicationContext.MainForm != null)
{
this.applicationContext.MainForm.Visible = true;
}
}
if (context != null)
{
this.currentForm = context.MainForm;
}
try
{
flag2 = this.LocalModalMessageLoop(this.currentForm);
}
}
finally
{
this.Dispose();
}
可以看到它完成了两个部分,一是将窗体设为可见,另一个是呼叫LocalModalMessageLoop,嗯,好象有那么点意思了。是不是对应了经典程序中的ShowWindow和消息泵呀,那我们再看看LocalModalMessageLoop是不是起到了消息泵的作用呢,还是来看源码。
bool flag2 = true;
while (flag2)
{
UnsafeNativeMethods.GetMessageW(out msg1, NativeMethods.NullHandleRef, 0,
0);//还有一些判断代码
{
UnsafeNativeMethods.TranslateMessage(out msg1);
UnsafeNativeMethods.DispatchMessageW(ref msg1);
}
}
同样上面的代码是一个小部分,但是关键部分,清楚地看到跟原来的处理方式是一样的。需要说明的是实际上CLR考虑了在非Unicode的Windows系统上调用不同的函数如DispatchMessageA之类的。
到此,咱们完全可以看出,Windows编程原理都是一致的,无论是C#
WINFOR还是c++。再把基础好好把握下吧。。。。。。