электроника & программирование музыкальные устройства на микроконтроллерах

К оглавлению

Создание нестандартных окон в Windows

Третий способ создания круглого окна или круглое окно c четырьмя областями

RndWnd3

Создадим круглое окно c четырьмя областями, используя редактор ресурсов RCE и технологию Broken Window (ломаное окно). Для этого в редакторе ресурсов RCE создадим ресурс ломаного окна, содержащий четыре области (Рис.1). Также для успешной генерации проекта Broken Window необходимо добавить в ресурсы таблицу акселераторов и строку с заголовком главного окна.

Далее сгенерируем проект Broken Window, используя команду Проект->Генератор кода->Проект Broken Window в меню редактора ресурсов RCE (Рис.2).

Сгенерированные файлы будут помещены в указанную при генерации проекта папку (в нашем случае RndWnd3).

Наиболее важные файлы проекта:

Папка BrokenWindow - cодержит набор классов BrokenWindow
BWMainWnd.h, BWMainWnd.cpp - класс ломаного окна (главного окна)
RndWnd.cpp - точка входа в программу
BWLDArea.h, BWLDArea.cpp
BWLUArea.h, BWLUArea.cpp
BWRDArea.h, BWRDArea.cpp
BWRUArea.h, BWRUArea.cpp
- классы областей ломанного окна

Создадим в Visual Studio проект Win32, удалим из него все файлы по умолчанию и включим сгенерированные из папки RndWnd3 (Рис.3).

При этом в свойствах файла stdafx.cpp необходимо изменить параметр "Создавать или использовать предварительно скомпилированный заголовочный файл" на "Создавать предварительно скомпилированные заголовки (/Yc)" (Рис.4).

Скомпилируем проект и запустим полученное приложение. На экране должен появиться черный квадрат, который можно перемещать мышкой. Для закрытия приложения используйте сочетание клавиш Alt+F4.

Добавим меню в приложение. Для этого в класс главного окна добавим переменную m_hMainMenu - дескриптор главного меню, а также обработчики событий: CreateEvent - создание окна, ContextMenuEvent - вывод контекстного меню, CommandEvent - команды меню. В обработчике CreateEvent создадим меню, в обработчике ContextMenuEvent выведем меню, а в обработчике DestroyEvent (уже имеется в классе главного окна) удалим меню. В CommandEvent организуем обработку команд меню. Также добавим функцию диалогового окна About для диалога "О программе", который будет вызываться одной из команд меню.

BWMainWnd.h

 class CBWMainWnd : public CBrokenWinCore
 {
 public:
   CBWMainWnd(void);
   ...

   DECLARE_BWAREA_MAP()

   // События
 protected:
   virtual int CreateEvent(HWND hBrkWin, LPCREATESTRUCT lpCS);
   virtual void DestroyEvent();
   virtual void CloseEvent();
   virtual void ContextMenuEvent(UINT xPos, UINT yPos);
   virtual void CommandEvent(int id, HWND hwndCtl, UINT codeNotify);

   // Данные
 private:
   HMENU m_hMainMenu;   // Главное меню
 };

BWMainWnd.cpp

 // Обработчик сообщений для окна "О программе".
 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
 {
   UNREFERENCED_PARAMETER(lParam);
   switch (message)
   {
      case WM_INITDIALOG:
         return (INT_PTR)TRUE;

      case WM_COMMAND:
          if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
         {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
         }
         break;
   }
   return (INT_PTR)FALSE;
 }

 // Конструктор
 CBWMainWnd::CBWMainWnd(void)
 {
   m_hMainMenu = NULL;
 }

 // Создание главного окна
 int CBWMainWnd::CreateEvent(HWND hBrkWin, LPCREATESTRUCT lpCS)
 {
   // Загрузить главное меню
   m_hMainMenu = ::LoadMenu(g_hInstance, MAKEINTRESOURCE(IDC_RNDWND));

   return 0;
 }

 // Удаление главного окна
 void CBWMainWnd::DestroyEvent()
 {
   // Удалить главное меню
   if (m_hMainMenu != NULL)
   {
      ::DestroyMenu(m_hMainMenu);
      m_hMainMenu = NULL;
   }
   // Выход из приложения
   PostQuitMessage(0);
 }

 // Вывод контекстного меню
 void CBWMainWnd::ContextMenuEvent(UINT xPos, UINT yPos)
 {
   // Вывести меню
   ::TrackPopupMenuEx(::GetSubMenu(m_hMainMenu, 0), TPM_LEFTALIGN | TPM_TOPALIGN, xPos, yPos, m_hWnd, NULL);
 }

 // Обработка команды
 void CBWMainWnd::CommandEvent(int id, HWND hwndCtl, UINT codeNotify)
 {
   switch (id)
   {
   case IDM_ABOUT:
      DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_ABOUTBOX), m_hWnd, About);
      break;
   case IDM_EXIT:
      // Уничтожить главное окно
      ::DestroyWindow(m_hWnd);
      break;
   }
 }

Теперь, если щелкнуть на окне приложения правой кнопкой мыши, то будет выведено меню.

Перейдём к прорисовке областей ломаного окна. Для начала очистим фон главного окна. Для этого добавим в класс главного окна событие прорисовки.

BWMainWnd.h

 class CBWMainWnd : public CBrokenWinCore
 {
 public:
   CBWMainWnd(void);
   ...

   DECLARE_BWAREA_MAP()

   // События
 protected:
   ...
   virtual void DrawEvent(HDC hDC);
   ...
 };

