《MFC dialog中加入OpenGL窗体》

最近学习了如何在MFC对话框程序中加入OpenGL窗体的方法,在这里将自己的实现过程归纳一下。

步骤零: 加入PictureControl控件

新建MFC对话框程序,删除对话框上的按钮控件的Label控件,然后向窗体添加PictureControl控件,作为绘制的窗体。

将该控件的ID设置为:IDC_RENDER

步骤一: 加入OpenGL的lib文件和头文件

在项目上单击右键,添加OpenGL的lib文件,freeglut_static.lib和gltools.lib,如下。

然后在stdafx.h中包含相关的头文件如下:

步骤二: 设置对话框的头文件***Dlg.h

在对话框头文件中声明相关的变量:

     HDC hrenderDC;  //设备上下文
HGLRC hrenderRC; //渲染上下文
float m_yRotate; //转速
int PixelFormat; //像素格式

在对话框头文件中声明相关方法:

     BOOL SetWindowPixelFormat(HDC hDC);  //设定像素格式
BOOL CreateViewGLContext(HDC hDC); //view GL Context
void RenderScene(); //绘制场景

加入消息映射函数:

afx_msg void OnTimer(UINT nIDEvent);

具体的对话框头文件如下:

 // OpenGLTest1Dlg.h : 头文件
// #pragma once // COpenGLTest1Dlg 对话框
class COpenGLTest1Dlg : public CDialogEx
{
// 构造
public:
COpenGLTest1Dlg(CWnd* pParent = NULL); // 标准构造函数 BOOL SetWindowPixelFormat(HDC hDC); //设定像素格式
BOOL CreateViewGLContext(HDC hDC); //view GL Context
void RenderScene(); //绘制场景 HDC hrenderDC; //设备上下文
HGLRC hrenderRC; //渲染上下文
float m_yRotate; //转速
int PixelFormat; //像素格式 // 对话框数据
enum { IDD = IDD_OPENGLTEST1_DIALOG }; protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现
protected:
HICON m_hIcon; // 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnTimer(UINT nIDEvent);
DECLARE_MESSAGE_MAP()
};

步骤三: 设置对话框的源文件***Dlg.cpp

a. 开启定时器消息循环

在消息循环的代码块中加入ON_WM_TIMER()消息循环:

 BEGIN_MESSAGE_MAP(COpenGLTest1Dlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_TIMER()
END_MESSAGE_MAP()

这里的OnTimer函数用于相应SetTimer消息。当SetTimer设置的时间到了,就会自动调用OnTimer()函数。

写OnTimer函数的函数体,如下所示:

 void COpenGLTest1Dlg::OnTimer(UINT nIDEvent) //实时绘制场景
{
// TODO: Add your message handler code here and/or call default
RenderScene();
m_yRotate +=;
CDialog::OnTimer(nIDEvent);
}

b. 写函数SetWindowPixelFormat,用于生成像素格式

    函数体如下所示:

 BOOL COpenGLTest1Dlg::SetWindowPixelFormat(HDC hDC)
{
PIXELFORMATDESCRIPTOR pixelDesc; pixelDesc.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pixelDesc.nVersion = ; pixelDesc.dwFlags = PFD_DRAW_TO_WINDOW |
PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER |
PFD_TYPE_RGBA; pixelDesc.iPixelType = PFD_TYPE_RGBA;
pixelDesc.cColorBits = ;
pixelDesc.cRedBits = ;
pixelDesc.cRedShift = ;
pixelDesc.cGreenBits = ;
pixelDesc.cGreenShift = ;
pixelDesc.cBlueBits = ;
pixelDesc.cBlueShift = ;
pixelDesc.cAlphaBits = ;
pixelDesc.cAlphaShift = ;
pixelDesc.cAccumBits = ;
pixelDesc.cAccumRedBits = ;
pixelDesc.cAccumGreenBits = ;
pixelDesc.cAccumBlueBits = ;
pixelDesc.cAccumAlphaBits = ;
pixelDesc.cDepthBits = ;
pixelDesc.cStencilBits = ;
pixelDesc.cAuxBuffers = ;
pixelDesc.iLayerType = PFD_MAIN_PLANE;
pixelDesc.bReserved = ;
pixelDesc.dwLayerMask = ;
pixelDesc.dwVisibleMask = ;
pixelDesc.dwDamageMask = ; PixelFormat = ChoosePixelFormat(hDC,&pixelDesc);
if(PixelFormat==) // Choose default
{
PixelFormat = ;
if(DescribePixelFormat(hDC,PixelFormat,
sizeof(PIXELFORMATDESCRIPTOR),&pixelDesc)==)
{
return FALSE;
}
} if(SetPixelFormat(hDC,PixelFormat,&pixelDesc)==FALSE) {
return FALSE;
} return TRUE;
}

c. 写函数CreateViewGLContext,用于生成渲染上下文

具体函数体如下:

 BOOL COpenGLTest1Dlg::CreateViewGLContext(HDC hDC)
{
hrenderRC = wglCreateContext(hDC); if(hrenderRC==NULL)
return FALSE; if(wglMakeCurrent(hDC,hrenderRC)==FALSE)
return FALSE; return TRUE;
}

d. 写函数RenderScene,用于绘制场景

具体函数体如下:

 void COpenGLTest1Dlg::RenderScene()
{ /////////////////////////////////////////////////
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity();
glTranslatef(0.0f,0.0f,-6.0f); // Move Left 1.5 Units And Into The Screen 6.0
glRotated(m_yRotate, 0.0, 1.0, 0.0);
glBegin(GL_TRIANGLES); // Drawing Using Triangles glVertex3f( 0.0f, 1.0f, 0.0f); // Top
glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
glEnd(); // Finished Drawing The Triangle
SwapBuffers(hrenderDC);
}

e. 在对话框初始化程序OnInitDialog中添加初始化代码

具体代码如下:

 ///////////////////////OPENGL INIT/////////////////////////
CWnd *wnd=GetDlgItem(IDC_RENDER);
hrenderDC=::GetDC(wnd->m_hWnd);
if(SetWindowPixelFormat(hrenderDC)==FALSE)
return ; if(CreateViewGLContext(hrenderDC)==FALSE)
return ; glPolygonMode(GL_FRONT,GL_FILL);
glPolygonMode(GL_BACK,GL_FILL);
///////////////////////////////////////////
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH);
glViewport(,,,);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(,,0.1,100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
/////////////////////////////////////////////////////////////////////////
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY); SetTimer(,,); ////////////////////////////////////////////////////////////////

    f. 整个.cpp源代码

 // OpenGLTest1Dlg.cpp : 实现文件
