《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

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

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

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

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

加入消息映射函数:

1 afx_msg void OnTimer(UINT nIDEvent);

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

 1 // OpenGLTest1Dlg.h : 头文件
 2 //
 3
 4 #pragma once
 5
 6
 7 // COpenGLTest1Dlg 对话框
 8 class COpenGLTest1Dlg : public CDialogEx
 9 {
10 // 构造
11 public:
12     COpenGLTest1Dlg(CWnd* pParent = NULL);    // 标准构造函数
13
14     BOOL SetWindowPixelFormat(HDC hDC);  //设定像素格式
15     BOOL CreateViewGLContext(HDC hDC);   //view GL Context
16     void RenderScene();  //绘制场景
17
18     HDC hrenderDC;  //设备上下文
19     HGLRC hrenderRC;  //渲染上下文
20     float m_yRotate;  //转速
21     int PixelFormat;    //像素格式
22
23 // 对话框数据
24     enum { IDD = IDD_OPENGLTEST1_DIALOG };
25
26     protected:
27     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
28
29
30 // 实现
31 protected:
32     HICON m_hIcon;
33
34
35     // 生成的消息映射函数
36     virtual BOOL OnInitDialog();
37     afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
38     afx_msg void OnPaint();
39     afx_msg HCURSOR OnQueryDragIcon();
40     afx_msg void OnTimer(UINT nIDEvent);
41     DECLARE_MESSAGE_MAP()
42 };

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

a. 开启定时器消息循环

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

1 BEGIN_MESSAGE_MAP(COpenGLTest1Dlg, CDialogEx)
2     ON_WM_SYSCOMMAND()
3     ON_WM_PAINT()
4     ON_WM_QUERYDRAGICON()
5     ON_WM_TIMER()
6 END_MESSAGE_MAP()

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

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

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

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

    函数体如下所示:

 1 BOOL COpenGLTest1Dlg::SetWindowPixelFormat(HDC hDC)
 2 {
 3 PIXELFORMATDESCRIPTOR pixelDesc;
 4
 5 pixelDesc.nSize = sizeof(PIXELFORMATDESCRIPTOR);
 6 pixelDesc.nVersion = 1;
 7
 8 pixelDesc.dwFlags = PFD_DRAW_TO_WINDOW |
 9      PFD_SUPPORT_OPENGL |
10      PFD_DOUBLEBUFFER |
11      PFD_TYPE_RGBA;
12
13 pixelDesc.iPixelType = PFD_TYPE_RGBA;
14 pixelDesc.cColorBits = 32;
15 pixelDesc.cRedBits = 0;
16 pixelDesc.cRedShift = 0;
17 pixelDesc.cGreenBits = 0;
18 pixelDesc.cGreenShift = 0;
19 pixelDesc.cBlueBits = 0;
20 pixelDesc.cBlueShift = 0;
21 pixelDesc.cAlphaBits = 0;
22 pixelDesc.cAlphaShift = 0;
23 pixelDesc.cAccumBits = 0;
24 pixelDesc.cAccumRedBits = 0;
25 pixelDesc.cAccumGreenBits = 0;
26 pixelDesc.cAccumBlueBits = 0;
27 pixelDesc.cAccumAlphaBits = 0;
28 pixelDesc.cDepthBits = 0;
29 pixelDesc.cStencilBits = 1;
30 pixelDesc.cAuxBuffers = 0;
31 pixelDesc.iLayerType = PFD_MAIN_PLANE;
32 pixelDesc.bReserved = 0;
33 pixelDesc.dwLayerMask = 0;
34 pixelDesc.dwVisibleMask = 0;
35 pixelDesc.dwDamageMask = 0;
36
37 PixelFormat = ChoosePixelFormat(hDC,&pixelDesc);
38 if(PixelFormat==0) // Choose default
39 {
40  PixelFormat = 1;
41  if(DescribePixelFormat(hDC,PixelFormat,
42   sizeof(PIXELFORMATDESCRIPTOR),&pixelDesc)==0)
43  {
44   return FALSE;
45  }
46 }
47
48 if(SetPixelFormat(hDC,PixelFormat,&pixelDesc)==FALSE)
49
50 {
51  return FALSE;
52 }
53
54 return TRUE;
55 } 

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

具体函数体如下:

 1 BOOL COpenGLTest1Dlg::CreateViewGLContext(HDC hDC)
 2 {
 3 hrenderRC = wglCreateContext(hDC);
 4
 5 if(hrenderRC==NULL)
 6  return FALSE;
 7
 8 if(wglMakeCurrent(hDC,hrenderRC)==FALSE)
 9  return FALSE;
10
11
12
13 return TRUE;
14 } 

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

