Таблица 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.