用MATLAB GUI做一个简单的绩点计算界面

本文主要记录如何用MATLAB自带的GUI功能做一个绩点计算界面。并以此来简单介绍一下MATLAB GUI的使用过程。完整代码见:https://github.com/ZhouJiaHuan/compute-GPA-master

启动guide工具箱

guide是MATLAB用来制作GUI界面的工具性,我们只要在MATLAB命令窗口中输入命令guide即可打开GUI制作界面,如下图:
data
在新建GUI这一栏中提供了几种常用的界面,这里我们直接选用BLANK空白界面即可。
data
这样就会生成一张初始的空白界面,我们可以直接点击工具栏中绿色的运行按钮看一下初始界面的效果。
data
文件名保存为test.fig,点击运行后,发现一共生成了两个文件,一个是界面文件test.fig,另一个是对应的test.m文件。test文件中保存的就是界面文件中的所有信息。一般我们制作GUI界面分成2个步骤:(1)设计GUI界面,即在界面上添加一些我们需要的控件等;(2)写回调函数,简单的说,每一个控件被添加到界面上肯定是有其特定的功能(显示信息、按钮操作等)。比如你想通过按一个按钮去执行特定的功能,这个时候你就把需要执行的代码写在按钮的回调函数里。

一个简单GUI示例

为了帮助理解这个过程,我们先来建立一个简单的GUI来介绍:要求在界面上放置1个按钮,和3个文本框,其中两个文本框用来输入两个数,当按下按钮的时候,计算两个数的和并显示在第三个文本框中。

我们现在刚刚的空白界面上添加几个控件(3个文本框和1个按钮),直接从左侧的控件中拖过来即可。如下图所示:
data
文本框中默认显示是内容是“可编辑文本”,我们可以通过双击控件来修改该控件的属性,这里我们先修改第一个文本框的属性:
data
上图中我分别修改了3个属性:将显示的字体设为20号、将默认显示的字符串设为“0”、
这里需要重点注意的是Tag属性,它每个控件的句柄名,可以理解为每一个控件的名字,在下面写回调函数的时候,都需要通过Tag属性的值来传递数据,因此,所有控件的Tag属性内容不能相同。

按照相同的方法我们依次修改剩下来的控件的属性,并添加一些静态文本增强可读性:
data

以上只是简单地把界面做好了,为了实现我们需要的功能,还需要写回调函数,我们再想一下我们需要实现的功能:按下求和按钮后,计算两个数的和,最后显示在文本框中。因此,我们只需要写求和按钮的回调函数,并读取两个文本框中的信息,然后把计算的结果传递到第三个文本框中。

这里需要介绍GUI中用于传递数据的函数:set()和get()。set()函数用于修改某个控件的属性值。比如我想把Tag名为“add1”的文本框的显示内容改成“1”,可以通过下面的代码实现:

1
set(handles.add1, "string", 1)

同样,我们如果想要获取一个Tag名为“add1”的文本框内容,可以通过get()实现:

1
num1 = str2num(get(handles.add1, "string"))

由于获取到数据的类型是string格式的,在计算的时候需要转换。因此用str2num()完成转换过程。

在了解了set()和get()的基本用法,下面我们就来看看求和按钮的回调函数怎么写。

右击求和按钮选择查看回调,继续选择Callback,会打开test.m文件,并自动创建回调函数,如下图:
data
data
回调函数的名字是根据控件的Tag属性创建的,由于我求和的Tag属性是“add”,因此对应的回调函数名字叫“add_Callback”
在函数体中添加如下代码:

1
2
3
4
num1 = str2num(get(handles.add1, 'string'));
num2 = str2num(get(handles.add2, 'string'));
result = num1 + num2;
set(handles.sum, 'string', result);

data
运行测试结果:
data

大功告成,还是很简单的吧,下面我们就步入正题,制作我们计算绩点的界面吧!

绩点计算工具

第一步当然还是设计界面,如下:
data
界面上的控件主要有两类,右侧是一组按钮,中间是需要显示是成绩单信息。我们期望的功能如下:

  • 点击导入成绩表,会打开文件浏览器,查找本地的成绩表并导入,同时在中间显示基本的信息;
  • 点击计算绩点,按照指定的绩点计算方法计算绩点,计算成功后弹出提示信息;
  • 点击导出结果,保存计算好的绩点并保存到本地的表格中;
  • 点击退出,退出程序

下面我们就依次编写4个按钮的回调函数:

