Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ОСиСП - методички / OS&SP_Lab_2.6(shell).doc
Скачиваний:
95
Добавлен:
18.05.2015
Размер:
1.12 Mб
Скачать

Обработка wm_measureitem

Когда оболочка посылает нашему расширению сообщение WM_MEASUREITEM для запроса размеров нашего пункта меню, мы начинаем с проверки, затребованы ли размеры нашего собственного пункта меню. Если тест пройден, мы получаем размеры битмапа, затем вычисляем размер всего пункта меню.

Сначала размер битмапа:

STDMETHODIMP CBmpCtxMenuExt::OnMeasureItem ( MEASUREITEMSTRUCT* pmis, LRESULT* pResult )

{

BITMAP bm;

LONG lThumbWidth;

LONG lThumbHeight;

// Check that we're getting called for our own menu item.

if ( m_uOurItemID != pmis->itemID )

return S_OK;

m_bmp.GetBitmap ( &bm );

m_lBmpWidth = bm.bmWidth;

m_lBmpHeight = bm.bmHeight;

Далее, мы вычисляем размер эскиза, и, исходя из этого, размер всего пункта меню. Если картинка меньше, чем максимальный размер эскиза (который в демонстрационном проекте 64х64), то она будет нарисована как есть. Иначе, картинка будет нарисована размером 64х64. Это может исказить ее вид, но опять же, создание приятного вида эскиза оставлено для упражнений.

// Calculate the bitmap thumbnail size.

lThumbWidth = (m_lBmpWidth <= m_lMaxThumbnailSize) ? m_lBmpWidth :

m_lMaxThumbnailSize;

lThumbHeight = (m_lBmpHeight <= m_lMaxThumbnailSize) ? m_lBmpHeight :

m_lMaxThumbnailSize;

// Calculate the size of the menu item, which is the size of the thumbnail +

// the border and padding (which provides some space at the edges of the item).

m_lItemWidth = lThumbWidth + m_lTotalBorderSpace;

m_lItemHeight = lThumbHeight + m_lTotalBorderSpace;

Теперь, когда у нас есть размер пункта меню, мы сохраняем размеры обратно в MENUITEMSTRUCT, которую мы получили с сообщением. Проводник зарезервирует достаточно места в меню для нашего пункта.

// Store the size of the item in the MEASUREITEMSTRUCT.

pmis->itemWidth = m_lItemWidth;

pmis->itemHeight = m_lItemHeight;

*pResult = TRUE; // we handled the message

return S_OK;

}

Обработка wm_drawitem

Когда мы получаем сообщение WM_DRAWITEM, проводник требует, чтобы мы действительно вывели наш пункт меню. Мы начинаем с вычисления прямоугольника, в котором мы нарисуем объемную границу вокруг эскиза. Это не обязательно тот же прямоугольник, которые занимает пункт меню, потому что меню может оказаться шире, чем размер, который мы установили в обработчике WM_MEASUREITEM.

STDMETHODIMP CBmpCtxMenuExt::OnDrawItem ( DRAWITEMSTRUCT* pdis, LRESULT* pResult )

{

CDC dcBmpSrc;

CDC* pdcMenu = CDC::FromHandle ( pdis->hDC );

CRect rcItem ( pdis->rcItem ); // RECT of our menu item

CRect rcDraw; // RECT in which we'll be drawing

// Check that we're getting called for our own menu item.

if ( m_uOurItemID != pdis->itemID )

return S_OK;

// rcDraw will first be set to the RECT that we set in WM_MEASUREITEM.

// It will get deflated as we go along.

rcDraw.left = (rcItem.right + rcItem.left - m_lItemWidth) / 2;

rcDraw.top = (rcItem.top + rcItem.bottom - m_lItemHeight) / 2;

rcDraw.right = rcDraw.left + m_lItemWidth;

rcDraw.bottom = rcDraw.top + m_lItemHeight;

// Shrink rcDraw to account for the padding space around

// the thumbnail.

rcDraw.DeflateRect ( m_lMenuItemSpacing, m_lMenuItemSpacing );

Первый шаг рисования - окрашивание фона пункта меню. Элемент itemState структуры DRAWITEMSTRUCT показывает, отмечен наш пункт меню, или нет. Это определяет, какой цвет мы используем для фона.

// Fill in the background of the menu item.

if ( pdis->itemState & ODS_SELECTED )

pdcMenu->FillSolidRect ( rcItem, GetSysColor ( COLOR_HIGHLIGHT ));

else

pdcMenu->FillSolidRect ( rcItem, GetSysColor ( COLOR_3DFACE ));

Далее, мы рисуем вдавленую границу, чтобы эскиз выглядел в меню утопленным.

// Draw the sunken 3D border.

for ( int i = 1; i <= m_l3DBorderWidth; i++ )

{

pdcMenu->Draw3dRect ( rcDraw, GetSysColor ( COLOR_3DDKSHADOW ),

GetSysColor ( COLOR_3DHILIGHT ));

rcDraw.DeflateRect ( 1, 1 );

}

Последний шаг - нарисовать сам эскиз. Я выбрал простой путь и просто сделал вызов StretchBlt(). Результат не всегда красивый, но моей целью было сохранить простоту кода.

// Create a new DC and select the original bitmap into it.

dcBmpSrc.CreateCompatibleDC ( &dc );

dcBmpSrc.SelectObject ( &m_bmp );

// Blit the bitmap to the menu DC.

pdcMenu->StretchBlt ( rcDraw.left, rcDraw.top, rcDraw.Width(), rcDraw.Height(),

&dcBmpSrc, 0, 0, m_lBmpWidth, m_lBmpHeight, SRCCOPY );

*pResult = TRUE; // we handled the message

return S_OK;

}

Замечу, что в реальном расширении было бы хорошей идеей использовать для рисования свободный от мерцания класс, чтобы пункт меню не мерцал, когда вы перемещаете над ним мышь.

Вот несколько экранных кадров меню! Сначала - это меню в невыбраном и в выбранном состоянии.

А здесь - меню в оболочке версии 4.00. Заметьте, как в выбранном состоянии инвертируются все цвета, делая его безобразным.

Соседние файлы в папке ОСиСП - методички