Учебно-методическое пособие к лабораторным работам по дисциплине «Математическое моделирование приборных системах»


НазваниеУчебно-методическое пособие к лабораторным работам по дисциплине «Математическое моделирование приборных системах»
страница4/5
ТипУчебно-методическое пособие
1   2   3   4   5

Лабораторное занятие №17-№22

Реализация вычислений с помощью графического интерфейса (GUI)


Наличие графического интерфейса служит косвенным признаком коммерциализуемости программного обеспечения. По существу современные стандарты и пользовательские ожидания требуют присутствия GUI(Graphical User Interface) в любой программе. Разумеется, вопрос о том, является ли М-файл полноценной программой, остается дискуссионным – мы отвечаем на него положительно. В научно-исследовательской работе можно обходиться без каких-то оболочек, довольствуясь командной строкой, но лучше затратить сразу немного времени на создание оболочки, чтобы далее в цивилизованных условиях проводить вычислительные эксперименты и отладку содержания математических моделей.

Описание работы по созданию GUI превосходно описано в мультимедийной справке: см. закладку Help-> Demos->MATLAB->Creating Graphical User Interfaces или файл Macromedia Player \demos\CreatingaGUIwithGUIDE.swf. См. также раздел справки Getting Started->Creating Graphical User Interfaces. Существует три основных шага: зарисовка желаемого интерфейса (кнопочки, тестовые боксики и пр.) в редакторе GUIDE, генерация М-кода графической оболочки и модификация последнего и текста своей расчетной программы с целью их связывания. Последний шаг наиболее существенен. Отметим, что вызванной из графического интерфейса программе не возбраняется писать служебные сообщения по-прежнему в командное окно. Ниже рассмотрим простейший пример GUI-программы, вычисляющей сумму двух чисел A+B.


Войдем в редактор - на главном меню. Уменьшим размеры будущего окна до 200*300 пиксел (пользуясь сеткой). Формат сетки можно задать через Tools->Grid and Rulers. Полезно установить флажок Snap Grid – «Выравнивание по сетке». Теперь отобразим два окна – Инспектора Свойств и Обозревателя Объектов (View->Property Inspector, Object Browser); это можно сделать и через иконки . Каждая кнопка или флажок, перетаскиваемая на полотно с палитры слева, имеют такие свойства как имя (tag), цвет и вызываемую функцию. Менять свойства объекта можно либо через контекстное меню, связанное с ним, либо щелкая по его названию в древе на Обозревателе (свойства автоматически отображаются в Инспекторе). Изменим цвет на зеленый, имя на Summa. Добавим два текстовых бокса под именами ValueA и ValueB. Для этого перетащим первый из Edit Box слева, поменяем его цвета, tag и value. Щелкнув правой кнопкой мыши по нему, выберем Dublicate. На новом объекте изменим его tag и остальные параметры. Создадим статический текст – не путать имя и текстовую метку! Тем же способом создадим бокс (имя – result) и надпись результат и две кнопки Push Button – «Закрыть» и «Пуск».

Перейдем ко второму шагу. Сначала посмотрим опции – Tools->GUI Option. Мы видим, что по умолчанию стоит «Сгенерировать и М-файл, и рисуночный файл *.fig». Поменяем только параметр масштабируемости окна (на proportional). Сохраним файлы под именем my1 (это делается за одну операцию), M-файл откроется автоматически. Готовясь к третьему шагу, подготовим простенький демофайл my1exec.m:

function q=my1exec(p)

q=p(1)+p(2);

end

Верхнюю часть кода my1.m-файла редактировать нецелесообразно, о чем нас предупреждают комментарии (рекомендуется внимательно прочитать эти сгенерированные автоматически комментарии). Внесем изменения согласно таблице:


Название процедуры

Добавленный код

my1_OpeningFcn

my.A=0;my.B=0;setappdata(hObject,'mydata',my);


ValueA_Callback

my=getappdata(handles.Summa,'mydata');

my.A=str2double(get(hObject,'String'));

setappdata(handles.Summa,'mydata',my);


ValueB_Callback

my=getappdata(handles.Summa,'mydata');

my.B=str2double(get(hObject,'String'));

setappdata(handles.Summa,'mydata',my);


CloseMy_Callback

rmappdata(handles.Summa,'mydata');

delete(handles.Summa);


Go_Callback

my=getappdata(handles.Summa,'mydata');

res=my1exec([my.A my.B]);

set(handles.result,'String',num2str(res));



