23
Dec
2008

Lucrand la un proiect recent, a trebuit sa afisez o notificare catre utilizator asemanatoare celei din Office atunci cand un noi email este primit. Din pacate nu am putut gasi ceva foarte util care sa mearga cu Visual Studio 2003 si 2005. Desigur, daca folositi Visual Studio 2008 aveti la dispozitie asa ceva in MFC, pentru ca noile extensii din SP1 (sau Feature Pack inainte) ofera un set de clase pentru ferestre de notificare. Dar daca nu folositi Visual Studio 2008 aveti aceiasi problema ca si mine. Articolul de fata prezinta un set de clase pe care l-am dezvoltat pentru a rezolva problema mea.

Iata mai jos cateva imagini cu ferestre de notificare customizate in diferite stiluri.

Notificare de email simpla Notificare de email in stilul Office 2003

Notificare de terminare download in stilul Firefox 3 Notificare de melodie nou in Winamp


Descriere framework

In continuare ma voi referi la setul de clase cu termenul framework, chiar daca acesta nu reprezinta un framework in toata puterea cuvantului. Clasele care il alcatuiesc sunt grupate in 3 categorii:

  • dialogul de notificare: clasa de baza pentru toate ferestrele de notificare pe care vreti sa le afisati; aspectul sau poate fi customizat cu stiluri.

    Clasele CMailAlert, CFirefoxAlert si CWinampAlert nu fap parte din framework, ci sunt doar implementari prin demo-ul oferit cu acest articol.

  • Stiluri: o ierarhie de clase care trateaza mesajele de desenare a fundalului si zonei non-client a ferestrei de notificare.

  • Controale: diferite controale customizate (label, hyperlink, imagine, push button) care pot fi utilizate intr-o dialog de notificare.

CAlertDialog

Aceasta este o clasa derivate din CDialog si reprezinta clasa de baza pentru orice fereastra de notificare pe care vreti s-o afisati. Are urmatoarele caracteristici:

  • afiseaza un dialog deasupra taskbar-ului cu animatie de tip blending pentru afisare si ascundere
  • animatie, timp de vizibilitate si nivel de transparenta customizate
  • ramane activa atat timp cat cursorul se afla pe fereastra (de cate ori cursorul ajunge in zona ferestrei, timerul pentru terminarea vizibilitatii este resetat)
  • permite mutarea ferestrei cu mouse-ul (tinand butonul stanga apasat) in limitele ecranului (indiferent de numarul de monitoare)
  • poate fi parametrizata cu un stil pentru desenarea fundalului si zonei non-client

Aceasta clasa are doar trei metode publice:

  • Show(): afiseaza dialogul cu animatie de tip blending; se poate specifica timpul de aparitie, timpul cat fereastra sa ramana vizibila, opacitatea maxima (255 inseamna complet opac, 0 complet transparent) si daca fereastra sa ramana vizibila (complet opaca) atat timp cat cursorul se afla pe ea;
  • Hide(): ascunde dialogul instant, anuland orice animatie;
  • SetAlertStyle(): seteaza obiectul de stil pentru tratarea mesajelor de desenare a fundalului si zonei non-client.

OnNcPaint() apeleaza HandleNcPaint() al obiectului de stil, iar OnEraseBkgnd() apeleaza HandleEraseBkgnd(). Daca aceste functii returneaza FALSE, tratarea mesajului este delegata catre clasa de baza (CDialog).

CAlertStyle

Aceasta este o clasa de baza pentru toate stilurile folosite pentru cusomizarea dialogului de notificare. Are urmatoarele metode virtuale:

  • HandleNcPaint(): trateaza desenarea zonei non-client a ferestrei;
  • HandleEraseBkgnd(): trateaza desenarea fundalului ferestrei;
  • OnInitialize(): apelata pentru initializari de orice fel, la crearea ferestrei;

CAlertStyleDefault

O implementarea simpla pentru un stil, care nu trateaza desenarea fundalului si deseneaza o simpla margine in jurul ferestrei de notificare.

CAlertStyleOffice2003

Acesta este un stil asemanator Office 2003. Afiseaza un gradient albastru pentru fundal, o margine neagra in jurul ferestrei si are o bara mica, inchisa la culoare in partea de sus a ferestrei.

CAlertStyleFirefox

Creaza o infatisare asemanatoare ferestrei de notificare a downloadurilor din Firefox 3, cu un dreptunghi albastru si un fundal de culoarea COLOR_BTNFACE.

CAlertStyleWinamp

Creaza o infatisare asemanatoare ferestrei de notificare a lansarii unei noi melodii in Winamp, cu o margine rotunjita si un gradient de gri in fundal.

CAlertLabel

Acesta este un control static care are un fundal transparent. Se poate seta culoarea pentru text. In mod implicit aceasta este negru. Acest control foloseste un bitmap, pastrat intr-un cache intern, pentru desenarea fundalului. Cand fundalul din spatele controlului se schimba acest cache trebuie s fie invalidat prin apelul functiei InvalidateCachedBitmap().

CAlertHyperlink

Acest control este derivat din CAlertLabel si ofera urmatoarele functionalitati in plus:

  • poate afisa text in culori diferite atunci cand cursorul este deasupra sa si atunci cand nu este
  • poate afisa textul subliniat
  • poate afisa un cursor diferit atunci cand mouseul este deasupra
  • notifica parintele sau cand utilizatorul face un click pe control

CAlertPictureCtrl

Acest control (derivat din CAlertLabel) afiseaza o imagine, care poate fi transparenta. Prezinta urmatoarele functionalitati:

  • poate afisa fie un icon fie un bitmap
  • poate folosi o culoare pentru transparenta imagini (care culoare din imagine sa fie transparenta)

