Опубликован: 10.03.2009 | Доступ: свободный | Студентов: 2297 / 280 | Оценка: 4.31 / 4.07 | Длительность: 09:23:00
Лекция 2:

Библиотека классов MFC

Полосы прокрутки

В Windows есть два типа полос прокрутки. Элементы первого типа являются частью окна (включая диалоговое окно), поэтому их называют полосами прокрутки окна. Элементы второго типа существуют независимо и называются независимыми полосами прокрутки. Элементы первого типа описываются классом CWnd, а второго - CScrollBar.

Создание стандартных полос прокрутки

Если требуется, чтобы окно содержало стандартные полосы прокрутки, они должны быть явно заданы. Применительно к главному окну это означает, что при вызове функции Create() в качестве параметров стиля должны быть указаны опции WS_VSCROLL и WS_HSCROLL. В случае диалогового окна, достаточно установить соответствующие опции диалога в ресурсном редакторе. Если все это сделано, то полосы прокрутки будут отображаться в окне автоматически.

Независимые полосы прокрутки в диалогах

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

Обработка сообщений полосы прокрутки

Так как полоса прокрутки пришла из 16-разрядной Windows 3.1, то управлять полосой прокрутки довольно сложно. Полоса прокрутки сама ничего не делает. Даже для того, чтобы она "прокручивалась" на экране, необходим дополнительный программный код. Полосы прокрутки при выполнении над ними действий посылают сообщения WM_VSCROLL и WM_HSCROLL при активизации соответственно вертикальной или горизонтальной полосы прокрутки. Эти сообщения обрабатываются функциями со следующими прототипами:

afx_msg void CWnd::OnVScroll(UINT SBCode, int Pos, CScrollBar *SB);
afx_msg void CWnd::OnHScroll(UINT SBCode, int Pos, CScrollBar *SB);

Следует отметить, что при наличии нескольких горизонтальных или вертикальных полос прокрутки для всех них будет вызываться один и тот же обработчик. Первый параметр, SBCode, содержит код выполненного над полосой прокрутки действия. Если работа ведется с вертикальной полосой прокрутки, то при каждом изменении положения ползунка на одну позицию вверх посылается код SB_LINEUP. При изменении позиции на одну вниз посылается код SB_LINEDOWN. Аналогично, при постраничном перемещении генерируются коды SB_PAGEUP и SB_PAGEDOWN. Если работа ведется с горизонтальной полосой прокрутки, то при каждом передвижении ползунка на одну позицию влево посылается код SB_LINELEFT. При изменении его положения на одну позицию вправо посылается код SB_LINERIGHT. При постраничном перемещении генерируются сообщения SB_PAGELEFT и SB_PAGERIGHT. Для обоих типов полос прокрутки при перемещении ползунка на новую позицию посылается код SB_THUMBPOSITION. Если при этом кнопка мыши удерживается нажатой, то дополнительно генерируется сообщение с кодом SB_THUMBTRACK. Это позволяет отслеживать перемещения ползунка, прежде чем мышь будет отпущена. Параметр Pos указывает текущую позицию ползунка. Если сообщение сгенерировано стандартной полосой прокрутки, то параметр SB будет равен 0. Если же оно было сгенерировано независимой полосой прокрутки, то этот параметр будет содержать указатель на объект. Это предоставляет весьма неуклюжий способ различать, какая конкретно независимая полоса прокрутки сгенерировала сообщение. Для этого нужно использовать функцию CWnd:: GetDlgCtrlID(), которая возвращает идентификатор элемента управления. Такое неудобство связано с тем, что MFC повторяет внутреннее устройство Windows, а не является библиотекой сверхвысокого уровня для быстрой разработки приложений.

Управление полосой прокрутки

Ранее, для установки различных параметров полосы прокрутки, использовались отдельные функции, которые были в Windows 3.1. С появлением Windows 95 появилась возможность управления полосами прокрутки с помощью одной функции SetScrollInfo(). Эта функция позволяет сделать полосу прокрутки пропорциональной (в этом случае, чем меньше диапазон полосы прокрутки, тем длиннее будет ее ползунок). Функция GetScrollInfo() предназначена для чтения параметров полосы прокрутки. В отличие от старых функций, эти функции работают с 32-разрядными данными. Для стандартных полос прокрутки используется функция:

BOOL CWnd::SetScrollInfo(int Which, LPSCROLLINFO pSI, BOOL Redraw = TRUE);

Значение Which указывает, с горизонтальной или вертикальной полосой ведется работа. Параметр pSI указывает на структуру, содержащую информацию для полосы прокрутки. Последний параметр задает необходимость перерисовки полосы прокрутки. Обычно используется значение по умолчанию. Для независимых полос прокрутки используется функция:

BOOL CScrollBar::SetScrollInfo(LPSCROLLINFO pSI, BOOL Redraw = TRUE);

Оба параметра имеют такой же смысл.Для чтения параметров стандартных полос прокрутки используется функция:

BOOL CWnd::GetScrollInfo(int Which, LPSCROLLINFO pSI, UINT Mask = SIF_ALL);

Информация, получаемая от полосы прокрутки, записывается в структуру по адресу pSI. Значение параметра Mask определяет, какая информация записывается в структуру. По умолчанию заполняются все поля. Для независимых полос прокрутки вариант функции таков:

BOOL CScrollBar::SetScrollInfo(LPSCROLLINFO pSI, UINT Mask = SIF_ALL);

Значение параметров аналогичное предыдущему случаю. Во всех вариантах функций используется следующая структура типа SCROLLINFO:

typedef struct tagSCROLLINFO
 {
UINT cbSize; // размер самой структуры
UINT fMask; // маска для параметров
int nMin; // нижняя граница диапазона
int nMax; // верхняя граница диапазона
UINT nPage; // размер страницы
int nPos; // позиция ползунка
int nTrackPos; // позиция ползунка во время перемещения
} SCROLLINFO;