Сделаем ряд замечаний. Во-первых, структура файла несколько отличается от обычного М-файла, приближаясь к Си-коду. Все подфункции написаны как бы параллельно, отражая специфику ориентированного на события программирования. Во-вторых, за небольшими уточнениями оказывается, что созданное окно тождественно объекту класса figure. В-третьих, за некоторыми исключениями каждому компоненту окна соответствуют две по названию связанные с ним процедуры – Callback и CreateFcn. Вторая функция автоматически вызывается при его создании (в языке Си аналогично «конструктору» объекта при его инициализации), а вторая – при наступлении некоторых событий, с ним связанных. Напомним, что событием в Windows называется нажатие клавиши, щелчок мыши в определенном месте экрана и прочее вызванное внешними причинами (например, пользователем) изменение среды. Полезно посмотреть Инспектор до и после сохранения М-файла, сравнить изменения полей/свойств, которые заканчиваются на Fcn; кроме того, мы видим, что можно определять не только две функции, связанные с компонентом, а более. В-четвертых, функция OpeningFcn, идущая вверху и относящаяся к figure целиком, является конструктором окна. Путем промежуточного переприсвоения указатель на нее выводится вовне (OutputFcn).

Важнейшее значение имеет уникальная для конкретного окна GUI-структура, имя которой автоматически генерируется как handles. По сути это объект класса структура, поля которого являются указателями на все дочерние объекты, включая и сам figure. Она передается параметром в каждую процедуру и позволяет программисту изнутри обмениваться данными между дочерними компонентами окна. В нее можно записывать и пользовательские данные; поскольку значении переменных среды регистрируются циклически, то при изменении handles (путем прибавления лишнего поля, не обязательно указателя) простого присвоения недостаточно, а следует применять дополнительно команду guidata.

Ключевой момент в создании GUI-программы – это организация обмена данными между расчетной программой и вызывающей ее оболочкой. В первую очередь для этого нужны те переменные, доступ к которым является общим. Один из путей слишком очевиден – обращение к глобальным переменным (см. маркер global). В разбираемом примере реализован путь добавления данных не путем наращения handles, а с помощью организации т.н. пользовательских данных. Они непосредственно не видны из различных функций (например, Callback-ов), но к ним можно получить доступ парой функций – getappdata, setappdata. Поэтому их удобнее всего инкапсулировать в одну структуру; тем не менее, при желании пользователь может ввести несколько таких структур (в отличие от GUI-данных, которые уникальны). В руководстве описан еще один способ – через свойство UserData, ассоциированным с каждым компонентом окна и фундаментальные функции set(handles.NNN,…) и get (здесь NNN – имя компонента, задаваемое в свойстве Tag).

Подробнее разберем пример. Назначение GUI-программы – по числам, вводимым пользователем в два бокса, вычислить при нажатии на кнопку «Пуск» их сумму и отобразить ее в третьем боксе. При нажатии на кнопку «Закрыть» окно закрывается. В функции my1_OpeningFcn на лету создаем двупольную структуру my, затем данные в ней копируем/инкапсулируем в пользовательскую структур mydata. Эта структура впредь будет ассоциирована с figure, указатель на которую временно совпадает с hObject, но статически свопадает с handles.Summa. Следующие две строки таблицы описывают изменение пользовательских данных – функция Callback вызывается после «отщелкивания» курсора от бокса. Триада команд является типической: считывание пользовательских данных (Application Data) в локальную переменную, ее изменение и запись их обратно. Во второй команде по указателю hObject=handles.ValueA(B) мы получаем доступ к тексту, набранному пользователем в боксе, затем преобразуем строку в число. В предпоследней строке таблицы «для очистки совести» уничтожаем пользовательские данные и закрываем окно традиционной командой уничтожения динамической переменной по указателю. Последняя строка таблицы собственно и содержит то, ради чего писалась оболочка. Считываем пользовательские данные, числа А и В, вызываем параметрически файл my1exec.m с кодами расчета; результаты, возвращаемые в переменную res, напрямую подаются в свойство компонента result (изменение свойств происходит визуально в третьем боксе).
Пример:

  1. Реализовать усеченную версию игры «О, счастливчик» в виде последовательности окон. Файл MS Excel содержит базу вопросов-ответов в формате колонок: А – вопрос, B – правильный ответ, СDE – неправильные ответы, F – начисляемые очки за вопрос.


При решении примера вспомним, как мы поступали ранее при зарисовке графиков, создавая множество figure. Теперь наши возможности расширены за счет команд вызова стандартных типов окон – см. MATLAB-> Functions -- By Category-> Creating Graphical User Interfaces-> Predefined Dialog Boxes. И в данном случае не графика довлеет над расчетной программой, а наоборот.

Сценарий программы таков:

  1. Спросить пользователя, использовать ли настройки по умолчанию?

  2. Yes – задать путь к новой базе, новый шрифт и вид окна ответов, затем показать шкалу прогресса процесса (waitbar);No – самим задать

  3. В цикле показывать вопросное окно, верность/неверность ответа и суммарный балл и предложение продолжить

Соответственно после задания пробной базы в Excel (OLbase.xls) представим макет программы Olucky.m:

%Primary function

function Olucky=Olucky()
%Default param

function [OLbasepath,OLFont,OLStyle]=OluckyDef()

