Студопедия

КАТЕГОРИИ:

АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

Подстройка очертания окна под контур изображения




 

Все когда-то видели окна непрямоугольной формы. Типичным примером может служить проигрыватель музыкальных файлов WinAmp. Эта глава посвящена реализации механизма преобразования формы окна к форме битового образа хранящегося в файле ресурсов. Для того чтобы нам получить очертание окна по изображению, нам как минимум необходимо само изображение. После того как необходимое изображение подобрано, его следует добавить в файл ресурсов проекта и как-нибудь обозвать. Окно, с которым мы будем проводить операцию, следует создавать без заголовка. Во первых потому что заголовок особо и не нужен, а во вторых так просто проще реализовать задуманное. Если вам всё же требуется заголовок, который скорее всего будет обрезан, то используйте обычный стиль окна типа WS_OVERLAPPEDWINDOW или WS_BORDER и т.п. Но для компенсации высоты заголовка окна вам понадобится или найти способ получения его высоты используя размеры клиентской области и размеры окна и соответственно изменять координату Y, или вы можете использовать GetWindowDC вместо GetDC. Как создавать окна вы можете прочитать в разделе «Минимальное приложение на Win32 API».

 

В нашем случае окно будет создаваться со стилями WS_SYSMENU, WS_POPUP и WS_OVERLAPPED. При получении сообщения WM_CREATE определяем размер изображения и подгоняем размер окна под этот размер. Всё это можно проделать следующим образом:

1. Получаем контекст устройства окна, используя функцию GetDC()

2. Загружаем изображение из ресурсов используя LoadBitmap()

3. Создаем контекст устройства, совместимый с главным окном используя CreateCompatibleDC()

4. Заносим информацию об изображении в структуру BITMAP при помощи функции GetObject()

5. Ассоциируем изображение с контекстом устройства путем выбора этого изображения в контексте устройства используя SelectObject()

6. Освобождаем контекст устройства через ReleaseDC()

7. Перемещаем окно и изменяем его размер соответственно размерам изображения при помощи функции MoveWindow()

 

После того как окно было подогнано под размер изображения, требуется создать регион, соответствующий изображению. Методика создания региона состоит в следующем: Сканируя попиксельно линию пикселей определяем является ли текущий пиксель прозрачным(тот цвет который отсекается - гипотетически прозрачен, во всяком случае после создания региона и построения по нему окна, область такого цвета будет действительно прозрачной). Прозрачность определяется точкой на изображении с координатой 0,0. В принципе можно передавать тот цвет который вы называете прозрачным, а не использовать определенную координату. После встречи в сканируемой строке первого непрозрачного пикселя, начинаем отсчет количества непрозрачных пикселей до тех пор пока опять не встретится прозрачный. По координатам начала и конца отсчёта создаем прямоугольный регион высотой в одну линию и шириной от начала непрозрачной области до её конца. После создания региона, его следует комбинировать с тем регионом, по которому в дальнейшем будет строиться окно. После комбинирования регионов продолжаем сканировать линию до конца и в случае обнаружения непрозрачной области повторяем процедуру создания и комбинирования регионов. Тем же самым способом проходим по всем линиям создавая и комбинируя регионы. В конечном результате будет создан регион основанный на прозрачных и непрозрачных областях.

 

Ниже приведена реализация данного метода:

 

void ShapeForm(HWND winhandle,HDC &bmapDC,BITMAP &btmap,HRGN &retcombine, COLORREF trans)