Поле fMask определяет, какое из полей структуры содержит требуемую информацию. Используются константы с префиксом SIF_, которые можно объединять операцией "| ". Поле nPos содержит статическую позицию ползунка. Поле nPage содержит размер страницы для пропорциональных полос прокрутки. Для получения обычной пропорциональной полосы прокрутки в этом поле нужно задать значение 1. Поля nMin и nMax содержат нижнюю и верхнюю границы диапазона полосы прокрутки. Поле nTracksPos содержит позицию ползунка при его перемещении, это значение не может быть установлено.

Графический вывод

Классические функции графического устройства

При выводе на экран графической информации: линии, текста, изображения и т.п. программа обращается к функциям GDI (graphic device interface) интерфейса графического устройства. Эти функции поддерживаются каркасом MFC и для удобства разработчика объединены в классы. Основным классом для работы с графикой является класс CDC и производные от него CPaintDC, CClientDC, CWindowDC, которые отличаются от базового класса только конструкторами и деструкторами. Исключением является класс CMetaFileDC. Класс CDC инкапсулирует понятие контекста устройства DC (device context).

Контекст устройства DC(device context) – структура данных, которая определяет набор графических объектов и методов для графического вывода. Контекст устройства является посредником между операционной системой Windows и устройством вывода, тем самым обеспечивается аппаратная независимость программы. Весь процесс отображения графики осуществляется с помощью этого класса.

Особенности производных классов контекста устройства

Объекты CMetaFileDC обеспечивают доступ к метафайлам Windows. Вызовы функций-членов класса CMetaFileDC записываются в связанном с соответствующим объектом файле. Для построения изображения требуется воспроизвести последовательность команд, записанных в метафайле.

Классы CClientDC и CWindowDC отличаются друг от друга лишь тем, что представляют для рисования различные области окна. CClientDC представляет клиентскую часть (часть окна без рамки, заголовка, меню, панели управления и строки состояния). CWindowDC – полнооконный контекст устройства, позволяет рисовать в произвольной области окна программы.

Объекты класса CPaintDC используются только в обработчике сообщения WM_PAINT, генерируемого в ответ на вызов функций UpdateWindow или RedrawWindow и необходимы, если требуется переопределить функцию OnPaint() для конкретного дисплея. По умолчанию обработчик OnPaint() вызывает OnDraw(CDC*) с уже настроенным нужным образом контекстом. Конструктор CPaintDC определен так, что выполняет все действия необходимые для инициализации данного дисплея.

Создание и уничтожение объектов CDC

Управление созданием и удалением объектов CDC является важной частью каждой программы. При неправильной работе с контекстами теряется память до завершения работы программы. Рассмотрим два варианта корректной работы с объектами CDC.

1. Создать объект в стеке, тогда он будет уничтожен автоматически:

void CMyView::SomeFunction(...)
{
CRect cr;
CClientDC dc(this);
dc.GetClipBox(cr);
}

2. Получить указатель на объект с помощью CWnd::GetDC(), при этом перед выходом из функции вызвать ReleaseDC():

void CMyView::SomeFunction(...)
{
  CRect rect;
  CDC* pDC = GetDC();
  pDC->GetClipBox(rect);
  ReleaseDC(pDC);
}

Замечание: нельзя удалять CDC – объект, указатель на который передается функции OnDraw. За его удаление отвечает каркас MFC.

Состояние контекста устройства. Объекты GDI

Состояние контекста устройства определяется связанными с ним графическими объектами. Свойства контекста устройства назначаются с помощью методов класса CDC. GDI- объекты загружаются в контекст устройства вызовом перегруженной функции SelectObject. В любой текущий момент с контекстом может быть связан только один объект каждого типа. Все объекты GDI представлены в MFC с помощью классов. CGdiObject – базовый абстрактный класс для GDI объектов, которые являются экземплярами классов наследников.

  1. CBitmap – класс, инкапсулирующий растровые изображения (битовые массивы). Растровые изображения используются для отображения картинок и создания кистей.
  2. CBrush – кисть. Точечный шаблон, использующийся для закрашивания областей окна.
  3. CFont – шрифт. Полный набор символов алфавита определенного вида и размера. Шрифты хранятся на диске как ресурсы.
  4. CPallete – палитра. Таблица преобразования цветов, позволяет приложению полностью задействовать цветовые возможности устройства, не вызывая конфликта с другими приложениями, работающими с этим же устройством.
  5. CPen – перо. Инструмент для рисования линий и границ фигур.
  6. CRgn – регион. Область окна, определяемая прямоугольником, эллипсом или всевозможными их комбинациями.

При создании GDI объектов вызываются конструкторы соответствующих классов. Но для некоторых этого недостаточно. Например, создание объектов типа CFont или CRgn требует вызова CreateFont(…) или CreatePolygonRgn(…). Прежде чем удалять GDI объект, его требуется вначале "отсоединить" от контекста устройства. Память, выделенная под GDI объекты, принадлежит процессу и освобождается при его завершении. Такие объекты как растровые изображение занимают значительный объем памяти и за их своевременным удалением необходимо следить.

Пример работы с GDI – объектом:

void CMyView::OnDraw(CDC* pDC)
{
  CPen myPen(PS_SOLID, 2, RGB(255,0,0));
  CPen *oldPen = pDC->SelectObject(&myPen);  //Присоединение нового пера и сохранение старого
//------------------------------------
  //Рисование....
//------------------------------------
 
pDC->SelectObject(oldPen);  //Возвращение контекста устройства в прежнее состояние
} //созданное в стеке перо будет удалено при выходе из функции

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