Дата публикации статьи: 10.06.2006 10:44

ГЛАВА 1. Графические функции API в среде Visual Basic

    Считается, что возможности Visual Basic, связанные с построением визуального интерфейса, обработкой баз данных и офисным программированием, являются выдающимися по простате и скорости разработки, а для работы с графикой VB не приспособлен. Такое мнение сложилось возможно потому, что VB не имеет встроенного объекта для работы с графикой подобного Canvas, инкапсулирующего GDI32. Поскольку VB получает с помощью Declare клиентские возможности по отношению к Win32 (следовательно и к GDI32.DLL), а такие объекты VB как Form и PictureBox предоставляют доступ к контексту устройства (Form1.hDC Picture1.hDC), все возможности, связанные с программированием графики доступны разработчикам, использующим VB. Для программирования с помощью команды Declare нужно только разобраться с передачей параметров из VB в API-функции.
    Рассмотрим простой пример работы с графическими функциями API в среде Visual Basic (см. проект папка N1/). Создайте проект типа Standard EXE. Поместите в форму четыре кнопки. Введите в раздел General после Option Explicit следующий код:

Option Explicit
Dim Lim As Long
Dim BackVal As Long
Dim RecordDC As Long
Dim DCWin As Long
Dim WindHandle As Long
Dim DCPicture As Long
Private Type POINTAPI
    X As Long
    Y As Long
End Type
Private ArrayPoint() As POINTAPI
Private Declare Function CreateSolidBrush& Lib "gdi32" (ByVal crColor _
							As Long)
Private Declare Function SelectObject& Lib "gdi32" (ByVal hDC _
				As Long, ByVal hObject As Long)
Private Declare Function DeleteObject& Lib "gdi32" (ByVal hObject _
							As Long)
Private Declare Function SaveDC& Lib "gdi32" (ByVal hDC As Long)
Private Declare Function RestoreDC& Lib "gdi32" (ByVal hDC As Long, _
						ByVal nSavedDC As Long)
Private Declare Function SetPixel& Lib "gdi32" (ByVal hDC As Long, _
		ByVal X As Long, ByVal Y As Long, ByVal crColor As Long)
Private Declare Function GetWindowDC& Lib "user32" (ByVal hwnd As Long)
Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal _
							hDC As Long) As Long
Private Declare Function Rectangle& Lib "gdi32" (ByVal hDC As Long, _
	ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long)
Private Declare Function Polygon& Lib "gdi32" (ByVal hDC As Long, lpPoint As _
POINTAPI, ByVal nCount As Long)

    Обратите внимание на пользовательский тип POINTAPI. Так как объявление Type POINTAPI можно считать синонимом структуры в языке C, значит Private ArrayPoint() As POINTAPI – это массив структур в которых будут хранятся координаты точек для функции API Polygon, которая принимает по ссылке (по умолчанию в VB параметры передаются по ссылке) в качестве параметра указатель (адрес) на массив структур POINTAPI. Аналогичная функция на C выглядит следующим образом - Polygon(HDC hdc, CONST POINT*ipPoints, int nCount), а массив структур POINT, указатель на который ей надо передать, можно создать так - POINT points[5]={0x,0y,1x,1y,2x,2y,3x,3y,4x,4y}. Переменная int nCount указывает на число используемых вершин в многоугольнике. В обработчики событий формы введите следующий код:

Private Sub Form_Load()
Lim = 0
WindHandle = Form1.hwnd
DCPicture = Form1.hDC
End Sub
Private Sub Form_Paint()
Dim oldBrush As Long
Dim BrushBlue As Long
Dim iCount As Long
Dim iCountX As Long
Dim iCountY As Long
BrushBlue = CreateSolidBrush(QBColor(11))
oldBrush = SelectObject&(DCPicture, BrushBlue)
For iCount = 0 To 15 Step 1
 iCountX = iCountX + Lim
  For iCountX = iCountX To iCountX + 5 Step 1
   SetPixel DCPicture, iCountX, 25, QBColor(iCount)
    For iCountY = 26 To 38 Step 1
     SetPixel DCPicture, iCountX, iCountY, QBColor(iCount)
    Next iCountY
  Next iCountX