{

int x,y,startx=0;

HRGN temp;

COLORREF tst;

//Прозрачный цвет

if(trans==NULL)

trans = GetPixel(bmapDC,0,0);

//Мы должны создать регион с которым в дальнейшем

//будем комбинировать временные регионы

retcombine=CreateRectRgn(0,0,0,0);

//Временный регион

temp = CreateRectRgn(0,0,0,0);

//Проход по высоте

for(y=0;y<=btmap.bmHeight-1;y++)

{

//Проход по ширине

for(x=0;x<=btmap.bmWidth-1;x++)

{

//Получаем пиксель в текущем местоположении

tst=GetPixel(bmapDC,x,y);

 

//Является ли пиксель прозрачным?

if(tst!=trans)

{

//Нет. Начинаем отсчитывать пиксели до очередного прозрачного

//Сохраняем текущую координату x

startx=x;

//Сканируем до первого прозрачного символа

while((x<=btmap.bmWidth)&&((GetPixel(bmapDC,x,y))!=trans))

x++;

//Откат на один пиксель назад, так как текущий символ уже прозрачен

x--;

//Создаем регион по координатам начала и конца

//непрозрачной области толщиной в одну линию

temp=CreateRectRgn(startx,y,x,y+1);

//Комбинируем регионы

CombineRgn(retcombine,retcombine,temp,RGN_OR);

}

}

}

}

Теперь основываясь на полученном регионе придаем окну такую же форму. Для этого воспользуемся функцией SetWindowRgn после чего обновим окно для его перерисовки. Ниже приведен код иллюстрирующий всё вышеописанное:

 

case WM_CREATE:

//Создаем очертание окна

//Получаем контекст устройства окна для создания совместимого контекста

hdc=GetDC(hWnd);

// Загружаем изображение

iface = LoadBitmap((HINSTANCE)GetWindowLong(hWnd,GWL_HINSTANCE),

MAKEINTRESOURCE(IDB_SHAPEBITMAP));

//Создаем контекст устройства совместимый с главным окном

ifaceDC = CreateCompatibleDC(hdc);

//Получаем данные изображения и помещаем в переменную BITMAP

GetObject(iface,sizeof(bmap),&bmap);

//Выбираем изображение в контекст устройства

SelectObject(ifaceDC,iface);

//освобождаем контекст устройства

ReleaseDC(hWnd,hdc);

//Подгоняем размер окна под размер изображения

MoveWindow(hWnd,60,60,bmap.bmWidth,bmap.bmHeight,true);

//Посылаем сообщение WM_PAINT для обновления окна

UpdateWindow(hWnd);

//Формируем очертания окна. Передаем дескриптор будущего региона

//функция изменит его, и по этому региону мы сформируем новое

//очертание окна

ShapeForm(hWnd,ifaceDC,bmap,combine,NULL);

//Устанавливаем регион окну

SetWindowRgn(hWnd,combine,true);

// Отображаем окно

ShowWindow(hWnd,SW_SHOW);

//Обновляем окно

UpdateWindow(hWnd);

break;

Но и этого пока мало. Нам ведь не требуется невразумительное окошко с дыркой посередине? Не требуется. По этому надо на окно натянуть то изображение, по которому и строилось очертание окна. Проделывается это элементарно. Просто при обработке сообщения WM_PAINT вызываем функцию BitBlt и копируем изображение с одного контекста устройства(его мы создали при создании окна и загрузке изображения)в текущий контекст устройства.

 

case WM_PAINT:

hdc = BeginPaint(hWnd,&ps);

//Здесь мы просто перерисовываем изображение на окне.

//Хотя окно и приняло очертание изображения, это не означает что

//и выглядеть оно начало также

BitBlt(hdc,0,0,bmap.bmWidth,bmap.bmHeight,ifaceDC,0,0,SRCCOPY);

EndPaint(hWnd,&ps);

break;

 

Как корректно завершить приложение с графическим интерфейсом из него самого

Надо послать главному окну приложения сообщение WM_CLOSE из любого места программы (по крайней мере из класса вид я проверял):

AfxGetMainWnd()->PostMessage(WM_CLOSE);

 

Например, можно научить приложение закрываться по нажатию клавиши Escape. Для этого создайте обработчик события WM_CHAR:










Последнее изменение этой страницы: 2018-04-12; просмотров: 360.

stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда...