Реализация стиля Office XP

Реализация стиля Office XP
ToolBarXP

Недавно я пытался найти в сети ToolBar-элемент в стиле
Office XP. Поиски мои не увенчались успехом – все элементы были либо сложны в
встраивании в проект, либо платны. Тогда я принял отчаянные меры – написал
сам… А, как оказалось, в написании тулбара не было оссобенных проблем. Вот
как я сделал.

Создал MFC SDI проект с именем StyleXP. С помощью
ClassWizard’а добавил новый класс CToolBarXP, наследованный от CToolBar (CToolBar
в списке нет, но я выбрал CToolBarCtrl и вручную изменил имя предка). Дальше
встал вопрос: “Какие функции перегружать?”. Просмотрев весь
предоставленный список в ClassWizard’е, я выбрал WM_PAINT. Долго я с ним
провозился, но таки вышло вот что:

void
CToolBarXP::OnPaint()

{

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

 // TODO: Add your message handler code here

 CRect rt, rItem;

 COLORREF face, shdw, cbtn;

 BYTE r,g,b;

 WORD BtnLength;

 // Берём
клиентскую область эл-та

 GetClientRect(rt);

 // Выщитываем
цвет бэк-граунда(для пущей красоты

 // я решил
слегка отклониться от стандартного цвета).

 face =
GetSysColor(COLOR_3DFACE);

 r = GetRValue(face)+10;

 g = GetGValue(face)+10;

 b = GetBValue(face)+10;

 face = PALETTERGB(r,g,b);

 // Таким
же образом выщитываем цвет выделенной кнопки…

 cbtn =
GetSysColor(COLOR_3DFACE);

 r = GetRValue(cbtn)-10;

 g = GetGValue(cbtn)-10;

 b = GetBValue(cbtn)-10;

 cbtn = PALETTERGB(r,g,b);

 // и цвет рамки

 shdw = GetSysColor(COLOR_3DSHADOW);

 r = GetRValue(shdw)+10;

 g = GetGValue(shdw)+10;

 b = GetBValue(shdw)+10;

 shdw = PALETTERGB(r,g,b);

 // Заполняем тол-бар бэкграундом

 dc.FillSolidRect(rt, face);

 // Создаём перо

 CPen pen;

 pen.CreatePen(0, 1, shdw);

 dc.SelectObject(&pen);

 TBBUTTON btn;

 BtnLength =
LOWORD(GetToolBarCtrl().GetButtonSize());// Получаем ширину кнопки

 // Перебираем все кнопки

 for(int i = 0, x = 0, n = 0; i !=
GetToolBarCtrl().GetButtonCount(); i++)

 {

     GetToolBarCtrl().GetButton(i, &btn);//
Получаем данные о кнопке

     if(btn.fsStyle & TBSTYLE_SEP)// Сепаратор ?

     {

         dc.MoveTo(x+2,
2);// Рисуем вертикальную линию

         dc.LineTo(x+2, 20);

         x += 6;

     }

     if(m_nSelected == i)// На кнопке мышка?

     {

         //
Создаём кисть и перо

         CPen
pn;

         CBrush br;

         pn.CreatePen(0, 1, shdw);

         br.CreateSolidBrush(cbtn);

         dc.SelectObject(&pn);

         dc.SelectObject(&br);

         //
Получаем рект кнопки

         GetItemRect(i,
rItem);

         // Рисуем рамку

         dc.Rectangle(rItem);

         // Рисуем иконку кнопки

        
GetToolBarCtrl().GetImageList()->Draw(&dc, n, CPoint(x+2, 2), 0);

         x += BtnLenght;

         n++;

     }

     else if(!btn.fsStyle & TBSTYLE_SEP)// Кнопка в обычном состоянии

     {

        
GetToolBarCtrl().GetImageList()->Draw(&dc, n, CPoint(x+3, 3), 0);

         x += BtnLenght;

         n++;

     }

 }

 // Do not call CToolBarCtrl::OnPaint() for
painting messages

}

Так, сразу пока не отвлёкся – в класс надо добавить
переменную:

class CToolBarXP :
public CToolBarCtrl

{

//***********************************************

protected:

 int
m_nSelected;// Номер кнопки под мышкой 🙂

 //{{AFX_MSG(CToolBarXP)

 afx_msg void OnPaint();

 //}}AFX_MSG

 DECLARE_MESSAGE_MAP()

};

В конструкторе класса надо надо инициализировать сию
переменную числом -1.

Теперь добавляем через КлассВизард обработку
перемещений мышкой:

void
CToolBarXP::OnMouseMove(UINT nFlags, CPoint point)

{

 CToolBar::OnMouseMove(nFlags, point);

 CRect rt;

 TBBUTTON btn;

 // Перебираем кнопки

 for(int i = 0; i !=
GetToolBarCtrl().GetButtonCount(); i++)

 {

     GetToolBarCtrl().GetButton(i, &btn);//
Получаем данные о кнопке

     GetItemRect(i,
rt);// Получаем рект кнопки

     if(btn.fsStyle
& TBSTYLE_SEP) continue;// Сепараторы пропускаем

     if(rt.PtInRect(point)
&& m_nSelected != i)// Мышка над этой?

     {

         m_nSelected = i;// Сохраняем выделение

         Invalidate();// Перерисовываем

         SetTimer(11, 100, NULL);// Пускаем таймер

         return;

     }

 }

}