// #include "stdafx.h"
#include "OpenGLTest1.h"
#include "OpenGLTest1Dlg.h"
#include "afxdialogex.h" #ifdef _DEBUG
#define new DEBUG_NEW
#endif // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialogEx
{
public:
CAboutDlg(); // 对话框数据
enum { IDD = IDD_ABOUTBOX }; protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现
protected:
DECLARE_MESSAGE_MAP()
}; CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
} void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
} BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP() // COpenGLTest1Dlg 对话框 COpenGLTest1Dlg::COpenGLTest1Dlg(CWnd* pParent /*=NULL*/)
: CDialogEx(COpenGLTest1Dlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
} void COpenGLTest1Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
} BEGIN_MESSAGE_MAP(COpenGLTest1Dlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_TIMER()
END_MESSAGE_MAP() // COpenGLTest1Dlg 消息处理程序 BOOL COpenGLTest1Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
} // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码
///////////////////////OPENGL INIT/////////////////////////
CWnd *wnd=GetDlgItem(IDC_RENDER);
hrenderDC=::GetDC(wnd->m_hWnd);
if(SetWindowPixelFormat(hrenderDC)==FALSE)
return ; if(CreateViewGLContext(hrenderDC)==FALSE)
return ; glPolygonMode(GL_FRONT,GL_FILL);
glPolygonMode(GL_BACK,GL_FILL);
///////////////////////////////////////////
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH);
glViewport(,,,);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(,,0.1,100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
/////////////////////////////////////////////////////////////////////////
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY); SetTimer(,,); ////////////////////////////////////////////////////////////////
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
} void COpenGLTest1Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
} // 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。 void COpenGLTest1Dlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), ); // 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + ) / ;
int y = (rect.Height() - cyIcon + ) / ; // 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
} //当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR COpenGLTest1Dlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
} BOOL COpenGLTest1Dlg::SetWindowPixelFormat(HDC hDC)
{
PIXELFORMATDESCRIPTOR pixelDesc; pixelDesc.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pixelDesc.nVersion = ; pixelDesc.dwFlags = PFD_DRAW_TO_WINDOW |
PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER |
PFD_TYPE_RGBA; pixelDesc.iPixelType = PFD_TYPE_RGBA;
pixelDesc.cColorBits = ;
pixelDesc.cRedBits = ;
pixelDesc.cRedShift = ;
pixelDesc.cGreenBits = ;
pixelDesc.cGreenShift = ;
pixelDesc.cBlueBits = ;
pixelDesc.cBlueShift = ;
pixelDesc.cAlphaBits = ;
pixelDesc.cAlphaShift = ;
pixelDesc.cAccumBits = ;
pixelDesc.cAccumRedBits = ;
pixelDesc.cAccumGreenBits = ;
pixelDesc.cAccumBlueBits = ;
pixelDesc.cAccumAlphaBits = ;
pixelDesc.cDepthBits = ;
pixelDesc.cStencilBits = ;
pixelDesc.cAuxBuffers = ;
pixelDesc.iLayerType = PFD_MAIN_PLANE;
pixelDesc.bReserved = ;
pixelDesc.dwLayerMask = ;
pixelDesc.dwVisibleMask = ;
pixelDesc.dwDamageMask = ; PixelFormat = ChoosePixelFormat(hDC,&pixelDesc);
if(PixelFormat==) // Choose default
{
PixelFormat = ;
if(DescribePixelFormat(hDC,PixelFormat,
sizeof(PIXELFORMATDESCRIPTOR),&pixelDesc)==)
{
return FALSE;
}
} if(SetPixelFormat(hDC,PixelFormat,&pixelDesc)==FALSE) {
return FALSE;
} return TRUE;
} BOOL COpenGLTest1Dlg::CreateViewGLContext(HDC hDC)
{
hrenderRC = wglCreateContext(hDC); if(hrenderRC==NULL)
return FALSE; if(wglMakeCurrent(hDC,hrenderRC)==FALSE)
return FALSE; return TRUE;
} void COpenGLTest1Dlg::RenderScene()
{ /////////////////////////////////////////////////
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity();
glTranslatef(0.0f,0.0f,-6.0f); // Move Left 1.5 Units And Into The Screen 6.0
glRotated(m_yRotate, 0.0, 1.0, 0.0);
glBegin(GL_TRIANGLES); // Drawing Using Triangles glVertex3f( 0.0f, 1.0f, 0.0f); // Top
glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
glEnd(); // Finished Drawing The Triangle
SwapBuffers(hrenderDC);
} void COpenGLTest1Dlg::OnTimer(UINT nIDEvent) //实时绘制场景
{
// TODO: Add your message handler code here and/or call default
RenderScene();
m_yRotate +=;
CDialog::OnTimer(nIDEvent);
}

