Партнерка на США и Канаду по недвижимости, выплаты в крипто

  • 30% recurring commission
  • Выплаты в USDT
  • Вывод каждую неделю
  • Комиссия до 5 лет за каждого referral

dc. SelectStockObject( NULL_PEN );

dc. SelectStockObject( LTGRAY_BRUSH );

dc. Ellipse( 0, 0, 100, 100 );

2.8 Удаление объектов GDI

Перья, кисти и другие объекты GDI занимают не только память программы, но и служебную память GDI, объем которой ограничен. Поэтому крайне важно удалять объекты GDI, которые больше не нужны. При автоматическом создании объектов CPen, CBrush, CFont и др. подклассов CGdiObject соответствующие объекты GDI автоматически удаляются из деструкторов этих классов. Если же объекты CGdiObject создавались динамически оператором new, то обязательно надо вызывать для них оператор delete. Явно удалить объект GDI, не уничтожая объект CGdiObject, можно вызовом функции CGdiObject::DeleteObject. Стандартные объекты GDI, даже "созданные" функцией CreateStockObject, удалять не надо.

Visual C++ может автоматически отслеживать объекты GDI, которые вы забыли удалить. Для этого применяется перегрузка оператора new. Чтобы разрешить такое слежение в конкретном исходном файле, после директивы включения заголовочного файла Afxwin. h надо добавить директиву определения макроса:

#define new DEBUG_NEW

После завершения работы приложения номера строк и имена файлов, содержащие не удаленные объекты GDI, будут показаны в отладочном окне Visual C++.

Для удаления объектов GDI важно знать, что нельзя удалить объект, который выбран в контексте устройства. Следующий пример является ошибочным:

void CMainWindow::OnPaint()

{

CPaintDC dc( this );

CBrush brush( RGB(255, 0, 0) );

dc. SelectObject( &brush );

dc. Ellipse( 0, 0, 200, 100 );

}

Ошибка заключается в том, что объект CPaintDC создается раньше CBrush. Т. к. оба объекта созданы автоматически, и CBrush – вторым, то его деструктор будет вызван первым. Следовательно, соответствующая кисть GDI будет удаляться до того, как будет удален объект dc. Эта попытка будет неудачной. Вы можете исправить положение, если создадите кисть первой. Но везде соблюдать подобное правило в программе тяжело, и очень утомительно искать такие ошибки.

НЕ нашли? Не то? Что вы ищете?

В GDI нет функции для отмены выбора объекта в контексте, вроде UnselectObject. Решение заключается в том, чтобы перед удалением объекта CPaintDC выбрать в нем другие объекты GDI, например, стандартную кисть GDI. Многие программисты поступают по-другому: при первом выборе в контексте устройства собственного объекта GDI сохраняют указатель на предыдущий объект, который возвращается функцией SelectObject. Затем, перед удалением контекста, в нем выбираются те объекты, которые были в нем "по умолчанию". Например:

CPen pen( PS_SOLID, 1, RGB(255, 0, 0) );

CPen* pOldPen = dc. SelectObject(&pen);

CBrush brush( RGB(0, 0, 255) );

CBrush* pOldBrush = dc. SelectObject( &brush );

dc. SelectObject( pOldPen );

dc. SelectObject( pOldBrush );

Способ с использованием стандартных объектов GDI реализуется так:

CPen pen( PS_SOLID, 1, RGB(255, 0, 0) );

dc. SelectObject( &pen );

CBrush brush( RGB(0, 0, 255) );

dc. SelectObject( &brush );

dc. SelectStockObject( BLACK_PEN );

dc. SelectStockObject( WHITE_BRUSH );

При динамическом создании объектов GDI нельзя забывать про оператор delete:

CPen* pPen = new CPen( PS_SOLID, 1, RGB(255, 0, 0) );

CPen* pOldPen = dc. SelectObject( pPen );

dc. SelectObject( pOldPen );

delete pPen;

3. Резюме

Чтобы обеспечить доступ к устройствам графического вывода одновременно нескольким программам, в Windows применяется специальный системный механизм – контекст устройства. Все операции рисования приложения выполняют с помощью контекста устройства. Это служебная структура, в которой хранятся все характеристики конкретного устройства, необходимые модулю GDI для рисования пикселей и графических примитивов. Контекст устройства в MFC представлен классом CDC, от которого унаследованы подклассы для разновидностей контекстов устройств Windows, например, CPaintDC, CClientDC, CWindowDC.

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

В физической системе координат устройства расстояния измеряются в пикселах. Точка (0, 0) всегда располагается в левом верхнем углу поверхности отображения, ось x направлена вправо, а y – вниз. У логической системы координат эти параметры могут быть другими. Начало координат можно разместить в любом месте поверхности изображения, можно изменить ориентацию осей и масштаб (этим управляет режим преобразования координат).

