Программирование на C++ глазами хакера


Нестандартные окна


Еще в 1995 году почти все окна были прямоугольными, и всех это устраивало. Но несколько лет назад начался самый настоящий бум на создание окон неправильной формы. Любой хороший программист считает своим долгом сделать свое окно непрямоугольной формы, чтобы его программа явно выделялась среди всех конкурентов.

Лично я против нестандартных окон, и использую их очень редко. Об этом мы уже говорили в начале книги, но я напоминаю, потому что этот вопрос очень важен для любого коммерческого продукта. Но иногда сталкиваешься с ситуацией, когда необходимо сделать окно красивым и произвольной формы. Да и специфика рассматриваемых в книге примеров позволяет использовать воображение, как угодно. Поэтому мы просто обязаны рассмотреть данную тему очень подробно.

Для начала попробуем создать окно овальной формы. Создайте новый проект Win32 Project и подкорректируйте функцию InitInstance в соответствии с листингом 3.3. Код, который вам надо добавить, выделен комментариями.

Листинг 3.3. Создание окна овальной формы
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd;

hInst = hInstance; // Store instance handle in our global variable

hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

if (!hWnd) { return FALSE; }

// Начало кода, который надо добавить HRGN FormRgn, RectRgn; RECT WRct; GetWindowRect(hWnd, WRct); FormRgn=CreateEllipticRgn(0,0,WRct.right-WRct.left,WRct.bottom-WRct.top);

RectRgn=CreateRectRgn(100, 100, WRct.right-WRct.left-100,WRct.bottom-WRct.top-100); CombineRgn(FormRgn,FormRgn,RectRgn,RGN_DIFF); SetWindowRgn(hWnd, FormRgn, TRUE); // Конец кода



ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd);

return TRUE; }

Первым делом надо объявить две переменные:

FormRgn типа HRGN — используется для хранения регионов, которые описывают внешний вид окна;

WRect типа RECT — для хранения размеров и положения окна, чтобы знать область, по которой строить овал.

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


HRGN CreateEllipticRgn( int nLeftRect, // х - координата левого верхнего угла int nTopRect, // у - координата левого верхнего угла int nRightRect, // х - координата правого нижнего угла int nBottomRect // у - координата правого нижнего угла );

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

int SetWindowRgn( HWND hWnd, // Указатель на окно HRGN hRgn, // Предварительно созданный регион BOOL bRedraw // Флаг перерисовки окна );

Эта функция назначает указанному в качестве первого параметра окну созданный регион, который передается во втором параметре. Если последний параметр (флаг) равен TRUE, то окно после назначения нового региона будет перерисовано, иначе это придется сделать в явном виде самостоятельно. В предложенном коде после установки региона есть вызов функции UpdateWindow, которая перерисовывает окно, поэтому последний параметр можно было бы установить и в FALSE.

Запустите приложение, и вы увидите окно овальной формы ( 3.3).

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

HRGN FormRgn, RectRgn; RECT WRct; GetwindowRect(hWnd, WRct); FormRgn=CreateEllipticRgn(0,0,WRct.right-WRct.left,WRct.bottom-WRct.top);

RectRgn=CreateRectRgn(100, 100, WRct.right-WRct.left-100, WRct.bottom-WRct.top-100); CombineRgn(FormRgn,FormRgn,RectRgn,RGN_DIFF); SetWindowRgn(hWnd, FormRgn, TRUE);



3.3. Окно овальной формы

Здесь объявлены две переменные типа HRGN. В первой (FormRng) создается овальный регион функцией CreateEllipticRgn, а во второй — прямоугольный с помощью функции CreateRectRgn. Для функции CreateRectRgn так же как и при создании овального региона указываются четыре координаты, задающие размер прямоугольника. Результат сохраняется в переменной RectRng.

После создания двух областей они объединяются с помощью функции CombineRng:

int CombineRgn( HRGN hrgnDest, // Указатель на результирующий регион HRGN hrgnSrc1, // Указатель на первый регион HRGN hrgnSrc2, // Указатель на второй регион int fnCombineMode // Метод комбинирования );



Эта функция комбинирует два региона hrgnSrc1 и hrgnSrc2 и помещает результат в переменную HrgnDest.

В функции необходимо задать режим слияния (переменная fnCombineMode). Можно указать один из следующих вариантов:

RGN_AND — объединить два региона (область перекрывания);

RGN_COPY — копировать (копия первой области);

RGN_DIFF — объединить разницей (удаление второй области из первой);

RGN_OR — объединить области;

RGN_XOR — объединить области, исключая все пересечения.

Результат работы программы вы можете увидеть на 3.4.



3.4. Овальное окно с прямоугольным отверстием в центре

Примечание
Исходный код этого примера вы можете найти в каталоге \Demo\Chapter3\NoneUniformWindow.
Изменять форму можно не только у окон, но и у некоторых элементов управления. Давайте рассмотрим, как это делается.

Создайте новый проект типа MFC Application. Нам сейчас не понадобится минимальный код, поэтому для упрощения воспользуемся объектной библиотекой MFC.

В Мастере создания проекта откройте раздел Application Type и выберите тип приложения Dialog based ( 3.5). Остальные настройки можно не менять. Я дал проекту имя None.

Откройте файл ресурсов и в разделе DIALOG дважды щелкните по пункту IDD_NONE_DIALOG. Поместите на форму ( 3.6) один компонент List Control.

Теперь, чтобы с этим элементом управления можно было работать, щелкните по нему правой кнопкой мыши и выберите в появившемся меню пункт Add Variable.... В открывшемся окне достаточно ввести имя переменной в поле Variable name. Укажите имя ItemsList ( 3.7). Нажмите кнопку Finish, чтобы завершить создание переменной.



З.5. Выбор типа приложения в окне Мастера создания проекта



З.6. Форма будущей программы None



З.7. Окно создания переменной для элементов управления



3.8. Результат работы программы None

Откройте файл NoneDlg.cpp и найдите здесь функцию CNoneDlg::OnInitDialog(). В самый конец функции, где написан комментарий // TODO: Add extra initialization here, добавьте следующий код:



// TODO: Add extra initialization here RECT WRct; HRGN FormRgn; ::GetWindowRect(ItemsList, WRct); FormRgn=CreateEllipticRgn(0,0,WRct.right-WRct.left,WRct.bottom-WRct.top); ::SetWindowRgn(ItemsList, FormRgn, TRUE);

Здесь выполняется уже знакомый код, только вместо указателя на окно используется переменная элемента управления List Control. Перед функциями GetWindowRect и SetWindowRect стоит знак "::", который указывает на необходимость использования этих функций из набора WinAPI, а не MFC.

Примечание
Исходный код этого примера вы можете найти на компакт - диске в каталоге \Demo\Chapter3\None.

Содержание раздела