MATLAB GUI设计II 多功能模式题目生成器 四则运算 | 界面切换 | 字符串处理 | cell数组 | GUI

前言

让我先吐槽一下
_(:△」∠) _

这个可以用来整人的程序花费了我整整一天多的时间

全内容整整800行代码 生成的pdf说明报告长达26P

总体来说 这个GUI可以实现较多的复杂功能
整体结构我没有进行过优化处理 此方案仅供参考与学习
不过这样有一个优点就是比优化的简洁代码更容易理解与入门

本GUI支持

  • 界面切换
  • 模组可视化操作
  • 基于cell数组的多数据存储与处理
  • 混合模式选择
  • 无括号的二级四则混合运算
  • 多弹出式菜单选择
  • 多单选按钮
  • 多复选框
  • 字符串处理
  • 生成导出及引用文件
  • 整人恶搞
  • 提升数学
  • 默写古诗
  • 四级备考

版本为R2018b 中文版本

传说已经结束,而历史才刚刚开始

好了,我们开始吧
在这里插入图片描述

-------------------------
Tips:
需注意子函数代码段中有许多变量以及贯通全程序的全局变量
为了避免错误的发生 这里采用了多写不少写的原则
可根据具体情况自行调整

在这里插入图片描述

GUI

首先是GUI页面的绘制 这里不再过多赘述

以我个人绘制的GUI进行接下来的内容演示样本 (因为懒就不调整样式之类折腾了)
在这里插入图片描述

全局变量声明

global mode;                     %模式选择
global num_questions;            %题数
global calculation_range;        %数级
global calculation_degree;       %难度
global poetry_type;              %诗歌混合模式
global English_type;             %单词混合模式
global calculation_type1;        % “+” 勾选情况
global calculation_type2;        % “-” 勾选情况
global calculation_type3;        % “×” 勾选情况
global calculation_type4;        % “÷” 勾选情况
global mode_demon;               %噩梦模式选择
global mode_infinite;            %无尽模式选择
global D;                        % cell型数组1——题目式
D=cell(1000,2);
global E;                        % cell型数组2——答案式
E=cell(1000,2);

界面切换

本GUI采取了三种主要界面

数学/语文/英语 菜单

互斥单选按钮的实现

切换三个界面可以通过对三个单选按钮的Callback响应来实现

即设置 set函数的参数 这里采用了

set(H,Name,Value)

Name即为所选控件的名称 这里选取了其中一个 单选按钮 (radiobutton1/radiobutton2/radiobutton3)

set(handles.radiobutton2,'Value',0)
set(handles.radiobutton3,'Value',0)
Value效果
0取消选中/勾选
1选中/勾选控件

在 radiobutton1 的 Callback 中设置 radiobutton2/radiobutton3的 Value属性 值为0

radiobutton2/radiobutton3 同理

这样即可完成一组互斥按钮

按钮组

我这里采用的是另一个方法 ——— 将几项互斥选项的单选按钮放在一个按钮组内;

处于按钮组中的某一个单选按钮 (radiobutton)被选中后,其他的自动变成不选的状态;

这个方法相对于上一种更加简单,但个人建议最好只用于互斥单选按钮这一种情况


模组可视化

切换界面的情况下,如果各界面的选项与布局不同,就要考虑一下是否需要将各模块选择性隐藏

即 对各模块进行选择性可视化处理

单选按钮的选项反馈

该代码片中包含了多模块的显示选项 Visible属性 的设置

function radiobutton1_Callback(hObject, eventdata, handles)
global mode;
mode = 1;

set(handles.text2,'Visible','on');
set(handles.text4,'Visible','on');
set(handles.checkbox1,'Visible','on');
set(handles.checkbox2,'Visible','on');
set(handles.checkbox3,'Visible','on');
set(handles.checkbox4,'Visible','on');
set(handles.popupmenu2,'Visible','on');
set(handles.popupmenu3,'Visible','on');

set(handles.text3,'Visible','off');

set(handles.popupmenu4,'Visible','off');

set(handles.popupmenu5,'Visible','off');
Visible效果
0控件隐藏
1控件显示

在一个界面设置需要显示的控件 Visible属性 值为 1 不显示的控件 Visible属性 值为 0

即可实现不同界面菜单的不同模块分别显示

(这里的 mode为选择模式的信息传递 可以选择性忽略)


混合多模式选择

通过多选择的控件的叠加,可以实现多种排列组合的效果
在这里插入图片描述

弹出菜单的选项反馈

与单选按钮 (radiobutton)相似,弹出菜单(popupmenu)可以通过读取其 Value属性 的值来达到不同选项的信息传递,这里传递的值是num_questions(题目数量)全局变量

