Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Графический интерфейс GDI в Microsoft Windows

© Александр Фролов, Григорий Фролов
Том 14, М.: Диалог-МИФИ, 1993, 288 стр.

[Назад] [Содеожание] [Дальше]

3.3. Приложение GETCOLOR

Приложение GETCOLOR демонстрирует использование системных цветов и только что описанной функции ChooseColor. Оно также обрабатывает сообщение WM_SYSCOLORCHANGE.

В окне приложения (рис. 3.5) во время обработки сообщения WM_PAINT рисуется прямоугольник (при помощи специально созданной кисти и пера). Для цвета фона и кисти используются системные цвета. Для выбора цвета пера следует щелкнуть мышью в окне приложения, при этом будет вызвана функция ChooseColor.

Рис. 3.5. Главное окно приложения GETCOLOR

Экспериментируя с приложением GETCOLOR, попробуйте изменить системные цвета при помощи приложения Control Panel. Вы увидите, что после выполнения изменений изменится цвет фона окна и цвет, которым закрашена внутренняя область прямоугольника (этот цвет совпадает с цветом заголовка окна). Цвет рамки не зависит от системных цветов и устанавливается при помощи диалоговой панели.

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

Так как функция ChooseColor не поддерживает работу с цветовыми палитрами, в режиме со средним цветовым разрешением (256 цветов) вам будет доступен тот же самый набор цветов, что и в режиме с низким цветовым разрешением.

Если у вас есть такая возможность, запустите приложение GETCOLOR в режиме высокого цветового разрешения True Color. Убедитесь, что в этом случае вы можете выбрать для пера любой цвет. Все цвета будут чистыми, так как в этом режиме смешанные цвета не используются.

Исходный текст приложения приведен в листинге 3.1.


Листинг 3.1. Файл getcolor/getcolor.cpp


// ----------------------------------------
// Приложение GETCOLOR
// Выбор цвета, работа с системными цветами
// ----------------------------------------

#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <commdlg.h>
#include <mem.h>

// Прототипы функций
BOOL InitApp(HINSTANCE);
LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);
BOOL GetPenColor(HWND, COLORREF *);

// Имя класса окна
char const szClassName[]   = "GetColorClass";

// Заголовок окна
char const szWindowTitle[] = "Get Color";

// Идентификатор копии приложения
HINSTANCE hInst;

// Идентификаторы кистей и перьев
HBRUSH hbrush, hbrushOldBrush;
HPEN hpen, hpenOldPen;

// =====================================
// Функция WinMain
// =====================================
#pragma argsused

int PASCAL
WinMain(HINSTANCE hInstance, 
        HINSTANCE hPrevInstance,
        LPSTR     lpszCmdLine, 
        int       nCmdShow)
{
  MSG  msg;   // структура для работы с сообщениями
  HWND hwnd;  // идентификатор главного окна приложения

  // Инициализируем приложение
  if(!InitApp(hInstance))
      return FALSE;

  // Сохраняем идентификатор копии приложения
  hInst = hInstance;

  // Создаем главное окно приложения
  hwnd = CreateWindow(
    szClassName,         // имя класса окна
    szWindowTitle,       // заголовок окна
    WS_OVERLAPPEDWINDOW, // стиль окна
    CW_USEDEFAULT,       // задаем размеры и расположение
    CW_USEDEFAULT,       // окна, принятые по умолчанию
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    0, 0, hInstance, NULL);      
                       
  // Если создать окно не удалось, завершаем приложение
  if(!hwnd)
    return FALSE;

  // Рисуем главное окно
  ShowWindow(hwnd, nCmdShow);
  UpdateWindow(hwnd);

  // Запускаем цикл обработки сообщений
  while(GetMessage(&msg, 0, 0, 0))
  {
    DispatchMessage(&msg);
  }
  return msg.wParam;
}

// =====================================
// Функция InitApp
// Выполняет регистрацию класса окна
// =====================================

