Приветствую!
Оцените штучку
.
При рисовании в Windows с использованием простого
GDI довольно много однообразного кода тратится на выборку в
DC необходимого объекта (с сохранением предыдущего), ну естественно использование, а потом выборку сохраненного объекта. Дык ведь окромя обычных
HGDIOBJ есть еще куча параметров
DC —
BkMode,
ROP2,
MapMode, ... и все надо сохранять. К примеру:
//
// Drawing item
void CExtendedListBox::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
if(0 == GetCount())
return;
//
// Drawing blue background if item is selected
if(lpDIS->itemState & ODS_SELECTED)
{
CRect rcRect(lpDIS->rcItem);
rcRect.DeflateRect(1, 1, 1, 1);
HPEN pnPen = (HPEN)::SelectObject(lpDIS->hDC, m_pnSelectedPen);
HBRUSH brBrush = (HBRUSH)::SelectObject(lpDIS->hDC, m_brSelectedBack);
::RoundRect(lpDIS->hDC, rcRect.left, rcRect.top, rcRect.right, rcRect.bottom, 5, 10);
::SelectObject(lpDIS->hDC, pnPen);
::SelectObject(lpDIS->hDC, brBrush);
} // if
else
{
::FillRect(lpDIS->hDC, &(lpDIS->rcItem), m_brBackground);
} // else
//
// Centering icon vertically
CRect rcRect(lpDIS->rcItem);
rcRect.DeflateRect(5, 3, 15, 5);
::DrawIcon(lpDIS->hDC, rcRect.left, rcRect.top, m_pimgList->ExtractIcon(m_clbiItems[lpDIS->itemID].nImageIndex));
//
// Text
rcRect.DeflateRect(40, 0, 0, 0);
int nMode = SetBkMode(lpDIS->hDC, TRANSPARENT);
::DrawText(lpDIS->hDC, m_clbiItems[lpDIS->itemID].strItemText,
m_clbiItems[lpDIS->itemID].strItemText.GetLength(), rcRect, DT_END_ELLIPSIS | DT_LEFT | DT_WORDBREAK);
SetBkMode(lpDIS->hDC, nMode);
}
Напряжно за этм следить, не правда ли? Все эти приведения типов, многократные
SelectObject. В общем, под давлеием сего факта родился такой вот трехколесный велосипед
:
#pragma once
//
// ObjectSelector
// GenericObjectType - generic object type
// ObjectType - type of the object being selected into...
// DeviceContext - ...a device context of this type
// SelectorFunction - function that performs the said selection
template <typename GenericObjectType, typename ObjectType, typename DeviceContext,
GenericObjectType (__stdcall *SelectorFunction)(DeviceContext, GenericObjectType)>
class ObjectSelector
{
ObjectType m_obj;
DeviceContext m_dc;
//
// Disabling default and copy
// constructors
ObjectSelector(void)
{ }
ObjectSelector(const ObjectSelector&)
{ }
public:
//
// Constructor
ObjectSelector(DeviceContext dc, ObjectType obj) :
m_dc(dc),
m_obj((ObjectType)SelectorFunction(dc, obj))
{
}
//
// Destructor
~ObjectSelector(void)
{
SelectorFunction(m_dc, m_obj);
}
};
//
// Specializations
typedef ObjectSelector<HGDIOBJ, HBITMAP, HDC, SelectObject> BitmapSelector;
typedef ObjectSelector<HGDIOBJ, HBRUSH, HDC, SelectObject> BrushSelector;
typedef ObjectSelector<HGDIOBJ, HFONT, HDC, SelectObject> FontSelector;
typedef ObjectSelector<HGDIOBJ, HPEN, HDC, SelectObject> PenSelector;
typedef ObjectSelector<HGDIOBJ, HRGN, HDC, SelectObject> RgnSelector;
typedef ObjectSelector<int, int, HDC, SetBkMode> BkModeSelector;
typedef ObjectSelector<int, int, HDC, SetROP2> Rop2Selector;
typedef ObjectSelector<int, int, HDC, SetMapMode> MapModeSelector;
typedef ObjectSelector<int, int, HDC, SetPolyFillMode> PolyFillModeSelector;
typedef ObjectSelector<int, int, HDC, SetStretchBltMode> StretchBltModeSelector;
typedef ObjectSelector<COLORREF, COLORREF, HDC, SetBkColor> BkColorSelector;
Тут все просто. Создаете на стеке объект небоходимого класса (передаете ему DC и соответствующий дескриптор
GDI объекта) и все. Соответственно, при выходе из функции (или из блока) в
DC выбирается старый (сохраненный в недрах
ObjectSelectora объект). Так что с использованием этого класса можно так вот причесать вышеприведенный код:
//
// Drawing item
void CExtendedListBox::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
if(0 == GetCount())
return;
//
// Drawing blue background if item is selected
if(lpDIS->itemState & ODS_SELECTED)
{
CRect rcRect(lpDIS->rcItem);
rcRect.DeflateRect(1, 1, 1, 1);
PenSelector psPen(lpDIS->hDC, m_pnSelectedPen);
BrushSelector bsBrush(lpDIS->hDC, m_brSelectedBack);
::RoundRect(lpDIS->hDC, rcRect.left, rcRect.top, rcRect.right, rcRect.bottom, 5, 10);
} // if
else
{
::FillRect(lpDIS->hDC, &(lpDIS->rcItem), m_brBackground);
} // else
//
// Centering icon vertically
CRect rcRect(lpDIS->rcItem);
rcRect.DeflateRect(5, 3, 15, 5);
::DrawIcon(lpDIS->hDC, rcRect.left, rcRect.top, m_pimgList->ExtractIcon(m_clbiItems[lpDIS->itemID].nImageIndex));
//
// Text
rcRect.DeflateRect(40, 0, 0, 0);
BkModeSelector bmsBack(lpDIS->hDC, TRANSPARENT);
::DrawText(lpDIS->hDC, m_clbiItems[lpDIS->itemID].strItemText,
m_clbiItems[lpDIS->itemID].strItemText.GetLength(), rcRect, DT_END_ELLIPSIS | DT_LEFT | DT_WORDBREAK);
}
И это еще не самый "рисовательный" код.
Жду комментариев