Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Programming_Windows_95_Part_I.pdf
Скачиваний:
96
Добавлен:
05.06.2014
Размер:
4.61 Mб
Скачать

135

PatBlt(hdc, 0, -100, 100, 100, dwROP);

или

PatBlt(hdc, 100, 0, -100, -100, dwROP);

или

PatBlt(hdc, 100, -100, -100, 100, dwROP);

Простейший путь задать правильные параметры функции PatBlt — это установить xDest и yDest в левый верхний угол прямоугольника. Если ваш режим отображения определяет координату y так, что она возрастает при движении вверх, то используйте отрицательную величину параметра yHeight. Если ваш режим отображения определяет координату x так, что она возрастает при движении влево (что почти не встречается), то используйте отрицательную величину параметра xWidth.

Перенос битов с помощью функции BitBlt

В некотором смысле функция BitBlt — это расширенная функция PatBlt. Она делает все то же, что и PatBlt, а также вовлекает второй контекст устройства в логическую операцию. Ниже приведен синтаксис функции:

BitBlt(hdcDest, xDest, yDest, xWidth, yHeight, hdcSrc, xSrc, ySrc, dwROP);

Вызов функции BitBlt модифицирует приемный контекст устройства (его описатель hdcDst) в рамках прямоугольника, заданного логической точкой (xDesr, yDest) и параметрами xWidth и yHeight, заданными в логических единицах. Эти параметры определяют прямоугольник в соответствии с тем, как описано в предыдущем разделе. Функция BitBlt также использует прямоугольник из контекста устройства источника (описатель контекста hdcSrc). Этот прямоугольник начинается в логической точке (xSrc, ySrc) и имеет ширину xWidth логических единиц и высоту yHeight логических единиц.

Функция BitBlt осуществляет логическую операцию над тремя элементами: кистью, выбранной в контексте устройства приемника, пикселями прямоугольника в контексте устройства источника и пикселями прямоугольника в контексте устройства приемника. Результат заносится в прямоугольник приемного контекста устройства. Вы можете использовать любой из 256 ROP кодов в качестве параметра dwROP функции BitBlt. Пятнадцать ROP кодов, имеющих имена, приведены в следующей таблице.

Шаблон: (Pattern) (P)

1 1 1 1 0 0 0 0

Булева

ROP код

Имя

Источник: (Source) (S)

1 1 0 0 1 1 0 0

операция

 

 

Приемник: (Destination) (D)

1 0 1 0 1 0 1 0

 

 

 

Результат: (Result)

0 0 0 0 0 0 0 0

0

0x000042

BLACKNESS

 

0 0 0 1 0 0 0 1

~(S|D)

0x1100A6

NOTSRCERASE

 

0 0 1 1 0 0 1 1

~S

0x330008

NOTSRCCOPY

 

0 1 0 0 0 1 0 0

S&~D

0x440328

SRCERASE

 

0 1 0 1 0 1 0 1

~D

0x550009

DSTINVERT

 

0 1 0 1 1 0 1 0

P^D

0x5A0049

PATINVERT

 

0 1 1 0 0 1 1 0

S^D

0x660046

SRCINVERT

 

1 0 0 0 1 0 0 0

S&D

0x8800C6

SRCAND

 

1 0 1 1 1 0 1 1

~S|D

0xBB0226

MERGEPAINT

 

1 1 0 0 0 0 0 0

P&S

0xC000CA

MERGECOPY

 

1 1 0 0 1 1 0 0

S

0xCC0020

SRCCOPY

 

1 1 1 0 1 1 1 0

S|D

0xEE0086

SRCPAINT

 

1 1 1 1 0 0 0 0

P

0xF00021

PATCOPY

 

1 1 1 1 1 0 1 1

P|~S|D

0xFB0A09

PATPAINT

 

1 1 1 1 1 1 1 1

1

0xFF0062

WHITENESS