BOOL
InitApp(HINSTANCE hInstance)
{
  ATOM aWndClass; // атом для кода возврата
  WNDCLASS wc;    // структура для регистрации
                  // класса окна
  // Записываем во все поля структуры нулевые значения
  memset(&wc, 0, sizeof(wc));

  // Устанавливаем системный цвет для фона окна
  wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);

  wc.lpszMenuName  = NULL;
  wc.style         = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc   = (WNDPROC) WndProc;
  wc.cbClsExtra    = 0;
  wc.cbWndExtra    = 0;
  wc.hInstance     = hInstance;
  wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
  wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wc.lpszClassName = (LPSTR)szClassName;

  // Регистрация класса
  aWndClass = RegisterClass(&wc);

  return (aWndClass != 0);
}

// =====================================
// Функция WndProc
// =====================================

LRESULT CALLBACK _export
WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  HDC hdc;
  PAINTSTRUCT ps;

  switch (msg)
  {
    case WM_CREATE:
    {
      // Создаем кисть и перо для рисования прямоугольника
      hbrush =
        CreateSolidBrush(GetSysColor(COLOR_ACTIVECAPTION));
      hpen  = CreatePen(PS_SOLID, 10, RGB(0,0,0));
      return 0;
    }

    case WM_SYSCOLORCHANGE:
    {
      // Если кисть была создана, удаляем ее
      // и затем создаем заново
      if(hbrush)
      {
        DeleteBrush(hbrush);
        hbrush =
          CreateSolidBrush(GetSysColor(COLOR_ACTIVECAPTION));
      }
      return 0;
    }

    // Рисование в окне
    case WM_PAINT:
    {
      RECT rc;

      // Получаем контекст отображения для
      // рисования во внутренней области окна 
      hdc = BeginPaint(hwnd, &ps);

      // Выбираем новую кисть и новое перо
      hbrushOldBrush = SelectBrush(hdc, hbrush);
      hpenOldPen = SelectPen(hdc, hpen);

      // Рисуем прямоугольник
      Rectangle(hdc, 10, 20, 300, 50);

      // Выбираем старую кисть и старое перо
      SelectBrush(hdc, hbrushOldBrush);
      SelectPen(hdc, hpenOldPen);

      // Освобождаем контекст отображения
      EndPaint(hwnd, &ps);
      return 0;
    }

    case WM_LBUTTONDOWN:
    {
      COLORREF clrref;

      // Выбираем новый цвет для пера
      if(GetPenColor(hwnd, &clrref))
      {
        // Если выбрали новый цвет, удаляем перо,
        // а затем создаем новое
        DeletePen(hpen);
        hpen  = CreatePen(PS_SOLID, 10, clrref);

        // Перерисовываем окно
        InvalidateRect(hwnd, NULL, TRUE);
      }
      return 0;
    }

    case WM_DESTROY:
    {
      // Удаляем созданные нами кисть и перо
      DeleteBrush(hbrush);
      DeletePen(hpen);

      PostQuitMessage(0);
      return 0;
    }

    default:
      break;
  }
  return DefWindowProc(hwnd, msg, wParam, lParam);
}

// ---------------------------------------------------
// Функция GetPenColor
// Выбор цвета пера
// ---------------------------------------------------

BOOL GetPenColor(HWND hwnd, COLORREF *clrref)
{
  CHOOSECOLOR cc;
  COLORREF aclrCust[16];
  int i;

  // Подготавливаем массив цветов
  // "Custom Colors"
  for (i = 0; i < 16; i++)
    aclrCust[i] = RGB(255, 255, 255);

  // Записываем нулевые значения во все
  // неиспользуемые поля структуры CHOOSECOLOR
  memset(&cc, 0, sizeof(CHOOSECOLOR));

  // Заполняем необходимые поля
  cc.lStructSize = sizeof(CHOOSECOLOR);
  cc.hwndOwner = hwnd;
  cc.rgbResult = RGB(0, 0, 0);
  cc.lpCustColors = aclrCust;
  cc.Flags = 0;

  // Выбираем цвет и возвращаем результат
  if (ChooseColor(&cc))
  {
    *clrref = cc.rgbResult;
    return TRUE;
  }
  else
    return FALSE;
}