导入成绩表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
% --- Executes on button press in Load_score.
function Load_score_Callback(hObject, eventdata, handles)
% hObject handle to Load_score (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global NUM TXT RAW
% 打开成绩表
[filename, pathname] = uigetfile({'*.xls'; '*.xlsx'});
full_name = strcat(pathname,filename);
% 导入成绩表信息
[NUM,TXT,RAW] = xlsread(full_name);
% 显示表格信息(路径、班级人数、课程数)
set(handles.Load_state,'string',full_name);
set(handles.Stu_num,'string',num2str(size(RAW,1)-1));
set(handles.Course_num,'string',num2str(size(RAW,2)-2));

这里需要注意的是,成绩表需要满足读取的格式,如下:
data

课程需要满足格式:课程名/类型/学分

计算绩点

1
2
3
4
5
6
7
8
9
10
11
12
% --- Executes on button press in Compute_GPA.
function Compute_GPA_Callback(hObject, eventdata, handles)
% hObject handle to Compute_GPA (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global NUM RAW;
global GPA;
% 获取课程名和课程学分
[~, credit] = get_course_credit(RAW);
% 计算绩点
[GPA,~] = compute_GPA(NUM,credit);
msgbox('计算完成');

函数中调用了另外两个函数,分别定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function [course, credit] = get_course_credit(RAW)
% Function:
% 读取表格数据中学生信息(包括学号和姓名)
% Input
% RAW: 课程成绩表,第一行为表头,前两列分别为学号和姓名,成绩从第三列开始;
% 学号|姓名|课程1/必修课/学分1|课程2/必修课/学分2|
% ** | ** | ** | ** |
% ** | ** | ** | ** |
% ** | ** | ** | ** |
% Output
% course: (1,n),cell类型,存放所有的课程名(n门课程)
% credit: (1,n),double类型数组,存放所有课程对应的学分

num_course = size(RAW,2)-2; % 不包含前两列(学号、姓名)
course = null(num_course);
credit = null(num_course);
for i = 1:num_course
course_name_credit = RAW{1,i+2}; %课程/必修课/学分
course_credit = regexp(course_name_credit,'/','split'); %切分
course{i} = course_credit{1}; % 课程名
credit(i) = str2double(course_credit(end)); % 学分
end

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function [GPA,GPA_per_course] = compute_GPA(NUM,credit)
% Function:
% 计算所有学生的平均绩点(加权平均)
% Input
% NUM: (m,n),double型,存放所有m个学生的所有n门课程成绩,每一行对应一个学生的成绩
% score_11 | score_12 | score13 | --- | score_1n |
% score_21 | score_22 | score23 | --- | score_2n |
% ******** | ******** | ******* | --- | ******** |
% score_m1 | score_m2 | scorem3 | --- | score_mn |
% credit: (1,n),double型,存放所有课程的学分
% Output
% GPA: (m,1),double类型,存放所有学生的平均绩点
% GPA_per_course: (m,n),double类型,存放所有学生所有课程的的绩点

scores = NUM;
GPA_per_course = (scores-50)/10;
GPA_per_course(GPA_per_course<0) = 0;
GPA = GPA_per_course*credit'/sum(credit);

导出结果

1
2
3
4
5
6
7
8
9
10
% --- Executes on button press in Write_to_xls.
function Write_to_xls_Callback(hObject, eventdata, handles)
% hObject handle to Write_to_xls (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global RAW;
global GPA;
sorted_result = Sort_result(RAW, GPA);
xlswrite('sorted_GPA_result.xls',sorted_result);
msgbox('已导出至当前路径:sorted_GPA_result.xls');

代码中调用了Sort_result()函数来对结果进行排序,具体的定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function sorted_result = Sort_result(RAW, GPA)
% Function:
% 对绩点按降序排序并保存
% Input
% RAW: 课程成绩表,第一行为表头,前两列分别为学号和姓名,成绩从第三列开始;
% 学号|姓名|课程1/必修课/学分|课程2/必修课/学分|
% ** | ** | ** | ** |
% ** | ** | ** | ** |
% ** | ** | ** | ** |
% GPA: (m,1),double类型,绩点
% write_to_xls:0或1,表示是否导出xls文件
% Output
% sorted_result: cell类型,排序结果,[排名,学号,姓名,绩点]

[id, name] = get_id_name(RAW);
num_stu = length(name);
rank = 1:num_stu; rank = rank';
name_sorted = null(num_stu,1);
id_sorted = null(num_stu,1);

[GPA_sorted,Index] = sort(GPA,'descend');
for i = 1:num_stu
id_sorted{i,1} = id{Index(i)};
name_sorted{i,1} = name{Index(i)};
end
title = {'排名', '学号','姓名', '绩点'};
sorted_result = [title;
num2cell(rank),id_sorted,name_sorted,num2cell(GPA_sorted)];

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[id, name] = get_id_name(RAW);
num_stu = length(name);
rank = 1:num_stu; rank = rank';
name_sorted = null(num_stu,1);
id_sorted = null(num_stu,1);

[GPA_sorted,Index] = sort(GPA,'descend');
for i = 1:num_stu
id_sorted{i,1} = id{Index(i)};
name_sorted{i,1} = name{Index(i)};
end
title = {'排名', '学号','姓名', '绩点'};
sorted_result = [title;
num2cell(rank),id_sorted,name_sorted,num2cell(GPA_sorted)];

退出

1
2
3
4
5
6
% --- Executes on button press in Quit.
function Quit_Callback(hObject, eventdata, handles)
% hObject handle to Quit (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
close(gcf);

最后看一下最终的效果:
data


写在最后的话:
感谢你一直读到这里,希望本篇博客对你有点帮助。关于本篇博客中的任何问题欢迎指出,虚心接受各位大佬的教导!