《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. NW.js桌面应用开发(一)

    NWjs中文网 Electron中文网 一些需要了解的历史与特性,其实就是 NW.js 和 Electron的争议,建议还是亲自阅读一下各自的官网说明 1.下载SDK版工具 从淘宝NPM镜像下载,速度 ...

  2. java 判断数据是否为空

    /** * 方法描述:自定义判断是否为空 * 创建作者:李兴武 * 创建日期:2017-06-22 19:50:01 * * @param str the str * @return the bool ...

  3. 什么是nuget?nuget包是如何管理

    本文链接:https://blog.csdn.net/Microsoft_Mao/article/details/101159800做windows开发的,迟早会接触到nuget这个东西,那么今天我们 ...

  4. AcWing 开平方 浮点数二分

    #include<iostream> using namespace std; int main() { double x; cin>>x; ,r=x; ) //for(int ...

  5. php设计模式之观察者模式实例代码

    php提供的两个接口,一个被观察者接口SplSubject,一个或多个观察者接口SPLObserver,和一个可以储存对象的类SplObjectStorage.被观察者有三个方法,需要实现这三个方法, ...

  6. 题解【SP8002】HORRIBLE - Horrible Queries

    题面 题解 这是一道线段树的模板题. 题目需要我们维护一个支持区间修改.区间查询的一个数据结构,很容易想到线段树. 然后发现和洛谷上线段树的模板1是同一道题. 由于本题中每个数的初始值都为\(0\), ...

  7. Android开发实战——记账本(4)

    开发日志(4)——MainActivity 在MainActivity中编写了几个方法.首先,点击账本的一条记录可以选择删除他,然后重写了fab,使之在点击他后能够添加记录.还写了删除全部记录的方法. ...

  8. 【Python】【爬虫】爬取酷狗音乐网络红歌榜

    原理:我的上篇博客 import requests import time from bs4 import BeautifulSoup def get_html(url): ''' 获得 HTML ' ...

  9. codeforce 427 C. Checkposts(tarjan 强连通分量)

    题目链接:http://codeforces.com/contest/427/problem/C 题目大意是有n个junctions,这些junctions之间有m条道路,两两相连,现在在juncti ...

  10. HBase 启动后HMaster进程自动消失

    原因分析 1.hadoop 与 hbase 版本不兼容,导致的异常. 2.log日志信息显示 org.apache.hadoop.hbase.TableExistsException: hbase:n ...