V tomto Φlßnku si ukß₧eme, jak zakßzat strßnku v PropertySheet.
Jde nßm o to, aby se u₧ivatel nemohl na danou strßnku dostat ₧ßdn²m zp∙sobem a aby
zßlo₧ka svßzanß s touto strßnkou byla vykreslena jin²m zp∙sobem.Nap°φklad jako je
tomu na nßsledujφcφm obrßzku:
Abychom dosßhli po₧adovanΘho stavu musφme zajistit nßsledujφcφ
akce:
1. Pod∞dit potomka ze t°φdy CPropertySheet.
2. RozÜφ°it t°φdu o Φlenskou prom∞nnou, kterß bude dr₧et informace o zakßzan²ch
strßnkßch.
3. Zajistit vykreslovßnφ zakßzan²ch zßlo₧ek
4. Zakßzat p°epnutφ do zakßzanΘ zßlo₧ky.
Prvnφ bod asi nepot°ebuje komentß°, a proto se hned podφvßme na
dalÜφ bod. Ke ka₧dΘ strßnce si budeme dr₧et informace, zda je povolenß, Φi ne. K
tomu nßm poslou₧φ pole bajt∙, kde ka₧dΘ strßnce bude odpovφdat jeden zßznam. Pro
p°φstup k poli zavedeme metody SetEnableState a GetEnableState.
Abychom si zjednoduÜili prßci, budou se nenastavenΘ polo₧ky chßpat, jako by strßnky
byly povolenΘ. Metody tedy budou vypadat takto:
void PRO_PropertySheet::SetEnableState(int iPage, bool bEnable)
{
// Pokud je strßnka mimo rozsah, p°idßme informace o daÜφch
// strßnkßch.
if (iPage >= m_oStatusArray.GetSize())
{
// Stav nastavujeme na povolen
while (iPage >= m_oStatusArray.GetSize())
m_oStatusArray.Add(1);
}
// Nastavφme konkrΘtnφ strßnku
m_oStatusArray.SetAt(iPage, (BYTE)bEnable);
}
//-----------------------------------------------------------------
bool PRO_PropertySheet::GetEnableState(int iPage)
{
// Pokud jsme mimo nastavenφ, tak se tvß°φme, jako ₧e je strßnka
// povolena.
if (iPage>=m_oStatusArray.GetSize())
return true;
// Jinak poctiv∞ zφskßme stav
return m_oStatusArray.GetAt(iPage) ? true : false;
} |
Snad je vÜe jasnΘ z komentß°∙. Navr₧en² algoritmus nenφ
p°ipraven na odstra≥ovßnφ strßnek, ale proto₧e to nenφ p°φliÜ b∞₧nß akce,
bude nßm to (zatφm) takto vyhovovat.
Nynφ m∙₧eme p°istoupit ke t°etφmu bodu - vykreslovßnφ. Abychom
mohli p°evzφt vykreslovßnφ, je t°eba nastavit prvek TabControl, kter²
t°φda CPropertySheet obsahuje, tak aby jsme se o vykreslovßnφ starali my,
t°eba nßsledovn∞:
BOOL PRO_PropertySheet::OnInitDialog()
{
// Volßme metodu p°edka
BOOL bResult = CPropertySheet::OnInitDialog();
// Zφskßme ukazatel na prvek TabControl
CTabCtrl *poTabCtrl = GetTabControl();
if (!poTabCtrl->GetSafeHwnd())
return FALSE;
// Zφskßme p∙vodnφ styl
DWORD dwStyle = GetWindowLong(poTabCtrl->GetSafeHwnd(), GWL_STYLE);
// Nastavφme styl, ₧e se o vykreslovßnφ starßme my
dwStyle |= TCS_OWNERDRAWFIXED;
::SetWindowLong(poTabCtrl->GetSafeHwnd(), GWL_STYLE, dwStyle);
return bResult;
} |
V okam₧iku, kdy nastavφme styl OwnerDraw, se musφme o vykreslenφ
postarat. SystΘm zajistφ, ₧e pro ka₧dou vykreslovanou zßlo₧ku je volßna metoda OnDrawItem,
kde zajistφme vykreslenφ textu. Pokud zjistφme, ₧e zßlo₧ka vede na zakßzanou
strßnku, zobrazφme text "zakßzan∞", tedy vmßΦkle Üed∞. Toto se snadno
zajistφ dvojit²m vykreslenφm na posunut²ch sou°adnicφch, jak je vid∞t ze
zdrojovΘho textu:
void PRO_PropertySheet::OnDrawItem(
int nIDCtl,
LPDRAWITEMSTRUCT lpDIS)
{
// P°evedeme si HDC na CDC abychom mohli pou₧φvat metody
CDC oDC;
oDC.Attach(lpDIS->hDC);
CRect rcItem = lpDIS->rcItem;
// Pokud zobrazujeme vybranou zßlo₧ku, je t°eba zruÜit bφlou
// odd∞lovacφ Φßru. Toho docφlφme t°eba vymazßnφm celΘ zßlo₧ky
if (lpDIS->itemState == ODS_SELECTED)
{
oDC.FillSolidRect(&rcItem, RGB(192,192,192));
rcItem.OffsetRect(1, 1);
}
else
rcItem.OffsetRect(2, 2);
// Zφskßme text zßlo₧ky, kter² je ulo₧en p°φmo v informacφch
// prvku TabControl.
CString strText;
TC_ITEM oItem;
oItem.mask = TCIF_TEXT;
oItem.pszText = strText.GetBuffer(200);
oItem.cchTextMax = 200;
GetTabControl()->GetItem(lpDIS->itemID, &oItem);
strText.ReleaseBuffer();
// Pokud je strßnka povolena, zßlo₧ku vykreslφme jako b∞₧n² text
if (GetEnableState(lpDIS->itemID))
{
oDC.DrawText(strText, rcItem,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
}
else
{
// Pokud je strßnka zakßzßna,
// tak vykreslφme nejprve text bφle
oDC.SetBkMode(TRANSPARENT);
COLORREF clrOld = oDC.GetTextColor();
oDC.SetTextColor(RGB(255,255,255));
oDC.DrawText(strText, rcItem,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
// a potΘ tmav∞ Üed∞ na sou°adnicφch o bod vedle v obou osßch
oDC.SetTextColor(RGB(128,128,128));
rcItem.OffsetRect(-1, -1);
oDC.DrawText(strText, rcItem,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
oDC.SetTextColor(clrOld);
}
// Odd∞lφme t°φdu CDC a HDC, proto₧e jinak by doÜlo ke
// zruÜenφ kontextu za°φzenφ.
oDC.Detach();
} |
Poslednφ co musφme zajistit, je aby se u₧ivatel nemohl p°epnout do
zakßzanΘ strßnky. Toto se °eÜφ pomocφ notifikaΦnφch zprßv. Bohu₧el tyto zprßvy
chodφ pouze v p°φpad∞, ₧e dojde k p°epnutφ myÜφ, pomocφ klßvesnice (CTRL + TAB,
atp.) budeme muset reakci °eÜit jinak.
BOOL PRO_PropertySheet::OnNotify(
WPARAM wParam,
LPARAM lParam,
LRESULT* pResult)
{
NMHDR* pnmh = (NMHDR*)lParam;
// Tato notifikace urΦuje, ₧e dojde k p°epnutφ strßnek. Ulo₧φme si
// posledn∞ vybranou strßnku, abychom se m∞li kam p°epnout v
// p°φpad∞, ₧e se nepoda°φ p°epnout na cφlovou strßnku.
if (pnmh->code == TCN_SELCHANGING)
{
int iPage = GetTabControl()->GetCurSel();
m_nLastSelPage = iPage;
*pResult = TRUE;
}
// Tato notifikace urΦuje, ₧e doÜlo k p°epnutφ strßnky.
if (pnmh->code == TCN_SELCHANGE)
{
// Pokud p°epnutß strßnka je zakßzanß,
int iPage = GetTabControl()->GetCurSel();
// tak se p°epneme na tu, kterß byla aktivnφ p°ed p°epnutφm.
if (!GetEnableState(iPage))
SetActivePage(m_nLastSelPage);
}
// Dßme Üanci p°edkovi
return CPropertySheet::OnNotify(wParam, lParam, pResult);
} |
Poslednφ problΘm, kter² musφme vy°eÜit, se t²kß p°epnutφ
pomocφ klßvesnice. Tato akce je vytvß°ena v metod∞ PreTranslateMessage
p°edka. Tuto metodu kompletn∞ p°ekryjeme a napφÜeme vlastnφ sprßvu p°epφnßnφ
strßnek, kde zakß₧eme p°epnutφ do nepovolen²ch strßnek, nap°φklad takto:
BOOL PRO_PropertySheet::PreTranslateMessage(MSG* pMsg)
{
ASSERT_VALID(this);
// allow tooltip messages to be filtered
if (CWnd::PreTranslateMessage(pMsg))
return TRUE;
// Pokud je to "naÜe" kombinace...
if (pMsg->message == WM_KEYDOWN &&
GetAsyncKeyState(VK_CONTROL) <0 &&
(pMsg->wParam == VK_TAB || pMsg->wParam == VK_PRIOR
|| pMsg->wParam == VK_NEXT)
)
{
// Zjistφme vybranou strßnku
int iPage = GetTabControl()->GetCurSel();
int nDirect; // Prom∞nnß p°edstavuje sm∞r posunu
// Zjistφme sm∞r posunu
nDirect = +1;
if (pMsg->wParam == VK_TAB && GetAsyncKeyState(VK_SHIFT) < 0)
nDirect = -1;
if (pMsg->wParam == VK_PRIOR)
nDirect = -1;
// Posun na dalÜφ (p°edchozφ) strßnku
iPage += nDirect;
// Pokud jsme p°φliÜ daleko (blφzko) upravφme na sprßvnß Φφsla
if (iPage >= GetPageCount())
iPage = 0;
if (iPage < 0)
iPage = GetPageCount()-1;
// Test, zda je strßnka povolena
if (!GetEnableState(iPage))
{
// Pokud ne, tak nalezneme nejbli₧Üφ povolenou v
// po₧adavanΘm sm∞ru.
int iIndex = iPage;
while (!GetEnableState(iPage))
{
iPage += nDirect;
if (iPage >= GetPageCount())
iPage = 0;
if (iPage < 0)
iPage = GetPageCount()-1;
}
}
// Nastavφme strßnku
SetActivePage(iPage);
// TRUE, jako ₧e jsme zprßvu obslou₧ili
return TRUE;
}
// handle rest with IsDialogMessage
return PreTranslateInput(pMsg);
} |
Tφmto jsme splnili poslednφ krok. T°φda mß jeÜt∞ pßr
nedostatk∙, jejich₧ °eÜenφ ale nenφ nic nßroΦnΘho, to jist∞ ka₧d² zvlßdne:
1. Nenφ oÜet°eno odebφrßnφ strßnek a jejich synchronizace s
naÜφm polem nastavenφ.
2. V zßlo₧kßch se vykresluje jenom text.
3. Zakßzanß strßnka lze vybrat programov∞.
Kompletnφ zdrojov² text a p°φklad pou₧itφ lze nalΘzt v sekci
Download tohoto Φlßnku. |