function popupmenu1_Callback(hObject, eventdata, handles)
global num_questions;
num_questions=0;

value = get(handles.popupmenu1, 'value');
switch value
    case 1
        warndlg('请选择题目数量','warning');
        num_questions=0;
    case 2
        num_questions=10;    
    case 3        
        num_questions=20;
    case 4
        num_questions=50;
end

这里case 1的情况是默认 ~ ~ ~ 题 目 ~ ~ ~ 未选择情况

在这里加入一个

warndlg('这是你想要提示的内容','warning');

即可完成简单回馈提示
在这里插入图片描述
如果这里别的反馈回这个弹出菜单并且修改了其 Value属性
同时 你的case语句中第一项不是1而是0 那需要的是0的结果 修改了 Value -> 0 那这个菜单就隐藏了
在这里插入图片描述
所以请注意非·非常规情况下case最好从1开始(1代表的是弹出菜单string里面的第一行)

Tips:进入循环前的检验

这个判断语句有点长
懒一点可以跳过这里

if ( (mode==0)||(num_questions==0)|| (    ((calculation_range==0)||(calculation_degree==0)||  ((calculation_type1==0)&&(calculation_type2==0)&&(calculation_type3==0)&&(calculation_type4==0)))&&(poetry_type==0)&&(English_type==0)  )   )
    warndlg('请确认已选择所有必需选项!','warning');

这是用来确认所有必需的选项或者选项组合无未选择情况


四则混合运算

局部变量声明

global A;       %数据位
global B;       %符号位
global C;       %组合位
global D;
global E;
D0="";          %字符串1初始化
D1="";          %字符串2初始化
str="";         %字符串3初始化

随机数字位的生成

            %列式
            %C负责输出文本 B负责运算法则 A负责数据模拟及存储
        
            A=[];%数据位
            for i=1:calculation_degree
                A(i)=unidrnd(calculation_range);
            end

A(i)存储 unidrnd函数 生成的 1 至 calculation_degree 的随机整数

混合符号位的生成

case下的符号选择

这里的符号位存储有点像压栈一样 勾选的把你塞进去,不要的把你踢了

            B="";                     %符号位
            calculation_type_num=1;
            
            if(calculation_type1==1)
                str(calculation_type_num)="+";
                calculation_type_num=calculation_type_num+1;
            end
            
            if(calculation_type2==1)
                str(calculation_type_num)="-";
                calculation_type_num=calculation_type_num+1;
            end
            
            if(calculation_type3==1)
                str(calculation_type_num)="×";
                calculation_type_num=calculation_type_num+1;
            end
            
            if(calculation_type4==1)
                str(calculation_type_num)="÷";
                calculation_type_num=calculation_type_num+1;
            end
            
            calculation_type_num=calculation_type_num-1;
            
            for j=1:(calculation_degree-1)
                B(j)=str(unidrnd(calculation_type_num));
            end

calculation_type_num 用来计数需要的符号数量,与之后的存储进数组部分有关系;

calculation_typeN的值可以从各个复选框的value值中获得,也可以在子函数中完成判断再通过全局变量传递 同理 1勾选 0取消;

在判断好各个符号位是否选择的情况后,将其存储在 B 中;

最终组合位的生成

奇位存数字,偶位存符号;

            C="";%组合位
            for k=1:(2*calculation_degree-1)
                if mod(k,2)
                    C(k)= A((k+1)*1/2); %奇数位
                else
                    C(k)= B(k*1/2);%偶数位
                end
            end
                        
            C(2*calculation_degree)="=";

cell数组

cell数组,即元胞数组,是MATLAB的一种特殊数据类型,可以理解为一种大型广义矩阵,每个单元可以储存不同的数据类型,可以是数、字符、矩阵、元胞数组等,可以用来进行混合数据存储和大量数据处理;

直接赋值:cell1={1,'str',[1,2,3],[1,2;3,4]};

预分配内存后再赋值:cell1=cell(1,4);cell1={1,'str',[1,2,3],[1,2;3,4]};

这里介绍的是cell数组的简单使用,详细请参考matlab参考手册

cell数组调用时:cell1{M,N}=A; (A可以是数、字符、矩阵、元胞数组等)
这里请注意 要用 { } 调用cell数组 (这里我迷了好久,string和cell型不能混用)

            for mn=1:2*calculation_degree
                D0=D0+C(mn);
            end
            
            D{l,1}=D0;

先用个循环把数字位和符号位拼接成字符串D0,再用D(cell型数组)存储(这里列只需要用一列);