OLbasepath=0,OLFont=1,OLStyle=2,

end
%New param

function [OLbasepath,OLFont,OLStyle]=OluckyNew()

OLbasepath=0,OLFont=-1,OLStyle=-2,

end
%Quest/Answer

function Result=OluckyRes(Number,Summa)

Result=9,

end
[a,b,c]=OluckyDef();a,

[a,b,c]=OluckyNew();b,

c=OluckyRes(3,4),

Olucky=777;

end

Разумеется, пока синтаксически верная программа ничего не делает. Начнем заполнять подфункцию OluckyNew. Соответствующие GUI-вызовы основаны на uigetfile, uisetfont, msgbox:
function [OLbasepath,OLFont1,OLStyle]=OluckyNew()

[f,fpath]=uigetfile('*.xls','Где вопросы?','C:\');

OLbasepath=[fpath,f];

button=questdlg('Ответы по вертикали?','Кнопки или списки...','Да','Нет','Да');

if (strcmp(button,'Да')), OLStyle=true; else OLStyle=false; end;

h=msgbox('Сейчас вам будет предложено выбрать шрифт',...

'Или шрифты','help','non-modal');waitfor(h);OLFont1=uisetfont(OLFont);

end

Отметив, что переменная OLFont есть структура, пишем OluckyDef
function [OLbasepath,OLFont,OLStyle]=OluckyDef()

OLbasepath='OLbase.xls';OLStyle=true;

OLFont=struct('FontName','Times New Roman','FontUnits','points',...

'FontSize',12,'FontWeight','normal','FontAngle','italic');

end
Чтобы код был исполняемым, произведем замену в запускающей части кода.
button=questdlg('Применить параметры по умолчанию?','Вы ленивы?','Да','Нет','Да');

[OLbasepath,OLFont,OLStyle]=OluckyDef();

if(strcmp(button,'Нет')), [OLbasepath,OLFont,OLStyle]=OluckyNew(); end;

xlsread(OLbasepath,-1);
Составим новую функцию чтения xls-данных и соответственно заменим последнюю строку на вызов этой вложенной фукнции:

%Read xls

function [N,Quest,Ans,Weight]=OLread(path)

[Weight,NQuestAns]=xlsread(OLbasepath,'A:F');

N=size(NQuestAns);N=N(1);

Quest=NQuestAns(2:N,1);Ans=NQuestAns(2:N,2:5);N=N-1;

end

….

[N,Quest,Ans,Weight]=OLread(OLbasepath);
Теперь обратимся к функции, которая должна выполняться в цикле - OluckyRes. Если пользователь решает прервать игру, то она возвращает -1.

%Quest/Answer

function Result=OluckyRes(Number,Summa)

message={{};{};{}};

message{1}=strcat('После ',int2str(Number(1)),'-го вопроса');

message{2}=strcat('у вас в кошельке ',int2str(Summa),' тысяч рублей');

message{3}='Не пора ли забрать деньги?';

button=questdlg(message,'Отвечать иль не отвечать?','Да','Нет','Нет');

%QuestN+AnsN+TrueAnsN - все, что знаем о N-м вопросе

AnsN={Ans{Number(1),Number(2)},Ans{Number(1),Number(3)},...

Ans{Number(1),Number(4)},Ans{Number(1),Number(5)}};

QuestN=Quest{Number(1)};TrueAnsN=Ans{Number(1),1};WN=Weight(Number(1));

if (strcmp(button,'Да')),

Result=-1;

elseif (OLStyle)

[ind,ok]=listdlg('ListString',AnsN,'SelectionMode','single',...

'PromptString',QuestN,'ListSize',[400 100]);

if (ok==0), ind=1; end;

if (strcmp(AnsN{ind},TrueAnsN))

Result=Summa+WN;

else

Result=Summa;

end

else

message=strvcat('Мудрецы говорят:',AnsN{1},'Соглашаясь, нажмите крестик');

button=questdlg(message,QuestN,AnsN{2},AnsN{3},AnsN{4},AnsN{3});

if (strcmp(button,'')), button=AnsN{1}; end;

if (strcmp(button,TrueAnsN))

Result=Summa+WN;

else

Result=Summa;

end;

end;

end

По параметру OLStyle определяем, что применяем – listdlg или questdlg. Перед этим, однако, загружаем из основной базы данных вопрос под номером QuestN и соответствующие ответы и цену ответа. Если ответ оказывается правильным, то сумма приращивается на цену ответа, выводясь в переменную Result.

После того, как мы определились с реализацией опроса по некоторому вопросу из базы данных, нужно написать функцию сортировки ответов (чтобы пользователь не привык к правильности первого варианта).

%SortAnswer

function Num=OluckySort(Num)

for i=1:20,

ind=floor(1+4*rand(1));ind1=floor(1+4*rand(1));

v=Num(ind1);Num(ind1)=Num(ind);Num(ind)=v;

end

end

Теперь в основное тело программы осталось добавить цикл.

%Number - номер вопроса по счету, номера ответов в колонке xls... если равен 1, то

%правильный

Summa=0;Numb=[1 2 3 4];

for n=1:N,

Numb=OluckySort(Numb);Number=[n Numb];Result=OluckyRes(Number,Summa);

if (Result<0), break, end;

Summa=Result;

end;

Olucky=Summa,
Мы показали, что даже с помощью стандартных диалоговых окон в MATLAB можно создать нечто практически полезное. Разумеется, с помощью созданного самими интерфейса можно было бы сделать игру более элегантной и «отшлифованной».

  1. В масштабируемом окне создать интерфейс, содержащем большинство элементов палитры, с целью адаптировать его к программе MyTriangle (см. пример №3 Лабораторной работы №3, часть 1).




Нулевым шагом здесь является просмотр файта MyTriangle.m и зарисовка на бумаге эскиза будущего GUI-окна.

Окно имеет четыре больших компонента: оси, панель выбора параметров треугольника (внутри нее не поместившаяся снизу подпанель «Площадь и углы»), панель «Медианы/ Биссектрисы/Высоты» и панель «Параметры графика». Сценарий таков.

Пользователь задает длины сторон треугольника, причем третью он может задать через полосу прокрутки. Дополнительно в развертывающемся меню он может выбрать тип треугольника, если не хочет вводить лишних сторон (например, если треугольник прямоугольный). Три «галочки» даны, если он захочет поменять порядок следования сторон. «Утопленная» кнопка с надписью «abc» играет роль четвертой галочки на случай, если треугольник задается через две стороны и угол между ними. После этого нажимается кнопка «Задать треугольник», он решается, и полупустые боксы ниже заполняются значениями углов, площади, медиан и т.п. При этом также сам треугольник рисуется на осях. Затем пользователь может перейти к более сложным задачам, связанным с расчетом площадей при разных длинах сторон – это последняя панель. Здесь он выбирает: какой тип графика ему нужен, нужно ли отображать линии сетки и внешний бокс, способ задания пределов изменения. Разумеется, все завершает кнопка «Построить».

Отметим некоторые особенности. Для масштабируемости окна выбрать GUI-options свойство Resize behaviour как Propotional до его сохранения Для установки размеров окна нужно в его (figure) Инспекторе свойств задать: Units=pixels, Position=[100, 100, 800, 600]. Для задания позиций popup-меню и/или Listbox нужно в Инспекторе найти свойство String и щелкнуть по пиктограмме . Все панели, кроме панели «Тип», имеют тип Panel; указанная же панель имеет тип buttongroup. Для создания меню окна необходимо исполнить пункт меню GUIDE Tools->Menu Editor. Пункты меню «Сохранить->bmp» и «Сохранить->jpg» добавлены с тем, чтобы пользователь мог сохранять картинку, изображенную на осях. Заметим, что можно было поступить более просто, выведя обычное меню окна figure (проставив в Инспекторе его свойств Menubar=figure), но гибче составить свое меню. Что касается создания панелей инструментов, тосредствами GUIDE это невозможно, однако, в режиме командной строки можно использовать команду uitoolbar.

Что касается зарисовки «парадного треугольника», то здесь пришлось программировать. Мы выбрали несколько более сложный путь, пренебрегая советом писать код в функцию OpeningFcn окна. Вместо этого, не найдя функции CreateFcn для осей axes1 в сгенерированном коде MyTriangle1.m, нужно создать ее следующим универсальным способом – нужно выделить в GUIDE оси, в контекстном меню выбрать View->CreateFcn; при этом во-первых, в М-файл дописывается кусок кода, и во-вторых, связь с этим фрагментом задается явно внутри fig-файла (посмотрите в Инспекторе свойсв для axes1 поле CreateFcn). Осталось только для верности сохранить оба файла – это делается стандартным способом.

В сгенерированный фрагмент кода необходимо дописать несколько строк, причем обратите внимание на последнюю строчку. Ее присутствие вызвано тем, что структура handles заполняется указателями только после исполнения всех CreateFcn от дочерних объектов окна.
function axes1_CreateFcn(hObject, eventdata, handles)

x=[1 3 5 1];y=[1 4 2 1];plot(x,y);

axis([0 6 0 6]);axis manual;grid on;

handles.axes1=hObject;guidata(gcf, handles);
Заполним сразу и код-обработчик пункта меню «Сохранить». Для примера рассмотрим сохранение bmp-файла (для простоты он сохраняется с именем photo в текущий каталог, легко можно было бы сделать сохранение гибче – с помощью диалоговых окон). Итак, читается указатель на оси, вычисляется абсолютная позиция осей axes1, из-за особенностей фукнции getframe нам необходимо немного расширить прямоугольную область, чтобы в «снимок» уместились шкалы осей, поэтому немного изменяем вектор rect. Далее связка трех функций: снятия снимка в переменную photo, затем ее перекодировка (с расщеплением) в пиксельный образ и сохранение последнего в файл. Написание Callback-а для подпункта jpg очевидно.
function bmp_Callback(hObject, eventdata, handles)

h=handles.axes1;rect=get(h,'Position');rect1=get(h,'OuterPosition');

rect=[rect1(1)-rect(1) rect1(2)-rect(2) rect1(3) rect1(4)];

photo=getframe(h,rect);[photo,cmp]=frame2im(photo);

imwrite(photo,'photo.bmp','bmp');beep;


  1. Реализовать «решение треугольника» и более сложные функции в GUI-программе


Помимо fig-файла будем использовать три M-файла: MyTriangle1.m (он уже сгенерирован и является управляющим), MyTriangle0exec.m (копия MyTriangle.m, решающая единичный треугольник) и MyTriangle1exec.m (здесь проводятся все действия по построению графиков, включая, например, параметрические расчеты кривых). Управляющий файл, разумеется, будет содержать прикладные данные, но не следует «втаскивать» в них какие-то многомерные массивы, нужные для построения графиков – достаточно просто передать при вызове исполняемых файлов указатель на те оси, в пределах которых и будут строиться кривые.

Начнем с изначальной установки данных приложения. Добавим в функцию MyTriangle1_OpeningFcn GUI-файла блок:
%Задание данных приложения

mt=struct('Square',6,'Sides',[3 4 5],'Angles',[0 0 90],...

'Medians',[1 1 1],'Bisectors',[2 2 2], 'Heights',[3 3 3]);

setappdata(hObject,'MTriangle',mt);
Обратимся к панели задания треугольника и запишем обработчики текстовых боксов через View->Callbacks (поскольку боксы находятся на панели, то, к сожалению, функции вызова для них не были сгенерированы ранее, но, тем не менее, как не трудно убедиться, указатели на каждый бокс присутствуют в структуре hahdles). Например, для бокса, соответствующего стороне b:
function edit2_Callback(hObject, eventdata, handles)

mt=getappdata(handles.output,'MTriangle');

mt.Sides(2)=str2double(get(hObject,'String'));

setappdata(handles.output,'MTriangle',mt);
Что касается стороны с, то вначале запишем обработчик для полосы прокрутки:
function slider1_Callback(hObject, eventdata, handles)

mt=getappdata(handles.output,'MTriangle');

pos=get(hObject,'Value');flag=get(handles.togglebutton1,'Value');

if (flag)

pos1=abs(mt.Sides(1)-mt.Sides(2));pos2=mt.Sides(1)+mt.Sides(2);

pos=pos1+pos*(pos2-pos1);mt.Sides(3)=pos;

else

pos=180*pos;mt.Angles(3)=pos;

end;

set(handles.edit3,'String',num2str(pos));

setappdata(handles.output,'MTriangle',mt);
Первая ветка условного оператора соответствует ненажатой кнопке «abc» (возвращаемое ею значение равно 1) и ситуации ввода трех сторон. Отметим, что мы не стали принудительно изменять для слайдера его предельные значения (они равны 0 и 1).

Обработчик для третьего бокса выглядит так:
function edit3_Callback(hObject, eventdata, handles)

mt=getappdata(handles.output,'MTriangle');

pos=str2double(get(hObject,'String'));flag=get(handles.togglebutton1,'Value');

if (flag)

mt.Sides(3)=pos;

pos1=abs(mt.Sides(1)-mt.Sides(2));pos2=mt.Sides(1)+mt.Sides(2);

pos=(pos-pos1)/(pos2-pos1);

else

mt.Angles(3)=pos;pos=pos/180;

end;

set(handles.slider1,'Value',pos);

setappdata(handles.output,'MTriangle',mt);
Напишем обработчик для кнопки-триггера (начальное значение установим как 1). Обратим внимание, что поле Value обновляется автоматически, и мы лишь сменяем надпись и цвет кнопки:
function togglebutton1_Callback(hObject, eventdata, handles)

q=get(hObject,'Value');

if (~q)

set(hObject,'String','abC');

set(hObject,'BackgroundColor',[1 1 0.5]);

else

set(hObject,'String','abc');

set(hObject,'BackgroundColor',[0.5 1 0.5]);

end;
Напишем фрагмент обработчика всплывающего меню (с учетом показаний «галочек» - здесь есть некая избыточность). Выбранный тип треугольника влияет на показания полей боксов сторон a,b,c, но еще не на сами данные приложения.
function popupmenu1_Callback(hObject, eventdata, handles)

pos=get(hObject,'Value');mt=getappdata(handles.output,'MTriangle');

flags=[get(handles.checkbox1,'Value') get(handles.checkbox2,'Value') get(handles.checkbox3,'Value')],

switch (pos)

case 1

side=1;for i=1:3, if flags(i) side=mt.Sides(i); end; end;

set(handles.edit1,'String',num2str(side));

set(handles.edit2,'String',num2str(side));

set(handles.edit3,'String',num2str(side));

case 4

side=(mt.Sides(1)^2+mt.Sides(2)^2)^0.5;

set(handles.edit3,'String',num2str(side));

otherwise ;

end
Теперь перейдем к обработке кнопки запуска. Имеющиеся данные, если поля менялись, должны составить данные приложения. Структуру данных MTriangle надлежит также дозаполнить вызовом уже расчетных процедур. Затем результаты следует отобразить в боксах панели «Медианы/…» и построить треугольник.
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)