具体函数体如下:

 1 void COpenGLTest1Dlg::RenderScene()
 2 {
 3
 4
 5  /
 6  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 7
 8
 9  glLoadIdentity();
10  glTranslatef(0.0f,0.0f,-6.0f);      // Move Left 1.5 Units And Into The Screen 6.0
11  glRotated(m_yRotate, 0.0, 1.0, 0.0);
12  glBegin(GL_TRIANGLES); // Drawing Using Triangles
13
14   glVertex3f( 0.0f, 1.0f, 0.0f);     // Top
15   glVertex3f(-1.0f,-1.0f, 0.0f);     // Bottom Left
16   glVertex3f( 1.0f,-1.0f, 0.0f);     // Bottom Right
17  glEnd();           // Finished Drawing The Triangle
18  SwapBuffers(hrenderDC);
19 } 

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

具体代码如下:

 1 ///OPENGL INIT/
 2     CWnd *wnd=GetDlgItem(IDC_RENDER);
 3     hrenderDC=::GetDC(wnd->m_hWnd);
 4     if(SetWindowPixelFormat(hrenderDC)==FALSE)
 5       return 0;
 6
 7      if(CreateViewGLContext(hrenderDC)==FALSE)
 8       return 0;
 9
10     glPolygonMode(GL_FRONT,GL_FILL);
11     glPolygonMode(GL_BACK,GL_FILL);
12     ///
13     glEnable(GL_TEXTURE_2D);
14     glShadeModel(GL_SMOOTH);
15     glViewport(0,0,259,231);
16     glMatrixMode(GL_PROJECTION);
17     glLoadIdentity();
18     gluPerspective(45,1,0.1,100.0);
19     glMatrixMode(GL_MODELVIEW);
20     glLoadIdentity();
21     glShadeModel(GL_SMOOTH);       // Enable Smooth Shading
22     glClearColor(0.0f, 0.0f, 0.0f, 0.5f);    // Black Background
23     glClearDepth(1.0f);         // Depth Buffer Setup
24     glEnable(GL_DEPTH_TEST);       // Enables Depth Testing
25     glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
26     /
27     glEnableClientState(GL_VERTEX_ARRAY);
28     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
29
30     SetTimer(1,10,0);
31
32     //// 

    f. 整个.cpp源代码

  1 // OpenGLTest1Dlg.cpp : 实现文件
  2 //
  3
  4 #include "stdafx.h"
  5 #include "OpenGLTest1.h"
  6 #include "OpenGLTest1Dlg.h"
  7 #include "afxdialogex.h"
  8
  9
 10 #ifdef _DEBUG
 11 #define new DEBUG_NEW
 12 #endif
 13
 14
 15 // 用于应用程序“关于”菜单项的 CAboutDlg 对话框
 16
 17 class CAboutDlg : public CDialogEx
 18 {
 19 public:
 20     CAboutDlg();
 21
 22 // 对话框数据
 23     enum { IDD = IDD_ABOUTBOX };
 24
 25     protected:
 26     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
 27
 28 // 实现
 29 protected:
 30     DECLARE_MESSAGE_MAP()
 31 };
 32
 33 CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
 34 {
 35 }
 36
 37 void CAboutDlg::DoDataExchange(CDataExchange* pDX)
 38 {
 39     CDialogEx::DoDataExchange(pDX);
 40 }
 41
 42 BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
 43 END_MESSAGE_MAP()
 44
 45
 46 // COpenGLTest1Dlg 对话框
 47
 48
 49
 50
 51 COpenGLTest1Dlg::COpenGLTest1Dlg(CWnd* pParent /*=NULL*/)
 52     : CDialogEx(COpenGLTest1Dlg::IDD, pParent)
 53 {
 54     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
 55 }
 56
 57 void COpenGLTest1Dlg::DoDataExchange(CDataExchange* pDX)
 58 {
 59     CDialogEx::DoDataExchange(pDX);
 60 }
 61
 62 BEGIN_MESSAGE_MAP(COpenGLTest1Dlg, CDialogEx)
 63     ON_WM_SYSCOMMAND()
 64     ON_WM_PAINT()
 65     ON_WM_QUERYDRAGICON()
 66     ON_WM_TIMER()
 67 END_MESSAGE_MAP()
 68
 69
 70 // COpenGLTest1Dlg 消息处理程序
 71
 72 BOOL COpenGLTest1Dlg::OnInitDialog()
 73 {
 74     CDialogEx::OnInitDialog();
 75
 76     // 将“关于...”菜单项添加到系统菜单中。
 77
 78     // IDM_ABOUTBOX 必须在系统命令范围内。
 79     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
 80     ASSERT(IDM_ABOUTBOX < 0xF000);
 81
 82     CMenu* pSysMenu = GetSystemMenu(FALSE);
 83     if (pSysMenu != NULL)
 84     {
 85         BOOL bNameValid;
 86         CString strAboutMenu;
 87         bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
 88         ASSERT(bNameValid);
 89         if (!strAboutMenu.IsEmpty())
 90         {
 91             pSysMenu->AppendMenu(MF_SEPARATOR);
 92             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
 93         }
 94     }
 95
 96     // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
 97     //  执行此操作
 98     SetIcon(m_hIcon, TRUE);            // 设置大图标
 99     SetIcon(m_hIcon, FALSE);        // 设置小图标
100
101     // TODO: 在此添加额外的初始化代码
102     ///OPENGL INIT/
103     CWnd *wnd=GetDlgItem(IDC_RENDER);
104     hrenderDC=::GetDC(wnd->m_hWnd);
105     if(SetWindowPixelFormat(hrenderDC)==FALSE)
106       return 0;
107
108      if(CreateViewGLContext(hrenderDC)==FALSE)
109       return 0;
110
111     glPolygonMode(GL_FRONT,GL_FILL);
112     glPolygonMode(GL_BACK,GL_FILL);
113     ///
114     glEnable(GL_TEXTURE_2D);
115     glShadeModel(GL_SMOOTH);
116     glViewport(0,0,259,231);
117     glMatrixMode(GL_PROJECTION);
118     glLoadIdentity();
119     gluPerspective(45,1,0.1,100.0);
120     glMatrixMode(GL_MODELVIEW);
121     glLoadIdentity();
122     glShadeModel(GL_SMOOTH);       // Enable Smooth Shading
123     glClearColor(0.0f, 0.0f, 0.0f, 0.5f);    // Black Background
124     glClearDepth(1.0f);         // Depth Buffer Setup
125     glEnable(GL_DEPTH_TEST);       // Enables Depth Testing
126     glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
127     /
128     glEnableClientState(GL_VERTEX_ARRAY);
129     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
130
131     SetTimer(1,10,0);
132
133     ////
134     return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
135 }
136
137 void COpenGLTest1Dlg::OnSysCommand(UINT nID, LPARAM lParam)
138 {
139     if ((nID & 0xFFF0) == IDM_ABOUTBOX)
140     {
141         CAboutDlg dlgAbout;
142         dlgAbout.DoModal();
143     }
144     else
145     {
146         CDialogEx::OnSysCommand(nID, lParam);
147     }
148 }
149
150 // 如果向对话框添加最小化按钮,则需要下面的代码
151 //  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
152 //  这将由框架自动完成。
153
154 void COpenGLTest1Dlg::OnPaint()
155 {
156     if (IsIconic())
157     {
158         CPaintDC dc(this); // 用于绘制的设备上下文
159
160         SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
161
162         // 使图标在工作区矩形中居中
163         int cxIcon = GetSystemMetrics(SM_CXICON);
164         int cyIcon = GetSystemMetrics(SM_CYICON);
165         CRect rect;
166         GetClientRect(&rect);
167         int x = (rect.Width() - cxIcon + 1) / 2;
168         int y = (rect.Height() - cyIcon + 1) / 2;
169
170         // 绘制图标
171         dc.DrawIcon(x, y, m_hIcon);
172     }
173     else
174     {
175         CDialogEx::OnPaint();
176     }
177 }
178
179 //当用户拖动最小化窗口时系统调用此函数取得光标
180 //显示。
181 HCURSOR COpenGLTest1Dlg::OnQueryDragIcon()
182 {
183     return static_cast<HCURSOR>(m_hIcon);
184 }
185
186 BOOL COpenGLTest1Dlg::SetWindowPixelFormat(HDC hDC)
187 {
188 PIXELFORMATDESCRIPTOR pixelDesc;
189
190 pixelDesc.nSize = sizeof(PIXELFORMATDESCRIPTOR);
191 pixelDesc.nVersion = 1;
192
193 pixelDesc.dwFlags = PFD_DRAW_TO_WINDOW |
194      PFD_SUPPORT_OPENGL |
195      PFD_DOUBLEBUFFER |
196      PFD_TYPE_RGBA;
197
198 pixelDesc.iPixelType = PFD_TYPE_RGBA;
199 pixelDesc.cColorBits = 32;
200 pixelDesc.cRedBits = 0;
201 pixelDesc.cRedShift = 0;
202 pixelDesc.cGreenBits = 0;
203 pixelDesc.cGreenShift = 0;
204 pixelDesc.cBlueBits = 0;
205 pixelDesc.cBlueShift = 0;
206 pixelDesc.cAlphaBits = 0;
207 pixelDesc.cAlphaShift = 0;
208 pixelDesc.cAccumBits = 0;
209 pixelDesc.cAccumRedBits = 0;
210 pixelDesc.cAccumGreenBits = 0;
211 pixelDesc.cAccumBlueBits = 0;
212 pixelDesc.cAccumAlphaBits = 0;
213 pixelDesc.cDepthBits = 0;
214 pixelDesc.cStencilBits = 1;
215 pixelDesc.cAuxBuffers = 0;
216 pixelDesc.iLayerType = PFD_MAIN_PLANE;
217 pixelDesc.bReserved = 0;
218 pixelDesc.dwLayerMask = 0;
219 pixelDesc.dwVisibleMask = 0;
220 pixelDesc.dwDamageMask = 0;
221
222 PixelFormat = ChoosePixelFormat(hDC,&pixelDesc);
223 if(PixelFormat==0) // Choose default
224 {
225  PixelFormat = 1;
226  if(DescribePixelFormat(hDC,PixelFormat,
227   sizeof(PIXELFORMATDESCRIPTOR),&pixelDesc)==0)
228  {
229   return FALSE;
230  }
231 }
232
233 if(SetPixelFormat(hDC,PixelFormat,&pixelDesc)==FALSE)
234
235 {
236  return FALSE;
237 }
238
239 return TRUE;
240 }
241
242
243 BOOL COpenGLTest1Dlg::CreateViewGLContext(HDC hDC)
244 {
245 hrenderRC = wglCreateContext(hDC);
246
247 if(hrenderRC==NULL)
248  return FALSE;
249
250 if(wglMakeCurrent(hDC,hrenderRC)==FALSE)
251  return FALSE;
252
253
254
255 return TRUE;
256 }
257
258 void COpenGLTest1Dlg::RenderScene()
259 {
260
261
262  /
263  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
264
265
266  glLoadIdentity();
267  glTranslatef(0.0f,0.0f,-6.0f);      // Move Left 1.5 Units And Into The Screen 6.0
268  glRotated(m_yRotate, 0.0, 1.0, 0.0);
269  glBegin(GL_TRIANGLES); // Drawing Using Triangles
270
271   glVertex3f( 0.0f, 1.0f, 0.0f);     // Top
272   glVertex3f(-1.0f,-1.0f, 0.0f);     // Bottom Left
273   glVertex3f( 1.0f,-1.0f, 0.0f);     // Bottom Right
274  glEnd();           // Finished Drawing The Triangle
275  SwapBuffers(hrenderDC);
276 }
277
278 void COpenGLTest1Dlg::OnTimer(UINT nIDEvent) //实时绘制场景
279 {
280  // TODO: Add your message handler code here and/or call default
281  RenderScene();
282  m_yRotate +=3;
283  CDialog::OnTimer(nIDEvent);
284 } 

