Курсовая работа (т): Расширение свойств элементов управления ActiveX средствами ATL

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

Чтобы прокручивать в цикле битовые изображения, нам потребуется способ передвижения кадра. В данной работе мы будем менять кадр из обработчика сообщения WM_TIMER. Используйте мастер Add Windows Message Handler Wizard для направления сообщения WM_TIMER на класс САхСаг. Мастер модифицирует карту сообщений и добавит пустой код для метода OnTimer(). В реализации метода увеличиваем на 1 номер кадра и проверяем достижение верхнего предела числа кадров (от трех до пяти в зависимости от скорости машины). При смене кадра перерисовываем изображение с помощью FireViewChange():

//CAxCar::OnTimer(UINT uMsg, WPARAM wparam, LPARAM lParam, BOOL& bHandled)

{

m_currImage = m_currImage + 1; (m_currImage >= m_currMaxFrames) _currImage = 0;

(); 0;

}

Теперь запустим таймер окна. Вернёмся к реализации свойства Animate и добавим вызовы SetTimer() или KillTimer() в зависимости от значения параметра AnimVal. Тем самым конечный пользователь получит возможность запускать и прекращать анимационный цикл посредством свойства СОМ:

// Создаем или прекращаем таймер

//CAxCar::put Animate (AnimVal newVal)

{ bAnimate = newVal; (::IsWindow(rn_hWnd) && (m_bAnimate -- Yes)) (l, 250); if(::IsWindow(m_hWnd)) (l); S_OK;

}

Последний шаг, который необходимо выполнить перед отображением битовых массивов в OnDraw(), - это установить текущую верхнюю границу числа кадров. Проделаем это в методе SpeedUp(). После модификации переменной m_currMaxFrames посылаем наши события:

// Устанавливаем верхнюю границу числа кадров и посылает событие

//CAxCar::SpeedUp()

