Graphics—对话框操作

终于用OpenGL实现了漫游、粒子系统以及无语的黑盒3D,下面就是头疼的碰撞检测了~要不然偷懒不用OpenGL写了?估计导师会训我啊啊啊啊
累死~~~还是补篇笔记吧,要不然快忘了。

接着上一次的Graphics—菜单设置笔记继续说吧。

其实对话框这东西真的很好玩(o)/~
声明:操作方法不一,我只是把做小型绘图系统的经验记录一下。

先立个flag吧(任务要求):三个绘图选择
(1)画国民党党徽
(2)画共青团团徽
(3)画多角星,需要手动输出一个(2 ~ 100)的整数n,表示绘制n角星

源码在这里:

#include <GL/glut.h>
#include <math.h>
#include <stdio.h>
const double PI = acos(-1.0);
struct Color {
    double x, y, z;
    Color(double x = 0, double y = 0, double z = 0)
    : x(x), y(y), z(z) {}
};
struct Point {
    double x, y;
    Point(double x = 0, double y = 0) : x(x), y(y) {}
};
Color c[1000 + 1];
Point p[1000 + 1], p1[1000 + 1], p2[1000 + 1];
void Ring(double r, Color C) {
    glColor3d(C.x, C.y, C.z); glBegin(GL_POLYGON);
    for(int i = 0; i < 10000; i++) {
        double D = 360.0 / 10000 * i / 180 * PI;
        glVertex2d(r * cos(D), r * sin(D));
	}
	glEnd();
}
void Star(double r, int n, Color C, double r0, Color C1, Color C2) {
    //定义n角星凸起的点为顶点,凹下去的点为次顶点
    //画一个n角星,其中r定义顶点到中心的距离,C代表颜色
    //r0代表次顶点到中心的距离
    //若r0不为0则直接使用,反之使用r0 = r * 3 / 8.
    //C1表示顶点到中心是否连线,C2表示次顶点到中心是否连线
    //颜色第一个参数为-1时,说明不连线,反之使用相应颜色连线
    double dis_to_next = 360.0 / n; //顶点间角度
    for(int i = 0; i < n; i++) {
        double D = (dis_to_next * i + 90) / 180 * PI;
        p1[i] = {r * cos(D), r * sin(D)};
    }
    double r_incycle;//次顶点到中心距离
    if(r0 == 0) {
        r_incycle = r * 3 / 8;
    }
    else {
        r_incycle = r0;
    }
    for(int i = 0; i < n; i++) {
        double D = (180 / n + 90 + i * dis_to_next) / 180 * PI;
        p2[i] = {r_incycle * cos(D), r_incycle * sin(D)};
    }
    glColor3d(C.x, C.y, C.z);
    glBegin(GL_POLYGON);//先以次顶点画多边形
    for(int i = 0; i < n; i++) {
        glVertex2d(p2[i].x, p2[i].y);
    }
    glEnd();
    glColor3d(C.x, C.y, C.z);
    for(int i = 0; i < n; i++) {//再逐步涂色
        glBegin(GL_TRIANGLES);
        glVertex2d(p2[i].x, p2[i].y);
        glVertex2d(p1[(i + 1) % n].x, p1[(i + 1) % n].y);
        glVertex2d(p2[(i + 1) % n].x, p2[(i + 1) % n].y);
        glEnd();
    }
    glColor3f(0, 0, 0);  glBegin(GL_LINE_LOOP);
    for(int i = 0; i < n; i++) {//把n角星的边变成黑色
        glVertex2d(p1[i].x, p1[i].y);
        glVertex2d(p2[i].x, p2[i].y);
    }
    glEnd();
    for(int i = 0; i < n; i++) {
        if(C1.x != -1) {//顶点到中心连线
            glColor3d(C1.x, C1.y, C1.z);
            glBegin(GL_LINES);
            glVertex2d(p1[i].x, p1[i].y);
            glVertex2d(0, 0);
            glEnd();
        }
        if(C2.x != -1) {//次顶点到中心连线
            glColor3d(C2.x, C2.y, C2.z);
            glBegin(GL_LINES);
            glVertex2d(p2[i].x, p2[i].y);
            glVertex2d(0, 0);
            glEnd();
        }
    }
}
void myDisplay1(void) {
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glClear(GL_COLOR_BUFFER_BIT);
	Ring(0.5, (Color){0, 0, 1});
    Star(0.5, 14, (Color){1, 1, 1}, 0.3, (Color){-1, 0, 0}, (Color){-1, 0, 0});
	Ring(0.265, (Color){0, 0, 1});
	Ring(0.238, (Color){1, 1, 1});
	glFlush();
}
void myDisplay2(void) {
    glClearColor(0.0, 0.0, 0.0, 0.0);
	glClear(GL_COLOR_BUFFER_BIT);
	Ring(0.55, (Color){1, 1, 0});
	Ring(0.5, (Color){1, 0, 0});
	Star(0.5, 5, (Color){1, 1, 0}, 0.18, (Color){0, 0, 0}, (Color){0, 0, 0});
	glFlush();
}
int n;
void myDisplay3(void) {
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT);
    Ring(0.5, (Color){1, 0, 1});
    Star(0.5, n, (Color){1, 1, 1}, 0, (Color){1, 0, 0}, (Color){0, 0, 0});
    glFlush();
}
int main(int argc, char *argv[]) {
    printf("Welcome!

Instruction:

1, The emblem of the kuomintang

");
    printf("2, The Communist Youth League badge

3, The pattern of the flower

");
    printf("Please choose operator(1~3): ");
    int op; scanf("%d", &op);
    while(op < 1 || op > 3) {
        printf("error!
Please choose again: ");
        scanf("%d", &op);
    }
    if(op == 3) {
        printf("Please choose the number of nodes(2~100): ");
        scanf("%d", &n);
        while(n < 2 || n > 100) {
            printf("error!
Please choose again: ");
            scanf("%d", &n);
        }
    }
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(600, 600);
    glutCreateWindow("Hello World!");
    if(op == 1) {
        glutDisplayFunc(&myDisplay1);
    }
    else if(op == 2) {
        glutDisplayFunc(&myDisplay2);
    }
    else {
        glutDisplayFunc(&myDisplay3);
    }
    glutMainLoop();
    return 0;
}

一、新建对话框(类)

ID修改成一个好记的名字IDD_Choose


然后对于这个对话框,新建一个类(类名就为CChooseDialog吧)


接着,我们来美工一下对话框吧!这里要用到“工具箱”

这里要使用Radio Button,直接拖动放到对话框里面


对每个Button,选择 属性/Caption,修改名字标题名分别为“国民党党徽”、“共青团团徽”、“绘制多角星”。再拖入一个Edit Control(编辑框),用于输入整数n,绘制n角星。

二、分析过程,添加变量和函数

这时候,我们分析一下整个过程:
初始,编辑框不可用。而当我们选择绘制多角星时,它便可以使用,其次在输入数据的时候,要可以判断输入的是否是2~100的整数。

对于编辑框,我们需要添加一个类别为value的CString变量m_data来存储输入的数据以及一个类别为control的变量m_control来控制编辑框是否可用

添加虚函数OnInitDialog()函数,之后初始化对话框使得编辑框处于不可使用状态。

BOOL CChooseDialog::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// TODO:  在此添加额外的初始化
	m_control.EnableWindow(false);
	return TRUE;  // return TRUE unless you set the focus to a control
	// 异常:  OCX 属性页应返回 FALSE
}
我们在ChooseDialog.cpp函数里面设置两个变量op,n
int Op, n; // Op 表示1~3 这三种绘图操作,n代表多角星的角数
添加三个Radio Button 对应的BN_CLICKED消息处理函数

void CChooseDialog::OnBnClickedRadio1()
{
	// TODO:  在此添加控件通知处理程序代码
	Op = 1;
	m_control.EnableWindow(false); // 编辑框不可用
}


void CChooseDialog::OnBnClickedRadio2()
{
	// TODO:  在此添加控件通知处理程序代码
	Op = 2;
	m_control.EnableWindow(false); // 编辑框不可用
}


void CChooseDialog::OnBnClickedRadio3()
{
	// TODO:  在此添加控件通知处理程序代码
	Op = 3;
	m_control.EnableWindow(true); // 编辑框可用
}
加入“确定按钮“对应的事件函数(注意,要去掉对话框自带的“确定”和“取消”按钮,我们自己拖入两个Button 改好名字即可)


到这里,我们发现有一个小bug。如果点击了“取消按钮”,那么就表示本次选择无效。于是在ChooseDialog.cpp里面加入一个bool变量start表示本次选择是否有效。
bool start; // 表示本次选择是否有效
void CChooseDialog::OnBnClickedButton1() // 确定按钮
{
	// TODO:  在此添加控件通知处理程序代码
	if (Op == 1 || Op == 2) {
		start = true;
		SendMessage(WM_CLOSE); // 关闭对话框
		return;
	}
	if (Op == 3) {
		UpdateData(true); // 表示获取编辑框的数据
		/*判断输入数据是否满足2~100的整数*/
		bool flag = false;
		int len = m_data.GetLength();
		if (len >= 4) {
			MessageBox(_T("请输入2~100的整数"), _T("提示"));
			return;
		}
		n = 0;
		for (int i = 0; i < len; i++) {
			if (!(m_data[i] - '0' >= 0 && m_data[i] - '0' <= 9)) {
				flag = true; break;
			}
			else {
				n = n * 10 + (m_data[i] - '0');
			}
		}
		if (flag || (!flag && (n <= 1 || n > 100))) {
			MessageBox(_T("请输入2~100的整数"), _T("提示"));
		}
		else {
			start = true;
			SendMessage(WM_CLOSE);
		}
	}
}
void CChooseDialog::OnBnClickedButton2() // 取消按钮
{
	// TODO:  在此添加控件通知处理程序代码
	start = false;
	SendMessage(WM_CLOSE);
}

三、view类的调整

在StudyView.cpp里面加入头文件#include "ChooseDialog.h"
在StudyView.h里面继承ChooseDalog.cpp里面的Op、n、start变量
extern int Op, n;
extern bool start;
在StudyView.h里面加入绘图类,由于在上一篇笔记里面已经加入了Point 和 Color类,这里不再叙述
class Draw_Choose { // 7
public:
	bool init;       // the mark variable of Init function
	bool reshape;    // the mark variable of Reshape function
	bool Mouse;      // the mark variable of Mouse function 
	bool Keyboard;   // the mark variable of Keyboard function
	bool Motion;     // the mark variable of Mouse move fuction
	Draw_Choose(bool a = true, bool b = true, bool c = false, bool d = false, bool e = false) : init(a), reshape(b), Mouse(c), Keyboard(d), Motion(e) {}
	void Init() {
		glClearColor(0.0, 0.0, 0.0, 1.0);
	}
	void Reshape(int cx, int cy) {
		glViewport(0, 0, cx, cy);
		// 设置投影矩阵(透视投影)  
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluPerspective(60.0, (GLfloat)cx / (GLfloat)cy, 1.0, 1000.0);
		// 设置模型视图矩阵  
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		gluLookAt(0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
	};   // 改变窗口大小时对视窗进行的操作
	Color c[1000 + 1];
	Point p[1000 + 1], p1[1000 + 1], p2[1000 + 1];
	void Ring(double r, Color C) {
		glColor3d(C.x, C.y, C.z); glBegin(GL_POLYGON);
		for (int i = 0; i < 10000; i++) {
			double D = 360.0 / 10000 * i / 180 * PI;
			glVertex2d(r * cos(D), r * sin(D));
		}
		glEnd();
	}
	void Star(double r, int n, Color C, double r0, Color C1, Color C2) {
		double dis_to_next = 360.0 / n; //顶点间角度
		for (int i = 0; i < n; i++) {
			double D = (dis_to_next * i + 90) / 180 * PI;
			p1[i] = { r * cos(D), r * sin(D) };
		}
		double r_incycle;//次顶点到中心距离
		if (r0 == 0) {
			r_incycle = r * 3 / 8;
		}
		else {
			r_incycle = r0;
		}
		for (int i = 0; i < n; i++) {
			double D = (180 / n + 90 + i * dis_to_next) / 180 * PI;
			p2[i] = { r_incycle * cos(D), r_incycle * sin(D) };
		}
		glColor3d(C.x, C.y, C.z);
		glBegin(GL_POLYGON);//先以次顶点画多边形
		for (int i = 0; i < n; i++) {
			glVertex2d(p2[i].x, p2[i].y);
		}
		glEnd();
		glColor3d(C.x, C.y, C.z);
		for (int i = 0; i < n; i++) {//再逐步涂色
			glBegin(GL_TRIANGLES);
			glVertex2d(p2[i].x, p2[i].y);
			glVertex2d(p1[(i + 1) % n].x, p1[(i + 1) % n].y);
			glVertex2d(p2[(i + 1) % n].x, p2[(i + 1) % n].y);
			glEnd();
		}
		glColor3f(0, 0, 0);
		glLineWidth(1);
		glBegin(GL_LINE_LOOP);
		for (int i = 0; i < n; i++) {//把n角星的边变成黑色
			glVertex2d(p1[i].x, p1[i].y);
			glVertex2d(p2[i].x, p2[i].y);
		}
		glEnd();
		for (int i = 0; i < n; i++) {
			if (C1.x != -1) {//顶点到中心连线
				glColor3d(C1.x, C1.y, C1.z);
				glLineWidth(1);
				glBegin(GL_LINES);
				glVertex2d(p1[i].x, p1[i].y);
				glVertex2d(0, 0);
				glEnd();
			}
			if (C2.x != -1) {//次顶点到中心连线
				glColor3d(C2.x, C2.y, C2.z);
				glLineWidth(1);
				glBegin(GL_LINES);
				glVertex2d(p2[i].x, p2[i].y);
				glVertex2d(0, 0);
				glEnd();
			}
		}
	}
	void myDisplay1(void) {
		glClear(GL_COLOR_BUFFER_BIT);
		Ring(0.5, Color(0, 0, 1));
		Star(0.5, 14, Color(1, 1, 1), 0.3, Color(-1, 0, 0), Color(-1, 0, 0));
		Ring(0.265, Color(0, 0, 1));
		Ring(0.238, Color(1, 1, 1));
		glFlush();
	}
	void myDisplay2(void) {
		glClear(GL_COLOR_BUFFER_BIT);
		Ring(0.55, Color(1, 1, 0));
		Ring(0.5, Color(1, 0, 0));
		Star(0.5, 5, Color(1, 1, 0), 0.18, Color(0, 0, 0), Color(0, 0, 0));
		glFlush();
	}
	void myDisplay3(void) {
		glClear(GL_COLOR_BUFFER_BIT);
		Ring(0.5, Color(1, 0, 1));
		Star(0.5, n, Color(1, 1, 1), 0, Color(1, 0, 0), Color(0, 0, 0));
		glFlush();
	}
	void Display() {
		if (Op == 1) {
			myDisplay1();
		}
		else if (Op == 2) {
			myDisplay2();
		}
		else {
			myDisplay3();
		}
	}
};
修改StudyView.cpp里面的DrawPicture函数(Case为1是上一笔记里面的菜单,Case 为 1的代码可以忽略掉)
void CStudyView::DrawPicture()
{
	CRect rc; GetWindowRect(&rc);
	int cx = rc.Width(); int cy = rc.Height();
	if (Case == 1) {
		glClearColor(0.0, 0.0, 0.0, 0.0);
		glClear(GL_COLOR_BUFFER_BIT);

		glColor3f(1.0f, 1.0f, 1.0f);
		glRectf(-0.8f, -0.8f, 0.8f, 0.8f);
		Work m_work;
		m_work.Triangle(Color(0, 1, 0), Color(1, 1, 0), Color(1, 0, 0),
			Point(-0.8, 0.8), Point(0.8, 0.8), Point(0, -0.8));

		glBegin(GL_POLYGON);
		glColor3f(1.0f, 0.0f, 1.0f);
		GLfloat r = 0.5;
		for (int i = 1; i <= 1000; i++) {
			glVertex2f(r * cos(PI / 500 * i), r * sin(PI / 500 * i));
		}
		glEnd();

		GLfloat a = 1 / (2 - 2 * cos(72 * PI / 180)); // ???
		GLfloat x = a * cos(18 * PI / 180);
		GLfloat y = a * sin(18 * PI / 180);
		GLfloat z = a * cos(18 * PI / 180);
		glColor3f(0.0f, 0.0f, 1.0f);
		glBegin(GL_LINE_LOOP);
		glVertex2f(0.0f, a); glVertex2f(0.5f, -z);
		glVertex2f(-x, y);   glVertex2f(x, y);
		glVertex2f(-0.5f, -z);
		glEnd();

		m_work.Triangle(Color(1, 0, 0), Color(0, 0, 1), Color(1, 0, 1),
			Point(-0.65, -0.6), Point(-0.6, -0.7), Point(-0.7, -0.7));

		m_work.Triangle(Color(1, 0, 0), Color(1, 0, 1), Color(1, 1, 0),
			Point(0.65, -0.6), Point(0.7, -0.7), Point(0.6, -0.7));
		glFlush();
	}
	else if (Case == 2) {
		Draw_Choose m_work;
		m_work.Init();
		m_work.Reshape(cx, cy);
		m_work.Display();
	}	
}

四、在菜单里面加入一个“对话框绘图”

添加事件函数

void CStudyView::OnDraw_Choose()
{
	// TODO:  在此添加命令处理程序代码
	CChooseDialog dlg;
	dlg.DoModal();
	if (start) { // 本次选择有效
		Case = 2;
		SendMessage(WM_PAINT); // 绘图
	}
}

五、运行

一、选择国民党党徽,点击“确定”:

二、同理共青团团徽:

三、多角星:

(1)输入6.5,点击“确定”。提示错误

(2)输入acm,点击“确定”。提示错误

(3)输入6,点击“确定”。成功

(4)输入8,点击“取消”。出现的还是上一个6角星

肚子饿死了啊啊啊啊!!!

原文地址:https://www.cnblogs.com/Czhenyu/p/6503064.html