Обратите внимание на ряды из восьми нулей и восьми единиц, которые являются результатами логических операций. Двузначное шестнадцатиричное число, соответствующее этим битам, есть старшее слово ROP кода. Если мы можем создать таблицу результатов для тех шаблонов, источников и приемников, которые нам нужны, то мы можем легко определить ROP код из таблицы ROP кодов в разделе "References" пакета Microsoft Developer Studio. Мы сделаем это позднее. Если вы используете один из 16-ти ROP кодов, приведенных в предыдущей таблице, то можно работать с функцией PatBlt вместо BitBlt, поскольку вы не обращаетесь к контексту устройства источника.

Вы можете сделать так, что hdcSrc и hdcDst будут описывать один и тот же контекст устройства. В этом случае функция BitBlt выполняет логическую операцию над приемным прямоугольником, исходным прямоугольником и текущей кистью, выбранной в контексте устройства. Однако, существует некоторая доля риска при выполнении этой операции с контекстом устройства рабочей области. Если часть исходного прямоугольника закрыта другим окном, то Windows будет использовать пиксели этого окна как исходные. Windows ничего не знает о том, что какое-либо окно закрывает часть рабочей области вашего окна.

136

Тем не менее, примеры функции BitBlt, использующей один и тот же контекст устройства для источника и приемника, просты для понимания.

Функция:

BitBlt(hdc, 100, 0, 50, 100, hdc, 0, 0, SRCCOPY);

копирует прямоугольник с вершиной в логической точке (0, 0), шириной 50 и высотой 100 логических единиц в прямоугольную область с вершиной в логической точке (100,0).

Функция DrawBitmap

Функция BitBlt наиболее эффективна при работе с битовыми образами, которые выбраны в контекст памяти. Когда вы выполняете перенос блока битов (bit block transfer) из контекста памяти в контекст устройства вашей рабочей области, битовый образ, выбранный в контексте памяти переносится в вашу рабочую область.

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

DrawBitmap(hdc, hBitmap, xStart, yStart);

Было обещано, что мы ее напишем. Вот она:

void DrawBitmap(HDC hdc, HBITMAP hBitmap, int xStart, int yStart)

{

BITMAP bm; HDC hdcMem; DWORD dwSize;

POINT ptSize, ptOrg;

hdcMem = CreateCompatibleDC(hdc); SelectObject(hdcMem, hBitmap); SetMapMode(hdcMem, GetMapMode(hdc)); GetObject(hBitmap, sizeof(BITMAP),(LPVOID) &bm); ptSize.x = bm.bmWidth;

ptSize.y = bm.bmHeight; DPtoLP(hdc, &ptSize, 1); ptOrg.x = 0;

ptOrg.y = 0; DPtoLP(hdcMem, &ptOrg, 1); BitBlt(

hdc, xStart, yStart, ptSize.x, ptSize.y, hdcMem, ptOrg.x, ptOrg.y, SRCCOPY

);

DeleteDC(hdcMem);

}

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

Функция DrawBitmap сначала создает контекст памяти, используя функцию CreateCompatibleDC, затем выбирает в него битовый образ с использованием функции SelectObject. Режим отображения контекста памяти устанавливается таким же, как режим отображения контекста устройства вывода. Поскольку функция BitBlt работает с логическими координатами и логическими размерами, и учитывая то, что вы не предполагаете растягивать или сжимать битовый образ, параметры xWidth и yHeight функции BitBlt должны иметь значения в логических координатах, соответствующих размерам битового образа в физических координатах. Поэтому, функция DrawBitmap определяет размеры битового образа, используя функцию GetObject, и создает структуру POINT для сохранения в ней ширины и высоты. Затем она преобразует эту точку в логические координаты. Аналогичные действия осуществляются и в отношении начала координат битового образа — точки (0, 0) в координатах устройства.

Обратите внимание, что не имеет никакого значения, какая кисть выбрана в приемном контексте устройства (hdc), поскольку режим SRCCOPY не использует кисть.

Использование других ROP кодов

SRCCOPY — самое часто встречающееся значение параметра dwROP функции BitBlt. Вам будет трудно найти примеры использования других 255 ROP кодов. Поэтому здесь будет показано несколько примеров, в которых используются другие ROP коды.

Первый пример: пусть у вас есть монохромный битовый образ, который вы хотите перенести на экран. При этом, вы хотите отобразить битовый образ так, чтобы черные (0) биты не оказывали влияния на текущее содержание