%Фиксация входных данных

mt=getappdata(handles.output,'MTriangle');

ra=str2num(get(handles.edit1,'String'));mt.Sides(1)=ra;

rb=str2num(get(handles.edit2,'String'));mt.Sides(2)=rb;

rc=str2num(get(handles.edit3,'String'));

if (get(handles.togglebutton1,'Value'))

mt.Sides(3)=rc;

else

mt.Angles(3)=rc;

end

rflag=get(handles.togglebutton1,'String');

%Решение треугольника

[S,aA,bB,cC,Ma,Mb,Mc]=MyTriangle0exec(ra,rb,rc,rflag,'med');

mt.Sides=[aA(1) bB(1) cC(1)];mt.Angles=[aA(2) bB(2) cC(2)];

mt.Medians=[Ma Mb Mc];mt.Square=S;

[S,aA,bB,cC,Ma,Mb,Mc]=MyTriangle0exec(ra,rb,rc,rflag,'bis');mt.Bisectors=[Ma Mb Mc];

[S,aA,bB,cC,Ma,Mb,Mc]=MyTriangle0exec(ra,rb,rc,rflag,'hhh');mt.Heights=[Ma Mb Mc];

setappdata(handles.output,'MTriangle',mt);

%Обновление полей

set(handles.edit3,'String',num2str(mt.Sides(3)));

