Иллюстрированный самоучитель по Visual Studio.Net

         

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


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

Так как диалог будет вызываться по команде меню, откройте в окне редактора ресурс меню 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. Идентификаторы элементов управления

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




    Содержание раздела