137

рабочей области. Более того, вы хотите, чтобы для всех белых (1) битов рабочая область закрашивалась кистью, возможно цветной, созданной функцией CreateSolidBrush. Как это сделать?

Предполагается, что вы работаете в режиме отображения MM_TEXT, и что вы хотите отобразить битовый образ, начиная в точке (xStart, yStart) вашей рабочей области. У вас также есть описатель монохромного битового образа (hBitmap) и описатель цветной кисти (hBrush). Вы также знаете ширину и высоту битового образа, и они хранятся в переменной bm структуры BITMAP. Вот код программы:

hdcMem = CreateCompatibleDC(hdc); SelectObject(hdcMem, hBitmap); hBrush = SelectObject(hdc, hBrush);

BitBlt(hdc, xStart, yStart, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, 0xE20746L); SelectObject(hdc, hBrush);

DeleteDC(hdcMem);

Функция BitBlt выполняет логическую операцию над приемным контекстом устройства (hdc), исходным контекстом устройства (hdcMem) и кистью, выбранной в приемном контексте устройства. Вы создаете контекст памяти, выбираете в него битовый образ, выбираете цветную кисть в контекст устройства вашей рабочей области, и вызываете BitBlt. Затем вы выбираете исходную кисть в контекст устройства вашего дисплея и удаляете контекст памяти.

Осталось объяснить значение ROP кода 0xE20746 приведенного фрагмента программы. Этот код задает Windows выполнение следующей логической операции:

((Destination ^ Pattern) & Source) ^ Destination

Если опять непонятно, попробуйте разобраться в следующем:

Pattern:

1

1

1

1

0

0

0

0

Source:

1

1

0

0

1

1

0

0

Destination:

1

0

1

0

1

0

1

0

Result:

?

?

?

?

?

?

?

?

Для каждого черного бита битового образа (который будет выбран в исходный контекст памяти), вы хотите, чтобы приемный контекст устройства оставался неизменным. Это означает, что везде, где Source равен 0, вы хотите,

чтобы Result равнялся Destination:

Pattern:

1

1

1

1

0

0

0

0

Source:

1

1

0

0

1

1

0

0

Destination:

1

0

1

0

1

0

1

0

Result:

?

?

1

0

?

?

1

0

Полдела сделано. Теперь для каждого белого бита битового образа вы хотите, чтобы приемный контекст закрашивался шаблоном. Кисть, выбранная вами в приемный контекст устройства — это шаблон. Таким образом, везде где Source равен 1, вы хотите, чтобы Result равнялся Pattern:

Pattern:

1

1

1

1

0

0

0

0

Source:

1

1

0

0

1

1

0

0

Destination:

1

0

1

0

1

0

1

0

Result:

1

1

1

0

0

0

1

0

Это означает, что старшее слово ROP кода равняется 0xE2. Вы можете заглянуть в таблицу ROP кодов пакета

Microsoft Developer Studio и обнаружить, что полный ROP код равен 0xE20746.

Если обнаружится, что вы перепутали белые и черные биты при создании битового образа, то это легко исправить, используя другую логическую операцию:

Pattern:

1

1

1

1

0

0

0

0

Source:

1

1

0

0

1

1

0

0

Destination:

1

0

1

0

1

0

1

0

Result:

1

0

1

1

1

0

0

0

Теперь старшее слово ROP кода равно 0xB8, а весь ROP код равен 0xB8074A, что соответствует логической операции:

((Destination ^ Pattern) & Source) ^ Pattern

Теперь второй пример: вы можете заметить, что значки и курсоры состоят из двух битовых образов. Использование двух битовых образов позволяет этим объектам быть прозрачными или инвертировать цвет

138

закрываемых ими фрагментов экрана. Для монохромного значка или курсора, эти два битовых образа кодируются следующим образом:

Bitmap1:

0

0

1

1

Bitmap2:

0

1

0

1

Result:

Черный

Белый

Цвет

Инверсный

 

 

 

экрана

цвет экрана

