学生通常都会产生“好难啊,老师没有教过 ... ...” 这样的本能反应。在现行的教育体制下,学生已经习惯了完成老师布置的已知边界内的任务,面对未知往往素手无策甚至很容易产生恐惧。希望能够通过这个系列的教程治愈这种畏惧未知的病,提升学生面对未知时的效能感!
不会,没有教过,有什么关系,你那么聪明,那么优秀,快速学会它不就行了。
步骤一:用"Matlab"和“GUI”作为关键词在百度进行搜索,所得如下:
(1)从一个叫做“matlab gui是什么_百度知道”里边获取的信息:
G=graphic图形 U=user用户 I=interface界面
打个比方,GUI就是windows,没有GUI就是DOS。
Matlab是利用命令和脚本来进行交互的,所以,理论上只是采用命令窗口的输入和输出机制,也是可以进行猜数字游戏的编程的,不用涉及图形界面操作;但是,当前的任务要求利用图形界面进行猜数字游戏的编程,就需要了解Matlab GUI机制。
(2)如何开启GUI机制就成了接下来的关键:
技术有一个特点,你会的话,就没有难度;你不会的话,哪怕是一层窗户纸,真的就是一层窗户纸,你也会被蒙蔽双眼,不知道如何下手。找到度娘的第一个有关的信息就是“matlab_gui初学者教程”里边有提到
开启GUI机制的密码是 Guide
这个新建GUI界面的对话框有两个panel,第一个是"Create New GUI",第二个是"Open existing GUI",我们现在的工作目录什么都没有,自然是新建一个GUI。
可以新建一个简单的blank(空)的界面,然后往这个界面里边放置各种控件。
一个Gui程序,由两个部分组成。界面是界面,是表层,通过.fig文件进行控制;代码是代码,是底层,通过与.fig相同文件名的.m文件进行控制。
步骤一到这里就完成了,目的是初步了解Matlab GUI机制,它有表层的界面,也有底层的代码。接下来我们要通过步骤二更深入地理解Matlab GUI机制。
步骤二:如何利用GUI机制载入一幅简单的图片?
我们以魔方图片为例子,看看如何载入魔方图片。用photoshop切割并适当加工成800*600的.jpg格式的图片,命名为MagicMatrix_800600.jpg。
保存在当前工作目录E:\Courses\MatlabLearningCourse\MissionImpossible2_GuessNumber。
在保存GUI文件的一刹那,Matlab会自动生成两个文件,一个是.fig文件,对应guide开发界面的样子;另外一个是.m文件,是和.fig文件平行的代码控制文件。
GUI界面的样子:
代码控制.m文件里边的样子:
这时候是最具恐惧感的时刻,面对未知的恐惧,弥漫到整个全身,大部分人在这个时候都会有一种寸步难行举步维艰的感觉!我也曾经有过这种感觉,面对复杂的GUI机制有一种无力感,觉得自己无论如何都是搞不定GUI的。
* 为什么在你学习一门新的语言的时候需要一个老师,可能他的作用就是消除这层恐惧,让你能够大踏步地向前,直到“胜利”的彼岸。然而,老师的存在也会起到副作用,就是学生在面对已知的时候,得心应手;而在面对未知的时候,寸步难行!教育的终极目的是打造可持续发展的个体,也就是面对未知不会产生恐惧的个体,这些人才是真正的托起这个民族复兴梦想的人啊!
怀揣着梦想,我们把GUI .m文件里边的代码拷出来看看:
function varargout = LoadPic(varargin)
% LOADPIC MATLAB code for LoadPic.fig
% LOADPIC, by itself, creates a new LOADPIC or raises the existing
% singleton*.
%
% H = LOADPIC returns the handle to a new LOADPIC or the handle to
% the existing singleton*.
%
% LOADPIC('CALLBACK',hObject,eventData,handles,...) calls the local
% function named CALLBACK in LOADPIC.M with the given input arguments.
%
% LOADPIC('Property','Value',...) creates a new LOADPIC or raises the
% existing singleton*. Starting from the left, property value pairs are
% applied to the GUI before LoadPic_OpeningFcn gets called. An
% unrecognized property name or invalid value makes property application
% stop. All inputs are passed to LoadPic_OpeningFcn via varargin.
%
% *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one
% instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES
% Edit the above text to modify the response to help LoadPic
% Last Modified by GUIDE v2.5 22-Sep-2015 12:03:43
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @LoadPic_OpeningFcn, ...
'gui_OutputFcn', @LoadPic_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT
% --- Executes just before LoadPic is made visible.
function LoadPic_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to LoadPic (see VARARGIN)
% Choose default command line output for LoadPic
handles.output = hObject;
% Update handles structure
guidata(hObject, handles);
% UIWAIT makes LoadPic wait for user response (see UIRESUME)
% uiwait(handles.figure1);
% --- Outputs from this function are returned to the command line.
function varargout = LoadPic_OutputFcn(hObject, eventdata, handles)
% varargout cell array for returning output args (see VARARGOUT);
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Get default command line output from handles structure
varargout{1} = handles.output;
一开始,真的是无从下手啊,这都是些什么呀!!鲨鱼?
但是,只要你不因为害怕或者恐惧而拒绝去摸索它,仔细观察这些代码你会发现:虽然从外围看不懂代码的具体含义,但是,还是可以大致了解到这些代码都是由 "function"领衔的,GUI是一个“函数”分类机制?
这是一种感觉,这种感觉已经非常接近Matlab GUI机制的本质。Matlab是脚本语言,.m文件是由一组命令组成的,运行某个.m文件相当于逐行执行.m文件里边的命令。
而Matlab GUI则遵循的是“分发”的规则,属于典型的事件驱动型的,所有的函数都处于待命的状态,一旦你有所动作,比如点击了一个按钮,它就会触发这个动作背后对应的函数实现某种功能。这两种机制分别对应两种程序的思维模式,前一种是过程性的,后一种则是事件驱动的(学习过VB的,会对事件驱动不陌生,没错,VB就是典型的事件驱动的编程)。
问题就变成了,我们如果想做点什么,比如要载入图片,要从哪里开始切入,代码要写在哪个模块呢?要是理解了Matlab GUI机制,我们只要以某个事件去驱动它就可以了。
这里一开始,在什么都没有添加的情况下,总共有这么3个模块(那些注释,都是障眼法而已):
function varargout = LoadPic(varargin)
function LoadPic_OpeningFcn(hObject, eventdata, handles, varargin)
function varargout = LoadPic_OutputFcn(hObject, eventdata, handles)
通过百度搜索,我们了解到,添加任意一个控件,比如按钮或者编辑框,GUI的代码层也会增加函数,比如添加一个编辑框控件,它自动命名成edit1,那么就会在代码中出现一个新的函数:
编辑框控件在工具界面里边:
左边这列的第3个。
先往gui界面上添加一个editbox,
这时候.m文件里边的内容还没有任何改变,点击“保存”之后,这个时候.m文件就增加了一个新的Callback函数:
% --- Executes during object creation, after setting all properties.
function edit1_CreateFcn(hObject, eventdata, handles)
% hObject handle to edit1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles empty - handles not created until after all CreateFcns called
% Hint: edit controls usually have a white background on Windows.
% See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
* 事件驱动基本上就是这么一种特点,某个事件对应某个功能函数,事件触发函数/功能。
如果是这样,我们是不是可以尝试添加一个控件,比如按钮控件,点击这个按钮,在这个按钮对应的函数里边实现载入图片的功能。
这时候,我们要重新借助度娘,找到按钮控件对应的实现载入图片的代码,比如我们找到这样的代码:
% --- 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({'*.*';'*.jpg';'*.bmp';'*.gif';'*.png';'*.tif'},'Read Pic');
str = [pathname filename];
global src_img;
if ~isequal([pathname,filename],[0,0])
src_img = imread(str);
axes(handles.axes1);
imshow(src_img);
end
这段代码可以简单解读为两个部分,第一部分是如何选取图片文件;第二部分是读取该图片文件并呈现的部分。
[filename,pathname] = uigetfile({'*.*';'*.jpg';'*.bmp';'*.gif';'*.png';'*.tif'},'Read Pic');
这里用了一个 uigetfile的机制,在matlab的命令窗口中,输入这段代码,回车,这段代码会调用一个对话框:
当然,也可以通过在命令窗口里边输入 "help uigetfile" 了解uigetfile函数的机制:
uigetfile Standard open file dialog box.
[FILENAME, PATHNAME, FILTERINDEX] = uigetfile(FILTERSPEC, TITLE)
displays a dialog box for the user to fill in, and returns the filename
and path strings and the index of the selected filter. A successful
return occurs only if the file exists. If the user selects a file
that does not exist, an error message is displayed, and control
returns to the dialog box. The user may then enter another filename,
or press the Cancel button.
The FILTERSPEC parameter determines the initial display of files in
the dialog box. For example '*.m' lists all MATLAB code files. If
FILTERSPEC is a cell array, the first column is used as the list of
extensions, and the second column is used as the list of descriptions.
When FILTERSPEC is a string or a cell array, "All files" is appended
to the list.
When FILTERSPEC is empty the default list of file types is used.
Parameter TITLE is a string containing the title of the dialog box.
The output variable FILENAME is a string containing the name of the
file selected in the dialog box. If the user presses Cancel, it is set
to 0.
The output variable PATHNAME is a string containing the path of the
file selected in the dialog box. If the user presses Cancel, it is set
to 0.
The output variable FILTERINDEX returns the index of the filter
selected in the dialog box. The indexing starts at 1. If the user
presses Cancel, it is set to 0.
[FILENAME, PATHNAME, FILTERINDEX] = uigetfile(FILTERSPEC, TITLE, FILE)
FILE is a string containing the name to use as the default selection.
[FILENAME, PATHNAME] = uigetfile(..., 'MultiSelect', SELECTMODE)
specifies if multiple file selection is enabled for the uigetfile
dialog. Valid values for SELECTMODE are 'on' and 'off'. If the value of
'MultiSelect' is set to 'on', the dialog box supports multiple file
selection. 'MultiSelect' is set to 'off' by default.
The output variable FILENAME is a cell array of strings if multiple
filenames are selected. Otherwise, it is a string representing
the selected filename.
[FILENAME, PATHNAME] = uigetfile(..., 'Location', [X Y]) places the
dialog box at screen position [X,Y] in pixel units. This option is
supported on UNIX platforms only.
NOTE: THIS SYNTAX IS OBSOLETE AND WILL BE IGNORED
[FILENAME, PATHNAME] = uigetfile(..., X, Y) places the dialog box at
screen position [X,Y] in pixel units. This option is supported on UNIX
platforms only.
NOTE: THIS SYNTAX IS OBSOLETE AND WILL BE IGNORED.
Examples:
[filename, pathname, filterindex] = uigetfile('*.m', 'Pick a MATLAB code file');
[filename, pathname, filterindex] = uigetfile( ...
{'*.m;*.fig;*.mat;*.mdl', 'All MATLAB Files (*.m, *.fig, *.mat, *.mdl)';
'*.m', 'MATLAB Code (*.m)'; ...
'*.fig','Figures (*.fig)'; ...
'*.mat','MAT-files (*.mat)'; ...
'*.mdl','Models (*.mdl)'; ...
'*.*', 'All Files (*.*)'}, ...
'Pick a file');
[filename, pathname, filterindex] = uigetfile( ...
{'*.mat','MAT-files (*.mat)'; ...
'*.mdl','Models (*.mdl)'; ...
'*.*', 'All Files (*.*)'}, ...
'Pick a file', 'Untitled.mat');
Note, multiple extensions with no descriptions must be separated by semi-
colons.
[filename, pathname] = uigetfile( ...
{'*.m';'*.mdl';'*.mat';'*.*'}, ...
'Pick a file');
Associating multiple extensions with one description:
[filename, pathname] = uigetfile( ...
{'*.m;*.fig;*.mat;*.mdl', 'All MATLAB Files (*.m, *.fig, *.mat, *.mdl)'; ...
'*.*', 'All Files (*.*)'}, ...
'Pick a file');
Enabling multiple file selection in the dialog:
[filename, pathname, filterindex] = uigetfile( ...
{'*.mat','MAT-files (*.mat)'; ...
'*.mdl','Models (*.mdl)'; ...
'*.*', 'All Files (*.*)'}, ...
'Pick a file', ...
'MultiSelect', 'on');
This code checks if the user pressed cancel on the dialog.
[filename, pathname] = uigetfile('*.m', 'Pick a MATLAB code file');
if isequal(filename,0) || isequal(pathname,0)
disp('User pressed cancel')
else
disp(['User selected ', fullfile(pathname, filename)])
end
See also uigetdir, uiputfile.
Reference page in Help browser
doc uigetfile
一般这样多的说明,通过例子就可以大致了解这个函数的功能而不必逐行都看(从一大堆信息中提取有效信息是一种能力,我们真正的目的在于解决问题完成任务),uigetfile就是利用一个对话框选取一个文件,这个函数的返回值有两个 [filename, pathname],这里的filename就是文件名,这里的pathname是路径名。
我们可以通过将两个变量组合,变成一个全路径,也就是指向我们选取的图片文件的地址。
str = [pathname filename];
这段代码等同于:
str = srpintf('%s%s', pathname, filename);
我们可以在GUI界面里边添加一个按钮控件,试试这段代码的效果,根据个人习惯,代码部分要稍微做一点点调整:
[FileName,FilePath] = uigetfile({'*.*';'*.jpg';'*.bmp';'*.gif';'*.png';'*.tif'},'Read Pic');
PathName = sprintf('%s%s', FilePath, FileName);
为了保险起见,我们需要看看最后选取完成,文件的全路径是不是对的,需要借助fprintf函数把这个PathName字符串内容打印出来:
fprintf('%s', PathName)
点击Matlab Guide界面,或者直接运行 .m文件,它们的效果是一样的,就会弹出界面:
然后点击pushbutton1按钮,会弹出一个文件选取窗口:
选取其中一个文件:
这时候检查matlab的命令窗口,就会看到
E:\Courses\MatlabLearningCourse\MissionImpossible2_GuessNumber\MagicMatrix_800600.jpg>>
说明我们的代码是写对了。这里的显示有一点违和感,那是因为fprintf('%s', PathName)代码的问题,如果能够把代码改成fprintf('%s\n', PathName)添加一个换行'\n'运行的结果就更和谐了E:\Courses\MatlabLearningCourse\MissionImpossible2_GuessNumber\MagicMatrix_800600.jpg
>>
第二部分的代码的意思是读取图片文件并呈现(在Matlab GUI里,图片通常需要借助axes坐标轴控件显示出来),
src_img = imread(str);
axes(handles.axes1);
imshow(src_img);这三句话的意思分别是:将str指向的图片文件用imread函数读取出来,然后赋值给src_img;然后我们要激活axes1控件;最后是在这个激活的axes1控件里把src_img变量的内容显示出来。
步骤二能让我们更进一步地了解GUI机制,以一个按钮事件触发一个它对应的函数,在这个函数中添加代码来实现载入图片的功能。
GUI中的所有控件使用同一个handles结构体,handles结构体中保存了图形窗口中所有对象的句柄,可以使用handles获取或设置某个对象的属性。我从网上找了这个句柄图形系统的结构图,方便大家理解:
我们试着把整个界面放大一些,然后引入一个坐标轴控件,目的是在选取图片文件之后,能够将图片文件载入并呈现在坐标轴控件上。
具体的代码如下:
% --- 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,FilePath] = uigetfile({'*.*';'*.jpg';'*.bmp';'*.gif';'*.png';'*.tif'},'Read Pic');
PathName = sprintf('%s%s', FilePath, FileName);
fprintf('%s', PathName);
% 将选取的文件的全路径写入到handles.edit1控件中
set(handles.edit1, 'String', PathName);
% 将选取的图片文件,读取并赋值给 imgMatrix变量
imgMatrix = imread(PathName);
% 将这个图片矩阵赋值给 axes1控件
imshow(imgMatrix, 'parent', handles.axes1);
最后呈现的效果是这样: