关于C语言中的Windows.h
C语言中的Windows.h
其实吧这玩意我是不想写的,只要是个人就能理解这玩意的实用意义几乎为0,谁闲着没事会取用C语言去写一个交互界面啊,所以这玩意属于特殊情况下的特殊产物:老师强制要求使用C语言完成,又为了显得高级所以用这玩意(虽然最后也没有显得多么高级),这玩意写起来简直顶级折磨。其实经过查找,是可以用gui库代替的,但一是这玩意比Windows的原生API简单不了多少,二是引入gui库总会发生各种各样奇奇怪怪的报错,折磨了一会只好放弃(如果你说还有easyx可以用,但不好意思,我没有用msvc,用的是gcc,所以用不了)
总之经过一番痛苦面具,我终于写了一个基础的图形化界面出来,或许不怎么好看,但是它能跑,这就够了
接下来简单介绍一些需要用到的知识吧
主函数
1 |
|
如果你希望用Windows的API写一个图形化界面,那么必不可少的是首先引入windows.h
,然后写一个主函数,就是上面那个函数,这个函数的作用就相当于一般的C语言中的main函数,是整个程序的入口,看到那一长串的参数了吗,你一个都不用管,不需要在函数前声明,这些是由系统本身提供的参数,在运行时自动生成,但是我仍然会解释一下各个参数的含义
HINSTANCE
instance,翻译过来就是此刻,即刻,这个参数实际上是一个指针,指向的是程序此刻所占用的内存所在地,代表的是整个程序本身,你会发现第一个和第二个参数都是该类型,它们分别代表的是当前程序与上一个程序(或其父程序),现在,随着版本更新,第二个参数实际上已经没有了实际意义,在如今的代码中,系统将自动对齐赋值为NULLLPSTR ldCmdLine
这个参数实际上是个字符串,用来记录向命令行传递的参数,用来启动程序,我们接下来同样不用管nCmdShow
这个参数实际上是用来标识窗口状态的,如最大化最小化等等
了解了这些就可以在这个函数中写一些代码创建自己的图形化界面了
创建窗口
1 |
|
上面所展现的是简单的一个创建窗口流程,节选自我写的一个图书管理程序,接下来分开来讲一讲每个部分的含义
注册窗口类
1 |
|
就是这部分,一个窗口类就代表一个窗口,每创建一个窗口就应当注册一个窗口类,在C语言中这体现为一个结构体,来看看这个结构体中都有些什么吧
wc.lpfnWndProc = WindowProc
这是该窗口的过程函数,这个还没有提到,等会再说,如果向创建一个窗口看看效果的话直接写NULL就好wc.hInstance = hInstance
程序指针,说明这个窗口该运行在哪段程序下,赋的值就是刚才main函数中的第一个参数,这是有系统本身提供的,无需我们创造wc.lpszClassName = CLASS_NAME
这个类的名称,是这个类对外的标识,一般我们使用这个类的过程中都会以这个类的类名来作为指代,这里是刚定义的登陆界面类wc.hbrBackground = (HBRUSH)COLOR_WINDOW
这是这个类的背景的规定,,我调用了Windows的默认色彩(即5),并将其强制转换为画刷(HBRUSH),虽然这玩意事实上就是一个十六进制的数字用来表示十六种Windows常用的色彩,wc.hCursor = LoadCursor(NULL, IDC_ARROW)
这个参数是对当光标移动到当前页面时光标的参数的规定,使用默认值(等号左侧的函数无需关注其实际含义,就是用来获取当前鼠标歌参数的)
接下来就是注册或者说初始化这个类,也就是最后一行
展示窗口
1 |
|
上面前几次的计算都是为了创建窗口时确保窗口居中进行的,都是提前就规定好的,如果有需要直接用吧,
这里稍微吐槽一下这些奇奇怪怪的参数,最开始那两个参数SM_CXSCREEN和SM_CYSCREEN分别是define的0和1,就很难评价这种东西,不管替不替换这玩意的可读性都是一绝
接下来是创建窗口的部分也就是你所见的HWND
这个玩意的全称应该是handle of Windows,就是窗口的句柄(又是国内的奇葩翻译),handle有解决,处理的意思,也有把手把柄的含义,具体的含义请自己品,我也有点不会翻译了,这个东西在C语言中的本质也是一个指针,用来指向一个具体的窗口
CreateWindowEx的函数原型如下
1 |
|
简单解释一下,大概来说所谓的扩展窗口样式就是一些特殊的效果,主要支持(这些参数也是一串十六进制的数字)
WS_EX_TOPMOST
:窗口总是位于最前端。WS_EX_TOOLWINDOW
:创建工具窗口(如浮动工具栏)。WS_EX_LAYERED
:支持透明或半透明效果。
这里是0 ,即不需要任何样式,
然后是窗口样式,常见的样式如下
WS_OVERLAPPED
:标准的重叠窗口,带标题栏和边框。
WS_CAPTION
:窗口有标题栏。
WS_SYSMENU
:窗口有系统菜单(右键菜单)。
WS_MINIMIZEBOX
:窗口有最小化按钮。
WS_BORDER
:窗口带边框。
WS_POPUP
:创建弹出窗口。
WS_VISIBLE
:窗口初始时可见。
不同样式之间以|
分隔
然后是接下来的内容,我们这是最开始的窗口,本身没有父窗口,也不需要菜单,所以是两个NULL,程序实例就是系统提供的,然后附加数据部分可以无限填各种参数,但是我们不需要,所以NULL
然后展示对应的窗口 ShowWindow(hwnd, nCmdShow);
其中第二个参数可进行如下替换
**SW_SHOW
**:正常显示窗口。
**SW_HIDE
**:隐藏窗口。
**SW_MINIMIZE
**:最小化窗口。
**SW_MAXIMIZE
**:最大化窗口。
**SW_RESTORE
**:恢复窗口到正常状态。
信息输入
有了基础的界面,接下来就应该添加一些按钮来实现窗口了
首先我们要创建一个按钮
1 |
|
这里就要提出一个思想,就是对于Windows来说,所有的组件都是不同属性的窗口,首先看一看这个函数的原型
1 |
|
首先要解释一下关于窗口类名的事,Windows内置了几个窗口类名
分别是
"BUTTON"
:按钮。
"STATIC"
:静态文本标签。
"COMBOBOX"
:组合框。
"LISTBOX"
:列表框。
"EDIT":
编辑控件
然后这个按钮是登陆界面下的,所以是登陆窗口的字窗口,父窗口句柄选择登陆界面
还有一点注意,我们创建登陆按钮时创建了一个一个菜单,并选择将这个按钮在菜单中的名称命名为1
注意,这些窗口创建应当写在showWindows之前,写在展示窗口函数之后时不管用的
那么问题来了,我们只是创建了这些按钮和输入栏,如何知道它们被使用呢
这就需要理解电脑是如何获取键盘鼠标的操作信息的:消息队列
电脑回以极高的速度扫描各种硬件,并获得一个信息流,即我们所说的消息对列,在无操作时获得默认信息,在操作出现时消息队列中出现具体的操作信息,系统将其转义为具体的操作并进行执行,所以我们也应当在main函数中创建一个自己的消息队列
1 |
|
GetMessage(&msg, NULL, 0, 0)
是读取函数,会从系统的消息队列中不断读取信息并保存在msg中,最后两个0是只不限制消息类型,消息类型常见的有
**WM_PAINT
**:窗口需要重绘。
**WM_KEYDOWN
**:键盘按下事件。
**WM_LBUTTONDOWN
**:鼠标左键按下事件。
**WM_QUIT
**:程序退出消息。
然后是 TranslateMessage(&msg);
这个函数没什么可说的,翻译函数,将键盘输入的信息转换为人能理解的字符
DispatchMessage(&msg);
这个函数是分发函数,msg中包含自己从属于那个窗口的信息,它将会根据这个信息将信息分发至对应的过程函数进行处理
问题又来了,到底什么是过程函数呢
过程函数
贴一个我登录时的过程函数
1 |
|
还记得吗,登陆界面被绑定了这个过程函数,我们来看一看具体的内容
1 |
|
首先看一看这一行
这个函数的长相似乎不怎么对劲,它的返回值是什么类型?LRESULT,其实就是一个int,然后CALLBACK叫做函数签名或者说调用约定,CALLBACK是所有WINAPI的标准调用约定,然后就是函数名和参数了
接下来的代码只要英语好一点就可以理解,三个case分别是窗口创建时,检测到窗口内有命令出发时,窗口被关闭时
特别解释一下两点 if (LOWORD(wParam) == 1)
这个判断是重消息队列中读取到信息标识为1时进行操作,而这个标识就是刚才登陆按钮的标识
DefWindowProc(hwnd, uMsg, wParam, lParam);
这个是兜底的默认处理函数,负责处理一般的最小化,移动窗口等操作
MessageBox(hwnd, "创建用户界面失败!", "错误", MB_OK | MB_ICONERROR);
创建一个弹窗,从左到右依次是窗口句柄,窗口内容,窗口标题,窗口样式,具体样式类型如下
按钮类型(单选):
MB_OK
:只有一个 “确定” 按钮。MB_OKCANCEL
:包含 “确定” 和 “取消” 按钮。MB_YESNO
:包含 “是” 和 “否” 按钮。MB_RETRYCANCEL
:包含 “重试” 和 “取消” 按钮。
图标类型(单选):
MB_ICONERROR
:显示错误图标。MB_ICONWARNING
:显示警告图标。MB_ICONINFORMATION
:显示信息图标。MB_ICONQUESTION
:显示询问图标。
默认按钮类型:
MB_DEFBUTTON1
:第一个按钮为默认按钮。MB_DEFBUTTON2
:第二个按钮为默认按钮。MB_DEFBUTTON3
:第三个按钮为默认按钮。
其他函数
1 |
|
从输入栏中获取信息,三个参数分别是窗口句柄等待被输入的字符串指针,最大输入限制
接下来还有一个防止乱码的函数
1 |
|
这是以个创建字体的函数,具体的含义如下
1 |
|
最后将这以信息传递给对应的窗口即可
结语
终于写完了,痛苦啊,足足写了一下午才写完,也是至今写过最长的一篇,但是,不管怎么说,我写完啦!!
上今天的图