Функции рисования GDI условно делятся на несколько групп: рисование отрезков и кривых, рисование замкнутых фигур, отображение текста и др. Полный список функций рисования есть в разделе справочной системе Visual C++ по классу CDC, в котором эти функции оформлены в виде функций-членов.

При рисовании графических примитивов свойства отображения, например, цвет и стиль линии, задаются параметрами контекста устройства, среди которых наиболее важные – текущие выбранные объекты GDI (перо для рисования линий, кисть для заполнения областей, шрифт для вывода текста). Все классы-объекты GDI в MFC унаследованы от базового класса CGdiObject: CPen для перьев, CBrush для кистей, CFont для шрифтов. В каждом классе хранится дескриптор объекта GDI (в переменной-члене m_hObject).

Созданные программистом объекты GDI необходимо удалять. Перед удалением надо выбрать в контексте другой объект, т. к. текущий выбранный объект GDI удалить нельзя.

4. Упражнения

1)  Попробуйте выполнить примеры рисования, приведенные в лекции, подставляя фрагменты исходного текста в обработчик OnPaint приложения Hello (оно было рассмотрено в предыдущей лекции).

2)  Изучите англо-русский словарь терминов по теме 5-й лекции (см. CD-ROM).

3)  Выполните лабораторную работу №2, "Работа с модулем GDI" (см. CD-ROM).

Лекция 6. Работа с устройствами ввода. Использование меню

В Windows клавиатура и мышь являются основными устройствами ввода. Многие операции с мышью и клавиатурой Windows выполняет автоматически, например, выводит меню и отслеживает выбор в нем пункта, а затем посылает программе сообщение WM_COMMAND с кодом выбранной команды. Можно написать полноценное приложение, непосредственно не обрабатывая в нем сообщения мыши и клавиатуры.

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

Изучение способов обработки ввода с мыши и клавиатуры в Windows в основном сводится к ознакомлению с сообщениями мыши и клавиатуры, а также с набором функций API (и MFC), полезных для их обработки.

В данной лекции также рассматривается использование меню в MFC-приложениях. Практически все действия по обеспечению работы меню реализованы в модуле USER Windows (вывод на экран, перемещение по меню и уведомление приложения о выбранной команде). Приложения должны создать меню и обеспечить обработку выбираемых из них команд. В MFC предусмотрена маршрутизация команд меню в специально назначенные для их обработки функции-члены классов. С помощью обработчиков обновления меню приложение могло запрещать и помечать пункты меню в соответствии со своим текущим состоянием.

1. Получение данных от мыши

В целом в Windows с событиями мыши связаны более 20 сообщений, которые можно разделить на две категории: сообщения мыши, связанные с клиентской областью окна, и сообщения, связанные с неклиентской областью окна. Они одинаковы по смыслу, но различаются положением указателя в момент возникновения события. События бывают следующими:

·  нажатие или отпускание кнопки мыши;

·  двойной щелчок кнопкой мыши;

·  перемещение мыши.

В большинстве приложений сообщения неклиентской области игнорируются и Windows обрабатывает их автоматически (например, выполняет перетаскивание окна за строку заголовка).

1.1 Сообщения мыши, связанные с клиентской областью окна

Сообщения мыши данной группы приведены в таблице 6.1. Сообщения, имена которых начинаются с WM_LBUTTON, относятся к левой кнопке мыши, WM_MBUTTON –к средней кнопке, а WM_RBUTTON – к правой кнопке. Макросы карты сообщений и имена функций-членов CWnd для обработки сообщений мыши приведены в табл. 6.2.

Таблица 6.1. Сообщения мыши, связанные с клиентской областью окна

Сообщение

Когда посылается

WM_LBUTTONDOWN

Нажата левая кнопка мыши

WM_LBUTTONUP

Левая кнопка мыши отпущена

WM_LBUTTONDBLCLK

Двойной щелчок левой кнопкой мыши

WM_MBUTTONDOWN

Нажата средняя кнопка мыши

WM_MBUTTONUP

Средняя кнопка мыши отпущена

WM_MBUTTONDBLCLK

Двойной щелчок средней кнопкой мыши

WM_RBUTTONDOWN

Нажата правая кнопка мыши

WM_RBUTTONUP

Правая кнопка мыши отпущена

WM_RBUTTONDBLCLK

Двойной щелчок правой кнопкой мыши

WM_MOUSEMOVE

Указатель мыши перемещается над клиентской областью окна

Сообщение WM_xBUTTONUP обычно (но не всегда) идет после WM_xBUTTONDOWN. Сообщения мыши посылаются в окно, над которым располагается указатель. Поэтому, если пользователь нажмет левую кнопку над клиентской областью некоторого окна, а отпустит ее за пределами окна, то это окно получит только сообщение WM_LBUTTONDOWN. Многие программы реагируют только на сообщения о нажатии кнопок мыши. Если важно обрабатывать и нажатие, и отпускание кнопки, приложение должно использовать режим "захвата" мыши (см. п.1.2).

Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32