ООП IDE Borland C++ Builder Лекции 16. Проектирование графических приложений 1 Содержание 1. Построение графических изображений компонент Image 2. Канва - холст для рисования 3. Режимы рисования 4. События OnPaint 2 Вопрос 1 Построение графических изображений компонент Image 3 Компонент Image • Потребность вставить в приложение графические объекты: • графическая заставка, являющаяся логотипом приложения - компонент Image (Additional) • графические объекты при разработке приложения, работающего с базой данных –DBImage -DBImage. 4 Компонент Image Свойства компонента Image. • Picture - свойство, может содержать картинку • AutoSize - позволяет подгонять компонент под размер рисунка. • True -размер компонента Image будет автоматически подгоняться под размер помещенной в него картинки • False -изображение может не поместиться в компонент или, наоборот, площадь компонента может оказаться много больше площади изображения • Stretch позволяет подгонять рисунок под размер компонента 5 Компонент Image Свойства компонента Image. • Установить AutoSize = false, растянуть или сжать размер компонента Image и установить Stretch в true. • Рисунок займет всю площадь компонента, но изображение может исказиться. • Устанавливать Stretch в true может иметь смысл только для каких-то узоров, но не для картинок. • Stretch не действует на изображения пиктограмм, которые не могут изменять своих размеров. 6 Компонент Image • • • • • • • Свойства компонента Image. Center=true центрирует изображение на площади Image, если размер компонента больше размера рисунка. Transparent (прозрачность) = true - изображение в Image становится прозрачным - можно использовать для наложения изображений друг на друга. Поместить на форму второй компонент Image и загрузить в него мало заполненную, контурную картинку. Передвинуть Image так, чтобы они перекрывали друг друга, и в верхнем компоненте установить Transparent равным true. Верхняя картинка перестанет заслонять нижнюю. Возможное применение Transparent - наложение на картинку надписей, выполненных в виде битовой матрицы. Свойство Transparent действует только на битовые матрицы 7 Компонент Image - пример • Поместим на форму компонент Image. • Кнопка с … свойства Picture или двойной щелчок на Image, откроется окно Picture Editor, позволяющее загрузить в свойство Picture графический файл (кнопка Load), а также сохранить открытый файл под новым именем или в новой папке. • Щелкнуть на Load - откроется окно Load Picture. • По мере перемещения курсора в списке по графическим файлам в правом окне отображаются содержащиеся в них изображения. • В окне загрузки графического файла можно просмотреть изображение, и увидеть размер изображения. • После щелчка на ОК в компоненте Image отобразится выбранный объект. 8 Компонент Image - пример • При загрузке в процессе проектирования картинки из файла в Image, он не просто отображает ее, но и сохраняет в приложении. • Это дает возможность поставлять приложение без отдельного графического файла. • В Image можно загружать и внешние графические файлы в процессе выполнения приложения. • Рассмотрим пример, чтобы пользователь смог просматривать и загружать любые графические файлы. • Поместим на форму компонент ОреnPictureDialog и кнопку Button и в обработчике щелчка на кнопке введем код: if (OpenPictureDialog1->Execute()) Image1->Picture->LoadFromFile (OpenPictureDialog1->FileName); 9 Компонент Image - пример • Недостаток приложения - изображения могут быть разных размеров и их положение на форме или будет несимметричным, или они не будут помещаться в окне. • Чтобы форма автоматически настраиваться на размеры изображения, установим в Image1 свойство AutoSize равным true, и сделать следующие изменения: if (OpenPictureDialog1->Execute () ) { Image1->Picture->LoadFromFile(OpenPictureDialog1>FileName); Form1->ClientHeight = Image1->Height + 10; Image1->Top=Form1->ClientRect.Top + (Form1>ClientHeight - Image1->Height)/2; Form1->ClientWidth = Image1->Width + 10; Image1->Left=Form1->ClientRect.Left + (Form1>ClientWidth - Image1->Width)/2; } 10 Вопрос 2 Канва - холст для рисования 11 Канва - холст для рисования. Канва и пикселы • Многие компоненты в C++Builder (формы, графические компоненты Image, PaintBox, Bitmap и др.) имеют свойство Canvas (канва, холст) • Канва – это область компонента, на которой можно рисовать или отображать готовые изображения. • Канва содержит свойства и методы, существенно упрощающие графику C++Builder. • Все сложные взаимодействия с системой спрятаны для пользователя. • Каждая точка канвы имеет координаты X и Y. • Система координат канвы имеет началом левый верхний угол канвы. • X возрастает при перемещении слева направо, а Y при перемещении сверху вниз. 12 Канва - холст для рисования. Канва и пикселы • Координаты измеряются в пикселах. • Пиксел - это наименьший элемент поверхности рисунка, с которым можно манипулировать. • Важнейшее свойство пиксела - его цвет. • Для описания цвета используется тип TCoIor. • Для графики иногда этих предопределенных констант не хватает, т.е. могут понадобиться такие оттенки, которых нет в стандартных палитрах. • В этом случае можно задавать цвет 4-байтовым шестнадцатеричным числом. • Например: • $00FF0000 - чистый синий цвет, • $0000FF00 - чистый зеленый, • $000000FF - чистый красный • $00000000 - черный цвет, $00FFFFFF - белый. 13 • • • • • • Рисование по пикселам Рисовать на канве можно разными способами. 1 первый вариант - рисование по пикселам. Для этого используется свойство канвы Pixels представляет собой двумерный массив Canvas>Pixels[int X][int Y], который отвечает за цвета канвы. Canvas->Pixels[10][20] соответствует цвету пиксела, 10-го слева и 20-го сверху. С массивом пикселов можно обращаться как с любым свойством: изменять цвет, задавая пикселу новое значение, или определять его цвет по хранящемуся в нем значению. Например, Canvas->Pixels[10][20] = clBlack это задание пикселу черного цвета. 14 Рисование по пикселам • Пример: нарисовать график функции F(X) на канве компонента Image1, если известен диапазон ее изменения Ymax и Ymin и диапазон изменения аргумента Xmin и Хmах. • Это можно сделать такой процедурой: float x,y; // координаты функции int Px, Py; // координаты пикселов for (Рx = 0; Рx <= Image1->Width; Px++) { //х - координата, соответствующая пикселу с координатой Рх x = Xmin + Рx * (Xmax - Xmin)/ Image1->Width; y = F(x) ; //Pу - координата пиксела, соответствующая координате у Py = Image1->Height - (y - Ymin)*Image1->Height/(YmaxYmin); //Устанавливается черный цвет выбранного пиксела Image1->Canvas->Pixels[Px] [Py] = clBlack; } 15 • • • • • • Рисование по пикселам Вводятся переменные x и y, являющиеся значениями аргумента и функции, а также переменные Рx и Py, являющиеся координатами пикселов, соответствующими x и y. Функция состоит из цикла по всем значениям горизонтальной координаты пикселов Рx компонента Image1. Сначала выбранное значение Рx пересчитывается в соответствующее значение x. Затем производится вызов функции и определяется ее значение y. Это значение пересчитывается в вертикальную координату пиксела Py. И в заключение цвет пиксела с координатами (Рx, Py) устанавливается черным. 16 Рисование по пикселам • Пример приложения построения графика функции sin(x), для которой Xmin=0, Хmах=4π, Ymin=-1, Ymax=1. • Поместим на форму компонент Image и кнопку с надписью «Нарисовать», в обработчик события OnClick запишем следующий код: const double Pi =3.14159 float x, y; // координаты функции sin(x) int Px, Py; // координаты пикселов for (Рx = 0; Рx <- Image1->Width; Px++) { //x - координата, соответствующая пикселу с коорд. Рx x = Рx * 4 * Pi/Image1->Width; y = sin(x) ; //Py - координата пиксела, соответствующая координате y Py = Image1->Height - (y+1) * Image1->Height /2; Image1->Canvas->Pixels[Px][Py] = clBlack; } 17 Рисование с помощью пера Реn • • • • • 2 вариант рисования на канве – с помощью пера Pen. У канвы есть свойство Реn - перо. Это объект, в свою очередь имеет ряд свойств. Свойство Color - цвет, которым наносится рисунок. Свойство - Width (ширина линии) - задается в пикселах, по умолчанию равна 1. • Свойство Style определяет вид линии, может принимать следующие значения: psSolid Сплошная линия. psDash Штриховая линия. psDot Пунктирная линия. psDashDot Штрихпунктирная линия. psDashDotDot Линия, чередующая штрих и два пунктира. psClear Отсутствие линии. psInsideFrame Сплошная линия, но при Width > 1 допускающая цвета, отличные от палитры Windows. 18 Рисование с помощью пера Реn • Все стили со штрихами и пунктирами доступны только при Width=1. • В противном случае линии этих стилей рисуются как сплошные. • Стиль psInsideFrame - единственный, который допускает произвольные цвета. • Цвет линии при остальных стилях округляется до ближайшего из палитры Windows. • Свойство канвы PenPos определяет в координатах канвы текущую позицию пера. • Перемещение пера без прорисовки линии, т.е. изменение PenPos, производится методом канвы MoveTo(x,y) (где (x,y) - координаты точки, в которую перемещается перо). • Эта текущая точка становится исходной, от которой методом LineTo(x,y) можно провести линию в точку с координатами (x,y). • При этом текущая точка перемещается в конечную точку линии и новый вызов LineTo будет проводить точку из этой 19 новой текущей точки. Рисование с помощью пера Реn • Рассмотрим рисование пером графика синуса. • Добавим на форму еще один компонент Image. • Размеры обоих компонентов Image должны быть абсолютно одинаковы. • Сделать размеры компонентов абсолютно одинаковыми легко, выделив их оба и воспользовавшись командой всплывающего меню Size. • Затем в обработчике щелчка на кнопке сделаем соответствующие изменения: 20 Рисование с помощью пера Реn const double Pi = 3.14159; float x, y; // координаты функции sin(x) int Px, Py; // координаты пикселов Image2->Canvas->MoveTo(0,Image2->Height / 2) ; for (Рx = 0; Рx < Image1->Width; Px++) { x = Рx * 4 * Pi / Image1->Width; y = sin(x) ; Py = Image1->Height - (y+l) * Imagel->Height /2; Image1->Canvas->Pixels[Px][Py] = clBlack; Image2->Canvas->LineTo(Px,Py); // Проводится линия на втором графике } 21 Рисование с помощью пера Реn • Оба графика абсолютно одинакового размера • пересчет координат достаточно провести для одного из них, затем воспользоваться ими для рисования обоих графиков. • Качество двух одинаковых графиков сильно различается. • В левом на крутых участках сплошной линии нет - она распадается на - пикселы. • А правый график весь сплошной. • Это показывает, что при прочих равных условиях рисовать лучше пером. • Еще одно свойство компонента Image и его канвы. Можно задавать координаты пикселов, выходящие за пределы размеров канвы • Это позволяет не заботиться о том, какая часть рисунка попадает в рамку Image, а какая нет. 22 Рисование с помощью пера Реn • легко проверить это, увеличив, например, вдвое размах синусоиды. • Для этого достаточно изменить оператор, задающий значение y, на следующий: Y = 2 * sin(x) ; • Изобразится только та часть рисунка, которая помещается в рамку канвы. • Это позволяет легко осуществлять приложения, в которых пользователю предоставляется возможность увеличивать и просматривать в деталях какие-то фрагменты графиков. 23 Рисование с помощью пера Реn • Перо может рисовать не только прямые линии, но и фигуры. • Методы канвы, использующие перо для рисования фигур: Arc Рисует дугу окружности или эллипса. Chord Ellipse Рисует замкнутую фигуру, ограниченную дугой окружности или эллипса и хордой. Рисует окружность или эллипс. Pie Рисует сектор окружности или эллипса. Polygon Polyline Рисует замкнутую фигуру с кусочно-линейной границей. Рисует кусочно-линейную кривую. Rectangle Рисует прямоугольник. RoundRect Рисует прямоугольник со скругленными углами. 24 Рисование с помощью пера Реn Код, который рисует различные фигуры. Image1->Canvas->Font->Style << fsBold; Image1->Canvas->Arc(10,10,90,90, 90, 50,10,50) ; Image1->Canvas->TextOut (40, 60, "Arc") ; Image1->Canvas->Chord(110,10,190,90,190,50,110, 50) ; Image1->Canvas->TextOut(135,60,"Chord"); Image1->Canvas->Ellipse(210,10,290, 50) ; Image1->Canvas->TextOut(230,60,"Ellipse") ; Image1->Canvas->Pie(310,10,390,90,390,30,310,30); Image1->Canvas->TextOut(340,60,"Pie") ; TPoint points[5]; points[0] = Point(30,150) ; points[1] = Point(40,130); points[2] = Point(50,140); points[3] = Point(60,130) ; points[4] = Point(70,150) ; 25 Рисование с помощью пера Реn Код, который рисует различные фигуры. Image1->Canvas->Polygon(points,4); Image1->Canvas->TextOut(30,170,"Polygon"); points[0].x += 100; points[1].x += 100; points[2].x += 100; points[3].x += 100; points[4].x += 100; Image1->Canvas->Polyline(points, 4) ; Image1->Canvas->TextOut(130,170,"Polyline"); Image1->Canvas->Rectangle(230,120,280,160) ; Image1->Canvas->TextOut(230,170,"Rectangle") ; Image1->Canvas->RoundRect(330,120,380,160,20,20) ; Image1->Canvas->TextOut(325,170,"RoundRect") ; 26 Рисование с помощью пера Реn • Свойство канвы Brush - кисть определяет фон и заполнение замкнутых фигур на канве. • Brush - это объект, имеющий в свою очередь ряд свойств. • Свойство Color определяет цвет заполнения. • Свойство Style определяет шаблон заполнения (штриховку). • Свойство Bitmap является указателем на объект типа TBitmap и определяет нестандартное заполнение заданным шаблоном. • Шаблон задается битовой матрицей размером 8x8. • Если для кисти задан шаблон Bitmap, то заполнение производится именно этим шаблоном, независимо от значения свойства Style. • Шаблон Bitmap может создаваться в процессе выполнения приложения или, например, загружаться из 27 файла. Рисование с помощью пера Реn • Метод канвы FillRect (TRect SRect) заполняет заданным стилем или шаблоном прямоугольную область, заданную параметром Rect. • Для его задания проще всего использовать функцию Rect(x1,y1,x2,y2), возвращающую структуру Rect с координатами углов, заданных параметрами (x1, y1) и (x2, y2). • Функцию FillRect удобно, в частности, использовать для стирания изображения. Например, оператор Image1->Canvas->FillRect(Rect(0,0, Image1>Width,Image1->Height)); очищает всю площадь канвы компонента Image1. • Кисть участвует в заполнении фигур не только с помощью этой функции. • Все перечисленные ранее методы рисования замкнутых фигур тоже заполняют их с помощью кисти. • Это относится к методам Chord, Ellipse, Pie, Polygon28и Рисование с помощью пера Реn • Метод FloodFill - заполняет замкнутую область на канве. • Определен следующим образом: FloodFill(int x, int y, TColor Color, TFillstyle FillStyle); • Точка с координатами x и y является произвольной внутренней точкой заполняемой области, которая может иметь произвольную форму. • Граница этой области определяется сочетанием параметров Color и FillStyle. • Параметр Color указывает цвет, который используется при определении границы заполняемой области, а параметр FillStyle определяет, как именно по этому цвету определяется граница. 29 Рисование с помощью пера Реn • Параметр FillStyle может принимать одно из двух следующих значений: • fsSurface • fsBorder. • Если FillStyle = fsSurface, то заполняется область, окрашенная цветом Color, а на других цветах метод останавливается. • Если FillStyle = fsBorder, то наоборот, заполняется область окрашенная любыми цветами, не равными Color, a на цвете Color метод останавливается. • Для определения области закрашивания можно использовать координаты и цвет одного из пикселов, расположенных внутри области (если FillStyle = fsSurface) или снаружи ее (если FillStyle = fsBorder). 30 Вопрос 3 Режимы рисования 31 Режимы рисования пера Реn • У пера Реn имеется еще одно свойство - Mode (режим). • По умолчанию значение Mode = pmCopy. • Это означает, что линии проводятся цветом, заданным в свойстве Color. • Но возможны и другие режимы, в которых учитывается не только цвет Color, но и цвет соответствующих пикселов фона. • Наиболее интересным из этих режимов является режим pmNotХоr - сложение с фоном по инверсному исключающему ИЛИ. • Операция инверсного исключающего ИЛИ анализирует по битам два своих операнда. • Результирующий бит равен "0", если соответствующие биты двух операндов не равны друг другу, а при равенстве битов операндов результирующий бит равен "1". 32 Режимы рисования пера Реn • Каждый пиксел хранит цвет как набор битов. • Пусть фоновый пиксел имеет значение 0110011, а цвет пера установлен в 1111000. • Применение, операции pmNotXor к этим двум числам даст цвет со значением 0110100. • Этот цвет перо задаст данному пикселу. • А теперь посмотрим, что получится, если перо повторно пройдет по тому же пикселу. • В этом случае опять будет выполнена операция pmNotXor по отношению к цвету пера 1111000 и текущему цвету пиксела, который стал равен 0110100. • Применение pmNotXor к этим числам даст в результате 0110011, т.е. первоначальный цвет пиксела. 33 Режимы рисования пера Реn • Если нарисовать на фоне какую-то фигуру один раз, а затем нарисовать ту же фигуру повторно, то нарисованная фигура исчезнет и каждый пиксел вернется к своему первоначальному цвету. • Эту особенность режима pmNotXor, свойственную также режиму ртХог - сложение с фоном по исключающему ИЛИ, можно использовать для создания простенькой анимации. • Достаточно нарисовать нечто, затем стереть нарисованное, перерисовать немного измененным и рисунок будет представляться ожившим. 34 Режимы копирования и рисования канвы • Метод копирования канвы CopyRect позволяет копировать прямоуг. область источника изображения в прямоуг. область данной канвы. • Метод определен следующим образом: CopyRect(TRect &Dest, TCanvas * Canvas, TRect &Source); • Параметр Dest определяет прямоугольную область канвы, в которую производится копирование. • Параметр Canvas указывает источник, из которого копируется изображение. • Это может быть канва любого компонента: типа TImage, типа TBitmap и др. • В частном случае источником может быть и канва того же компонента, в который производится копирование. • Параметр Source определяет прямоугольную область в источнике изображения, которая копируется в область Dest. • Обе прямоугольные области и в источнике, и в приемнике 35 имеют тип Trect. Режимы копирования и рисования канвы • Копирование - это не просто перенос изображения, а сложное взаимодействие копируемого изображения и того, которое было до этого в области, куда производится копирование. • Характер этого взаимодействия определяется параметром CopyMode (режим копирования) той канвы, в которую производится копирование. • По умолчанию значение CopyMode равно cmSrcCopy. • Это единственный режим, при котором производится действительное копирование: изображение в Dest стирается и заменяется скопированным. • Есть два значения - cmWhiteness и cmBlackness, при которых собственно никакое копирование не производится: просто область закрашивается соответственно белым или черным цветом. • А все остальные режимы определяют сложное взаимодействие копируемого изображения с тем, которое 36 было в Dest. Режимы копирования и рисования канвы • Особый интерес представляет режим cmScrInvert, при котором изображения канвы и источника комбинируются, используя булеву операцию XOR. • Так же, как и для пера, повторное копирование в подобном режиме восстанавливает прежнее изображение на канве. • Интересен также режим cmSrcAnd. • Если копируемое изображение представляет собой контурный черный рисунок на белом фоне, то этот рисунок наложится на прежнее изображение канвы, а белый фон будет прозрачным, так что под ним будет видно первоначальное изображение. • В режиме cmSrcPaint аналогичный эффект будет, если копируемое изображение представляет собой белый контурный рисунок на черном фоне. 37 Режимы копирования и рисования канвы Примеры копирования в различных режимах. Image1->Canvas->CopyMode = cmSrcCopy; Image1->Canvas-> CopyRect(Rect(0,0,200,200),Image2->Canvas, Rect (0,0,200,200)); • обеспечивают копирование изображения фрагмента канвы компонента Image2 в указанную область канвы компонента Image1. • Изображение, которое ранее было на канве компонента Image1 в пределах области с координатами углов (0, 0) и (200, 200), просто заменяется новым. 38 Режимы копирования и рисования канвы Примеры копирования в различных режимах. Image1->Canvas->CopyMode = cmSrcInvert; Image1->Canvas>CopyRect(Rect(0,0,200,200),Image2->Canvas, Rect(0,0,200,200)) ; Image1->Canvas->CopyRect (Rect (0, 0, 200, 200) ,lmage2->Canvas,Rect (0,0,200,200)); • обеспечивают копирование изображения фрагмента канвы компонента Image2 в указанную область канвы компонента Image1 в режиме cmSrcInvert. • После выполнения функции CopyRect в первый раз изображения в компонентах Image1 и Image2 налагаются друг на друга, а в результате выполнения функции CopyRect во второй раз исходное изображение на канве компонента 39 Image1 восстанавливается. Режимы копирования и рисования канвы Примеры копирования в различных режимах. Image1->Canvas->CopyMode = cmWhiteness; Image1->Canvas>CopyRect(Rect(0,0,200,200),Image2->Canvas, Rect(0,0,200,200)) ; • просто очищают указанную область канвы компонента Image1, закрашивая ее белым цветом. • При этом изображение в компоненте Image2 никак не участвует в операциях копирования. 40 Режимы копирования и рисования канвы • Помимо методов копирования свойство CopyMode используется также методом рисования на канве Draw: void _fastcall Draw(int x, int y, TGraphic* Graphic); • Метод Draw рисует изображение, содержащееся в объекте, указанном параметром Graphic, сохраняя исходный размер изображения в его источнике и перенося изображение в область канвы объекта, верхний левый угол которой определяется параметрами x и y. • Источник изображения может быть битовой матрицей, пиктограммой или метафайлом. • Если источник - объект типа TBitmap, то перенос изображения производится в режиме, установленном свойством канвы CopyMode. 41 Режимы копирования и рисования канвы • • • • • Оператор Image1->Canvas->Draw(10,10,Bitmap1); рисует на канве компонента Image1 изображение из компонента Bitmap1 в область с координатами левого верхнего угла (10, 10). Метод рисования – DrawFocusRect - рисует изображение прямоугольника в виде, используемом для отображения рамки фокуса, операцией XOR. Функция DrawFocusRect объявлена следующим образом: void _fastcall DrawFocusRect(const Windows::TRect *Rect); где Rect - прямоугольная область. Поскольку при рисовании используется операция XOR, то повторный вызов этого метода с тем же значением Rect удаляет изображение 42 прямоугольника. Вопрос 4 События OnPaint 43 События OnPaint • Канву имеют многие компоненты, например, формы. • Все, что ранее рисовали на канве компонента Image, можно рисовать и на форме. • Кроме того, имеется специальный компонент PaintBox, имеющий канву и позволяющий рисовать на ней. • При рисовании на канве формы или PaintBox надо учитывать некоторые особенности. • Сначала выясним, о чем идет речь. • Откроем новое приложение, перенесем на него диалог OpenPictureDialog, кнопку и в обработчик щелчка на ней вставим операторы: 44 События OnPaint void _fastcall TForm1::ButtonlClick(TObject *Sender) { if (OpenPictureDialog1->Execute ()) { Graphics::TBitmap *Bitmap = new Graphics::TBitmap; try { Bitmap->LoadFromFile(OpenPictureDialog1->FileName); Form1->Canvas->Draw(0,0,Bitmap); } finally { Bitmap->Free(); } } } • . 45 События OnPaint • Эти операторы обеспечивают загрузку выбранного пользователем графического файла и отображение изображения непосредственно на канве формы. • Запустим приложение, выберем файл. • А теперь, не закрывая приложение, вернемся в C++Builder и, ничего там не делая, опять перейдем в приложение. • Если окно Редактора Кода, выступившее на первый план при переходе в C++Builder, целиком перекрыло окно приложения, то, вернувшись в него увидим, что картинка в окне исчезла. • Если же опять загрузим в него картинку и сдвинем окно приложения так, чтобы окно Редактора Кода не могло целиком его закрыть, то, повторив эксперимент с переходом в C++Builder и обратно увидим результат. 46 События OnPaint • Если окно какого-то другого приложения перекрывает на время окно приложения, то изображение, нарисованное на канве формы, портится. • В компоненте Image этого не происходило, поскольку в классе TImage уже предусмотрены все необходимые действия, осуществляющие перерисовку испорченного изображения. • А при рисовании на канве формы или других оконных компонентов эти меры должен принимать разработчик приложения. • Если окно было перекрыто и изображение испортилось, операционная система сообщает приложению, что в окружении что-то изменилось и что приложение должно предпринять соответствующие действия. • Как только требуется обновление окна, для него генерируется событие OnPaint. • В обработчике этого события нужно перерисовать 47 изображение. События OnPaint • Перерисовка может производиться разными способами в зависимости от приложения. • В примере можно было бы вынести объявление указателя Bitmap за пределы приведенной выше процедуры, т.е. сделать эту переменную глобальной: Graphics::TBitmap *Bitmap; • Тогда приведенная выше процедура загрузки файла примет вид: if (OpenPictureDialog1->Execute()) { Bitmap = new Graphics::TBitmap; Bitmap->LoadFromFile(OpenPictureDialog1>FileName); Canvas->Draw(0,0,Bitmap); } 48 • • • • События OnPaint Оператор Bitmap->Free() нужно перенести в обработчик события формы OnDestroy. Тогда в течение всего времени выполнения приложения будете иметь копию картинки в компоненте Bitmap и достаточно ввести в обработчик события OnPaint формы всего один оператор: if (Bitmap != NULL) Canvas->Draw(0,0,Bitmap); Оператор if используется, чтобы избежать ошибочного обращения к Bitmap, пока графический файл еще не загружался и объект Bitmap не создан. Теперь изображение на форме не портится при любых перекрытиях окон. 49 События OnPaint • Написанный обработчик перерисовывает все изображение. • При больших изображениях это может существенно замедлять перерисовку и вызывать неприятные зрительные эффекты. • Перерисовку можно существенно ускорить, если перерисовывать только испорченную область канвы. • У канвы есть свойство ClipRect типа TRect, которое в момент обработки события OnPaint указывает область, которая подлежит перерисовке. • Поэтому более экономным будет обработчик: if (Bitmap != NULL) Canvas->CopyRect (Canvas->ClipRect, Bitmap>Canvas, Canvas->ClipRect); • Он перерисовывает только область ClipRect, 50 которая испорчена.