set(handles.edit4,'String',num2str(mt.Square));h=0;

for i=1:3,

command=['h=handles.edit' int2str(4+i) ';'];eval(command);

set(h,'String',num2str(mt.Angles(i)));

command=['h=handles.edit' int2str(7+i) ';'];eval(command);

set(h,'String',num2str(mt.Medians(i)));

command=['h=handles.edit' int2str(10+i) ';'];eval(command);

set(h,'String',num2str(mt.Bisectors(i)));

command=['h=handles.edit' int2str(13+i) ';'];eval(command);

set(h,'String',num2str(mt.Heights(i)));

end;

%Построение треугольника

x=zeros(1,4);y=x;x(2)=mt.Sides(1);x(3)=x(2)-mt.Sides(2)*cosd(mt.Angles(3));

y(3)=y(2)+mt.Sides(2)*sind(mt.Angles(3));

x=x+abs(mt.Sides(1)-mt.Sides(2))*ones(1,4);y=y+ones(1,4);

axes(handles.axes1);cla;plot(x,y,'g-');p=sum(mt.Sides)/2+1;

set(gca,'Color',[1 1 0.5]);axis([0 p 0 p]);grid on;box on;
Чтобы как-то сократить число однотипных выводов в боксы нижней панели, мы воспользовались функцией eval. При построении треугольника удобно вначале сделать текущими осями оси axes1 (см. команду axes). Для лучшего вида окна добавим в функцию OpeningFcn начальные значения popup-меню и «галочек», а также начального значения в группе радиокнопок «Тип»:
% Доустановка параметров

