VS环境下用c编写第一个窗口程序

在windows下创建窗口的整个过程

1告诉系统,我们要创建一个怎样的窗口

通过WNDCLASS这个结构来告诉他,我们设置这个结构的不同字段,设置好字段后

调用registerClass函数来告诉系统,我们要注册一个这样的窗口类型

2 创建窗口

窗口类型可以理解为一个模板,接下来我们要告诉操作系统,我们要以XX模板创建一个窗口,怎么告诉他呢,就是调用函数CreateWindow

3 显示窗口

创建好窗口之后,默认是没有显示的,我们还需要让他显示出来,同样是调用ShowWindow来显示,调用这个函数来更新窗口UpdateWindow

4消息循环

创建好窗口之后,不是要等待用户的操作吗?比如鼠标单击,键盘按键等等

这些东西在window系统中都是一种消息

用Wndproc这个函数来专门处理这些消息

消息机制怎么循环的(重点)

一个消息的产生到结束是怎样的一个过程,就以用户点击鼠标为例

1用户在应用程序A上面单击了左键

2操作系统捕捉到这个单击左键的消息,就把它放在操作系统管理的消息队列中

3我们的程序创建好之后就通过GetMessage函数一直不停的去检测消息队列中是否有自己关心的消息(判断交给操作系统去管)

4获取到消息之后,操作系统(可以看到我们并没有在我们代码中直接调用)就调用窗口过程函数来处理,窗口过程函数就是WndProc,他怎么知道要调用这个函数来处理呢?是因为我们在注册窗口类的时候通过这段代码wc.lpfnWndProc=Wndproc;

5 如此循环,一直不停的处理消息,直到程序结束

准备工作

1 创建变量wc用于设置窗口类的信息,如窗口的样式,设置程序图标,设置鼠标,背景颜色等等

WNDCLASS wc;

style:指定类风格,这些风格可通过按位或操作组合起来

    CS_BYTEALIGNCLIENT:在字节边界上(x方向上)定位窗口的用户区域位置

    CS_BYTEALLGNWINDOW:在字节边界上(x方向上)定位窗口的位置

   CS_CLASSDC;该窗口类的所有窗口实例都共享一个窗口类DC;

  CS_DBLCLKS:允许向窗口发送双击鼠标键的消息

  CS_GLOBALCLASS:当调用CreateWindow或者CreateWindowEx函数来创建窗口时允许他的hInstance参数和

注册窗口类CS_GLOBALCLASS: 当调用CreateWindow 或 CreateWindowEx 函数来创建窗口时允许它的hInstance参数和注册窗口类时传递给
    RegisterClass 的 hInstance参数不同。如果不指定该风格,则这两个 hInstance 必须相同。
    CS_HREDRAW : 当水平长度改变或移动窗口时,重画整个窗口
    CS_NOCLOSE : 禁止系统菜单的关闭选项
    CS_OWNDC : 给予每个窗口实例它本身的DC。注意,尽管这样是很方便,但它必须慎重使用,因为每个DC大约要占800个字节的内存。
    CS_PARENTDC : 将子窗口的裁剪区域设置到父窗口的DC中去,这样子窗口便可以在父窗口上绘制自身。注意,这是子窗口还是从系统缓存中获取DC,而不是使用父窗口的DC。使用该风格可以提高系统性能。
    CS_SAVEBITS : 以位图形式保存被该窗口遮挡的屏幕部分,这样当给窗口移动以后,系统便可以用该保存的位图恢复屏幕移动的相应部分,从而系统不用向被该窗口遮挡的窗口发送 WM_PAINT 消息。该特性对于菜单类型的窗口比较合适,因为它通常是简短的显示一下之后便消失。设置该特性将增加显示该窗口的时间,因为它通常要先分配保存位图的内存。
    CS_VREDRAW : 当垂直长度改变或移动窗口时,重画整个窗口

lpfnWndProc:指向窗口过程

cbClsExtra:指定紧随在WNDCLASS数据结构后分配的字节数。系统将其初始化为零

cbWndExtra:指定紧随在窗口实例之后分配的字节数,系统将其初始化为零,如果程序正在用WNDCLASS结构

注册一个在RC资源描述文件中用CLASS指令创建的对话框,它必须设置这个字段为DLGWINDOWEXTRA

hInstance:标识了该窗口类的窗口过程所在的模块实例的句柄,不能为NULL;

hIcon:标识了该窗口的图标,hIcon字段必须是一个图标的句柄,若hIcon字段为NULL,则无论如何用户把应用程序缩至最小时,

