четверг, 29 апреля 2010 г.

Создание "слоеных" окон

Определенная часть GUI-разработчиков избалована готовыми фреймворками типа альфа-скинов и занимается "украшательствами" без разбору и оглядки на размеры своих приложений. Безусловно пользователь по-прежнему встречает по одежке. Но в итоге, примитивное приложение весит как Маткад. А ведь достаточно заглянуть в основы API чуть глубже и обойтись несколькими нативными функциями. К примеру, столь любимые окна с полупрозрачностью или слоеные окна. Начнем с того, что есть "слоеное" (layered) окно. Это окно, к которому особым образом применены свойства прозрачности. Как говорится в великом MSDN: "They include an alpha-blended cursor with a shadow, new transition effects including menu and ToolTip fade-in, menu selection fade-out, and an alpha-blended image drag in the shell. All of these effects were implemented by using the new functionality that Windows 2000 introduces, called layered windows". Что же это может дать нам? Прежде всего появляется возможность создавать: окна с любым коэффициентом прозрачности (плавное появление, угасание, анимация), окна с абсолютной прозрачностью для определенного цвета (формы нестандартной формы, "дырки"), окна с комбинированной прозрачностью.

Итак, попробуем же и мы сделать себе такое окно  (для удобства используем следующие структуры):
TApplication = Record                                                                              // Application.
  Handle     : HWND;                                                                                // Handle of application.
  Msg        : TMSG;                                                                                // Message for handler.
  WinClass   : TWndClass;                                                                           // Attributes of application.
 End;


Application.Handle := GetModuleHandle(Nil);                                                     // Creating App handle.
      FillChar(Application.WinClass, SizeOf(Application.WinClass), 0);
    With Application.WinClass Do                                                                    // Set up App properties.
    Begin
     Style         := CS_HREDRAW Or CS_VREDRAW;                                                     // Set style.
     hIcon         := LoadIcon(Application.Handle, PAnsiChar(APP_MAINICON));                        // Set icon.
     lpfnWndProc   := _AppHandler;                                                                  // Set handler
     hInstance     := Application.Handle;                                                           // Set main handle.
     hbrBackground := COLOR_BTNFACE + 1;                                                            // Set brush background.
     lpszClassName := PAnsiChar('GrayFurAppClass');                                                 // Set class name.
     hCursor       := LoadCursor(0, IDC_ARROW);                                                     // Set cursor.
    End;
    InitCommonControls;                                                                             // Initialize controls.
    RegisterClass(Application.WinClass);
Здесь мы создали приложение и зарегистрировали его в системе. Физически мы создали для наших форм "предка".
FormHandle :=                                                                   // Create form handle.
   CreateWindowEx(0, Application.WinClass.lpszClassName, '',                                        // Set class name and caption.
                  WS_POPUP,                                                                         // Set style.
                  Left,                                 // Set left.
                  Top,                                  // Set top.
                  Width,                                // Set width.
                  Height,                               // Set height.
                  0, 0, Application.Handle, Nil);                                                   // Set parent.

  FormHandle :=                                                             // Create image handle.
   CreateWindow(APP_STATIC, '',                                                                     // Create TImage control.
                WS_CHILD Or SS_BITMAP Or WS_VISIBLE,                                                // Styles of control.
                0,                                                                                  // Set left.
                0,                                                                                  // Set top.
                Width,                                  // Set width.
                Height,                                 // Set height.
                FormHandle,                                                       // Set parent handle.
                0, Application.Handle, Nil);   
                                                    // Set main parent handle.
  SetClassLong(FormHandle, GCL_HBRBACKGROUND, CreateSolidBrush(APP_COLOR));       // Set background form color.
  SetWindowLong(Warehouse.FormHandle,                                                       // Set window attributes.
                GWL_EXSTYLE,                                                                        // Style.
                GetWindowLong(FormHandle, GWL_EXSTYLE) Or WS_EX_LAYERED);         // Get old style + layered style.

  SetLayeredWindowAttributes(FormHandle,                                          // Handle of form.
                             0,                                                                     // Color.
                             255,                                                                   // Alpha blend value.
                             LWA_ALPHA);
Именно последнее действие и определяет свойства, которые мы присваиваем окну. Присвоим полную непрозрачность:
SetLayeredWindowAttributes(FormHandle,                                          // Handle of form.
                             0,                                                                     // Color.
                             255,                                                                   // Alpha blend value.
                             LWA_ALPHA);
А теперь полупрозрачность:
SetLayeredWindowAttributes(FormHandle,                                          // Handle of form.
                             0,                                                                     // Color.
                             128,                                                                   // Alpha blend value.
                             LWA_ALPHA);
Реализуем абсолютную прозрачность для конкретного цвета:
SetLayeredWindowAttributes(FormHandle,                                          // Handle of form.
                             $FF00FF,                                                                     // Color.
                             0,                                                                   // Alpha blend value.
                             LWA_COLORKEY);
Дадим половинную прозрачность всей форме и вырежем конкретный цвет:
SetLayeredWindowAttributes(FormHandle,                                          // Handle of form.
                             $FF0000,                                                                     // Color.
                             128,                                                                   // Alpha blend value.
                             LWA_ALPHA Or LWA_COLORKEY);
Включим стиль "слоеное окно" в свойства:
SetWindowLong(Warehouse.FormHandle,                                                       // Set window attributes.
                GWL_EXSTYLE,                                                                        // Style.
                GetWindowLong(FormHandle, GWL_EXSTYLE) Or WS_EX_LAYERED);
Наглядный пример данных действий:


Материал с ресурса журнала "ПРОграммист"
авторы: Шишкин Алексей и Сергей Бадло

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

Отправить комментарий

В комментариях уважайте собеседника, внимательно читайте посты и не додумывайте. Просьбы и предложения из разряда: «можно ваш Skype/Viber/телефон», «напишите мне в vk/FB», а также другие им подобные — игнорируются. Выход новых версий ПО, внешняя ссылка, переставшая работать с течением времени и т.п. не является основанием для претензий. Желающие спокойно подискутировать и высказаться — Welcome. Желающие спонсировать блог — Donate. Нарушение этих простых правил ведет к бану и удалению комментариев без предупреждения.