步骤四: 运行调试

运行结果如下所示:

转载于:https://www.cnblogs.com/wiener-zyj/p/4159310.html

《MFC dialog中加入OpenGL窗体》相关推荐

  1. ComeFuture英伽学院——2020年 全国大学生英语竞赛【C类初赛真题解析】(持续更新)

    视频:ComeFuture英伽学院--2019年 全国大学生英语竞赛[C类初赛真题解析]大小作文--详细解析 课件:[课件]2019年大学生英语竞赛C类初赛.pdf 视频:2020年全国大学生英语竞赛 ...

  2. ComeFuture英伽学院——2019年 全国大学生英语竞赛【C类初赛真题解析】大小作文——详细解析

    视频:ComeFuture英伽学院--2019年 全国大学生英语竞赛[C类初赛真题解析]大小作文--详细解析 课件:[课件]2019年大学生英语竞赛C类初赛.pdf 视频:2020年全国大学生英语竞赛 ...

  3. 信息学奥赛真题解析(玩具谜题)

    玩具谜题(2016年信息学奥赛提高组真题) 题目描述 小南有一套可爱的玩具小人, 它们各有不同的职业.有一天, 这些玩具小人把小南的眼镜藏了起来.小南发现玩具小人们围成了一个圈,它们有的面朝圈内,有的 ...

  4. 信息学奥赛之初赛 第1轮 讲解(01-08课)

    信息学奥赛之初赛讲解 01 计算机概述 系统基本结构 信息学奥赛之初赛讲解 01 计算机概述 系统基本结构_哔哩哔哩_bilibili 信息学奥赛之初赛讲解 02 软件系统 计算机语言 进制转换 信息 ...

  5. 信息学奥赛一本通习题答案(五)

    最近在给小学生做C++的入门培训,用的教程是信息学奥赛一本通,刷题网址 http://ybt.ssoier.cn:8088/index.php 现将部分习题的答案放在博客上,希望能给其他有需要的人带来 ...

  6. 信息学奥赛一本通习题答案(三)

    最近在给小学生做C++的入门培训,用的教程是信息学奥赛一本通,刷题网址 http://ybt.ssoier.cn:8088/index.php 现将部分习题的答案放在博客上,希望能给其他有需要的人带来 ...

  7. 信息学奥赛一本通 提高篇 第六部分 数学基础 相关的真题

    第1章   快速幂 1875:[13NOIP提高组]转圈游戏 信息学奥赛一本通(C++版)在线评测系统 第2 章  素数 第 3 章  约数 第 4 章  同余问题 第 5 章  矩阵乘法 第 6 章 ...

  8. 信息学奥赛一本通题目代码(非题库)

    为了完善自己学c++,很多人都去读相关文献,就比如<信息学奥赛一本通>,可又对题目无从下手,从今天开始,我将把书上的题目一 一的解析下来,可以做参考,如果有错,可以告诉我,将在下次解析里重 ...

  9. 信息学奥赛一本通(C++版) 刷题 记录

    总目录详见:https://blog.csdn.net/mrcrack/article/details/86501716 信息学奥赛一本通(C++版) 刷题 记录 http://ybt.ssoier. ...

  10. 最近公共祖先三种算法详解 + 模板题 建议新手收藏 例题: 信息学奥赛一本通 祖孙询问 距离

    首先什么是最近公共祖先?? 如图:红色节点的祖先为红色的1, 2, 3. 绿色节点的祖先为绿色的1, 2, 3, 4. 他们的最近公共祖先即他们最先相交的地方,如在上图中黄色的点就是他们的最近公共祖先 ...