set(handles.popupmenu1,'Value',6);

set(handles.checkbox1,'Value',1);

set(handles.radiobutton1,'Value',1); set(handles.uipanel4,'UserData',1); set(handles.listbox1,'UserData',[0 5]);
Работа с панелями кнопок имеет особенности. Хотя существуют указатели на каждую радиокнопку отдельно, равно как и указатель на группу в целом, функция обработчик составляется на группу и имеет название не Callback, а SelectionChangeFcn (это название проявляется в контекстном меню View Инспектора свойств для группы). В частности, такой механизм гарантирует единственность выбранного варианта. Шаблон функции перепишем из примера:
function uipanel4_SelectionChangeFcn(hObject, eventdata, handles)

% hObject handle to uipanel4 (see GCBO)

% eventdata reserved - to be defined in a future version of MATLAB

% handles structure with handles and user data (see GUIDATA)

switch get(hObject,'Tag') % Get Tag of selected object

case 'radiobutton1'

set(handles.uipanel4,'UserData',1);

case 'radiobutton2'

set(handles.uipanel4,'UserData',2);

case 'radiobutton3'

set(handles.uipanel4,'UserData',3);

case 'radiobutton4'

set(handles.uipanel4,'UserData',4);

end
Здесь нам важно сохранить выбор в какой-то переменной; удобным путем представляется использование такого способа сохранения данных, как поле UserData, в нашем случае, принадлежащего объекту buttongroup.

