使用MATLAB的GUIDE做简单的界面
文章目录
GUIDE简介
GUIDE(Graphical User Interfaces Development Environment) 是由窗口、光标、按键、菜单、文字说明等对象(Objects)构成的一个用户界面。用户通过一定的方法(如鼠标或键盘)选择、激活这些图形对象,使计算机产生某种动作或变化,比如实现计算、绘图等。
在MATLAB的命令行窗口中键入guide可以打开GUIDE。这个命令将打开GUIDE Quick Start对话框。它可以看作是一个简单的GUI应用程序的开发向导。利用它可以使用鼠标方便地在窗体上添加各种各样的控件。而且它会负责生成一个m文件,里边定义了各个控件的回调函数,简化了GUI应用程序的开发。当然matlab中GUI应用程序也可以使用纯代码生成。在MATLAB中,关于guide的使用方法, 参见帮助文档:MATLAB/Getting Started/Create Graphical User Interfaces/Laying Out a GUI/Starting GUIDE条目下。
参考:https://baike.baidu.com/item/guide/3947857?fr=aladdin
其实目前MATLAB是不建议用户使用GUIDE来构建App的,MATLAB更推荐使用App设计工具来构建App
以后有时间了可能会写一些App设计工具的系列文章(先鸽着……)
更多构建App的方法,请参考App 构建
小例子
读取图片小栗子
实现了读取图片,使用一组复选框来使用不同的方法对图像进行边缘提取
功能实现
- 首先是搭界面
- 码代码:打开回调函数callback即可 首先是按钮‘选择图片’
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
%选择图片路径
[filename, pathname] = uigetfile({'*.jpg';'*.bmp';'*.gif' },'选择图片');
%合成路径+文件名
str = [pathname, filename];
%读取图片
global im
im = imread(str);
%使用第一个axes1 即在axes1这个区域作图
axes(handles.axes1);
%显示图片
imshow(im)
然后是‘退出’按钮
% --- Executes on button press in pushbutton2.
function pushbutton2_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton2 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
%关掉程序
close(gcf)
然后是按钮组 ,打开回调里面的SelectChangefcn,一个switch搞定
function uibuttongroup1_SelectionChangedFcn(hObject, eventdata, handles)
% hObject handle to the selected object in uibuttongroup1
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global im%使用全局变量im
str =get(hObject, 'string');%拿到按钮名称
axes(handles.axes1);%指定在此之后的作图都在这个axes1里面画图
switch str
case '原图'
imshow(im)
case 'sobel)'
BW = edge(rgb2gray(im), 'sobel');
imshow(BW)
case 'prewitt'
BW = edge(rgb2gray(im), 'prewitt');
imshow(BW)
case 'canny'
BW = edge(rgb2gray(im), 'canny');
imshow(BW)
end
需要注意的是,要把读取的图片im 存为global全局变量,这样才能在两个函数之间调用。
结果展示:
成绩查询小栗子
功能实现
主要功能:在软件启动的时候,读取路径下的txt文件(里面存了一些学生的成绩),把学生姓名显示在左边的窗口,当用户点击姓名的时候,在右边窗口显示该学生的成绩。
首先是界面:
这里左边用了列表框,用来放读取到的数据 ,右边用到了可编辑文本,用来显示学生的成绩,上面的三个标签,用了静态文本。
代码:程序执行时 界面显示
%OpeningFcn 在程序执行功能的时候自动启动
function grade_OpeningFcn(hObject, eventdata, handles, varargin)
% Choose default command line output for grade
handles.output = hObject;
%以只读方式打开文件
fin = fopen('chengji.txt','r');
str = fgetl(fin);%返回文件中的下一行,并删除换行符
[str1 str2 str3 str4]= strread(str,'%s %s %s %s','delimiter',' ');%读取字符串 以空格作为分隔符
%四个标签暂时没用到
counter = 1;%用于计数
%读取名字 直到结尾(结尾返回1,循环结束)
while feof(fin) == 0
str = fgetl(fin);%读取第二行
[name yuwen shuxue yingyu] = strread(str,'%s %d %d %d','delimiter',' ');
xingming(counter) = name;
chengji(counter,:)=[yuwen shuxue yingyu];%给成绩的这一行赋值
counter = counter + 1;
end
set(handles.listbox1,'string',xingming);%在listbox1显示内容
handles.chengji = chengji;%将成绩存入handles结构体,方便以后使用
set(handles.edit1,'string',num2str(chengji(1,:)));%默认显示第一个人的成绩
fclose(fin);%关闭文件
% Update handles structure
guidata(hObject, handles);
当用户选择姓名的时候,显示成绩:
% --- Executes on selection change in listbox1.
function listbox1_Callback(hObject, eventdata, handles)
% hObject handle to listbox1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
value = get(hObject, 'value');%获取当前选项的索引值value 在本例中有五个人 每个人对应于一个索引值
set(handles.edit1,'string',num2str(handles.chengji(value,:)));
结果展示:
注意:在listbox的属性中, max 为用户依次可以选中的最大的元素数目。
读取Excle表格
功能实现
功能和上面那个差不多,不过这次可以手动选择文件,读取的文件为excle格式的,读取方式会有点区别。
界面设计:
多了个选择文件的按钮,和一个显示文件读取路径的窗口。
代码,首先是读取文件部分:
% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
%筛选文件类型为xlsx 和xls ,弹出的窗口的名字为chosse a file
[filename, pathname] = uigetfile({'*.xlsx';'*.xls'}, 'choose a flie');
%将文件路径保存下来
str = [pathname filename];
set(handles.edit2,'string',str);%显示文件路径及文件名字
xls_data = readcell(str);%以cell的形式读取excle文件
%在listbox1里面显示课程名字
set(handles.listbox1,'string',xls_data(2:end,1));
%在edit1里面显示第一门课对应的信息(类似于默认显示第一门的信息)
set(handles.edit1,'string', xls_data(2,:));
%将excle表格信息存到handles结构中,方便以后使用。
handles.xls_data = xls_data;
%更新guidata
guidata(hObject,handles);
可能是因为我的excle里面既有中文,又有数字,还有字符串,所以使用xlsread函数读取的时候,读取到是个空矩阵。使用readmatrix读取,所有的中文也都读取成了乱码。后来就使用了readcell进行读取,总算成功了。readcell牛逼!
然后就是listbox1的功能实现了:
% --- Executes on selection change in listbox1.
function listbox1_Callback(hObject, eventdata, handles)
% hObject handle to listbox1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
value =get(hObject,'value');
set(handles.edit1,'string', handles.xls_data(value+1,:).');
显示效果:
总结:set()可以控制各个控件上面的显示,可通过handles.name进行索引,name就是控件的tap标签。
还有个小小的问题,就是使用readcell读取后的变量,用set显示的时候,好像只能显示成列,尽管我使用了转置,而且在窗口单独试了,转成列的数据依旧显示成行,怀疑是set函数的问题,这个有时间再深究一下。
还有就是要找个时间总结一下matlab里面的数据结构,类型,比如通过(){} []这三个括号对数据进行索引有什么区别。
改进
错误处理方式
对于用户的一些错误操作,进行一些判断,防止软件过于脆弱。
这里对用户的输入进行了判断,以及错误提醒。
% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
[filename, pathname] = uigetfile({'*.xlsx','Excel Files(*.xls)';...
'*.txt','Txt Files(*.txt)'}, 'Choose a flie');
str = [pathname filename];
set(handles.edit2,'string',str);
if length(filename)<5
msgbox('您没有选择文件');
return;
end
fname = filename(1,end-2:end);
switch fname
case 'txt'
fin = fopen(str,'r');
counter = 1;%用于计数
%读取名字 直到结尾(结尾返回1,循环结束)
while feof(fin) == 0
str = fgetl(fin);%读取行
[name, yuwen, shuxue, yingyu] = strread(str,'%s %s %s %s','delimiter',' ');
txt_data(counter,:)=[name yuwen shuxue yingyu];%给成绩的这一行赋值
counter = counter + 1;
end
set(handles.listbox1,'string',txt_data(2:end,1));%在listbox1显示内容
handles.data = txt_data;%将成绩存入handles结构体,方便以后使用
set(handles.edit1,'string',txt_data(2,2:end));%默认显示第一个人的成绩
fclose(fin);%关闭文件
% Update handles structure
guidata(hObject, handles);
case 'lsx'
xls_data = readcell(str);
set(handles.listbox1,'string',xls_data(2:end,1));
set(handles.edit1,'string',xls_data(2,2:end));
handles.data =xls_data;
guidata(hObject,handles);
otherwise
msgbox('请选择正确的格式');
end
代码有点问题,以后有时间改改。
GUI的优化进度条
主要是 加了一个事件的进度条
case 'lsx'
xls_data = readcell(str);
h = waitbar(0,'正在读取文件哦');%创建一个waitbar 0为当前进度
pause(2)
waitbar(1,h,'读取完毕')% 进度显示为1
close(h)%关闭进度条
set(handles.listbox1,'string',xls_data(2:end,1));
set(handles.edit1,'string',xls_data(2,2:end));
handles.data =xls_data;
guidata(hObject,handles);
otherwise
msgbox('请选择正确的格式');
退出功能:
% --- Executes on button press in pushbutton2.
function pushbutton2_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton2 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
clc
clear all]
close(gcf);%gcf表示当前的GUI程序
程序打包及混合编程
首先是打包,进入有.fig和.m文件的路径中:输入
mcc -m untitled%untitled是guid的名字
然后生成了一个exe文件,还有一堆log文件。但是这个exe文件只有在装了matlab的电脑上运行,想在没有装matlab的电脑上运行,需要下载一个版本一致的matlab库函数MCRinstaller。
混合编程使用comtool
添加菜单active控件
这个因为版本问题,使用视频上的方法老是出错。
实现了播放视频的功能。
上代码:
第一种方法是通过proid和pos来建立activex(系统的视频控件)。
% 窗体打开前,执行该函数----------------------------------------------------
function playMTV_OpeningFcn(hObject, eventdata, handles, varargin)
handles.output = hObject;
pos=[0 0 0 0];
%MovieControl=actxcontrol('AMOVIE.ActiveMovieControl.2',pos);
%actxcontrol get(MovieControl) 查看文档属性
MovieControl=actxcontrol('WMPlayer.OCX.7',pos); %调用Windows的系统控件(activex控件)
handles.MovieControl=MovieControl; %绑定到全局变量中
mp=handles.MovieControl.currentMedia;
handles.output=mp;
guidata(hObject, handles);
% 打开文件按钮,播放视频----------------------------------------------------
function Untitled_2_Callback(hObject, eventdata, handles)
[filename pathname]=uigetfile('*.*','选择媒体文件'); %打开文件对话框
if ~filename %如果没有打开文件
return;
end
url1=[pathname filename]; %拼接绝对路径
set(handles.MovieControl,'URL',url1); %用MovieControl播放视频
% 窗体大小改变时,执行该函数------------------------------------------------
function figure1_SizeChangedFcn(hObject, eventdata, handles)
units=get(handles.figure1,'units');
set(handles.figure1,'units','pixels'); %将单位设置成像素
pos=get(handles.figure1,'Position');
set(handles.figure1,'units',units);
pos=[0 0 pos(3:4)];
move(handles.MovieControl,pos); %设置MovieControl控件的大小随窗体大小的改变而改变
% 退出按钮-----------------------------------------------------------------
function Untitled_3_Callback(hObject, eventdata, handles)
clc;
clear all;
close(gcf);
第二种是通过先把activex1拖进gui,然后通过Activex1这个tap来对视频控件进行操作(感觉所有的GUI控件都可以通过它的tag,使用set函数对它进行显示操作)。
% 窗体打开前,执行该函数----------------------------------------------------
function test_OpeningFcn(hObject, eventdata, handles, varargin)
%把activex1的currentMedia属性给mp
mp = handles.activex1.currentMedia;
% Choose default command line output for test
handles.output = mp;%将当前窗口的output属性设为mp
% Update handles structure
guidata(hObject, handles);%handles结构体里面包含hObject(即我们的这个GUi,figure1)的所有信息,更新的时候,handles对hObject负责,同步更新 hObject指该figure的句柄;
% 打开文件按钮,播放视频----------------------------------------------------
% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
[filename pathname] = uigetfile({'*.*'},'选择一个视频');
if ~filename
return;
end
url = [pathname filename];
set(handles.activex1,'URL',url);
% 窗体大小改变时,执行该函数------------------------------------------------
function figure1_SizeChangedFcn(hObject, eventdata, handles)
units=get(handles.figure1,'units');
set(handles.figure1,'units','pixels'); %将单位设置成像素
pos=get(handles.figure1,'Position');
set(handles.figure1,'units',units);
pos=[0 0 pos(3:4)];
move(handles.MovieControl,pos); %设置MovieControl控件的大小随窗体大小的改变而改变
参考:https://www.bilibili.com/video/BV1Ut411y7uh
总结
要点:
hObject指该figure的句柄;
handles.output = hObject;
guidata(hObject, handles);
这两行代码配合使用,意思就是把该figure的句柄存到handles结构体中的output字段里去;
目的是使figue的主函数返回该figure的句柄,见OutputFcn函数:
varargout{1} = handles.output;
主函数负责调度各个控件的callback响应。