Реализация стиля 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 и глядим. Вид, конечно, до первых двух классов не дотягивает, но… “сойдет для сельской местности”.

Красивого вам программирования!


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