Теперь настало время создать второй исполняемый файл MyTriangle.m. Достаточно будет вызывать его с 4-мя параметрами: hax – указатель на оси (handles.axes1), mt – номер процедуры, sides – вектор-строка со сторонами треугольника, limits – вектор пределов изменения (его трактовка зависит от функции). Тело файла, разумеется, содержит 4 вложенных функции, вызываемых из главной через оператор switch.
function mt=MyTriangle1exec (hax,mt,sides,limits)

function MT1=MT1()

MT1=0;

end

function MT2=MT2()

MT2=0;

end

function MT3=MT3()

MT3=0;

end

function MT4=MT4()

MT4=0;

end

switch mt

case 1

MT1()

case 2

MT2()

case 3

MT3()

case 4

end

mt=0;

end

Некоторым видоизменением решенного ранее примера №5-10 Работы №2 (часть 2) легко наполнить тела трех вложенных функций. Эффективным оказывается не циклический вызов MyTriangle0exec.m, а векторный вызов файла geroncore.m.

Перед оператором switch нужно расположить две команды, стирающие с осей прежние графики и устанавливающие оси на GUI-окне текущими: axes(hax);cla reset;
function MT1=MT1()

hold on; a=linspace(limits(1),limits(2),21);c=sides(3);

b=min([abs(c-limits(1)) abs(c-limits(2))]);

b=linspace(b,c+limits(2),8);MyColor=['y' 'm' 'c' 'r' 'g' 'b' 'w' 'k'];

Hlines=zeros(1,8);

for j=1:8,

Hline=plot(a,geroncore(a,b(j),c)); Hlines(j)=Hline;

Lname=strcat(num2str(j),': b= ',num2str(b(j)));

set(Hlines(j),'Color',MyColor(j),'DisplayName', Lname);

end;

legend('show');xlabel('a');ylabel('S(a)');axis on;axis tight;hold off;

MT1=0;

end

function MT2=MT2()

a=linspace(limits(1),limits(2),21);b=linspace(limits(3),limits(4),21);

[X,Y]=meshgrid(a,b);contourf(X,Y,geroncore(X,Y,sides(3)));colorbar;

Sname=strcat('S(a,b) at c= ',num2str(sides(3)));title(Sname);

xlabel('a');ylabel('b');axis on;axis tight;

MT2=0;

end

function MT3=MT3()

a=linspace(limits(1),limits(2),21);b=linspace(limits(3),limits(4),21);

[X,Y]=meshgrid(a,b);surf(X,Y,geroncore(X,Y,sides(3)));colorbar;

Sname=strcat('S(a,b) at c= ',num2str(sides(3)));title(Sname);

xlabel('a');ylabel('b');zlabel('S(a,b)');axis on;axis tight;

MT3=0;

end

function MT4=MT4()

a=linspace(limits(1),limits(2),101);b=linspace(limits(3),limits(4),101);

c=linspace(limits(5),limits(6),101);[X,Y]=meshgrid(a,b);

S=geroncore(a(50),b(50),c(50));MM=[];

Hsur=surf(X,Y,S*ones(101),'LineStyle','none');colorbar; colormap jet;

axis manual;axis([a(1) a(101) b(1) b(101) 0 2*S+2]);title('');

xlabel('a');ylabel('b');zlabel('S(a,b)');grid on;box on;

rect=get(hax,'Position');rect1=get(hax,'OuterPosition');

rect=[rect1(1)-rect(1) rect1(2)-rect(2) rect1(3) rect1(4)];

for t=c,

[S,rect1]=sprintf('Время С= %2.3f сек',t);title(S);

set(Hsur,'ZData',geroncore(X,Y,t)); drawnow;

MM=[MM,getframe(hax,rect)];

end;

movie2avi(MM,'mt4.avi','fps',2);

MT4=0;

end

Вернемся к GUI-файлу, точнее, к обработчику списка на панели «Параметры графика». Содержательную часть мы можем либо оставить для Callback-a кнопки пуска, либо частично обработать данные здесь же, используя вновь UserData для списка. Выбирая второе, будем иметь для обработчика:
function listbox1_Callback(hObject, eventdata, handles)

flag=get(hObject,'Value');mt=getappdata(handles.output,'MTriangle');

switch flag

case 1

a=mt.Sides(1);a=[a/2 2*a];b=mt.Sides(2);b=[b/2 2*b];

c=mt.Sides(3);c=[c/2 2*c];

case 2

a=[0 5];b=[0 5];c=[0 5];

case 3

a=[0 1];b=[0 1];c=[0 1];

end;

flag=get(handles.uipanel4,'UserData');

switch flag

case 1

set(hObject,'UserData',a);

case 2

set(hObject,'UserData',[a b]);

case 3

set(hObject,'UserData',[a b]);

case 4

set(hObject,'UserData',[a b c])