D{l,1}中的l为主循环次数,即题数;

四则混合运算的解答

这里比较长 大约30行

            %计算部分
            ans=0;
            for m=1:calculation_degree-1
                if(B(m)=="×"||B(m)== "÷")
                    switch(B(m))
                        case "×"
                            A(m+1)=A(m)*A(m+1);
                        case "÷"
                            A(m+1)=A(m)/A(m+1);
                    end
                end
            end
            
            for mm=1:calculation_degree-1 %乘除数据传递
                nn=calculation_degree-mm;
                if(B(nn)=="×"||B(nn)== "÷")
                    A(nn)=A(nn+1);
                end
            end
            
            ans=A(1);
            for p=1:calculation_degree-1
                if(B(p)=="+"||B(p)== "-")
                    switch(B(p))
                        case "+"
                            ans=ans+A(p+1);
                        case "-"
                            ans=ans-A(p+1);
                    end
                end
            end

这里采用的是先顺序二级运算乘除结果 并将结果前移,最终一级运算加减获得结果

示意图

数A 数B 数C 数D ③一级运算 ③一级运算 ①A 乘 B ①结果保存在C ①C 除 D ①结果保存在D ②二级运算结果通过二级运算符号传递 得到结果 数A 数B 数C 数D

傻瓜算法 简单吧

在这里插入图片描述

数字式&答案式的存储

cell数组模块中 已经提及了 数字式 D{l,1}的存储

这里是 答案式 的 组装过程

            D1=D0+num2str(ans);       %拼接 数字式 与 答案
            
            E{l,1}=D1;                %存储 答案式
            
            D0="";                    %初始化
            D1="";                    %初始化

需要注意的是 这里需要先用 num2str() 函数将 数值的ans答案 转换为 str字符串型 后 再进行拼接


字符串的存储与解析

