《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. IntelliJ IDEA 2017.3百度-----树状结构

    ------------恢复内容开始------------ ------------恢复内容结束------------

  2. rpm命令怎么指定安装位置

    rpm   -ivh    --prefix=路径      FILE.rpm

  3. 题解【洛谷P1807】最长路_NOI导刊2010提高(07)

    题面 题解 最长路模板. 只需要在最短路的模板上把符号改一下\(+\)初值赋为\(-1\)即可. 注意一定是单向边,不然出现了正环就没有最长路了,就好比出现了负环就没有最短路了. 只能用\(SPFA\ ...

  4. Linux - Shell - find - 基础

    概述 find 基础 背景 查找文件 人的记忆能力, 是有限的 计算机里的文件数量, 虽然不是无限, 但是也不少 要去找那些 记不清楚的文件, 必然要用查找 准备 OS centos7 用户 root ...

  5. fader

    fader在音频处理中是比较基础的处理.通常用于平滑的调节音量,或是音频的渐入和渐出效果. 比较常见的fader有line和cubic线型的fader. line fader即fader的渐变过程是线 ...

  6. 为什么Oracle等数据库软件可以同时创建多个连接

    首先我们要明确的是一个IP跟一个端口确定的是一个进程的地址,也就是我们运行了一个Oracle的数据库,这时候就已经确定的了. oracle监听器也是一个TCP/IP网络中的进程,默认的端口号是1521 ...

  7. 美多商城后台MIS系统部署之Nginx配置

    先进入Nginx的配置文件中,进行配置. Nginx配置文件夹的区别: cd /etc/nginx/conf.d/   创建.conf后缀的文件 /etc/nginx/sites-enabled  创 ...

  8. springboot项目入门解析

                     config:主要用来存储配置文件,以及其他不怎么动用的信息. controller:项目的主要控制文件 dao:           主要用来操作数据库 entit ...

  9. win7的mstsc无法远程的解决方法

    第一,开启远程功能,计算机上右击-属性,如下图. 第二,打开服务,开启这个,如下图 第三,为要远程的计算机设置账号和密码, 第四,mstsc时,可以设置记住密码,这样简单.

  10. 7-3 Path to Infinity(还没ac)

    留坑 #include<bits/stdc++.h> using namespace std; ; ; typedef long long ll; string s,t; ,tol2=,t ...