Большинство настольных графических приложений в MS Windows строятся на базе стандартных прямоугольных окон. Но Win32 API обладает средствами, которые способны превратить стандартное прямоугольное окно в нестандартное. Форма и функциональность такого окна будет зависеть только от фантазии разработчика. В данном разделе рассматривается пример создания круглого окна. Будет использоваться среда разработки Visual Studio.
Первое, что нужно сделать - это создать проект Win32 в Visual Studio. Для запуска мастера создания проектов выполняем команду
. В мастере выбираем тип проекта , задаем имя проекта и следуем дальнейшим указаниям. В результате работы мастера будут созданы начальные файлы проекта Win32.Зададим диаметр окна равным 100 пикселям. Для этого в файле RndWnd1.cpp определим константу:
#define MAIN_WIN_SIZE 100
Обычно стандартное главное окно приложения имеет строку заголовка, границу, системное меню, кнопку минимизации, кнопку максимизации, а также строку меню. В круглом окне придется отказаться от этих элементов, так как они будут обрезаны. Для отключения строки заголовка, границы, системного меню, кнопки минимизации и кнопки максимизации определим стиль главного окна как
. Для этого внесем изменения в сгенерированный мастером код функции в файле RndWnd1.cpp:hWnd = CreateWindow(szWindowClass, szTitle, WS_POPUP, 10, 10, MAIN_WIN_SIZE, MAIN_WIN_SIZE, NULL, NULL, hInstance, NULL);
Для отключения строки меню необходимо указать, что класс главного окна не содержит меню. Внесём изменения в сгенерированный мастером код функции
в файле RndWnd1.cpp:wcex.lpszMenuName = NULL;
В результате будет создано прямоугольное окно, не имеющее заголовка, границы, системного меню, кнопки минимизации, кнопки максимизации и строки меню. Чтобы сделать его круглым, необходимо установить круглый регион для окна. Для создания круглого региона в функции
после кода, создающего окно, добавим следующую строку:HRGN hMainWndRgn = CreateEllipticRgn(0, 0, MAIN_WIN_SIZE, MAIN_WIN_SIZE);
Теперь необходимо сделать созданный регион регионом главного окна. Для этого после создания региона добавим ешё одну строку кода:
SetWindowRgn(hWnd, hMainWndRgn, FALSE);
Теперь при запуске приложения будет выведено круглое окно. Но так как это окно не имеет никаких элементов управления, то и никакие операции с ним невозможны. Можно только его закрыть, нажав Alt+F4.
Для того, чтобы программа могла выполнять какие-то команды, добавим вывод контекстного меню при щелчке правой кнопки мыши в области главного окна. Для этого в файле RndWnd1.cpp объявим глобальную переменную, которая будет хранить дескриптор меню:
HMENU hMainMenu = NULL;
В функции
загрузим меню из ресурсов программы:hMainMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDC_RNDWND1));
При щелчке правой кнопки мыши оконная процедура получает сообщение
. Нам нужно, чтобы обработчик этого сообщения содержал код, который будет выводить меню. Для этого в оконную процедуру главного окна вставим следующий фрагмент:
case WM_CONTEXTMENU:
{
// Получить позицию мыши
int xPos = GET_X_LPARAM(lParam);
int yPos = GET_Y_LPARAM(lParam);
// Вывести меню
TrackPopupMenuEx(GetSubMenu(hMainMenu, 0),
TPM_LEFTALIGN | TPM_TOPALIGN, xPos, yPos, hWnd, NULL);
}
return 0;
В данном фрагменте функция
выводит в позиции курсора подменю пункта 0 меню hMainMenu. Нужно отредактировать ресурс меню в редакторе ресурсов, чтобы подменю пункта 0 содержало необходимые нам команды.Необходимо добавить возможность перемещения окна на экране. Сделаем, чтобы окно перемещалось при помощи левой кнопки мыши при нахождении курсора в любой области окна. Для этого необходимо обработать три сообщения от мыши и использовать механизм захвата мыши окном. Для начала объявим две статические локальные переменные в оконной процедуре
. Эти переменные буду содержать координаты захвата мыши:
static int iMouseCapture_xPos;
static int iMouseCapture_yPos;
Первое сообщение, которое мы должны обработать, это
. Оно посылается оконной процедуре при нажатии на левую кнопку мыши. Добавим обработчик данного сообщения в оконную процедуру:
case WM_LBUTTONDOWN:
{
// Получить позицию мыши
int xPos = GET_X_LPARAM(lParam);
int yPos = GET_Y_LPARAM(lParam);
// Захватить мышь
iMouseCapture_xPos = xPos;
iMouseCapture_yPos = yPos;
SetCapture(hWnd);
}
return 0;
В обработчике
Следующее сообщение, которое нам нужно обработать - это
. Оно передается при
перемещении курсора на экране. Вставим следующий фрагмент в оконную
процедуру для обработки этого сообщения:
case WM_MOUSEMOVE:
if (GetCapture() == hWnd)
{// Мышь захвачена
// Получить позицию мыши
int xPos = GET_X_LPARAM(lParam);
int yPos = GET_Y_LPARAM(lParam);
// Переместить окно
RECT WndRect;
GetWindowRect(hWnd, &WndRect);
int iOffset_xPos = xPos - iMouseCapture_xPos;
int iOffset_yPos = yPos - iMouseCapture_yPos;
SetWindowPos(hWnd, NULL, WndRect.left + iOffset_xPos,
WndRect.top + iOffset_yPos, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
}
return 0;
Сначала обработчик выполняет проверку на захват мыши окном. Если
захвата нет (не было нажатия на левую кнопку мыши в области окна), то обработчик
ничего не делает. Если захват есть, то обработчик перемещает окно на
экране при помощи функции
Последнее сообщение, которое нам необходимо обработать - это
. Данное сообщение посылается
оконной процедуре при отпускании левой кнопки мыши. Поместим следующий код в
оконную процедуру для обработки этого сообщения:
case WM_LBUTTONUP:
if (GetCapture() == hWnd)
{// Мышь захвачена
// Освободить мышь
ReleaseCapture();
}
return 0;
Обработчик проверяет захвачена ли мышь окном. Если мышь захвачена, то выполняется освобождение мыши.
Полный исходный код примера можно загрузить здесь