Visual C++ |
Si ens fixem en algunes aplicacions com WinAmp veurem que tenen un control en el qual apareix el títol de la cançó, l'autor, la durada i alguna altra informació que es va desplaçant de dreta a esquerra per poder mostrar-se en la seva totalitat.
En realitat el que fa WinAmp és moure el primer caràcter de la cadena mostrada al final de la mateixa, és a dir, fa una rotació de caràcters. Amb un control estàtic podem fer una cosa similar de forma molt senzilla.
Derivem una classe anomenada CHStaticRotativo de CStatic d'aquesta manera podrem
utilitzar-la de forma genèrica en qualsevol aplicació simplement afegint aquesta classe al nostre projecte.
class CHStaticRotativo : public CStatic
{
....
protected:
// Generated message map functions
//{{AFX_MSG(CHStaticRotativo)
afx_msg LRESULT OnSetText(WPARAM wParam, LPARAM lParam);
afx_msg void OnPaint();
afx_msg void OnTimer(UINT nIDEvent);
afx_msg void OnDestroy();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
bool m_flagTimer; // indica si el temporitzador ha estat establert
RECT m_rect; // rectangle del control
CString m_sTexto; // text que es mostra actualment
};
Per establir el text d'un control estàtic des d'una classe de diàleg utilitzem normalment la funció SetWindowText. No s'ha d'oblidar que hem d'assignar un identificador al control estàtic en temps de disseny del nostre diàleg, ja que per defecte s'assigna a -1. La funció SetWindowText envia el missatge WM_SETTEXT, així doncs hem de gestionar aquest missatge per assignar el text a la variable membre m_sTexto de la nostra classe CHStaticRotativo. Això ho fa la funció OnSetText.
LRESULT CHStaticRotativo::OnSetText(WPARAM wParam, LPARAM lParam)
{
SIZE size;
CWnd *pWndParent = NULL;
CClientDC dc(this);
// obtenim la mida del control
GetClientRect(&m_rect);
// assignem el text enviat per SetWindowText() des del diàleg
m_sTexto = _T((LPSTR)lParam);
// seleccionem la font per defecte del diàleg
pWndParent = GetParent();
if (pWndParent != NULL)
{
// seleccionem la font per defecte
dc.SelectObject(pWndParent->GetFont());
}
// obtenim la mida del text segons el context de dispositiu
GetTextExtentPoint32(dc.GetSafeHdc(), m_sTexto, m_sTexto.GetLength(), &size);
// si el text no hi cap en el control, inicialitzar temporitzador per a rotar-lo
// altrament no fa falta rotar-lo
if (size.cx > m_rect.right)
{
// establim el temporitzador a 200 mil·lisegons
UINT ok = SetTimer(ID_TIMER, 200, NULL);
ASSERT(ok != NULL);
m_flagTimer = true;
}
return 0L;
}
La gestió del missatge WM_SETTEXT no es pot afegir des de ClassWizard, per tant cal fer-ho a mà.
BEGIN_MESSAGE_MAP(CHStaticRotativo, CStatic)
//{{AFX_MSG_MAP(CHStaticRotativo)
ON_MESSAGE(WM_SETTEXT, OnSetText)
ON_WM_TIMER()
ON_WM_PAINT()
ON_WM_DESTROY()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
Cal afegir el gestor OnTimer per al missatge WM_TIMER. Aquí serà on actualitzem el text i obligarem que es repinti de nou.
void CHStaticRotativo::OnTimer(UINT nIDEvent)
{
if (nIDEvent == ID_TIMER)
{
// afegim el primer caràcter al final de la cadena...
m_sTexto += m_sTexto.GetAt(0);
// ... i l'eliminem del principi, és com si el text sencer
// es mogués una posició a l'esquerra
m_sTexto.Delete(0);
// obliguem que es repinti de nou
Invalidate();
}
CStatic::OnTimer(nIDEvent);
}
Quan sortim del diàleg hem d'eliminar el temporitzador utilitzant la funció KillTimer. Per a fer això el millor és utilitzar la funció OnDestroy la qual gestiona el missatge WM_DESTROY:
BOOL CHScrollingBannerStc::OnDestroy()
{
return CStatic::OnDestroy();
if (m_flagTimer)
KillTimer(ID_TIMER);
}
Finalment només ens queda la funció OnPaint per a la gestió del missatge WM_PAINT.
void CHStaticRotativo::OnPaint()
{
CWnd *pWndParent = NULL;
CPaintDC dc(this);
pWndParent = GetParent();
if (pWndParent != NULL)
{
// seleccionem la font per defecte
dc.SelectObject(pWndParent->GetFont());
}
// seleccionem el color de fons per defecte del control estàtic
CBrush bBrush(::GetSysColor(COLOR_3DFACE));
CBrush* pOldBrush;
pOldBrush = dc.SelectObject(&bBrush);
// omplim el control amb el color seleccionat
dc.FillRect(&m_rect, &bBrush);
// escrivim el text
dc.SetBkMode(TRANSPARENT);
dc.DrawText(m_sTexto, &m_rect, DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE);
dc.SelectObject(&pOldBrush);
bBrush.DeleteObject();
}
Ja tenim acabada la gestió del nostre control banner per rotació. Fixem-nos que si el text ja hi cap en el control no s'estableix el temporitzador, per la qual cosa no hi haurà rotació dels caràcters de la cadena, el seu aspecte serà com el d'un control estàtic normal amb un marc.
A la classe del diàleg hem de declarar una variable membre m_ctrlBanner de tipus CHStaticRotativo, després, en OnInitDialog cridar a la funció SetWindowText amb el text que desitgem.
BOOL CHBannerRotativoDlg::OnInitDialog()
{
CDialog::OnInitDialog();
m_ctrlBanner.SetWindowText(
"Aquest text és un exemple per al control de Banner horitzontal amb rotació de caràcters. - ");
return TRUE;
}
| Fonts | ... | h_banner_rotativo_sources.zip 19 Kb |
| Vegi's també | ... | Banner horitzontal per desplaçament del text |
| Banner vertical per desplaçament del text |