Обратите внимание, что в в файл исходного текста приложения включается файл commdlg.h:

#include <commdlg.h>

В этом файле описана функция ChoseColor, необходимые для нее константы и структура данных.

При регистрации класса окна для фона окна устанавливается системный цвет COLOR_APPWORKSPACE, соответствующей цвету окна MDI-приложений (примером такого приложения является Program Manager):

wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);

Когда вы изменяете системные цвета, GDI автоматически перерисовывает фон окна, определенный в классе окна (если для фона окна выбран системный цвет).

В процессе создания окна обработчик сообщения WM_CREATE создает кисть и перо, с помощью которых будет нарисован прямоугольник:

hbrush = CreateSolidBrush(GetSysColor(COLOR_ACTIVECAPTION));
hpen  = CreatePen(PS_SOLID, 10, RGB(0,0,0));

Перед завершением работы приложения обработчик сообщения WM_DESTROY удаляет созданные перо и кисть:

DeleteBrush(hbrush);
DeletePen(hpen);

Задача обработчика сообщения WM_PAINT заключается в том, чтобы выбрать в контекст отображения перо и кисть, нарисовать прямоугольник, а затем выбрать в контекст отображения старые перо и кисть:

hbrushOldBrush = SelectBrush(hdc, hbrush);
hpenOldPen = SelectPen(hdc, hpen);
Rectangle(hdc, 10, 20, 300, 50);
SelectBrush(hdc, hbrushOldBrush);
SelectPen(hdc, hpenOldPen);

Что происходит, когда вы с помощью приложения Control Panel изменяете системные цвета?

Все окна верхнего уровня активных приложений получают сообщение WM_SYSCOLORCHANGE. В ответ на это сообщение наше приложение удаляет кисть и создает ее заново:

case WM_SYSCOLORCHANGE:
{
  if(hbrush)
  {
    DeleteBrush(hbrush);
    hbrush =
      CreateSolidBrush(GetSysColor(COLOR_ACTIVECAPTION));
  }
  return 0;
}

Так как системные цвета изменились, константа COLOR_ACTIVECAPTION может теперь соответствовать другому цвету, поэтому в результате этой операции цвет кисти hbrush может измениться (но может и не измениться).

Заметьте, что приложение не выполняет никаких дополнительных действий, направленных на то, чтобы цвет фона окна изменялся в соответствии с изменением системных цветов - так как для цвета фона окна используется системный цвет, GDI выполняет все изменения самостоятельно.

Когда вы щелкаете левой клавишей мыши в окне приложения, обработчик сообщения WM_LBUTTONDOWN вызывает функцию GetPenColor, определенную в нашем приложении. Эта функция вызывает функцию ChooseColor, и, если вы выбрали с ее помощью цвет для пера, записывает этот цвет в переменную clrref. Затем обработчик сообщения от мыши удаляет существующее перо и создает новое, используя выбранный вами цвет. После этого он вызывает функцию InvalidateRect, что вызывает перерисовку окна приложения.

Функция GetPenColor подготавливает массив из 16 переменных типа COLORREF, содержащих белый цвет. Этот массив будет использован для инициализации цветов в области "Custom Colors" диалоговой панели выбора цветов.

Затем она инициализирует нужные поля структуры CHOOSECOLOR, записывая в остальные поля нулевые значения, после чего вызывает функцию ChooseColor.

Файл определения модуля для приложения GETCOLOR приведен в листинге 3.2.


Листинг 3.2. Файл getcolor/getcolor.def


; =============================
; Файл определения модуля
; =============================
NAME        GETCOLOR
DESCRIPTION 'Приложение GETCOLOR, (C) 1994, Frolov A.V.'
EXETYPE     windows
STUB        'winstub.exe'
STACKSIZE   8120
HEAPSIZE    1024
CODE        preload moveable discardable
DATA        preload moveable multiple

[Назад] [Содеожание] [Дальше]