OpenGL学习1(基于SDK):全屏窗口,按ESC退出

2025-10-20 21:57:13

1、windows程序框架,建立一个窗口。纯手打程序,自己加了一些注释,关于对这段程序的理解,欢迎和大家一起探讨

2、#include<windows.h>

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int iCmdShow)

{

WNDCLASS wndclass;       //注册窗口类

wndclass.cbClsExtra=0;   

wndclass.cbWndExtra=0;

wndclass.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH); //黑色背景

wndclass.hInstance=hInstance;         

wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);         //鼠标指针

wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);       //小图标

wndclass.lpfnWndProc=WndProc;                        //回调函数

wndclass.lpszClassName="HelloWin";                   //类名

wndclass.lpszMenuName=NULL;                          //

wndclass.style=CS_HREDRAW|CS_VREDRAW;                //垂直重绘和水平重绘

if(!RegisterClass(&wndclass))                        //注册窗口

{

MessageBox(NULL,"注册窗口失败!","error",MB_OK);

return 0;

}

HWND hwnd=CreateWindow("HelloWin","HelloWin",WS_OVERLAPPEDWINDOW,    //创建窗口

CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,

NULL,NULL,hInstance,NULL);

ShowWindow(hwnd,iCmdShow);           //显示窗口

UpdateWindow(hwnd);                  //更新

MSG msg;

while(GetMessage(&msg,NULL,0,0))      //消息循环

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}

LRESULT CALLBACK WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)       //回调函数,各种消息

{

PAINTSTRUCT ps;

switch(msg)

{

case WM_CREATE:

return 0;

case WM_PAINT:

{

HDC hdc=BeginPaint(hWnd,&ps);

EndPaint(hWnd,&ps);

return 0;

}

case WM_DESTROY:

PostQuitMessage(0);

return 0;

}

return DefWindowProc(hWnd,msg,wParam,lParam);         //预处理消息

}

3、上面的程序,运行之后显示的是一个背景色为黑色的窗口

OpenGL学习1(基于SDK):全屏窗口,按ESC退出

4、接下来我们实现下全屏显示。分为两步,一、修改显示设备的属性,二、对窗口样式做一些处理。

首先我们修改显示设备的属性,要用到的是LONG ChangeDisplaySettings(  LPDEVMODE lpDevMode,    DWORD dwflags         );

第一个参数,指向一个DEVMODE结构,MSDN上的说明是 ”describes the graphics mode to switch to“

DEVMODE包含很多字段,我们在这里用到的有

dmSize(结构大小),

dmBitsPerPel(每个像素的字节位)

dmPelsWidth(屏幕宽),

dmPelsHeight(屏幕高度),

dmFields(位标记,说明哪些字段有效,在这里将它设置为”DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT“表示前面设置的,屏幕高、宽和像素字节有效)

在这里需要注意的是dmPelsWidth和dmPelsHeight的值,需要设置成和CreateWindow里面的宽,高一样,比如我们这里都设置成为800,600。

第二个参数,我们用 CDS_FULLSCREEN,在新的显示模式下,将任务栏从屏幕移除,并强制windows留下其它的屏幕部分

该函数的如果成功返回DISP_CHANGE_SUCCESSFUL,还有返回 DISP_CHANGE_RESTART,表示计算机需重启来让设置的显示模式工作,等等(详情看msdn吧~)

所以,修改显示设备属性的代码段如下:

5、 DEVMODE dmScreenSettings;

memset(&dmScreenSettings,0,sizeof(dmScreenSettings));

dmScreenSettings.dmSize=sizeof(dmScreenSettings); //结构大小

dmScreenSettings.dmPelsHeight=600;  //屏幕的高

dmScreenSettings.dmPelsWidth=800;   //屏幕的宽

dmScreenSettings.dmBitsPerPel=16;  //像素字节位数

dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;  //位标记,标明哪些字节是有效的,对应前面设置的三个参数

if(ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)

{

if (MessageBox(NULL,"修改显示设备属性失败!是否继续用一般模式显示","提示",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)

{

fullscreen=FALSE;

}

else

{

MessageBox(NULL,"点击关闭窗口","ERROR",MB_OK|MB_ICONSTOP);

return FALSE;

}

}

6、修改了显示设备的属性后,我们要对窗口样式做一些处理,如,去掉窗口的顶层/边框,还要把鼠标指针给隐藏起来(因为全屏的窗口这些东西都没有)

代码段如下:

7、 dwExStyle=WS_EX_APPWINDOW; //隐藏顶层的窗口

dwStyle=WS_POPUP;   //没有边框的窗口

ShowCursor(FALSE);  //不显示鼠标指针

8、这样全屏就实现了,下面来说下设置ESC退出程序,只要在回到函数的消息处理中添加按键处理消息WM_KEYDOWN就可以了==

1、当ESC被按下,我们发送WM_CLOSE应用消息

2、在消息循环中判断msg.message是否为WM_CLOSE。关于这个,为了理解清楚,查了下文档,GetMessage里面的msg是用来接受来自线程消息队列里的消息信息的(英文不好,所以还是:Pointer to an MSG structure that receives message information from the thread's message queue. )而,msg.message指定消息成员(Specifies the message number.)如果接受到了WM_CLOSE消息,就用break,结束消息循环

程序段如下

9、回调函数里添加(按照此方式写,方面添加其他的按键处理)

case WM_KEYDOWN:

switch(wParam)

{

case VK_ESCAPE:

PostMessage(hWnd,WM_CLOSE,0,0);

break;

}

return 0;

2、消息处理函数改为:

MSG msg;

while(GetMessage(&msg,NULL,0,0))

{

if(msg.message==WM_CLOSE)

{

break;

}

TranslateMessage(&msg);

DispatchMessage(&msg);

}

10、好了这样就大功告成了,程序运行时没错的

OpenGL学习1(基于SDK):全屏窗口,按ESC退出

11、尝试了下用截图软件,显示分辨率是800*600,800*600之外的不能截,话说我是不是要研究下截图软件了==

最后贴出完整的程序吧,里面添加了一些其他的样式(去掉那些样式也能正常运行显示,所以自己理解就好啦,不理解的尽量去理解,还没理解到自己想要的程序,就不用,哼!),加了注释了,应该比较好懂

12、#include<windows.h>

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int iCmdShow)

{

DWORD dwExStyle;

DWORD dwStyle;

WNDCLASS wndclass;

wndclass.cbClsExtra=0;

wndclass.cbWndExtra=0;

wndclass.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);

wndclass.hInstance=hInstance;

wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);

wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);

wndclass.lpfnWndProc=WndProc;

wndclass.lpszClassName="HelloWin";

wndclass.lpszMenuName=NULL;

wndclass.style=CS_HREDRAW|CS_VREDRAW;

if(!RegisterClass(&wndclass))

{

MessageBox(NULL,"注册失败!","error",MB_OK);

return 0;

}

BOOL fullscreen=true;

if(MessageBox(NULL,"是否全屏显示?","提示",MB_YESNO|MB_ICONQUESTION)==IDNO)

{

fullscreen=false;

}

if(fullscreen)

{

DEVMODE dmScreenSettings;

memset(&dmScreenSettings,0,sizeof(dmScreenSettings));

dmScreenSettings.dmSize=sizeof(dmScreenSettings); //结构大小

dmScreenSettings.dmPelsHeight=600;  //屏幕的高

dmScreenSettings.dmPelsWidth=800;   //屏幕的宽

dmScreenSettings.dmBitsPerPel=16;  //像素字节位数

dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;  //位标记,标明哪些字节是有效的,对应前面设置的三个参数

if(ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)

{

if (MessageBox(NULL,"修改显示设备属性失败!是否继续用一般模式显示","提示",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)

{

fullscreen=FALSE;

}

else

{

MessageBox(NULL,"点击关闭窗口","ERROR",MB_OK|MB_ICONSTOP);

return FALSE;

}

}

if(fullscreen)

{

dwExStyle=WS_EX_APPWINDOW; //隐藏顶层的窗口

dwStyle=WS_POPUP;   //没有边框的窗口

ShowCursor(FALSE);  //不显示鼠标指针

}

else

{

dwExStyle=WS_EX_APPWINDOW|WS_EX_WINDOWEDGE;

dwStyle=WS_OVERLAPPEDWINDOW;

}

RECT  winRect;

winRect.left=0;

winRect.right=800;

winRect.top=0;

winRect.bottom=600;

AdjustWindowRectEx(&winRect, dwStyle,FALSE,dwExStyle);//依据所需客户矩形大小,计算需要的窗口矩形的大小。

                                                     // 计算出的窗口矩形随后可以传送给CreateWindowEx函数,

                                                     //用于创建一个客户区所需大小的窗口。

}

HWND hwnd=CreateWindowEx(dwExStyle,"HelloWin","HelloWin",

dwStyle|WS_CLIPSIBLINGS|WS_CLIPCHILDREN,  //WS_CLIPSIBLINGS|WS_CLIPCHILDREN参考后面的参考资料

0,0,800,600,

NULL,NULL,hInstance,NULL);

ShowWindow(hwnd,iCmdShow);

UpdateWindow(hwnd);

MSG msg;

while(GetMessage(&msg,NULL,0,0))

{

if(msg.message==WM_CLOSE)

{

break;

}

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}

LRESULT CALLBACK WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)

{

PAINTSTRUCT ps;

switch(msg)

{

case WM_CREATE:

return 0;

case WM_PAINT:

{

HDC hdc=BeginPaint(hWnd,&ps);

EndPaint(hWnd,&ps);

return 0;

}

case WM_KEYDOWN:

switch(wParam)

{

case VK_ESCAPE:

PostMessage(hWnd,WM_CLOSE,0,0);

break;

}

return 0;

case WM_CLOSE:

DestroyWindow(hWnd);

return 0;

case WM_DESTROY:

PostQuitMessage(0);

return 0;

}

return DefWindowProc(hWnd,msg,wParam,lParam);

}

13、最后主要的参考资料是《Beginning OpenGL Game Programming》以及Nehe的OpenGL中文教程

其他一些解读资料,来源博客,百科(好吧,不能加链接,只能标题,大家感兴趣可以搜一搜,我已深深地沉醉在不快乐痛苦的边缘了~):

WM_CLOSE WM_DESTROY WM_QUIT 区别

窗体的扩展样式和其值

关于DEVMODE的数据结构--显示设备的属性

很多框架在消息循环是喜欢用PeekMessage,所以,如何区别

WS_CLIPCHILDREN和WS_CLIPSIBLINGS的理解(不知道从哪转载的,图片挂了,但是点击右键-属性,把图片的地址贴到地址栏可以显示)

AdjustWindowRectEX函数 百科

14、最后申明下,版权的问题,如果您认为我侵犯了您或者其他人的著作权一定要跟我说呀~

声明:本网站引用、摘录或转载内容仅供网站访问者交流或参考,不代表本站立场,如存在版权或非法内容,请联系站长删除,联系邮箱:site.kefu@qq.com。
猜你喜欢