Gdi Objects Selector
От: Нахлобуч Великобритания https://hglabhq.com
Дата: 19.02.05 08:41
Оценка: 112 (9)
Приветствую!
Оцените штучку .
При рисовании в Windows с использованием простого GDI довольно много однообразного кода тратится на выборку в DC необходимого объекта (с сохранением предыдущего), ну естественно использование, а потом выборку сохраненного объекта. Дык ведь окромя обычных HGDIOBJ есть еще куча параметров DCBkMode, 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);    
}

И это еще не самый "рисовательный" код.
Жду комментариев
HgLab: Mercurial Server and Repository Management for Windows
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.