CAlertButton

Acesta este un control de tip push button cu urmatoarele caracteristici:

  • este intotdeauna plat
  • poate avea un icon sau un bitmap, care este intotdeauna afisat in centrul zonei client
  • poate avea o culoare care sa reprezinte culoarea transparenta din imagine
  • poate avea o culoare pentru desenarea fundalului cand cursorul este deasupra
  • isi notifica parintele cand este apasat

CAlertButtonClose

Acesta este un buton de notificare (CAlertButton) care afiseaza semnul X pentru inchidere (si nu necesita o resursa imagine pentru acest lucru).

Cum se foloseste framework-ul

In imaginea de mai jos este explicat de controale au fost folosite pentru crearea unei ferestre de notificare:

Pentru a crea o fereastra de notificare trebuie facute urmatoarele:

  • creaza un template de dialog (fara margine) si adauga, dupa necesiatati, controale statice (pentru label si hyperlink), butoane, controale imagine
  • adauga o clasa (derivata din CDialog) pentru dialog
  • include "AlertDialog.h" in header-ul clasei si schimba clasa de baza din CDialog in CAlertDialog (toate referintele)
  • pentru fiecare control customizat (de notificare) pe care il vrei in fereastra de notificare adauga o variabila cu mecanismul DDX. De exmplu, pentru un label cu care vrei sa afisezi un titlu, fa urmatoarele:
    • include "AlertLabel.h" in headerul clasei tale dialog
    • adauga o variabila de tip CAlertLabel la clasa

      CAlertLabel m_ctrlTitle;
    • asociaza variabila cu controlul in functia DoDataExchange():

      void CDemoAlert::DoDataExchange(CDataExchange* pDX)
      {
         CAlertDialog::DoDataExchange(pDX);
      
         DDX_Control(pDX, IDC_STATIC_TITLE, m_ctrlTitle);
      }
      
  • daca fundalul ferestrei de notificare se schimba, trebuie suprascrisa functia OnInvalidate() si apelat InvalidateCachedBitmap() pentru fiecare label, hyperlink, control imagine sau button.

    void CDemoAlert::OnInvalidate()
    {
       m_ctrlTitle.InvalidateCachedBitmap();
    }  
      
  • daca vrei sa fi notificat cand un hyperlink sau buton a fost apasat, trateaza mesajul corespunzator definit in "AlertMessages.h".
    • in clasa dialog adauga urmatoarele handlere:

         afx_msg LRESULT OnHyperlinkedClicked(WPARAM wParam,
                                              LPARAM lParam);
         afx_msg LRESULT OnButtonClicked(WPARAM wParam,
                                         LPARAM lParam);
            
    • adauga aceste handlere la harta de mesaje:

      BEGIN_MESSAGE_MAP(CDemoAlert, CAlertDialog)
         ON_MESSAGE(WMA_HYPERLINKCLICKED,
                    &CDemoAlert::OnHyperlinkedClicked)
         ON_MESSAGE(WMA_BUTTONCLICKED,
                    &CDemoAlert::OnButtonClicked)
      END_MESSAGE_MAP()
            
    • implementeaza handlerele; in mod normal probabil vei dori sa timiti un mesaj ferestrei parinte celei de notificare. In exemplul de mai jos cand un control este apasat, se ascunde fereastra de notificare, fara a se mai trimite un mesaj parintelui.

      LRESULT CDemoAlert::OnHyperlinkedClicked(WPARAM wParam,
                                               LPARAM lParam)
      {
         Hide();
      
         return 0;
      }
      
      LRESULT CDemoAlert::OnButtonClicked(WPARAM wParam,
                                          LPARAM lParam)
      {
         Hide();
      
         return 0;
      }      
            
  • In mod implicit CAlertDialog trateaza WM_LBUTTONDOWN si WM_LBUTTONUP pentru a permite mutarea ferestrei pe ecran cu mouseul. Daca un vrei acest comportament (de exemplu vrei sa inchizi ferastra in momentul in care userul da click pe ea) trateaza aceste mesaje in clasa dialog derivata. In aplicatia demo exista un exemplu pentru clasa CWinampAlert.

Aplicatia demo

In acest articol am pus la dispozitie o aplicatie demo care creaza trei ferestre de notificare diferite: o notiifcare de email nou, o notificare in stilul Firefox, si una in stilul Winamp (vezi imaginile de la inceputul articolului).

In aceasta aplicatie se pot modifica:

  • timpul de animatie (pentru afisare si ascundere) in milisecunde
  • timpul de vizibilitate (intervalul cuprins intre sfarsitul animatiei de afisare si inceputul animatiei de ascundere)
  • opaciatatea maxima, ca si procentaj (0 -100), 100 insemnand fereastra complet opaca
  • daca fereastra sa devica complet opaca (in caz ca nu e deja) cand cursorul este deasupra ei si sa ramana asa pana cand cursorul o paraseste; in acest caz, in momentul cand cursorul paraseste fereastra, timerul pentru vizibilitate este repornit.

Note

Puteti folosi codul din acest articol, modifica sau extinde in orice aplicatie (gratis sau comerciala) atat timp cat pastrazi notele de copyright. Daca creati noi controale sau functionalizati si sunteti dispusi sa le oferiti si altora, va rog sa ma contactati pentru a le integra cu codul de aici.

Multumiri

Parti de cod au fost luate sau inspirate din urmatoarele articole:


[phpBB Debug] PHP Warning: in file [ROOT]/phpbb/db/driver/mysqli.php on line 317: mysqli_free_result(): Couldn't fetch mysqli_result