Так… Ну и, собственно таймер:

void
CToolBarXP::OnTimer(UINT nIDEvent)

{

 if(nIDEvent ==
11)// На всякий пожарный

 {

     // Так где
же мышка ???

     CPoint
p(GetMessagePos());

     ScreenToClient(&p);

     // Берём границы кнопки

     CRect rect;

     GetClientRect(rect);

     // Проверка
на наличие внутри курсора

     if
(!rect.PtInRect(p))

     {

         // Если
мыши нет то оставляем слежение

         m_nSelected
= -1;

         // И
убиваем таймер (“А зачем нам кузнец? Нам кузнец не нужен…”) 😉

         KillTimer(11);

         // Не
забыть перерисовать кнопку

         Invalidate();

     }

 }

}

Фу… Вроде всё. А! Теперь лезем в MainFrame.h и
меняем тип переменной m_wndToolBar с CToolBar на CToolBarXP, незабыв перед этим
#include’ть файл с нашим тулбаром. Теперь всё! Жмём F7, ждём пока проект
скомпилируется и F5. Лицезреем красочный тулбар.

ReBarXP

Так, тулбар есть. Далее – CReBarXP. Ну это вообще
проще пареной репы: создаём MFC проект с помеченной галочкой Internet Explorer
ReBars. Добавляем новы класс CReBarXP, наследованный от CReBar, перегружаем у
него WM_PAINT и вписываем туда вот что:

void
CReBarXP::OnPaint()

{

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

 // TODO: Add your message handler code here

 CRect rt, rBand;

 COLORREF face, shdw;

 BYTE r,g,b;

 // Цвета(идеинтично CToolBarXP)

 GetClientRect(rt);

 face = GetSysColor(COLOR_3DFACE);

 r = GetRValue(face)+10;

 g = GetGValue(face)+10;

 b = GetBValue(face)+10;

 face = PALETTERGB(r,g,b);

 shdw = GetSysColor(COLOR_3DSHADOW);

 r = GetRValue(shdw)+10;

 g = GetGValue(shdw)+10;

 b = GetBValue(shdw)+10;

 shdw = PALETTERGB(r,g,b);

 CPen pen;

 pen.CreatePen(0, 1, shdw);

 //
Заливаем область

 dc.FillSolidRect(rt,
face);

 dc.SelectObject(&pen);

 // Перебираем
все бары

 for(UINT i = 0; i
!= GetReBarCtrl().GetBandCount(); i++)

 {

     GetReBarCtrl().GetRect(i, rBand);// Получаем рект

     for(int y = 4; y != rBand.Height()-4;
y+=2)// Ресуем симпатичную закраску

     {

         dc.MoveTo(rBand.left+3,rBand.top+y);

         dc.LineTo(rBand.left+6,rBand.top+y);

     }

 }

 // Do not call CReBar::OnPaint() for painting
messages

}

Всё! Теперь только меняем тип ReBar на
CReBarXP(обязательно вставив перед объявлением класса include-команду).

StatusBarXP

Так, так… ToolBarXP и ReBarXP есть. Теперь
StatusBar’ом займёмся. Проект как создавать я писать не буду, сразу переходим к
делу.

Добавляем новый класс CStatusBarXP, наследованный от
CStatusBar. В нём переопределяем OnPaint и пишим тудыва:

void CStatusBarXP::OnPaint()

{

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

 CRect rt, rPane;

 COLORREF face, shdw;

 CString Text;

 CFont* Font;

 BYTE r,g,b;

 //
Высчитываем цвета(большая часть кода:))

 GetClientRect(rt);

 face = GetSysColor(COLOR_3DFACE);

 r = GetRValue(face)-10;

 g = GetGValue(face)-10;

 b = GetBValue(face)-10;

 face = PALETTERGB(r,g,b);

 shdw = GetSysColor(COLOR_3DSHADOW);

 r = GetRValue(shdw)+10;

 g = GetGValue(shdw)+10;

 b = GetBValue(shdw)+10;

 shdw = PALETTERGB(r,g,b);

 CPen pen;

 CBrush br;

 pen.CreatePen(0, 1, shdw);

 br.CreateSolidBrush(face);

 Font = GetFont();

 dc.SelectObject(Font);

 dc.FillSolidRect(rt, face);

 dc.SelectObject(&pen);

 dc.SelectObject(&br);

 // А вот
непосредственно рисование:

 for(int i = 0;
i != GetCount();
i++)

 {// Перебираем все индикаторы

     GetStatusBarCtrl().GetRect(i, rPane);

     GetPaneText(i, Text);// Получаем текст

     rPane.bottom–;

     dc.Rectangle(rPane);//
Рисуем рамку

     // И текст,
если надо:

     if(GetPaneStyle(i))
dc.TextOut(rPane.left+3, rPane.top+1, Text);

     rPane.top += 1;

     rPane.left += 3;

     rPane.right -= 1;

     if(GetPaneStyle(i)) dc.DrawText(Text,
rPane, 0);

 }

}

Усё! Теперь только меняем тип переменной с CStatusBar
на CStatusBarXP и глядим. Вид, конечно, до первых двух классов не дотягивает,
но… “сойдёт для сельской местности”.

Красивого вам программирования!
Список литературы

Для подготовки данной работы были использованы
материалы с сайта http://www.realcoding.net/