{ _currSpeed += 5; ((m_maxSpeed - m_currSpeed) <= 10)

{ AboutToBlow(); currMaxFrames = ABOUT TO BLOW;

} (m_currSpeed >= m_maxSpeed)

{ _currSpeed = m_maxSpeed; _BlewUp(); currMaxFrames BLOWN UP; S_OK;

}

Рисуем изображения

Теперь все стоит на своих местах. Осталось только отобразить нужный битовый массив в реализации OnOraw():

//CAxCar::OnOraw(ATL ORAWINFO& di)

{ & rc = * (RECT*)di.prcBounds; (di.hdcOraw, rc.left, rc.top, rc.right, rc.bottom); bmInfo; oldBitmap; newBitmap; memOC; size; (m_carlmage[rn currImage], sizeof(brnlnfo), &brnInfo); .cx = bmlnfo.bmWidth; .cy = bmInfo.brnHeight; = rn_carImage[m_currImage]; = CreateCompatibleDC(di.hdcDraw); = (HBITMAP}SelectObject(rnernDC, newBitmap); (di.hdeDraw, re.left, re.top, re.right, rc.bottom, , 0, 0, size. ex, size.cy, SRCCOPY); (di.hdeDraw, oldBitmap); (memDC);

return S_OK;

}

Для запуска или прекращения анимации используется свойство Animate. Внутри программы это приводит к созданию или удалению ресурса таймера. Обработчик сообщения WM_TIMER отвечает за сдвиг текущего кадра и не превышение верхнего предела числа кадров. Этот верхний предел хранится в переменной m_ currMaxFrames и устанавливаемый в методе SpeedUp ().

2.4 Расширение специальных свойств

СОМ предоставляет особый интерфейс с именем IPropertyNotifySink, который дает возможность контейнеру принимать или не принимать новые установки свойств, а также информирует контейнер об изменении свойства. В файле IDL соответствующие свойства должны быть отмечены атрибутами [requestedit] и/или [bindable].

Вставим в IDL-файл нужный атрибут для каждого из свойств [default]-интерфейса IАхСаг:

// Связываем свойства с приемником свойств клиента

//

[object, uuid(65AOEEBF-745F-IID3-B92E-0020781238D4), dual, ("IAxCar Interface") ,pointer default (unique) IAxCar: IDispatch;

{

[id(1), helpstring("Add 5 to current speed")] SpeedUp();

[id(2), helpstring("Set the name and max speed of the car")] CreateCar([in] BSTR petName, [in] short maxSp);

[propget, id(3), helpstring("Should I animate?"), bindable, requestedit] Animate([out, retval] AnimVal *newVal);

[propput, id(3), helpstring("Should I animate?"), bindable, requestedit] Animate([in] AnimVal newVal);

[propget, id(4), helpstring("The max speed"), bindable, requestedit] MaxSpeed([out, retval] short *pVal);

[propput, id(4), helpstring("The max speed"), bindable, requestedit] MaxSpeed([in] short newVal);

[propget, id(5), helpstring("Car's pet name"), bindable, requestedit] PetName([out, retval] BSTR *pVal);

[propput, id(5), helpstring("Car's pet name"), bindable, requestedit] PetName([in] BSTR newVal);

[propget, id(6), helpstring("Current speed"), bindable, requestedit] Speed([out, retval] short *pVal);

[propput, id(6), helpstring("Current speed"), bindable, requestedit] Speed([in] short newVal);

[id(DISPID_ABOUTBOX), helpstring("About AxCars")] AboutBox();

};

После того как свойства исправлены, перепишем методы [propput] под использование FireOnEditRequest() и FireOnChanged(). Вот модифицированная реализация для свойства Animate:

{ (FAILED(FireOnRequestEdit(3))} II [id(3)] = Animate S FALSE; bAnimate = newVal; (::IsWindow(m_hWnd) && (m_bAnimate == Yes))(l, 500); if(::IsWindow(m_hWnd) (l); (3); //[id(3}] = Animate

return S_OK;

}

Параметр, передаваемый в методы FireOnRequestEdit () и FireOnChanged(), - это DISPID вашего специального свойства (т. е. атрибут [id] в IDL-определении).

2.5 Поддержка постоянства свойств

Здесь нам понадобится сделать некоторые изменения, чтобы контейнер помнил значения наших специальных свойств и между сеансами работы. АТL предоставляет автоматическую поддержку постоянства свойств на основе моделей потока байтов и объектов хранения, используя шаблоны IPersistStoragelrnpl<> и IPersistStreamlnitlmpl<>.

Нам предстоит отредактировать методы [propput] и внести в них последнее добавление: когда мы осуществляем новое присвоение внутренней переменной свойства, вызываем SetDirty(), чтобы отметить, что свойство изменилось. Таким образом клиент "понимает", какой именно элемент требуется сохранить. Вот окончательная версия метода put_Animate ():

//CAxCar::put_Animate(AnimVal newVal)

{ (FAILED(FireOnRequestEdit(3))) S FALSE; bAnimate = newVal; (::IsWindow(m_hWnd) && (m_bAnimate== Yes)) (l, 500); if(::IsWindow(m_hWnd)) (l);

(TRUE); (3);

return S_OK;

}

Откроем заголовочный файл класса, найдем карту свойств и исправим ее следующим образом:

//PROP MAP(CAxCar) _DATA _ENTRY ("_ cx", m _ sizeExtent. cx, VT UI4) _DATA_ENTRY ("_cy", m_sizeExtent. cy, VT UI4) _ENTRY ("Animate" , 3, CLSID_NULL) _ENTRY ("Speed" , 4, ,CLSID_NULL) _ENTRY ("PetName" , 5, CLSID_NULL) _ENTRY ("MaxSpeed" , 6, CLSID_NULL)

END_PROP_MAP()

2.6 Создание страницы пользовательских свойств

Позволим пользователю изменять на странице свойств свойства Animate, MaxSpeed И PetName . При создании страницы средствами АТL первым шагом будет вызов мастера ATL Object Wizard и вставка в нем нового объекта типа propertyPage из категории Controls. Используя этот мастер, добавим новую страницу, задав ConfigureCar в качестве ее имени. На вкладке Strings отредактируем поле Title по своему усмотрению.

Чтобы связать элементы GUI с соответствующими свойствами интерфейса IАхСаг, начнём с направления уведомления EN_CHANGE на каждое из полей редактирования, а уведомления BN_CLICKED - на поле флага, используя мастер Add Windows Message Handler. В реализации обработчиков событий сделаем доступной кнопку Арр1у путем вызова SetDirty():

//OnClickedCheckanim(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)

{ (TRUE); 0;

}

В методе Арр1у() нам требуется получить значения, содержащиеся в элементах GUI, и передать их соответствующим свойствам выбранных элементов управления. Вспомним, что IProperyPageImpl<> хранит массив указателей IUnknown (m_ppunk), которые соответствуют элементам управления, выбранным в контейнере. Используем этот массив для установки новых значений свойств в объектах. Счетчик выбранных на данный момент элементов управления хранится в переменной-члене m_nObjects. Вот код метода Арр1у():

//(Apply) (void)

{ (UINT i = 0; i < m_nObjects; i++)

{ * pCar = NULL; temp; ( IDC_EDITNAME, temp.m_str); _ppUnk[i]->QueryInterface(IID_IAxCar, (void**)&pCar)i >put_PetName(temp); >put_Animate(

(AnimVal)IsDlgButtonChecked(IDC_CHECKANIM)); >put_MaxSpeed(GetDlgItemInt(IDC_EDITSPEED)); >Release()i

} _bDirty = FALSE;

return S_OK;

}

Теперь нужно передать данные "в обратном направлении". Когда пользователь вызывает страницу свойств, хотелось бы, чтобы текущие значения свойств отображались в соответствующих позициях GUI. Обычно эти позиции редактируются в обработчике сообщения WM _INITDIALOG, которое посылается перед тем, как визуализировать диалог. Добавим запись WM _INITDIALOG в карту сообщений, а также следующий код:

LRESULT OnInitDialog(UINT uMsg, WPARAM wparam, LPARAM Iparam, & bHandled)

{CONVERSION; (m_nObjects > 0)

{ * pCar = NULL; tpSP; temp; _ppUnk[O]->QueryInterface(IID_IAxCar, (void**)&pCar);

pCar->get_MaxSpeed(&tempSP); tem1nt(1DC_ED1TSPEED, tempSP); curAnim; >get_Animate(&curAnim); (1DC_CHECKAN1M, (BOOL)curAnim);>get_PetName(&temp.m_str); ternText(1DC_ED1TNAME, W2A(temp.m_str)); >Release(); (FALSE);

} 0;

}

Вернемся к карте свойств и зададим в пользовательских свойствах применение соответствующей страницы вместо CLS1D_NULL (отсутствие страницы). Мастер ATL Object Wizard уже сгенерировал идентификатор CLSID для новой страницы, который можно найти в самом верху заголовочного файла класса. Используя эту константу, исправим карту свойств следующим образом:

//N_PROP_MAP(CAxCar)

PROP_DATA_ENTRY ("_cx", m_sizeExtent. cx, VT U14) _DATA _ENTRY ("_ cy", m _ sizeExtent. cy, VT U14) _ENTRY ("Animate", 3, CLSID_ConfigureCar) _ENTRY ("Speed", 4, CLSID_ConfigureCar) _ENTRY ("PetName", 5, CLSID_ConfigureCar) _ENTRY ("MaxSpeed", 6, CLSID _ ConfigureCar)

END PROP MAP ( )

2.7 Тестирование созданного элемента

Теперь можем протестировать нашу новую страницу. Поместим экземпляр модифицированного (и прекомпилированного) элемента управления в проект Visual Basic и запустим:

Рисунок 12 - Установка названия машины и скорости

интерфейс проектирование переменная анимация

Рисунок 13 - Тестирование автомобиля

Рисунок 14 - Предупреждающее сообщение

Рисунок 15 - Взрыв автомобиля

Выводы

В ходе данной курсовой работы был спроектированы элементы управления ActiveX средствами АТL. Все эти элементы используются как графические составные блоки. Чтобы поддерживать дополнительные функциональные возможности, выходящие за рамки простого кокласса, элементы управления реализуют несколько стандартных интерфейсов СОМ, служащих для отображения объектов, обеспечения их постоянства и поддержки страниц свойств. Создание полного элемента управления в АТL начинается с мастера Object Wizard.

Так же был изучено использование моделей постоянства свойств в СОМ и то, каким образом АТL поддерживает эти модели, предоставляя набор шаблонов и карту свойств. Карта свойств в АТL служит также для связывания свойств с соответствующими страницами свойств. Страница свойств - это еще один класс СОМ, поддерживающий стандартный интерфейс IPropertyPage.. Контейнер обнаруживает страницы, которые работают с коклассом, путем запроса ISpecifyPropertyPages..

В ходе работы был создан и протестирован, с помощью Visual Basic, полнофункциональный элемент управления ActiveX, с возможность расширения базовых свойств.

Список использованных информационных источников

1.      Трельсен Э.Модель СОМ и применение ATL3.0: Пер. с англ. - СПб.: БХВ-Петербург, 2001. - 928 с.

.        Шлее М. Qt. Профессиональное программирование на С++. - СПб: БХВ-Петербург, 2005. - 544 с.: ил.

3.      Роберт Дж. Оберг. Технология COM+. Основы и программирование: Пер. с англ.- М.: «Вильямс» <https://ru.wikipedia.org/w/index.php?title=%D0%92%D0%B8%D0%BB%D1%8C%D1%8F%D0%BC%D1%81_%28%D0%B8%D0%B7%D0%B4%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D1%81%D1%82%D0%B2%D0%BE%29&action=edit&redlink=1>, 2000. - С. 480.

.        Деннинг А. ActiveX для профессионалов: Пер. с англ. - СПб.: Питер, 1998. - 624 с.

Источник: https://www.bibliofond.ru/detail.aspx?id=869792