Windows выбирает битовый образ Bitmap1 в контекст памяти и использует функцию BitBlt с ROP кодом SRCAND для переноса битового образа на экран. Этот ROP код соответствует логической операции:

Destination & Source

Она сохраняет неизменными биты приемника, соответствующие единичным битам Bitmap1, и устанавливает в 0 биты, соответствующие нулевым битам Bitmap1. Затем Windows выбирает Bitmap2 в контекст устройства и использует функцию BitBlt с параметром SRCINVERT. Логическая операция такова:

Destination ^ Source

Данная операция сохраняет неизменными биты приемника, соответствующие нулевым битам Bitmap2, и инвертирует биты, соответствующие единичным битам Bitmap2.

Взгляните на первый и второй столбцы таблицы: Bitmap1 и SRCAND делают биты черными, а Bitmap2 и SRCINVERT инвертируют выбранные биты в белый цвет. Эти операции устанавливают белые и черные биты, которые составляют значок и курсор. Теперь посмотрите на третий и четвертый столбцы таблицы: Bitmap1 и SRCAND сохраняют дисплей неизменным, а Bitmap2 и SRCINVERT инвертируют цвета указанных битов. Эти операции делают значки и курсоры прозрачными или позволяют инвертировать цвет закрываемой области экрана.

Другой пример творческого использования ROP кодов приводится далее в этой главе при описании функции

GrayString.

Дополнительные сведения о контексте памяти

Мы использовали контекст памяти для передачи существующих битовых образов на экран. Вы можете также использовать контекст памяти для рисования на поверхности битового образа. Мы сделаем это в программе GRAFMENU в главе 10. Во-первых, вы строите контекст памяти:

hdcMem = CreateCompatibleDC(hdc);

Затем вы создаете битовый образ желаемого размера. Если вы хотите создать монохромный битовый образ, его можно сделать совместимым с hdcMem:

hBitmap = CreateCompatibleBitmap(hdcMem, xWidth, yHeight);

Для создания битового образа с такой же организацией цветов, как и у видеотерминала, сделайте битовый образ совместимым с hdc:

hBitmap = CreateCompatibleBitmap(hdc, xWidth, yHeight);

Теперь вы можете выбрать битовый образ в контекст памяти:

SelectObject(hdcMem, hBitmap);

А затем вы можете рисовать в этом контексте памяти (т. е. на поверхности битового образа), используя все функции GDI, рассмотренные в этой главе. Когда вы впервые создаете битовый образ, он содержит случайные биты. Поэтому есть смысл начать с использования функции PatBlt с ROP кодом WHITENESS или BLACKNESS для стирания фона контекста памяти.

Когда вы закончите рисование в контексте памяти, просто удалите его:

DeleteDC(hdcMem);

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

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

SCRAMBLE.MAK

#------------------------

# SCRAMBLE.MAK make file

#------------------------

scramble.exe : scramble.obj

139

$(LINKER) $(GUIFLAGS) -OUT:scramble.EXE scramble.obj $(GUILIBS)

scramble.obj : scramble.c $(CC) $(CFLAGS) scramble.c

SCRAMBLE.C

/*------------------------------------------------

 

SCRAMBLE.C --

Scramble(and Unscramble) Screen

 

(c) Charles Petzold, 1996

------------------------------------------------

*/

#include <windows.h> #include <stdlib.h>

#define NUM 200

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)

