• 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角星

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

  • 相关阅读:
    81. Search in Rotated Sorted Array II (Array; Divide-and-Conquer)
    LeetCode Word Ladder
    LeetCode Word Search II
    LeetCode Invert Binary Tree
    LeetCode Implement Stack using Queues
    Bash:字符串操作
    LeetCode Basic Calculator
    LeetCode Rectangle Area
    Java 远程调试
    LeetCode Count Complete Tree Nodes
  • 原文地址:https://www.cnblogs.com/Czhenyu/p/6503064.html
Copyright © 2020-2023  润新知