Диалог для исследования решений
Сейчас мы быстрыми
темпами, не углубляясь в детали, создадим диалог, работающий в немодальном режиме
и позволяющий исследовать решения уравнения Пуассона при разных значениях свойств
среды, произвольном расположении источников поля и произвольных граничных условиях.
Так как диалог
будет вызываться по команде меню, откройте в окне редактора ресурс меню IDR_MAINFRAME
и приведите его в соответствие со следующей схемой. В меню File должна быть
только одна команда Exit, в меню Edit уберите все команды и вставьте одну команду
Parameters, индекс (ID_EDIT_PARAMETERS) ей будет присвоен автоматически. Остальные
меню оставьте без изменения. С помощью редактора диалогов создайте новое диалоговое
окно (форму), которое имеет вид, изображенный на рис. 11.4. Типы элементов управления,
размещенных в окне диалога, и их идентификаторы сведены в табл. 11.1. Затем
создайте класс для управления диалогом.
- Вызовите контекстное
меню в форме диалога и выберите команду Add Class.
- В качестве типа класса
выберите MFC Class.
- В окне мастера MFC Class
Wizard задайте имя класса CParamDlg, базовый класс CDialog, идентификатор
диалога: IDD_PARAM и нажмите кнопку Finish.

Рис. 11.4.
Форма диалога для управления параметрами краевой задачи
Таблица
11.1. Идентификаторы элементов управления
|
|
|
|
Окно редактирования
Source
|
|
Окно редактирования
Start группы Source
|
|
Окно редактирования
End группы Source
|
|
Окно редактирования
Value
|
|
Окно редактирования
Start группы Properties
|
|
Окно редактирования
End группы Properties
|
|
Окно редактирования
Nodes
|
|
Окно редактирования
Distance
|
|
Окно редактирования
Decrement
|
|
Окно редактирования
g группы Left Boundary
|
|
Окно редактирования
d группы Left Boundary
|
|
Окно редактирования
g группы Right Boundary
|
|
Окно редактирования
d группы Right Boundary
|
|
|
|
Кнопка Add группы
Properties
|
|
|
|
|
|
Вручную введите
изменения в файл с объявлением класса, так чтобы он стал: ftpragma once
class
CParamDlg :
public
CDialog {
//=====
Будем общаться с окном
friend
class CChildView;
DECLARE_DYNAMIC(CParamDlg)
public:
//=====
Будем помнить его адрес
CChildView
*m_pView;
//=====
В конструкторе запросим его адрес
CParamDlg(CChildView*
р) ;
virtual
~CParamDlg () ;
//
Dialog Data
enum
{ IDD = IDD_PARAM );
protected:
virtual
void DoDataExchange(CDataExchange* pDX) ;
DECLARE_MESSAGE_MAP()
);
Для всех четырех
кнопок на форме диалога создайте обработчики уведомлений, или, используя терминологию
Microsoft, Control Event типа BN_CLICKED. Вы помните, что это делается с помощью
небольшой кнопки Control Event, которая расположена на панели инструментов окна
Properties. В это окно надо входить в тот момент, когда фокус находится на соответствующей
кнопке. Во всяком случае, именно так это работает в бета-версии Studio.Net.
Для обмена
данными с шестью окнами редактирования (IDC_SOL)RCE, IDC_SOURCE1, IDC_SOURCE2,
IDC_PROP, IDC_PROP1, IDC_PROP2) создайте с помощью мастера Add Member Variable
Wizard шесть переменных:
//====
Интенсивность источника поля
double
m_Source;
//
Индекс ячейки сетки, где расположено начало источника
int
m_Src!dl;
//
Индекс ячейки сетки, где расположен конец источника
int
m_Srdd2;
//====
Значение физического свойства ячейки сетки
double
m_Prop;
//
Индексы начала и конца области со свойством
m_Prop
int m_PropIdl;
int
m_PropId2;
В результате
этих действий в классе CParamDlg кроме указанных переменных должны появиться
шесть вызовов функции обмена данными DDX_Text, которые мастер размещает внутри
функции CParamDlg::DoDataExchange. Вручную добавьте в DoDataExchange еще семь
вызовов функции DDX_Text для обмена данными с переменными, которые расположены
не в диалоговом, а в оконном классе (cchildview). После этого функция должна
приобрести вид:
void
CParamDlg::DoDataExchange(CDataExchange* pDX) {
DDX_Text
(pDX, IDC_PROP2, m_Prop!d2);
DDXJText(pDX,
IDC_PROP1, m_Prop!dl);
DDX_Text(pDX,
IDC_PROP, m_Prop);
DDX_Text(pDX,
IDC_SOURCE2, m_Srdd2);
DDX_Text(pDX,
IDC_SOURCE1, ra_SrcIdl);
DDX_Text(pDX,
IDC_SOURCE, m_Source);
//=====
Обмен с переменными оконного класса
DDX_Text(pDX,
IDC_NODES,m_pView->m__n);
DDX_Text(pDX,
IDC_DIST, m_pView->m_L);
DDX_Text(pDX,
IDC_DECR, m_pView->m_k);
DDX_Text(pDX,
IDC_LEFTG, m_pView->m_g0);
DDX_Text(pDX,
IDC_LEFTD, ra_pView->m_d0);
DDX_Text(pDX,
IDC_RIGHTG, mj?View->m_gn);
DDX_Text(pDX,
IDC_RIGHTD, m_pView->m_dn);
CDialog::DoDataExchange(pDX);
}
При нажатии
на одну из кнопок Add в соответствующем контейнере параметров системы (m_f или
m_r) должны произойти замены значений по индексам, определяемым диапазоном (m_Srddl,
m_Srdd2) ИЛИ (m_Prop!dl, m_Prop!d2). В первом случае вы вводите новые источники
поля, а во втором — изменяете свойства среды. В уже существующие заготовки функций
обработки нажатия на кнопки введите такие коды:
void
CParamDlg::OnClickedApply(void) {
//======
Считываем данные из окон
UpdateDataO
;
//======
Заново решаем систему и выводим график
m_jpView->Solve
() ; }
void
CParamDlg::OnClickedAddsource(void)
{
UpdateData();
//======
Изменяем контейнер m_f (источников поля)
for
(
int i=m_Src!dl; i <= m_Srdd2; i + + ) {
if
(0 <= i && i < m_pView~>m_n)
m_pView->m_f[i]
= -m_Source; )
m_pView->Solve0;
}
void
CParamDlg::OnClickedAddprop(void) { UpdateDataO ;
//======
Изменяем контейнер m_r (свойств среды)
for
(int i=m_Prop!dl; i <= m_PropId2; i++) {
if
(0 <= i &i i < m_pView->m_n && m_Prop > 0.)
m_pView->ra_r[i]
= m_Prop; }
m_pView->Solve();
}
void
CParamDlg::OnClickedCancel
(void)
{
//======
Закрываем немодальный диалог
m_pView->m_pDlg
= 0;
DestroyWindow();
}
Измените коды
конструктора класса так, чтобы запоминался обратный указатель на объект оконного
класса. Заодно сверьте начало файла ParamDlg.h с тем фрагментом, что приведен
ниже:
#include
"stdafx.h"
#include
"Heat.h"
#include"ParamDlg.h"
IMPLEMENT_DYNAMIC(CParamDlg,
CDialog)
CParamDlg::CParamDlg(CChildView*
p)
:
CDialog(CParamDlg::IDD, p)
{
m_pView
= p;
//=====
Начальное значение свойств среды
//=====
не должно равняться нулю
m_Prop
=1.0;
m_Prop!dl
= 0;
m_Prop!d2
= 0;
m_Source
=0.0;
m_Src!dl
= 0;
m_Srdd2
= 0;
}
CParamDlg::~CParamDlg()
{
}
Инициализация
диалога, как вы помните, должна производиться в обработчике сообщения WM_INITDIALOG.
Здесь я опять попадаю в ловушку. В рамках Visual C++ Studio.Net вы не найдете
WM_INITDIALOG в списке доступных сообщений, но вместо этого найдете функцию
OnlnitDialog в списке виртуальных функций (overrides). Введите в класс CParamDlg
эту функцию. В ней мы просто отодвинем окно диалога, чтобы оно при появлении
на экране не заслоняло график. Другие установки должны происходить автоматически:
BOOL
CParamDlg::OnInitDialog(void) {
CDialog:rOnlnitDialog();
CRect
r;
//=====
С помощью контекста устройства
//=====
узнаем размеры всего экрана CClientDC dc(this);
int
w = dc.GetDeviceCaps(HORZRES);
int
h = dc.GetDeviceCaps(VERTRES);
//=====
Узнаем размеры окна диалога GetWindowRect(&r);
//=====
Смещаем его вправо и вниз
r.OffsetRect(w-r.right-10,h-r.bottom-30);
MoveWindow(Sr);
return
TRUE;
}
В данный момент
полезно запустить приложение и поучиться сражаться с ошибками, которые вызваны
тем, что классы приложения не очень хорошо знакомы между собой. Добавьте директиву:
#include
"ChildView.h"
в список директив
файла ParamDlg.cpp, а также директиву
#include
"ParamDlg.h"
в список директив
файла ChildView.cpp. После этого исправления вы увидите еще одно сообщение об
ошибке, которое напомнит вам о том, что еще не реализована работа с диалогом
в немодальном режиме. Для этого надо немного потрудиться. Введите в класс CChildView
реакцию на событие выбора пользователем команды меню ID_EDIT_PARAMETERS. Напомним,
что это делается с помощью кнопки Events окна Properties. В обработчике мы открываем
диалог в немодальном режиме:
void
CChildView::OnEditParameters(void) {
//=====
Если диалог не открыт,
if
(!m_pDlg)
{
//==
Динамически создаем объект диалогового класса
m_pDlg
= new CParamDlg(this);
//==
и после этого создаем окно диалога
m_pDlg->Create(IDD_PARAM);
}
}
В окне свойств
для формы диалога установим в True свойство visible. В классе cParamDlg следует
переопределить виртуальную функцию PostNcDestroy, в теле которой необходимо
освободить память, занимаемую объектом диалогового класса:
void
CParamDlg::PostNcDestroy(void)
{
delete
this;
}
После этого
диалог должен работать. Задайте точечный источник поля в узле 100, и вы увидите
график решения, которое имеет вид, показанный на рис. 11.5.


Рис. 11.5.
Управление параметрами краевой задачи из диалога


Рис.
11.6 Распределение поля в неоднородной среде при наличии
осточнтков