BWMainWnd.cpp

 // Прорисовка главного окна
 void CBWMainWnd::DrawEvent(HDC hDC)
 {
   Graphics graph(hDC);

   // Получить размер главного окна
   RECT ClRect;
   ::GetClientRect(m_hWnd, &ClRect);

   // Очистить фон
   Color BkColor;
   BkColor.SetFromCOLORREF(TRANSPARENT_COLOR);
   SolidBrush brush(BkColor);
   graph.FillRectangle(&brush, 0, 0, ClRect.right, ClRect.bottom);
 }

Добавим в класс главного окна переменную m_AreaState, определяющую состояние областей ломаного окна, а также методы для получения/установки данной переменной.

BWMainWnd.h

 enum AREA_STATE
 {
   NONE,
   LEFT_UP,
   RIGHT_UP,
   LEFT_DOWN,
   RIGHT_DOWN
 };

 class CBWMainWnd : public CBrokenWinCore
 {
 public:
   CBWMainWnd(void);
   ...

   // Методы
 public:
   AREA_STATE GetAreaState();
   void SetAreaState(AREA_STATE State);

   // Данные
 private:
   AREA_STATE m_AreaState;   // Состояние областей главного окна
   ...
 };

BWMainWnd.cpp

 // Конструктор
 CBWMainWnd::CBWMainWnd(void)
 {
   ...
   m_AreaState = NONE;
 }

 // Получить состояние областей главного окна
 AREA_STATE CBWMainWnd::GetAreaState()
 {
   return m_AreaState;
 }

 // Установить состояние областей главного окна
 void CBWMainWnd::SetAreaState(AREA_STATE State)
 {
   m_AreaState = State;
 }

Прорисуем одну из областей ломаного окна, например, левую нижнюю (класс CBWLDArea). Для этого добавим в класс CBWLDArea переменную m_pPath, в которой будет храниться контур области, а также обработчики событий: InitEvent - инициализация области, DeInitEvent - деинициализация области, DrawEvent - прорисовка области. В обработчике InitEvent создадим контур области, который потом будет закрашиваться в обработчике DrawEvent. В обработчике DeInitEvent произведём освобождение всех задействованных ресурсов.

BWLDArea.h

 class CBWLDArea : public CBrkWinArea
 {
 public:
   CBWLDArea(WORD AreaID, POINT AreaPos, SIZE AreaSize, CBrokenWinCore* pBrokenWin);
   ...

   // События
 protected:
   virtual void InitEvent();
   virtual void DeInitEvent();
   virtual void DrawEvent(HDC hDC);

   // Данные
   GraphicsPath* m_pPath;   // Контур области
 };

BWLDArea.cpp

 // Конструктор
 CBWLDArea::CBWLDArea(WORD AreaID, POINT AreaPos, SIZE AreaSize, CBrokenWinCore* pBrokenWin)
 : CBrkWinArea(AreaID,AreaPos,AreaSize,pBrokenWin)
 {
   m_pPath = NULL;
 }

 // Инициализация области
 void CBWLDArea::InitEvent()
 {
   // Вычислить параметры области
   Rect AreaRect(0, -m_Size.cy, 2 * m_Size.cx, 2 * m_Size.cy);

   // Создать контур области
   m_pPath = new GraphicsPath();
   m_pPath->AddArc(AreaRect, 90, 90);
   m_pPath->AddLine(0, 0, m_Size.cx - 1, 0);
   m_pPath->CloseFigure();
 }

 // Деинициализация области
 void CBWLDArea::DeInitEvent()
 {
   // Удалить контур
   if (m_pPath != NULL)
   {
      delete m_pPath;
      m_pPath = NULL;
   }
 }

 // Прорисовка области
 void CBWLDArea::DrawEvent(HDC hDC)
 {
   Graphics graph(hDC);

   // Получить главное окно
   CBWMainWnd* pMainWnd = (CBWMainWnd*)m_pBrokenWin;
   _ASSERT(pMainWnd != NULL);

   // Получить состояние областей главного окна
   AREA_STATE AreaState = pMainWnd->GetAreaState();

   SolidBrush LeftPathBrush(Color(200, 0, 200));
   if (AreaState == LEFT_DOWN)
      LeftPathBrush.SetColor(Color(255, 0, 255));
   graph.FillPath(&LeftPathBrush, m_pPath);
 }

Добавим реагирование области на вход курсора в её пределы. Для этого добавим MouseInArea - обработчик события входа курсора в область и MouseOutArea - обработчик события выхода курсора из области.

BWLDArea.h

 class CBWLDArea : public CBrkWinArea
 {
 public:
   CBWLDArea(WORD AreaID, POINT AreaPos, SIZE AreaSize, CBrokenWinCore* pBrokenWin);
   ...

   // События
 protected:
   ...
   virtual void MouseInArea(POINT point);
   virtual void MouseOutArea();

   // Данные
   ...
 };

BWLDArea.cpp

 // Мышь вошла в область
 void CBWLDArea::MouseInArea(POINT point)
 {
   // Получить главное окно
   CBWMainWnd* pMainWnd = (CBWMainWnd*)m_pBrokenWin;
   _ASSERT(pMainWnd != NULL);

   pMainWnd->SetAreaState(LEFT_DOWN);
   pMainWnd->ReDrawBW();
 }

 // Мышь вышла из области
 void CBWLDArea::MouseOutArea()
 {
   // Получить главное окно
   CBWMainWnd* pMainWnd = (CBWMainWnd*)m_pBrokenWin;
   _ASSERT(pMainWnd != NULL);

   pMainWnd->SetAreaState(NONE);
   pMainWnd->ReDrawBW();
 }

Прорисовка остальных областей осуществляется аналогичным образом.

Исходный код примера

Полный исходный код примера можно загрузить здесь

К оглавлению

Комментарий:

© 2023, Burov Michael