最新文章

  1. C++模式学习------工厂模式
  2. 【渝粤教育】电大中专电商运营实操 (15)作业 题库
  3. 教程 | MySql都会了,确定不学习一下MyCat分片?
  4. qwtqplot用法
  5. 蓝桥杯 ALGO-103 算法训练 完数
  6. 世界首席WP(文字处理)布局绘制砖家横空出世
  7. JS编程:查找数组元素位置
  8. 泰迪杯数据挖掘挑战赛—数据预处理(一)
  9. 卸载华为系统wifi服务器,如何安装随行WiFi驱动及如何卸载驱动
  10. cdn贝免费套餐_CDN贝网站seo
  11. PDF文件怎么旋转保存
  12. php嵌入图片代码,php如何添加图片
  13. [BJDCTF2020]Mark loves cat 1——(超详细 三种方法)
  14. 全球与中国云浏览器隔离市场深度研究分析报告
  15. nodejs+koa2实现微信小程序签名和请求支付(二)
  16. 针对salaries表emp_no字段创建索引idx_emp_no,查询emp_no为10005, 使用强制索引。
  17. android 加固服务器,Python 脚本构建Android APK 自动加固、打渠道包并上传服务器
  18. 2023美国大学生数学建模竞赛选题建议
  19. 阿里“看”AI + “ET大脑”战略启动
  20. 文件压缩 - JavaScript/CSS/HTML/图片

热门文章

  1. 摘: cmd环境 使用一点知识
  2. MySQL安装错误:/usr/local/mysql/libexec/mysqld: unknown option '--skip-federated'
  3. 天鹅给癞蛤蟆的回信[转贴]
  4. iBatis学习第一天
  5. Java学习教程整理
  6. php如何循环输出图片,[图片 显示] 缩图循环显示(php,mysql,script)-PHP教程,PHP应用
  7. java websocket netty_基于netty实现的websocket
  8. 利用死信交换机接收死信
  9. Eureka-eureka原理分析
  10. MyBatis 实际使用案例-一级标签