Hlavnφ
Hlavnφ strana
Seznam Φlßnk∙
NejΦten∞jÜφ Φlßnky
Progres e-mailem
Visual C++ FAQ

Serißly
COM
ISAPI

banner2.gif (2546 bytes)

Nenechte si ujφt
NeobdΘlnφkovß okna
Tisk bez Preview
MFC a DLL
Logo v MDI ploÜe
Kouzla s kombo-boxem
V²jimky v C++

banner.gif (3305 bytes)

Zakßzanß strßnka v PropertySheet Radek Paviensk²
02.11.1999
[Hlavnφ strßnka]  |  [Rubrika]  |  [Download]

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:

rp_011199_propsheet_01.gif (2357 bytes)

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(11);
  }
  else
    rcItem.OffsetRect(22);
  
  // 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.


PodobnΘ Φlßnky:

Kdo Otßzka nebo p°ipomφnka

Prohlφ₧enφ p°φsp∞vk∙ nebo nov² p°φsp∞vek

O firm∞... Kontakt Ostatnφ