Работа с Visual Studio.Net
новости алматы

 

Диалог для исследования решений

Сейчас мы быстрыми темпами, не углубляясь в детали, создадим диалог, работающий в немодальном режиме и позволяющий исследовать решения уравнения Пуассона при разных значениях свойств среды, произвольном расположении источников поля и произвольных граничных условиях.

Так как диалог будет вызываться по команде меню, откройте в окне редактора ресурс меню IDR_MAINFRAME и приведите его в соответствие со следующей схемой. В меню File должна быть только одна команда Exit, в меню Edit уберите все команды и вставьте одну команду Parameters, индекс (ID_EDIT_PARAMETERS) ей будет присвоен автоматически. Остальные меню оставьте без изменения. С помощью редактора диалогов создайте новое диалоговое окно (форму), которое имеет вид, изображенный на рис. 11.4. Типы элементов управления, размещенных в окне диалога, и их идентификаторы сведены в табл. 11.1. Затем создайте класс для управления диалогом.

  1. Вызовите контекстное меню в форме диалога и выберите команду Add Class.
  2. В качестве типа класса выберите MFC Class.
  3. В окне мастера MFC Class Wizard задайте имя класса CParamDlg, базовый класс CDialog, идентификатор диалога: IDD_PARAM и нажмите кнопку Finish.

Рис. 11.4. Форма диалога для управления параметрами краевой задачи

Таблица 11.1. Идентификаторы элементов управления

Элемент

Идентификатор

Диалог

IDD_PARAM

Окно редактирования Source

IDC_SOURCE

Окно редактирования Start группы Source

IDC_SOURCE1

Окно редактирования End группы Source

IDC_SOURCE2

Окно редактирования Value

IDC_PROP

Окно редактирования Start группы Properties

IDCLPROP1

Окно редактирования End группы Properties

IDC_PROP2

Окно редактирования Nodes

IDC.NODES

Окно редактирования Distance

IDCJHST

Окно редактирования Decrement

IDC_DECR

Окно редактирования g группы Left Boundary

IDC_LEFTG

Окно редактирования d группы Left Boundary

IDCJ.EFTD

Окно редактирования g группы Right Boundary

IDC_RIGHTG

Окно редактирования d группы Right Boundary

IDC_RIGHTD

Кнопка Add группы Source

IDC_ADDSOURCE

Кнопка Add группы Properties

IDC_ADDPROP

Кнопка Apply

IDC_APPLY

Кнопка Close

IDCANCEL

Вручную введите изменения в файл с объявлением класса, так чтобы он стал: 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 Распределение поля в неоднородной среде при наличии осточнтков

 

Назад Начало