Next iCount
Rectangle Form1.hDC, 3, 3, 290, 20
BrushBlue = SelectObject&(DCPicture, oldBrush)
BackVal = DeleteObject&(BrushBlue)
End Sub

Private Sub Command1_Click()
DCWin = GetWindowDC(WindHandle)
    Rectangle DCWin, 3, 3, 290, 20
ReleaseDC WindHandle, DCWin
End Sub

Private Sub Command2_Click()
Lim = Lim + 1
Form1.Refresh
End Sub

Private Sub Command3_Click()
Lim = Lim - 1
Form1.Refresh
End Sub

Private Sub Command4_Click()
Dim oldBrush As Long
Dim BrushRed As Long
ReDim Preserve ArrayPoint(4)
ArrayPoint(0).X = 3
ArrayPoint(0).Y = 89
'''''
ArrayPoint(1).X = 151
ArrayPoint(1).Y = 101
'''''
ArrayPoint(2).X = 295
ArrayPoint(2).Y = 84
'''''
ArrayPoint(3).X = 301
ArrayPoint(3).Y = 130
'''''
ArrayPoint(4).X = 25
ArrayPoint(4).Y = 115
BrushRed = CreateSolidBrush(QBColor(12))
oldBrush = SelectObject&(DCPicture, BrushRed)
Polygon DCPicture, ArrayPoint(0), 5
BrushRed = SelectObject&(DCPicture, oldBrush)
BackVal = DeleteObject&(BrushRed)
End Sub

    Обратите внимание на код в обработчике события Private Sub Command4_Click(). В нем происходит передача массива структур функции Polygon. Контекст устройства хранится в глобальной переменной DCPicture, ее инициализация происходит в событии Private Sub Form_Load. Функция рисования многоугольника обрамлена следующими вызовами BrushRed = CreateSolidBrush(QBColor(12)) oldBrush = SelectObject&(DCPicture, BrushRed) и BrushRed = SelectObject&(DCPicture, oldBrush) BackVal = DeleteObject&(BrushRed). Все, что будет заключено между этими функциями и имеет замкнутый контур(например многоугольник) будет закрашено красным цветом.
    В событии Private Sub Command1_Click() происходит рисование прямоугольника на заголовке формы, но контекст устройства для поверхности вне рабочей(клиентской) области окна автоматически не предоставляется формой. Этот контекст необходимо получить с помощью функции DCWin = GetWindowDC(WindHandle). Теперь в переменной DCWin хранится идентификатор контекст для рисования за пределами клиентской области и его можно передавать любым графическим функциям API.
Самым главным событием является Private Sub Form_Paint(), так как Windows перерисовывает только то, что находится внутри этого события. Проверить это можно если запустить форму на выполнение.
    Запустите приложение. Нажмите кнопку “+” несколько раз, кнопка “Многоугольник” должна быть нажата последней, иначе красный многоугольник будет исчезать при нажатии на “+”. Вид формы приведен на рисунке 1.


Рис. 1

Если теперь передвинуть форму за левый край экрана, а потом вернуть восстановятся только те графические элементы, которые были помещены в событии Private Sub Form_Paint() (Рис.2).


Рис.2

    Цветные столбики нарисованы в тройном вложенном цикле и выводятся по одной точке(пикселю) функцией SetPixel DCPicture, iCountX, iCountY, QBColor(iCount). Найдите в примере строку Form1.Refresh – это значит, что событие Form_Paint применяется ко всей форме. Если форма будет с большим количеством графики чем сейчас Вы заметите нежелательное дрожание(которое и сейчас заметно). Для перерисовки только ограниченной части формы (например прямоугольной области вокруг цветных столбиков) воспользуйтесь функцией Private Declare Function InvalidateRect& Lib "user32" (ByVal hwnd As Long, lpRect As RECT, ByVal bErase As Long). После этого красный многоугольник перестанет исчезать при нажатии на кнопку “Плюс”, а дрожание всей формы исчезнет.