应用程序必须画一个图标。

hCursor:标识该窗口类的光标,hCursor必须是一个光标资源的句柄,若hCursor字段为NULL,则无论何时用户把应用程序缩至最小时,应用程序必须显示成设置光标形状

hbrBackground:标识了该窗口类的背景画笔,如果给出了颜色值,他必须时转换成下列的

HBRUSH类型之一的颜色 :
                COLOR_ACTIVEBORDER
                    COLOR_ACTIVECAPTION
                    COLOR_APPWORKSPACE
                    COLOR_BACKGROUND
                    COLOR_BTNFACE
                    COLOR_BTHSHADOW
                    COLOR_BTNTEXT
                    COLOR_CAPTIONTEXT
                    COLOR_GRAYTEXT
                    COLOR_HIGHLIGHT
                    COLOR_HIGHLIGHTTEXT
                    COLOR_INACTIVEBORDER
                    COLOR_INACTIVECAPTION
                    COLOR_MENU
                    COLOR_MENUTEXT
                    COLOR_SCROLLBAR
                    COLOR_WINDOW
                    COLOR_WINDOWFRAME
                    COLOR_WINDOWTEXT

 当hbrBackground字段为NULL时,每当需要绘制其用户区域时,应用程序必须自己来绘制其背景。应用程序可以通过处理WM_ERASEBKGND 消息或检查由 BeginPaint 函数填写的 PAINTSTRUCT 结构的fErase 字段来确定背景什么时候需要着色。

lpszMenuName:指向NULL结束的字符串,该字符串描述菜单的资源名,如同在资源文件里显示的名字一样。若使用一个整数标识菜单,可以使用MAKEINTRESOURCE宏。如果lpszMenuName为NULL,

  那么该窗口类的窗口将没有默认菜单。

lpszClassName:指向NULL结束的字符串,或者是一个原型(atom)。若该参数是一个原型,它必须是一个有先前调用RegisterClass或者 RegisterClassEx函数产生的类原型。类原型必须作为lpszClassName的低字,高字必须为0.若lpszClassName是一个字符串,它描述了窗口类名。这个类名可以是由RegisterClass或者RegisterClassEx注册的名字,或者是任何预定义的控件类名。

