![]() Студопедия КАТЕГОРИИ: АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Подстройка очертания окна под контур изображения
Все когда-то видели окна непрямоугольной формы. Типичным примером может служить проигрыватель музыкальных файлов 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; просмотров: 434. stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда... |