《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. # node中的url常用方法解析

    url字符串是一个结构化的字符串,由好几个有意义部分组成.我们在工作中不可避免的会用到其中的某个部分,最原始的通过字符串截取和正则匹配的方法难免用起来会不太方便和美观,所以在我们的nodejs中提供了 ...

  2. AcWing 两个简单的位运算操作

    //是柱状数组的一个基操作 //返回n的最后一位1:lowbit(n) = n & -n //比如 x=1010 那么返回10 x=101000 返回1000 #include<bits ...

  3. Junit +cucumber 运行报错 initiallizationError

    step1: 访问 https://search.maven.org/  搜索下载相关jar包 step2: 访问 http://maven.outofmemory.cn/info.cukes/cuc ...

  4. php curl请求 header头携带参数

    $headers = array(    'api-key:'.$key,    'authorization:'.$authorization,      ); //初始化    $curl = c ...

  5. nmon+Java Nmon Analyser进行nmon监控数据可视化分析

    我们知道nmon是一款轻量级的系统占用极少,监控功能非常强大支持跨平台ARM,centos,ubuntu等等系统的工具下载地:centos7 wget http://sourceforge.net/p ...

  6. JSON--WEB SERVICE

    Query ajax webservice:get 和 post 一.GET 方式 客户端 复制代码代码如下: var data = { classCode: "0001"}; / ...

  7. opencv:边缘提取

    #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace st ...

  8. mpvue 小程序 使用wx.request请求数据

    1.创建src下创建utils/wx-request.js const host = 'http://10.0.0.6:8081' function request (url, method, dat ...

  9. Springboot MongoTemplate

    springboot mongodb配置解析 MongoTemplate进行增删改查 mongoTemplate 手把手教springboot访问/操作mongodb(查询.插入.删除) Spring ...

  10. 有趣、实用的c# 游戏源码下载网站

    在游戏开发的学习或工作中,利用完好的游戏源码可以事半功倍,不仅可以逆向学习开拓思维,也可以大大减少设计周期. 那想用c#来编写游戏的话,游戏源码在哪里找呢?下面整理了几个性价比高一些的网站,推荐给大家 ...