Для управления внедренным элементом ActiveX надо
ввести в существующий диалоговый класс
CTestGLDlg объект (переменную типа)
класса-оболочки. Этот шаг тоже автоматизирован в
Studio.Net, так как введение объекта влечет
сразу несколько строк изменения кода.
-
Поставьте фокус на окно внедренного элемента
IDC_OPENGL в форме диалога и вызовите
контекстное меню.
-
В меню выберите команду Variable, которая
запустит мастер Add Member Variable Wizard.
-
Установите
флажок Control Variable и задайте в полях
диалоговой страницы мастера следующие
значения: Access — public, Variable type —
COpenGL, Variable name — * m_Ctrl, Control
ID - IDC_OPENGL
-
Обратите внимание на то, что в.поле Control
type уже выбран тип элемента OCX, и нажмите
кнопку Finish.
Результатом работы мастера являются следующие
строки программы:
-
объявление переменной COpenGL m_ctrl; в
файле заголовков TestGLDlg.h;
-
вызов функции DDX_Control(pDX, IDC_OPENGL,
m_ctrl), связывающей элемент управления в
окне диалога с переменной m_ctrl. Этот вызов
вы найдете в теле функции
CTestGLDlg::DoDataExchange;
Для обеспечения видимости вставьте в начало
файла TestGLDlg.h директиву:
#include
"opengl.h"
В конец файла Stdafx.h вставьте директивы
подключения заголовков библиотеки OpenGL:
#include <gl/gl.h>
// Будем пользоваться OpenGL
#include
<gl/glu.h>
Теперь следует поместить в окно диалога элементы
управления. Здесь мы не будем пользоваться
страницами свойств элемента, созданными нами в
рамках предыдущего проекта. Вместо этого мы
покажем, как можно управлять внедренным
элементом ActiveX с помощью объекта m_ctrl.
Перейдите в окно диалогового редактора и
придайте окну диалога IDD_TESTGL_DIALOG.
Идентификаторы для элементов управления можно
задать так, как показано в табл.
Таблица -
Идентификаторы элементов управления
Элемент |
Идентификатор |
Диалог |
IDD_TESTGL_DIALOG |
Кнопка Data
File |
IDCJILENAME |
Кнопка Back
Color |
IDC.BKCLR |
Переключатель Quads |
IDC_QUADS |
Переключатель Strips |
IDC_STRIPS |
Выпадающий
список Fill Mode |
IDC_FILL |
Ползунок Light (X) |
IDC_XPOS |
Кнопка
Close |
IDOK |
Для кнопки Quads установите свойство Group в
положение True, а для кнопки Strips — в False.
Обе они должны иметь свойство Auto в состоянии
True. Важно еще то, что числовые значения их
идентификаторов должны следовать по порядку. Для
кнопки Data File установите свойство
DefaultButton. Для выпадающего списка снимите
свойство Sort (сделайте его False) и слегка
растяните вниз его окно в открытом состоянии,
для этого сначала нажмите кнопку раскрывания.
Для ползунка вы можете установить свойство Point
в положение Top/Left. Обратите внимание на тот
факт, что в режиме дизайна вы можете открыть с
помощью правой кнопки мыши диалог со страницами
свойств для элемента IDC_OPENGL, одну из которых
мы создавали в предыдущем проекте. Теперь с
помощью Studio.Net введите в диалоговый класс
обработчики следующих событий:
-
OnClickedFilename —
нажата кнопка
IDC_FILENAME,
-
OnCiickedBkcir
—
нажата кнопка
IDC_BKCLR,
-
OnSelchangeFill
— изменился выбор в списке IDC_FILL,
-
OnClickedQuads
— нажата кнопка IDC_QUADS,
-
OnHScroll —
изменилась позиция ползунка IDC_XPOS,
-
OnClickedStrips
—
нажата кнопка
IDC_STRIPS.
Ниже мы приведем тела этих функций, а сейчас
отметим, что все они пользуются услугами
класса-оболочки для прямого вызова методов
СОМ-сервера. Однако, как вы могли заключить из
рассмотрения кодов класса COpenGL, на самом деле
вызов будет происходить с помощью интерфейса
IDispatch, а точнее его метода Invoke. Функция
cwnd: : invokeHelper, вызов которой вы видите во
всех методах COpenGL, преобразует параметры к
типу VARIANTARG, а затем вызывает функцию Invoke.
Если происходит отказ, то Invoke выбрасывает
исключение.
В диалоговом классе мы попутно произвели
упрощения, которые связаны с удалением ненужных
функций OnPaint и OnQueryDragicon. Эти изменения
обсуждались при разработке приложения Look. Во
избежание недоразумений, которые могут
возникнуть в связи с многочисленным ручным
редактированием, приведем коды как декларации,
так и реализации класса CTestGLDlg:
//=== Декларация диалогового класса (Файл
TestGLDlg.h)
#include
"opengl.h"
#pragma once
class CTestGLDlg :
public CDialog
{
public:
CTestGLDlg(CWnd* p
= NULL);
enum
{
IDD =
IDD_TESTGL_DIALOG
};
//======= Объект класса-оболочки
COpenGL m_Ctrl;
//======= Запоминаем способ изображения
BOOL m_bQuads;
//======= Реакции на регуляторы в окне диалога
void
OnSelchangeFill(void);
void
OnClickedFilename(void);
afx_msg void
OnHScroll(UINT nSBCode, UINT nPos, CScrollBar*
pScrollBar);
void
OnCiickedBkcir(void);
void
OnClickedQuads(void);
void
OnClickedStrips(void);
protected:
virtual
void
DoDataExchange(CDataExchange* pDX) ;
virtual
BOOL OnlnitDialog();
afx_msg void
OnSysCommand(UINT nID, LPARAM IParam);
DECLARE_MESSAGE_MAP()
};
В файл реализации методов класса мы кроме
функций обработки сообщений от элементов
управления вставили код начальной установки этих
элементов. Для этой цели нам опять понадобилась
связь с сервером, которую обеспечивает объект
m_ctrl класса-оболочки. Характерным моментом
является то, что обрабатываем событие WM_HSCROLL,
которое поступает окну диалога, вместо того
чтобы обработать уведомляющее событие
NM_RELEASEDCAPTURE, которое идет от элемента
типа Slider Control. Такая тактика позволяет
реагировать на управление ползунком клавишами, а
не только мышью:
#include
"stdafx.h"
#include
"TestGL.h"
#include
"TestGLDlg.h"
#ifdef
_DEBUG
#define new
DEBUG_NEW
#undef
THIS_FILE
static char
THIS_FILE[] = _FILE_;
#endif
//======
Пустое тело конструктора
CTestGLDlg::CTestGLDlg(CWnd* p) :
CDialog(CTestGLDlg::IDD, p){}
void
CTestGLDlg::DoDataExchange(CDataExchange* pDX) {
//====== Связывание переменной с элементом
DDX_Control(pDX,
IDCJDPENGL, m_Ctrl);
CDialog::DoDataExchange(pDX);
}
//====== Здесь мы убрали ON_WM_PAINT и т. д.
BEGIN_MESSAGE_MAP(CTestGLDlg, CDialog)
ON_WM_SYSCOMMAND()
//
}
}
AFX_MSG_MAP
ON_CBN_SELCHANGE(IDC_FILL, OnSelchangeFill)
ON_BN_CLICKED(IDC_FILENAME, OnClickedFilename)
ON_WM_HSCROLL()
ON_BN_CLICKED(IDC_BKCLR, OnClickedBkclr)
ON_BN_CLICKED(IDC_QUADS, OnClickedQuads)
ON_BN_CLICKED(IDC_STRIPS, OnClickedStrips)
END_MESSAGE_MAP()
//===== CTestGLDlg message handlers
BOOL
CTestGLDlg::OnInitDialog()
{
//======
Добываем адрес меню управления окном
CMenu* pSysMenu =
GetSystemMenu(FALSE);
if
(pSysMenu)
{
//======
Добавляем команду
About
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING,
IDM_ABOUTBOX,"About...");
}
//======
Загружаем стандартный значок
HICON hMylcon =
::LoadIcon(0,(char*)IDI_WINLOGO);
Setlcon(hMylcon,
TRUE); // Set big icon Setlcon(hMylcon, FALSE);
// Set small icon
CDialog::OnInitDialog();
//======
Начальная установка элементов
CComboBox *pBox = (CComboBox*)GetDlgltem(IDC_FILL);
pBox->AddString("Points");
pBox->AddString("Lines");
pBox->AddString("Fill");
pBox->SetCurSel (2);
//==== Выясняем состояние режима изображения
полигонов
m_Ctrl.GetQuad(&m_bQuads);
WPARAM w = m_bQuads
? BST_CHECKED : BST_UNCHECKED;
//=====
Устанавливаем состояние переключателя
GetDlgltem(IDC_QUADS)->SendMessage(BM_SETCHECK,
w, 0);
w = m_bQuads ? BST_UNCHECKED : BST_CHECKED;
GetDlgltem(IDC_STRIPS)->SendMessage(BM_SETCHECK,
w, 0);
return
TRUE;
}
void
CTestGLDlg::OnSysCommand(UINT nID, LPARAM iParam)
{
if
((nID S OxFFFO) == IDM_ABOUTBOX)
{
CDialog(IDD_ABOUTBOX).DoModal();
}
else
{
CDialog::OnSysCommand(nID, IParam);
}
}
//======
Выбор из списка типа
Combo-box
void
CTestGLDlg::OnSelchangeFill(void) "'*
{
DWORD
sel = ((CComboBox*)GetDlgltem(IDC_FILL))->GetCurSel();
sel = sel==0 ?
GL_POINT : sel==l ? GL_LINE
: GL_FILL;
m_Ctrl.SetFillMode(sel);
}
//==== Нажатие на кнопку запуска файлового
диалога
void CTestGLDlg::OnClickedFilename(void)
{
m_Ctrl.ReadData();
}
//======
Реакция на сдвиг ползунка
void CTestGLDlg::OnHScroll(UINT nSBCode, UINT
nPos, CScrollBar* pScrollBar)
{
//====== Выясняем текущую позицию, которая не во
//====== всех
случаях отражена в параметре nPos
nPos = ((CSliderCtrl*)GetDlgItem(IDC_XPOS))->GetPos()
;
m_Ctrl.SetLightParam (0, nPos);
}
//======
Запускаем стандартный диалог
void CTestGLDlg::OnClickedBkclr(void)
{
DWORD clr =
m_Ctrl.GetFillColor() ;
CColorDialog dig (clr);
dig.m_cc.Flags |=
CC_FULLOPEN;
if
(dlg.DoModal()==IDOK)
{
m_Ctrl.SetFillColor(dlg.m_cc.rgbResult);
}
}
//====== Запоминаем текущее состояние и
//====== вызываем метод сервера
void CTestGLDlg::OnClickedQuads(void)
{
m_Ctrl.SetQuad(m_bQuads = TRUE);
}
void CTestGLDlg::OnClickedStrips(void)
{
m_Ctrl.SetQuad(m_bQuads = FALSE);
}
В настоящий момент вы можете запустить
приложение, которое должно найти и запустить
DLL-сервер ATLGL, генерирующий изображение по
умолчанию и демонстрирующий его в окне
внедренного элемента типа ActiveX. Сервер должен
достаточно быстро реагировать на изменение
регулировок органов управления клиентского
приложения.
Подведем итог. В этом уроке мы научились:
-
вносить функциональность окна OpenGL в окно,
управляемое ATL-классом CWindow;
-
добавлять с помощью Studio.Net новые методы
в интерфейс, представляемый ко-классом;
-
учитывать особенности обработки сообщений
Windows в рамках ATL;
-
управлять контекстом передачи OpenGL,
связанным с окном внедренного СОМ-объекта;
-
создавать приложение-контейнер на базе MFC и
пользоваться услугами класса-оболочки для
управления СОМ-объектом.
|