WNDCLASS wc;//定义窗口类结构体变量
static TCHAR* szAppName=TEXT("noxue);//定义窗口类名称
HWND hwnd=NULL;//设置窗口句柄
MSG msg;//消息结构
//下面填充窗口类信息,如图标、鼠标样式、背景、过程函数等
wc.style=CS_HRENRAW|CS_VREDRAW;//窗口样式
wc.lpfnWndProc=WndProc;//过程函数
wc.cbClsExtra=0;//扩展字段
wc.cbWndExtra=0;//扩展字段
wc.hInstance=hlntance;//当前实例句柄
wc.hIcon=LoadIcon(hlnstance,IDI_APPLICATION);//设置程序图标
wc.hCursor=LoadCursor(NULL,IDC_ARROW);//设置鼠标
wc.hbrBackground=(HBURSH)GetstockObject(WHITE_BRUSH)://用白色填充背景
wc.lpszMenuName=NULL;//菜单
wc.lpszClassName=szAppName;

2设置完后就向操作系统注册窗口类

while(!RegisterClass(&wc))//如果注册失败,发出警告
{
   MessageBox(NULL,TEXT("程序只能在windowNT下运行),szAppName,MB_ICONERROR);
   return 0;
}

3  开始创建窗口

hwnd代表窗口句柄,或者说是我们现在创建窗口的一个编号,程序运行的时候会有一个变量保存当前正操作的窗口编号,如果这个变量与hwnd的值相同,说明用户正在操作该窗口

//创建窗口

hwnd=CreateWindow(szAppName,TEXT("c语言创建的第一个窗口“),WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDFAULT,600,300,NULL,NULL,hlnstance,NULL);
//要注册的窗口类名,窗口标题,窗口的风格,窗口距离屏幕左上角的横纵坐标,窗口的宽度】高度】夫窗口句柄、当前实例句柄,值向一个值的指针,该值传递给窗口WM_CREATE消息,一般为NULL;

//显示窗口

ShowWindow(hwnd,iCmdshow);

//更新窗口

UpdateWindow(hwnd);

4 消息循环

//消息循环,一直停在这里,退出消息循环就表示程序结束了
while(Getmessage(&msg),NULL,0,0)//GetMessage()函数是从调用线程的消息队列中取出一条消息;对于每一个应用程序窗口线程,操作系统都会为其建立一个消息队列,当我们的窗口有消息时(即所有与这个窗口线程相关的消息),操作系统会把这个消息放到该线程的消息队列当中,我们的窗口程序就通过这个函数从自己的消息队列中取出一条一条具体的消息并进行相应操作。
{
    TranslateMessage(&msg);//翻译消息,对“消息对”的转化,如对键盘的WM_KEYDOWN和WM_KEYUP消息对
//转化为WM_CHAR消息,并且将转化后的新消息投递到我们的消息队列中去,这个转化操作不会影响原来的消
//息,只会产生一个新得消息
    DispatchMessage(&msg);//分发消息,函数将我们取出的消息传到窗口的回调函数去处理,可以理解为该函数将取出的消息路由给操作系统,然后操作系统去调用我们的窗口回调函数对这个消息进行处理。
}
return msg.wParam;//消息循环结束,即程序结束时 将信息返回系统

5 创建按钮

LRESULT  CALLBACK  WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)

窗口过程函数决定了当一个窗口从外界接受到不同的信息时,所采取的不同的反应,即主要用于处理发送窗口的信息

hwnd 是处理窗口的句柄,message是消息ID,代表不同的消息类型,wParam和lParam代表了消息的附加信息,附加信息会随着消息类型的不同而不同

当键盘消息发出时,wParam的值为按下按键的虚拟键码,IParam则存储按键相关状态信息。因此如果窗口对传入的键盘消息处理时,只需要判断wParam的值即可

当鼠标消息发出时,wParam的值为鼠标按键的信息,IParam则存储鼠标的坐标,高字节代表y坐标,低字节代表x坐标,即

g_y=HIWORD(IParam),g_x=LOWORD(IParam);

在Win32API中,WPARAM和LPARAM都是32位,习惯上,我们用LPARAM传递地址,而WPARAM传递参数

如果我要判断鼠标左键是否按下,用WParam==WM_LBUTTONDOWN判断

IPARAM是PMouseHooKStruct类型,主要是获得发送窗口句柄,鼠标坐标,以及其他信息

IPARAM用的时候需要强制转换,转换成PMouseHookStruct类型

LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    switch(message)
    {
       case WM_DESTROY://发送结束请求,里面的参数为退出码
       PostQuitMessage(0);
       break;
     }
return DefWindowProc(hwnd,message,wParam,lParam);//调用默认的过程函数
}

win32窗口程序,基本框架

#include<windows.h>
int WINAPI WinMain(HINSTANCE hlnstance,HINSTANCE hPrevinstance,PSTR szCmdLine,int iCmdShow){
  return 0;
}

int :代表返回值是整形

WINAPI:这个是调用预定

WinMain:这个是函数名,就像是main

HINSTANCE:自定义数据类型,是句柄型数据类型,相当于装入内存的资源的ID,比如我们的程序被加载到内存中,就是一个资源,就有一个编号,WinMain函数的第一个参数就是表示我们当前运行这个程序本身的资源id

hlstance:应用程序当前实例的句柄,这个值其实就是程序加载到内存空间后的首地址

hPrevInstance:应用程序的先前实例的句柄,对于同一个程序打开两次,出现两个窗口第一次打开的窗口就是先前实例的窗口

PSTR szCmdLine:

typedef char CHAR;

typedef CHAR* LPSTR,*PSTR;

这就说明PSTR就是个char类型的指针而已

那么这就是这个参数的作用就是接受命令行参数

比如 启动程序的时候用如下命令:zixue7.exe.admin password

那么这个szCmdLine中保存就是admin password这个字符串

这个值可以直接使用,也可以通过GetCommandLine()函数获取到

int iCmdShow:这个是控制窗口的显示状态,比如最大化,最小化,隐藏。

#include<Windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevlnstance, PSTR szCmdLine, int iCmdShow)
{
	WNDCLASS wc;
	static TCHAR* szAppName = TEXT("zixue7");
	HWND hwnd = NULL;
	MSG msg;
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WndProc;
	wc.cbWndExtra = 0;
	wc.cbClsExtra = 0;
	wc.hInstance = hInstance;
	wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszClassName = szAppName;
	wc.lpszMenuName = NULL;
	if (!RegisterClass(&wc))
	{
		MessageBox(NULL, TEXT("程序只能在windowsNT下运行"),
			szAppName, MB_ICONERROR);
		return 0;
	}
	hwnd=CreateWindow(szAppName,TEXT("c语言编写的第一个窗口程序-www.zixue7.com"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		400, 
		300, 
		NULL,
		NULL,
		hInstance,
		NULL);
	ShowWindow(hwnd, iCmdShow);
	UpdateWindow(hwnd);
	while (GetMessage(&msg,NULL,0,0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
	}
	return DefWindowProc(hwnd, message, wParam, lParam);
}

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: C语言不是一种用于创建图形用户界面的语言,它通常用于系统级编程或底层开发。 如果你想写一个图形界面程序,建议使用其他语言,如 C++ , Python,Java等等。这些语言有更好的图形库,可以帮助您快速开发图形用户界面。 例如,在 C++ 中,您可以使用 Qt 库创建图形界面。在 Python 中,您可以使用 Tkinter 库。 ### 回答2: 要用C语言写一个窗口程序,可以使用一些库,如Windows API或者GTK+等。下面是一个使用Windows API编写的简单窗口程序的示例: ```c #include <windows.h> // 窗口过程函数 LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, uMsg, wParam, lParam); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // 注册窗口类 WNDCLASS wc = {0}; wc.lpfnWndProc = WindowProc; wc.hInstance = hInstance; wc.lpszClassName = "MyWindowClass"; RegisterClass(&wc); // 创建窗口 HWND hwnd = CreateWindowEx( 0, // 扩展样式 "MyWindowClass", // 窗口类名 "我的窗口程序", // 窗口标题 WS_OVERLAPPEDWINDOW, // 窗口样式 CW_USEDEFAULT, CW_USEDEFAULT, // 窗口位置 CW_USEDEFAULT, CW_USEDEFAULT, // 窗口大小 NULL, NULL, hInstance, NULL); // 其他参数 // 显示窗口 ShowWindow(hwnd, nCmdShow); // 进入消息循环 MSG msg = {0}; while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } ``` 这个示例代码使用了Windows API来创建一个窗口,其窗口类名为"MyWindowClass",窗口标题为"我的窗口程序"。窗口的消息处理采用了一个窗口过程函数`WindowProc`,该函数在收到`WM_DESTROY`消息时会调用`PostQuitMessage`来退出消息循环,然后窗口就会被销毁。在`WinMain`函数中,首先注册了窗口类,然后创建窗口,并显示出来,最后进入消息循环处理窗口消息。当消息循环结束时,返回消息的`wParam`作为`WinMain`函数的返回值。 ### 回答3: C语言是一种面向过程的编程语言,主要用于系统级编程和嵌入式开发。它本身并不直接支持图形界面的开发,但可以通过使用第三方库来编写窗口程序。 一种常用的图形界面库是GTK+(GIMP Toolkit),它是一个开源的自由软件的用户界面工具包,可以用来编写图形界面程序。以下是使用C语言和GTK+库编写一个简单窗口程序的基本步骤: 1. 引入头文件和库文件:在程序的开头引入需要用到的头文件,如<gtk/gtk.h>和<glib.h>,并在编译时链接GTK+库文件。 2. 初始化GTK+库:在主函数中调用gtk_init()函数来初始化GTK+库。 3. 创建顶层窗口:使用GtkWidget指针声明一个顶层窗口窗口,并使用gtk_window_new()函数来创建一个新的顶层窗口。 4. 设置窗口属性:使用gtk_window_set_title()设置窗口标题,使用gtk_container_set_border_width()设置窗口边框宽度,使用gtk_window_set_default_size()设置窗口默认大小等。 5. 创建其他界面组件:使用GtkWidget指针声明其他需要的界面组件,并使用相应的构造函数创建它们。 6. 设置组件属性和布局:使用gtk_widget_set_property()函数设置组件属性,如文字标签的文本内容等。使用gtk_box_pack_start()函数将组件添加到布局容器中。 7. 设置事件处理函数:使用g_signal_connect()函数来连接组件的信号和事件处理函数,相应的事件处理函数将在组件触发相应事件时被调用。 8. 显示窗口和消息循环:使用gtk_widget_show_all()函数显示所有添加的组件,并调用gtk_main()函数启动GTK+的主循环,等待事件的触发与处理。 9. 释放资源:在程序结束前,使用gtk_main_quit()函数终止主循环,并释放由GTK+库分配的资源。 以上是使用C语言和GTK+库编写窗口程序的大致步骤,具体的开发过程和代码实现可以根据实际需求进行调整和编写

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值