|
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
Клас для перегляду зображень Клас представлення документа CRightView служить для ілюстрації вмісту всіх документів, виявлених в поточній вибраній теці. У вікні CRightView ми рядами і стовпцями розмістимо інші прості вікна, керовані класом CWndGeom, які матимуть однаковий розмір і змальовуватимуть геометрію конструкції, відповідної даним документа. Причому зображення в контексті вікна відтворять самі документи, точніше об'єкти m_poly, які є в кожному з них. Далі вікна класу CWndGeom ми називатимемо картинками.
Оскільки кількість документів в поточній теці довільно і заздалегідь не відомо (але вони
всі мають бути доступні користувачеві), то, аби розмістити всі картинки,
розміри вікна CRightView мають бути змінними. Вікно має бути «гумовим».
Клас CRightView був спочатку створений майстром AppWizard як клас, здатний
прокручувати вміст свого вікна, оскільки як базовий клас для нього був вибраний csroliview.
Завдяки цьому клас придбав здатність стежити за розмірами свого вікна
і при необхідності створювати смуги горизонтальної і вертикальної прокрутки.
Наша мета - навчитися програмно управляти розмірами вікна прокрутки, динамічно
створювати і знищувати вікна картинок і правильно змальовувати в них геометрію
конструкції, спираючись на дані документа. Скоректуйте коди стартової заготівки
з інтерфейсом класу так, як показано нижче: #pragma
once //======
Клас для демонстрації вмісту документів class
CRightView : public CScrollView { //======
Попереджуюче оголошення класу картинок friend
class CWndGeom; protected: CSize
m_szView; // Реальні розміри вікна CSize
m_szScroll; // Розміри прокручуваного вікна CSize
m_szltem; // Розміри картинки CSize
m_szMargin; // Розміри полів CString
m_WndClass; // Рядок реєстрації картинки CRightView
() ; DECLARE_DYNCREATE(CRightView)
public: //====== Контейнер картинок vector<CWndGeom*>
m_pWnds; CTreeDoc*
GetDocument() { return
dynamic_cast<CTret=Doc*> (m_pDocument) ; } virtual
-CRightView(); void Show(); // Демонстрація картинок void Clear(); //
Звільнення ресурсів //
Overrides public: virtual void OnDraw(CDC* pDC); protected: virtual void OnlnitialUpdate() ; DECLARE_MESSAGE_MAP()
}; Внесіть
скорочення і зміни в коди реалізації класу так, як показано нижче: IMPLEMENTJDYNCREATE(CRightView,
CScrollView) BEGIN_MESSAGE_MAP(CRightView,
CScrollView) END_MESSAGE_MAP() CRightView::CRightView()()
CRightView::-CRightView(){} void
CRightView::OnDraw(CDC* pDC) { CTreeDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); } Смуги
прокрутки автоматично з'являються, коли реальні розміри вікна (m_szview)
стають менше розмірів прокручуваного вікна (m_szScroll), які треба задати як
аргументу функції SetScrollSizes. Якщо користувач збільшив розміри вікна і
вони стали рівними або більше тих, що були вказані, то смуги автоматично
зникають. Звідси витікає, що програміст повинен якось задати первинні
розміри m_szScroll, коли ще не відомі вимоги до них. Зазвичай це робиться
у функції OnlnitialUpdate. Проглянете коди цієї функції, і ви побачите, які
розміри прокручуваного вікна (за умовчанням) задав майстер AppWizard. Для стеження
за розмірами вікна вистави введіть в клас CRightview реакцію на повідомлення
WM_SI ZE, так само як ви це робили в класі CDrawView. Зміните коди цієї функції,
а також функції OnlnitialUpdate, в якій ми прирівнюємо початкові розміри
прокручуваного вікна до реальних: void CRightView::OnSize(UINT nType int ex int су)
{ CScrollView::OnSize(nType, ex, су); if (cx==0 || cy==0) return; //======
Запам'ятовуємо розміри вікна вистави m_szView = CSize (ex, су); } void CRightView::OnInitialUpdate() { CScrollView::OnInitialUpdate(); //======
Початкові розміри вікна m_szScroll = m_szView; SetScrollSizes(MM_TEXT, m_szScroll); }
Функція SetScrollSizes одночасно з розмірами задає і режим перетворення координат.
Найнеприємнішим і незрозумілішим моментом в спадкоємстві від класу CScrollView є те,
що функція SetScrollSizes не дозволяє задавати режими MM_ISOTROPIC і
MM_ANISOTROPIC, які дозволяють, як ви пам'ятаєте працювати з формулами. Цей недолік
MFC широко дискутувався як в MSDN, так і на одному з найпопулярніших сайтів
для програмістів - www. CodeGuru.com. Там же ви можете виявити деякі
вирішення цієї проблеми. Зміните конструктор класу. У момент свого народження
об'єкт класу CRi'ghtView повинен підготуватися до роботи з вікнами, керованими
класом CWndGeom. До того моменту, коли йому знадобиться створити серію таких
вікон, їх тип (клас вікон в сенсі структури типа WNDCLASS) вже має бути відомий
системі. Примітка
CRightView::CRightView()
{ m_szltem
= CSize (200,150); // Розміри картинки m_szMargin
= CSize (20,20); // Розміри полів try { //======
Спроба зареєструвати клас вікон m_WndClass=AfxRegisterWndClass(CS_VREDRAWICS_HREDRAW::LoadCursor(GetModuleHandle(0),(char*)
IDC_MYHAND), (HBRUSH)CreateSolidBrush(GetSysColor(COLOR_INFOBK))); } catch (CResourceException* pEx) { AfxMessageBox(_T("Клас вже зареєстрований")); pEx->Delete (); } } У конструкторі класу CRightView відбувається спроба зареєструвати новий клас вікон. Зазвичай відмов тут не буває, але технологія вимагає перевірити наявність збоївши, тому включаємо механізм обробки виключень (try-catch). Ми хочемо добитися особливої поведінки вікон з картинками, тому задамо для них свою форму курсора і свій колір фону. Колір фону вибирається з того набору, який надає система (див. довідку по функції GetSysColor), а курсор створили самі. Річ у тому, що системний курсор, що ідентифікується як i DC_HAND, працює не у всіх версіях Windows. Якщо ви працюєте в середовищі Windows 2000, то можете замінити в параметрі функції LoadCur sor виклик GetModuleHandle (0) на 0, а ідентифікатор IDC_MYHAND на IDC_HAND і працювати з системним курсором. В цьому випадку ресурс курсора IDC_MYHAND виявиться зайвим і його можна видалити. В даний момент ми передбачаємо, що в класі документа вже створений динамічний контейнер m_Shapes об'єктів класу CPolygon, кожен елемент якого відповідає даним, отриманим в результаті читання документів, виявлених в поточному каталозі. Тепер приступимо до розробки найскладнішої функції у складі класу CRightView, яка повинна:
Далі за
подію розвиваються автоматично. Після створення вікна cwndGeom система пошле йому
повідомлення WM_PAINT, в обробці якого треба створити і набудувати контекст
пристрою міні-вікна, а потім викликати функцію Draw для того полігону з контейнера
m_Shapes, індекс якого відповідає індексу вікна CWndGeom. Кожен полігон малює
себе самого в заданому йому як параметр контексті пристрою. Введіть у файл
реалізації класу CRightView наступний код: void CRightView::Show() { CTreeDoc
*pDoc = GetDocument0; //======
Кількість картинок int
nPoly = pDoc->m_Shapes.size(); //===
Обчислення кроку, з яким виводяться картинки int
dx = m_szltem.cx + m_szMargin.ex, dy
= m_szltem.cy + m_szMargin.cy, nCols
= m_szView.cx/dx; // Кількість колонок //======
Корекція if (nCols < 1)nCols = 1; if
(nCols > nPoly)nCols = nPoly; //======
Кількість рядів int
nRows = ceil(double(nPoly) /nCols); //=== Обчислення і установка розмірів вікна прокрутки m_szScroll = CSize(nCols*dx, nRows*dy); SetScrollSizes(MM_TEXT,
m_szScroll); //======
Координати і розміри першої картинки CRect r (CPoint(0,0), m_szltem); r.OffsetRect
(15,15); //======
Стиль вікна картинки DWORD
style = WS_CHILD | WS_BORDER | WS_VISIBLE; //======
Цикл проходу по рядах (n - лічильник картинок) for (int 1=0, n=0; i<nRows; i++) { //======
Цикл проходу по стовпцях for (int j=0; j<nCols && rKnPoly; j++, n++) { //======
Створюємо клас вікна картинки CWndGeora *pWnd = new CWndGeom(this, n); //======
Запам'ятовуємо його в контейнері m_pWnds.push_back(pWnd); //======
Створюємо Windows-окно pWnd->Create
(m_WndClass, 0, style, r this 0); //======
Зрушуємо позицію вікна управо r.OffsetRect (dx, 0); } //=== Починаємо новий ряд картинок (зрушення вліво-вниз) r.OffsetRect (-nCols*dx, dy); } } Істотним моментом в алгоритмі є те, що розмір прокручуваного вікна (m_szScroll) залежить від кількості картинок. Тому скільки б їх не було в поточній теці - всі будуть доступні за допомогою смуг прокрутки. Розташування і розміри картинок визначаються за допомогою об'єкту класу CRect. Метод Of f setRect цього класу дозволяє зрушувати прямокутник вікна в потрібному нам напрямі. Обслуговування
контейнера m_pWnds дочірніх вікон типа cwndGeom зв'язане з необхідністю стежити
за звільненням пам'яті, займаної вікнами, в ті моменти, коли відбувається перехід
від теки до теки у вікні CLef tview. Для цієї мети служить допоміжна функція
Clear, яку треба викликати як у відмічені вище моменти, так і при закритті
вікна. Останній випадок супроводиться автоматичним викликом деструкції класу
CRightview. З врахуванням сказаного введіть такі добавки у файл RightView.cpp: void CRightview::Clear() { //======
Цикл проходу по всіх адресах контейнера for (UINT i=0; Km_pWnds. size () ; i++) { //======
Знищення Windows-окна m_pWnds[i]->DestroyWindow(); // Звільнення пам'яті, займаної об'єктом delete m_pWnds[ i ]; } //===== Звільнення пам'яті, займаної контейнером m_pWnds.clear(); } //===== Деструкція класу викликає Clear CRightview::~CRightview() { Clear () ; }
рекламодавці: / LF KS выполнена доставка грузов Челябинск конечная |
|
|||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||