Управление
с помощью объекта класса-оболочки
Для управления
внедренным элементом 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.
Идентификаторы
для элементов управления можно задать так, как показано в табл. 9.2.
Таблица
9.2. Идентификаторы элементов управления
|
|
|
|
|
|
|
|
|
|
|
|
Выпадающий список
Fill Mode
|
|
|
|
|
|
Для кнопки
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 и пользоваться услугами класса-оболочки для управления СОМ-объектом.