end;

Теперь с обработчиком кноки пуска стало проще. Заметим, однако, что это сделало работу GUI-интерфейса менее корректной – ведь мы стали зависимыми от порядка нажатия на группу переключателей и список. Более правильный путь состоит в том, чтобы опрос всех параметров (переключателей, «галочек» и пр.) осуществлялся бы обработчиком кнопки пуска.
function pushbutton2_Callback(hObject, eventdata, handles)

mt=getappdata(handles.output,'MTriangle');

hax=handles.axes1;mt_=get(handles.uipanel4,'UserData');

sides=mt.Sides;limits=get(handles.listbox1,'UserData');

mt=MyTriangle1exec(hax,mt_,sides,limits);
Осталось только дописать простенький обработчик проверочного бокса «Сетка» и оставить ремарку пользователю:
function checkbox4_Callback(hObject, eventdata, handles)

grid;

function figure1_DeleteFcn(hObject, eventdata, handles)

disp('Приятных сновидений')

Задание:


  1. Рассмотреть стандартные типы окон, включая диалоговые. Адаптировать окно (quidetemplate1.fig в каталоге toolbox\matlab\uitools\guitemplates) под какую-либо простую программу.

  2. Создать GUI-окно, обладающее панелью инструментов, меню с тремя уровнями вложенности, которое возможно было бы масштабировать (включая пропорциональное увеличение осей и шрифтов). На панель инструментов вынести по крайней мере три пиктограммы. Предусмотреть небольшой логотип на окне

Указание: Возможности GUIDE здесь ограничены, в функции OpeningFcn можно предусмотреть команды постановки дополнительных элементов в окно.

  1. Реализовать на базе Примера игру «О, счастливчик» с собственным GUI-интерфейсом.


1   2   3   4   5

Похожие:

Учебно-методическое пособие к лабораторным работам по дисциплине «Математическое моделирование приборных системах» iconМетодические указания к лабораторным работам по дисциплине «Управление проектами»
Методические указания к лабораторным работам по дисциплине «Управление проектами» для студентов и слушателей факультета «Инженерный...

Учебно-методическое пособие к лабораторным работам по дисциплине «Математическое моделирование приборных системах» iconУчебно-методическое пособие по дисциплине «Трудовое право» для студентов,...
Учебно-методическое пособие по дисциплине «Трудовое право» составлено в соответствии с требованиями Государственного образовательного...

Учебно-методическое пособие к лабораторным работам по дисциплине «Математическое моделирование приборных системах» iconУчебно-методическое пособие по дисциплине «пропедевтика внутренних...
Учебно-методическое пособие предназначено для студентов 2-3 курсов педиатрического факультета кгму

Учебно-методическое пособие к лабораторным работам по дисциплине «Математическое моделирование приборных системах» iconМетодические рекомендации по разработке методических указаний к практическим...
Методические рекомендации по разработке методических указаний к практическим занятиям, лабораторным работам по дисциплине/ Составители...

Учебно-методическое пособие к лабораторным работам по дисциплине «Математическое моделирование приборных системах» iconУчебно-методическое пособие по дисциплине «Бюджетное планирование и прогнозирование»
Учебно-методическое пособие предназначено для бакалавров, обучающихся по направлению 38. 03. 01 «Экономика» профиль «Финансы и кредит»...

Учебно-методическое пособие к лабораторным работам по дисциплине «Математическое моделирование приборных системах» iconУчебно-методическое пособие по дисциплине «Русский язык и культура речи»
Учебно-методическое пособие по дисциплине «Русский язык и культура речи» для студентов 1 курса всех специальностей очной, заочной...

Учебно-методическое пособие к лабораторным работам по дисциплине «Математическое моделирование приборных системах» iconМетодические указания к лабораторным работам по математическому моделированию...
Методические указания к лабораторным работам по математическому моделированию и теории принятия решений

Учебно-методическое пособие к лабораторным работам по дисциплине «Математическое моделирование приборных системах» iconУчебно-методическое пособие минск 2014 содержание
Моделирование показателей и управление качеством и конкурентоспособностью туристической продукции

Учебно-методическое пособие к лабораторным работам по дисциплине «Математическое моделирование приборных системах» iconУчебно-методическое пособие по дисциплине «делопроизводство в кадровой службе»
Вражнова М. Н. Учебно-методическое пособие по дисциплине «Делопроизводство в кадровой службе». – М.: Мади (гту), 2009. – 35 с

Учебно-методическое пособие к лабораторным работам по дисциплине «Математическое моделирование приборных системах» iconУчебно-методическое пособие по дисциплине Предпринимательское право
Учебно-методическое пособие предназначено для изучения студентами юридического факультета учебной дисциплины «Предпринимательское...

Вы можете разместить ссылку на наш сайт:


Все бланки и формы на filling-form.ru




При копировании материала укажите ссылку © 2019
контакты
filling-form.ru

Поиск