Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Visual2.doc
Скачиваний:
5
Добавлен:
07.03.2016
Размер:
3.31 Mб
Скачать

9.2.2. Створення та видалення дочірніх вікон без використання архітектури «Документ-Вид»

Приклад створення та видалення дочірніх вікон знаходиться у папці DISK\Structure\Dchild_no_tem_1.

Створимо додаток Dchild_no_tem_1. В цьому додатку буде 2 дочірніх вікна та 1 клієнтське. Клієнтське вікно буде залежним від одного з дочірніх (рис. 9.5).

Дочірні вікна, це вікна, які вбудовані в головне вікно. Вони мають стиль WS_CHILD, та не можуть вийти за межі головного вікна.

Клієнтське вікно належить до батьківського вікна, але не має стилю WS_CHILD. Воно може виходити за межі головного вікна.

Рис. 9.5. Схема підключення класів вікон у додатку Dchild_no_tem_1

Для першого дочірнього вікна буде слугувати створений майстром клас CChildView (який ми перейменуємо у CChild1). Для другого вікна створимо клас CChild2 похідний від CFrameWnd, конструктор та деструктор якого винесемо у область видимості public.

Створимо клієнтське вікно CClient1, похідне від CFrameWnd, конструктор та деструктор якого також винесемо у public.

В класі CMainFrame зробимо вказівки на ці вікна.

class CMainFrame : public CFrameWnd

{

.............................................................

CChild1* m_child1;

CChild2* m_child2;

CClient1* m_client1;

.............................................................

};

В конструкторі CMainFrame вказівкам поставимо 0:

CMainFrame::CMainFrame()

{

m_child1 = 0;

m_child2 = 0;

m_client1 = 0;

}

Додамо в клас CMainFrame функції-відгуки OnChild1, OnChild2, відповідно для створення вікон CChild1, CChild2. Розглянемо функцію OnChild1 створення першого дочірнього вікна.

void CMainFrame::OnChild1()

{

if(m_child2) {delete m_child2; m_child2 = 0;}

if(m_child1) return;

SetWindowText("Child 1");

m_child1 = new CChild1;

if (!m_child1->CreateEx(

0, NULL, "", AFX_WS_DEFAULT_VIEW,

CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST))

return;

RecalcLayout();

}

В цій функції перевіряється наявність другого вікна – вказівка m_child2. Якщо вказівка не дорівнює нулю, об’єкт вікна видаляється. Далі йде перевірка чи вже є відкрите вікно m_child1, якщо є, – то виходимо з функції. На наступному етапі створюється вікно функцією Create. Якщо задано параметр NULL, то ім’я класу приймає значення "AfxFrameOrView42d" – це ім’я стандартного класу вікна. Останній рядок це виклик функції RecalcLayout для передачі повідомлення WM_SIZE вікну CMainFrame. Це повідомлення визиває перерахунок розмірів вікна m_child1, так як воно є дочірнім. Ми задали пустий прямокутник CRect(0, 0, 0, 0), так як вікно є вкладеним, тому заданий параметр ігнорується.

void CMainFrame::OnChild2()

{

if(m_client1) { delete m_client1;m_client1 = 0;}

if(m_child1) { delete m_child1;m_child1 = 0;}

if(m_child2) return;

SetWindowText("Child 2");

m_child2 = new CChild2;

// AFX_WS_DEFAULT_VIEW -> WS_CHILD|WS_VISIBLE|WS_BORDER

if(!m_child2->CreateEx(0, str, "Child 2",

WS_CHILD|WS_VISIBLE|WS_BORDER, CRect(0, 0, 0, 0),

this, AFX_IDW_PANE_FIRST))

return;

RecalcLayout();

}

Для створення вікна m_child2 виконуємо майже аналогічні дії. Відмінність полягає у тому, що перевіряється також наявність вікна m_client1. Це вікно створено на основі Windows-класу вікна, ім’я якого міститься у змінній str. А замість константи AFX_WS_DEFAULT_VIEW підставляємо 3 стиля вікна WS_CHILD | WS_VISIBLE | WS_BORDER. Ці стилі відповідають стилю AFX_WS_DEFAULT_VIEW.

Щоб побачити на екрані, яке саме вікно активне в даний момент, додамо в кожен з класів функції OnPaint:

void CChild1::OnPaint()

{

CPaintDC dc(this); // device context for painting

dc.TextOut(20,20,"Child 1");

}

void CClient1::OnPaint()

{

CPaintDC dc(this); // контекст для малювання

dc.TextOut(20,20,((CMainFrame*)

par_mainframe)->m_child1->str);

}

void CChild2::OnPaint()

{

CPaintDC dc(this);

dc.TextOut(50,50,"Child 2");

}

Як видно з коду функції CClient1::OnPaint, що вікно CClient1 виводить на екран текст з вікна CChild1, відносно якого воно є клієнтським. В клас CChild1 ми внесли текстову змінну у область public, яку і будемо виводити у клієнтському вікні:

CString str;

Виклик самого цього вікна (CClient1) робиться наступним чином:

void CMainFrame::OnClient1()

{

if(!m_child1||m_client1) return;

CRect rect;

GetWindowRect(&rect);

rect.OffsetRect(20,80);

SetWindowText("Client 1");

m_client1 = new CClient1;

m_client1->par_mainframe = this;

m_client1->CreateEx(0,NULL, "Client 1",

WS_VISIBLE|WS_OVERLAPPEDWINDOW,

rect,m_child1,0);

}

Відразу йде перевірка на наявність вікон: m_child1 – щоб було до чого прив’язати клієнтське вікно, m_client1 – щоб не створювати вікно повторно. За допомогою функцій GetWindowRect та OffsetRect визначаємо розміри вікна CMainFrame та переміщуємо отриманий прямокутник (на 20 пікселів праворуч, на 80 – вниз).

Далі важлива послідовність дій: 1) викликаємо конструктор CClient1 (вікно Windows ще не створено, але виділена пам’ять для класу); 2) вказівку par_mainframe прирівнюємо до this (прив’язуємо створюване вікно до головного вікна CMainFrame. Через цю прив’язку можна отримати дані CString str класу CChild1); 3) створюємо вікно функцією Create; зверніть увагу на параметр m_child1 (вікно буде клієнтським не відносно CMainFrame а відносно CChild1).

Змінимо стандартну панель інструментів. Замість стандартних кнопок створимо три власних для виклику вікон з ідентифікаторами ID_CLIENT1, ID_CHILD1, ID_CHILD2. Додамо функцію OnUpdateAll в клас CMainFrame, у якій буде контролюватися стан кнопок в залежності від відкритих вікон:

void CMainFrame::OnUpdateAll(CCmdUI* pCmdUI)

{

if(pCmdUI->m_nID==ID_CLIENT1)

{

if(m_child1)pCmdUI->Enable(1);

else pCmdUI->Enable(0);

}

if(pCmdUI->m_nID==ID_CHILD1)

{

if(m_child1)pCmdUI->SetCheck(1);

else pCmdUI->SetCheck(0);

}

if(pCmdUI->m_nID==ID_CHILD2)

{

if(m_child2)pCmdUI->SetCheck(1);

else pCmdUI->SetCheck(0);

}

}

При використанні функції SetCheck з параметром 1 відбувається натискання кнопки, а з параметром 0 – повертає кнопку у початкове становище (відтискає).

На рисунку 9.6. показано роботу додатку:

Рис. 9.6. Приклад роботи додатку Dchild_no_tem_1, із вікнами Child1 та Client1

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]