{

static int iKeep [NUM][4];

HDC

hdc, hdcMem;

int

cx, cy;

HBITMAP

hBitmap;

int

i, j, x1, y1, x2, y2;

if(LockWindowUpdate(GetDesktopWindow()))

{

 

hdc

= CreateDC("DISPLAY", NULL, NULL, NULL);

hdcMem = CreateCompatibleDC(hdc);

cx

= GetSystemMetrics(SM_CXSCREEN) / 10;

cy

= GetSystemMetrics(SM_CYSCREEN) / 10;

hBitmap = CreateCompatibleBitmap(hdc, cx, cy);

SelectObject(hdcMem, hBitmap);

srand((int) GetCurrentTime());

for(i = 0; i < 2; i++)

for(j = 0; j < NUM; j++)

{

if(i == 0)

{

iKeep [j] [0] = x1 = cx *(rand() % 10); iKeep [j] [1] = y1 = cy *(rand() % 10); iKeep [j] [2] = x2 = cx *(rand() % 10); iKeep [j] [3] = y2 = cy *(rand() % 10);

}

else

{

x1 = iKeep [NUM - 1 - j] [0];

y1 = iKeep [NUM - 1 - j] [1];

x2 = iKeep [NUM - 1 - j] [2];

y2 = iKeep [NUM - 1 - j] [3];

}

BitBlt(hdcMem, 0, 0, cx, cy, hdc, x1, y1, SRCCOPY);

BitBlt(hdc, x1, y1, cx, cy, hdc, x2, y2, SRCCOPY);

BitBlt(hdc, x2, y2, cx, cy, hdcMem, 0, 0, SRCCOPY);

Sleep(10);

}

DeleteDC(hdcMem);

140

DeleteDC(hdc);

DeleteObject(hBitmap);

LockWindowUpdate(NULL);

}

return FALSE;

}

Рис. 4.26 Программа SCRAMBLE

В программе SCRAMBLE нет оконной процедуры. В функции WinMain она получает контекст устройства для всего экрана:

hdc = CreateDC("DISPLAY", NULL, NULL, NULL);

а также контекст памяти:

hdcMem = CreateCompatibleDC(hdc);

Затем она определяет размеры экрана и делит их на 10:

xSize = GetSystemMetrics(SM_CXSCREEN) / 10;

ySize = GetSystemMetrics(SM_CYSCREEN) / 10;

Программа использует эти размеры для создания битового образа:

hBitmap = CreateCompatibleBitmap(hdc, xSize, ySize);

и выбирает его в контекст памяти:

SelectObject(hdcMem, hBitmap);

Используя функцию rand языка C, программа SCRAMBLE формирует четыре случайных величины, кратные значениям xSize и ySize:

x1 = xSize *(rand() % 10);

y1 = ySize *(rand() % 10);

x2 = xSize *(rand() % 10);

y2 = ySize *(rand() % 10);

Программа меняет местами два прямоугольных блока дисплея, используя три функции BitBlt. Первая копирует прямоугольник с вершиной в точке (x1, y1) в контекст памяти:

BitBlt(hdcMem, 0, 0, xSize, ySize, hdc, x1, y1, SRCCOPY);

Вторая копирует прямоугольник с вершиной в точке (x2, y2) в прямоугольную область с вершиной в точке (x1, y1):

BitBlt(hdc, x1, y1, xSize, ySize, hdc, x2, y2, SRCCOPY);

Третья копирует прямоугольник из контекста памяти в прямоугольную область с вершиной в точке (x2, y2):

BitBlt(hdc, x2, y2, xSize, ySize, hdcMem, 0, 0, SRCCOPY);

Этот процесс эффективно меняет местами содержимое двух прямоугольников на дисплее. SCRAMBLE делает это 200 раз, что может привести к полному беспорядку на экране. Но этого не происходит, потому что программа SCRAMBLE отслеживает свои действия, и перед завершением восстанавливает экран.

Вы можете также использовать контекст памяти для копирования содержимого одного битового образа в другой. Предположим, вы хотите создать битовый образ, содержащий только левый верхний квадрант другого битового образа. Если исходный битовый образ имеет описатель hBitmap, то вы можете скопировать его размеры в структуру типа BITMAP:

GetObject(hBitmap, sizeof(BITMAP),(LPVOID) &bm);

и создать новый неинициализированный битовый образ размером в одну четверть исходного:

hBitmap2 = CreateBitmap(bm.bmWidth / 2, bm.bmHeight / 2, bm.bmPlanes, bm.bmBitsPixel, NULL);

Теперь создаются два контекста памяти и в них выбираются исходный и новый битовые образы:

hdcMem1 = CreateCompatibleDC(hdc); hdcMem2 = CreateCompatibleDC(hdc);

SelectObject(hdcMem1, hBitmap);

SelectObject(hdcMem2, hBitmap2);

Теперь копируем левый верхний квадрант первого битового образа во второй:

Соседние файлы в предмете Операционные системы