语文和英语模块这部分有较大的相似性 这里一起讲了 (*´Д´) つ))´∀`)

调试源文件(内含.m文件以及.txt数据文件): 百度网盘 提取码:m5x2

从文件中逐行读取字符串

语文部分

                fid1=fopen('poetry_store.txt','r');%从保存文件中读取诗词信息
                for g=1:num_questions
                    line_tempt = fgetl(fid1);
                    len_temp=length(line_tempt);%判断诗句长度 这里是用的是符号仅逗号的诗句 句末符号已去除

英语部分

                    fid1=fopen('CET4_store.txt','r');%从保存文件中读取四级单词信息
                    for g=1:num_questions
                        line_temp = fgetl(fid1);
                        len_temp=length(line_temp);

fopen函数读取文件

fileID = fopen(filename,permission);

  • fileID为读取文件标识名(自定义)
  • filename为打开文件名
  • permission为打开方式
permissionmethod
r打开文件进行读取
w打开或创建要写入的新文件, 丢弃现有内容(如果有)即覆盖
a打开或创建要写入的新文件,将数据追加到文件末尾
r+打开文件进行读写
w+打开或创建用于读写的新文件,丢弃现有内容(如果有)即覆盖
a+打开或创建用于读写的新文件,将数据追加到文件末尾
A打开文件,在不自动刷新当前输出缓冲区的情况下追加内容
W打开文件进行写入,不自动刷新当前输出缓冲区

翻译自matlab参考手册
(后两个基本上不用)

  • fgetl函数用于逐行读取字符串
  • line_temp为目前单行待处理字符串
  • len_temp为目前单行待处理字符串长度

加工字符串并分别存储

语文部分

                    D{g,1}=line_tempt(1:(len_temp-1)*0.5);%具体范围根据具体情况判断
                    D{g,2}=line_tempt((len_temp+3)*0.5:len_temp);
                    E{g,1}=D{g,1};
                    E{g,2}=D{g,2};
                end
                fclose(fid1);
                switch(poetry_type)                   %选择性设置填空
                    case 1
                        for it1=1:num_questions
                            D{it1,1}="____________________";
                        end
                    case 2
                        for it1=1:num_questions
                            D{it1,unidrnd(2)}="____________________";
                        end
                    case 3
                        for it1=1:num_questions
                            D{it1,2}="____________________";
                        end
                end

英语部分

                        flag=1;
                        i2=1;
                        while flag                      %判断空格所在位
                            if (line_temp(i2)==' ')
                                flag=0;
                            end
                            i2=i2+1;
                        end
                        D{g,1}=line_temp(1:i2-2);      %空格前为单词
                        D{g,2}=line_temp(i2:len_temp); %空格后为译意
                        E{g,1}=D{g,1};
                        E{g,2}=D{g,2};
                    end
                    fclose(fid1);
                    switch(English_type)               %选择性设置填空
                        case 1
                            for it1=1:num_questions
                                D{it1,1}="____________________";
                            end
                        case 2
                            for it1=1:num_questions
                                D{it1,unidrnd(2)}="____________________";
                            end
                        case 3
                            for it1=1:num_questions
                                D{it1,2}="____________________";
                            end
                    end

此处说明了当初设置列为2的原因
即 分开存储 左右两部分

  • D为原始存储内容的拆分形式
  • E为原始存储内容的拆分形式加工后的存储新内容

向文件内写入数据

多模式下的选择性输出

case 1 2 3分别代表三种模式 数学 语文 英语

blanks(N);

blanks函数 代表N个空格;

winopen(‘answer.txt’);

在文件读写操作完成后,使用 winopen函数打开文件;

    fid=fopen('answer.txt','w');
    
    for h=1:num_questions
        switch(mode)
            case 1
                fprintf(fid,'%s\n',E{h,1});
            case 2
                fprintf(fid,'%17s %s%s %s %s\n',E{h,1},blanks(4),'-',blanks(6),E{h,2});
            case 3
                fprintf(fid,'%s %s%s %s %s\n',E{h,1},blanks(4),'-',blanks(6),E{h,2});
        end
    end
    winopen('answer.txt');
    fclose(fid);

fprintf函数格式

fprintf(FID,FORMAT, A, …);

FORMAT is a character vector that describes the format of the output fields, and
can include combinations of the following:
* Conversion specifications, which include a % character, a
conversion character (such as d, i, o, u, x, f, e, g, c, or s), and optional
flags, width, and precision fields. For more details, type “doc fprintf” at
the command prompt.

以上是matlab 的 help 内容简单介绍 别看了上面这段没用

以下是翻译后内容
在这里插入图片描述

ConversionDetails
%d or %i十进制
%u十进制
%o八进制
%x十六进制 a-f
%X十六进制 A-F
%f定点表示法(使用精度运算符指定小数点后的位数)
%e指数表示法,小e,例如3.141593e+00
%E指数表示法,大E,例如3.141593E+00
%g比较紧凑的%e或%f,后面不带零(使用精度操作符指定有效数字的数目)
%G比较紧凑的%E或%f,后面不带零(使用精度操作符指定有效数字的数目)
%c单个字符
%s字符向量或字符串数组

特殊符号

Special CharacterRepresentation
单引号‘’
百分比%%
反斜杠\\
警报\a
退格\b
换页\f
新行\n
回车\r
水平 Tab / 跳格\t
垂直 Tab / 跳格\v
一种字符,其Unicode®数值可以用十六进制数N表示\xN
一种字符,其Unicode数值可以用八进制数N表示\N

这个翻译累死我了 淦(。A。)

更加详细用法请参考matlab 参考手册 命令行内输入 doc fprintf


噩梦模式&无尽模式(整人专用)这个别看了吧

FBI WARNING!
在主代码开始循环前插入一段魔鬼 代码

if(mode_demon==1)                           %这里可是地狱啊
    num_questions=num_questions.*unidrnd(5);
else if(mode_infinite==1)
        num_questions=1000;
    end
end

记得 这个噩梦模式(mode_demon)是叠加的
如果不怕电脑卡飞那就来吧 几万道GKD

( ´థ౪థ)σ
在这里插入图片描述


事后杂谈

这次的代码书写花了一天多的时间 中间挺绝望的
在这里插入图片描述
不过最终爬出深渊 还是 挺 快 乐 的

这份BLOG写了 1W+字 都快整吐了

头有点痛了 下午三点四十终于是快完成了 剩下的扔给审核了

累了累了 去躺一会了

初始阅读量32…也就是我修改了32次???
在这里插入图片描述
那么 就这样结束了

这段代码 太耗精神了 我感觉我的身体已经菠萝菠萝哒了

大致的程序以及核心内容都已经放出来了

那么 剩下的包括.m .fig .txt数据文件在内的 全套解决方案.zip 打包文件 就 积分下载了 (也就5积分)

白给版的 等过一段时间 或者 浏览量挺多了K++ 再放出来 算良心了吧

源代码

白给直接拿走 >> 大鸽鸽给点浏览量或者积分吧 (´・ω・`) 动 力 强 劲 2 5 5 0 0 !
积分支持一下 >> 只要5积分哦 _ (:△」∠)_
下次一定

看完麻烦点个赞哦

链接:https://pan.baidu.com/s/1NjkVhCpe-FAP3h7nzzwO2Q
提取码:7ai1

2021.11.27 Released

  • 9
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值