步骤四: 运行调试

运行结果如下所示:

《MFC dialog中加入OpenGL窗体》的更多相关文章

  1. 简单物联网:外网访问内网路由器下树莓派Flask服务器

    最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...

  2. 利用ssh反向代理以及autossh实现从外网连接内网服务器

    前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...

  3. 外网访问内网Docker容器

    外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...

  4. 外网访问内网SpringBoot

    外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...

  5. 外网访问内网Elasticsearch WEB

    外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...

  6. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  7. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  8. 怎样从外网访问内网CouchDB数据库

    外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...

  9. 怎样从外网访问内网DB2数据库

    外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...

  10. 怎样从外网访问内网OpenLDAP数据库

    外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...

随机推荐

  1. vue组件引入

    /src/route/index.js import Demo2 from '@/pages/demo2/index.vue' { path : '/demo2', name : 'demo2', c ...

  2. 【Unity|C#】基础篇(0)——C#与.NET框架

    [学习资料] <C#图解教程>(第1章):https://www.cnblogs.com/moonache/p/7687551.html 电子书下载:https://pan.baidu.c ...

  3. Flink系统配置

    Flink 系统配置 Flink 提供了多个配置参数,用于调整Flink的行为与性能,所有参数均在flink-config.yaml 文件中.下面我们介绍一下几个主要配置. Java and Clas ...

  4. MySQL5.7的参数优化

    https://www.cnblogs.com/zhjh256/p/9260636.html query_cache_size = 0query_cache_type=0innodb_undo_tab ...

  5. testng的注解

    今天又学了点testng的新知识.原来在testng执行用例时,同一个class中的各个method按照字母顺序执行.为了实现自定义顺序执行,怎么办呢? 加入注解priority,举例如下: http ...

  6. Django_MTV和虚拟环境

    1. MVT模型 2. 虚拟环境 """ 1.安装虚拟环境的命令: 1)sudo pip install virtualenv #安装虚拟环境 2)sudo pip in ...

  7. 每天进步一点点------Xilinx DCM

    时钟---锁相环 1.       Xilinx DCM 数字时钟管理模块(Digital Clock Manager,DCM)是基于Xilinx的其他系列器件所采用的数字延迟锁相环(DLL,Dela ...

  8. Django中的check指令和sqlmigrate指令

    官方文档的解释如下: Django 有一个自动执行数据库迁移并同步管理你的数据库结构的命令 - 这个命令是 migrate,我们马上就会接触它 - 但是首先,让我们看看迁移命令会执行哪些 SQL 语句 ...

  9. 出现 HTTP Status 500 - Servlet.init() for servlet springmvc threw exception 异常

    出现这种异常在网上搜了搜 ,大多数都是说jdk和tomcat版本的问题:而我前几天都是运行得好好的,今天就编写了代码一运行项目发现报了这个错误.后台仔细看了看错误信息.结果是在你的项目中有相同的req ...

  10. JDBC简单代码

    1..写简单sql语句执行 DROP TABLE IF EXISTS `jdbctest`; CREATE TABLE `jdbctest` ( `id` ) NOT NULL AUTO_INCREM ...