Рисунки в delphi 7

Рисунки в delphi 7

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

Графика в Windows

Когда приложению требуется вывести какую-либо информацию на экран дисплея, операционная система — Windows — предоставляет ей в свое распоряжение оконно-ориентированную графику. Это означает, что каждая форма (как, впрочем, и ряд других объектов) рассматривается как поверхность для рисования — холст (canvas).

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

За точку отсчета координат в окнах принимается левый верхний угол его клиентской области, ограниченной рамкой (т.е. как раз те габариты, что отражаются свойствами ClientHeight и ClientWidth). Для других элементов, имеющих холст для рисования, подобной рамки может и не быть — в таком случае рамками такого виртуального холста выступают границы объекта.

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

Хорошая новость состоит в том, что Delphi имеет целый ряд готовых к использованию компонент, заботиться о рисовании которых разработчику совершенно незачем, поскольку всю рутинную работу уже выполнили разработчики Delphi и VCL. Более того, в VCL есть множество "заготовок", на основании которых можно создавать собственные компоненты, опять-таки без непосредственного обращения к функциям графического вывода.

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

Объект Canvas

Для многих элементов интерфейса в Windows-приложениях используется компоненты, основанные на классе TWinControl, являющегося прямым наследником уже рассмотренного нами класса TControl. Но множество других визуальных компонент происходят от другого его наследника — класса TGraphicControl, являющийся более простым и имеющим такое свойство, как Canvas, при помощи которого можно в буквальном смысле рисовать в Windows. Собственно говоря, свойство Canvas имеется не только у этого класса, но и у ряда других, в том числе и основанных на TWinControl. Впрочем, в любом случае это свойство будет представлено одним и тем же классом — TCanvas.

Объект Canvas инкапсулирует в себе взаимодействие с Windows GDI (Graphic Device Interface — интерфейс графического устройства). GDI обрабатывает весь графический вывод, предназначенный для экрана монитора, а так же для принтеров и иных печатающих устройств. Но поскольку взаимодействие с GDI, как, впрочем, и с другими подсистемами Windows API напрямую — дело хлопотное и чреватое ошибками, то в Delphi и был предусмотрен класс TCanvas, предоставляющий сравнительно простой и удобный доступ к GDI.

Сам по себе холст (Canvas) представляет собой поверхность, на которую можно выводить текст и иные графические изображения — линии, прямоугольники, эллипсы и т.д. Но при ближайшем рассмотрении можно увидеть, что этот холст представляет собой плоскость, состоящую из отдельных точек — пикселей. Пиксель — это базовый элемент графического ввода, представляющий собой отдельную точку. Фактически, при рисовании на холсте вы просто закрашиваете его отдельные точки тем или иным цветом. Но, разумеется, работая с холстом посредством методов, предоставляемых классом TCanvas, можно без лишних хлопот выводить не только точки, но и текст, линии, прямоугольники, многоугольники, окружности, и даже готовые изображения. Рассмотрим основные свойства и методы объекта Canvas, обратившись к таблице 9.1.

Таблица 9.1. Свойства и методы TCanvas

Свойство (метод) Тип значений или параметры Описание
Pixels Матрица TColor Предоставляет доступ к любому пикселю холста, чтобы узнать или изменить его цвет
Pen TPen Свойства пера для черчения линий
Brush TBrush Свойства кисти для заполнения внутренних областей фигур
Font TFont Свойства шрифта для вывода текста
MoveTo X, Y: Integer Устанавливает текущую позицию пера
LineTo X, Y: Integer Проводит линию от текущей позиции к указанной
TextOut X, Y: Integer; const Text: string Выводит заданный текст, начиная с указанных координат
Rectangle X1, Y1, X2, Y2: Integer или Rect: TRect Рисует прямоугольник указанных размеров. Цвет рамки определяется текущим значением свойства Pen, а цвет заливки – свойством Brush
Ellipse X1, Y1, X2, Y2: Integer или Rect: TRect Рисует эллипс, вписанных в прямоугольник указанных размеров. Цвет рамки определяется текущим значением свойства Pen, а цвет заливки – свойством Brush
Polygon Points: array of TPoint Рисует многоугольник по указанным вершинам
PolyLine Points: array of TPoint Рисует ломаную линию, соединяющую указанные точки
Draw X, Y: Integer; Graphic: TGraphic Выводит графическое изображение, начиная от указанных координат (левого верхнего угла)

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

Здесь мы обратились к 1-му элементу 1-го ряда массива, которой как раз и соответствует левому верхнему углу холста, и назначили ему значение clRed, т.е. установили красный цвет.

Поскольку с использованием различных методов объекта Canvas можно выводить не только точки, но и различные фигуры, а так же текст, то остальные свойства как раз позволяют настроить параметры вывода этих фигур и текста. Так, для текста используется свойство Font, являющееся, в свою очередь, классом TFont и имеющим такие свойства, как Color (цвет), Name (гарнитура шрифта), Size (размер) и Style (стиль). Последнее свойство имеет 4 флага, позволяющих сделать шрифт полужирным, наклонным, подчеркнутым или зачеркнутым:

Canvas.Font.Color:=clBlue; //шрифт будет синего цвета Canvas.Font.Name:=’Arial’; //выбрана гарнитура Arial Canvas.Font.Size:=12; //установлен размер шрифта в 12pt Canvas.Font.Style:=[fsBold,fsItalic]; //шрифт будет полужирным наклонным

Что касается таких свойств холста, как Pen и Brush, то для них предусмотрено изменение цвета и стиля линии (для Pen) или заполнения (для Brush). Кроме того, для пера можно определить ширину линии и режим наложения цвета. Соответственно, мы имеем следующие свойства:

  • Color — определяет цвет линии для пера или заполнения для кисти;
  • Style — определяет стиль линии или заливки. Для линии возможны следующие значения: psSolid, psDash, psDashDot, psDashDotDot, psClera и psInsideFrame. Для заливки: bsSolid, bsClear, bsHorizontal, bsVertical, bsFDiagonal, bsBDiagonal, bsCross, bsDiagCross;
  • Width — определяет толщину линии в пикселях.

Следует учитывать, что изменить стиль линии возможно только в том случае, если ее толщина установлена в 1 пиксель (что, впрочем, является значением по умолчанию). При любом другом значении толщины линия всегда будет сплошной — psSolid.

Читайте также:  Вычисление логарифма по основанию 2

Черчение фигур

Чтобы лучше представить себе использование объекта Canvas, попробуем использовать его свойства и методы для рисования фигур. Для начала попробуем вывести простую линию на поверхность формы, для чего создадим новое приложение, щелкнем по автоматически созданной форме (Form1), после чего перейдем в окно инспектора объекта и на закладке Events дважды щелкнем по строке напротив надписи OnClick. В ответ на это Delphi создаст обработчик события FormClick в редакторе кода:

procedure TForm1.FormClick(Sender: TObject); begin end;

Теперь остается поместить в него код, рисующий линию. Поскольку у формы уже имеется свойство Canvas, то будет достаточно просто обратиться к его методам MoveTo и LineTo. Пусть линия начнется в точке со смещением в 10 пикселей от левого верхнего угла по вертикали и горизонтали, и продлится до точки в 200 пикселей по горизонтали. В результате код получится следующим:

procedure TForm1.FormClick(Sender: TObject); begin Form1.Canvas.MoveTo(10,10); Form1.Canvas.LineTo(200,10); end;

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

Здесь в обоих случаях мы построили правильные фигуры, т.е. окружность и квадрат. Но поскольку для класса TCanvas не определены методы, строящие именно эти фигуры, то мы использовали методы для построения эллипса и прямоугольника, рассматривая окружность и квадрат как частные случаи этих типов фигур. В то же время, при необходимости можно было бы создать собственные методы, добавив их к классу TCanvas. Сделать это, на самом деле, несложно: достаточно определить новый класс, являющийся наследником TCanvas, и определить для него 2 новых метода. Назовем такой класс TMyCanvas, а методы — Circle и Square:

TMyCanvas = class(TCanvas) procedure Circle(Rad, X, Y: integer); procedure Square(Size, X, Y: integer); end;

Определение этого класса следует поместить в части interface, непосредственно после определения класса TForm1, которое уже размещено в модуле самой Delphi. В части же implementation мы определим сами эти функции:

procedure TMyCanvas.Circle(Rad, X, Y: integer); begin end; procedure TMyCanvas.Square(Size, X, Y: integer); begin end;

Теперь остается написать код, выполняющий построение фигур. Для начала примем, тот факт, что для метода Circle параметр Rad означает радиус окружности, а параметры X и Y — ее центр. Таким образом, мы можем использовать унаследованный метод Ellipse, подставив нужные параметры в его вызов:

Ellipse(X-Rad, Y-Rad, X+Rad, Y+Rad);

Что касается метода Square, то его параметр Size будет означать размер стороны квадрата, а X и Y — координаты верхнего левого угла. Таким образом, можно использовать метод Rectangle, указав для него соответствующие параметры:

Rectangle(X, Y, X+Size, Y+Size);

Теперь, когда методы определены и новый класс готов, следует разобраться с тем, как его использовать. Прежде всего, нам понадобится определить переменную — экземпляр класса. Кроме того, нам понадобится создать ее, использовав конструктор Create. Ну и, наконец, используя свойство Handle (указатель), мы должны связать наш объект с холстом формы. Все это можно разместить во все том же методе обработки щелчка мышкой.

procedure TForm1.FormClick(Sender: TObject); var MC: TMyCanvas; begin MC:=TMyCanvas.Create; // используем конструктор родительского класса MC.Handle:=Canvas.Handle; // назначаем холст окна областью вывода MC.Circle(50,200,100); // рисуем окружность диаметром 50 пикселей MC.Square(50,100,100); // рисуем квадрат со сторонами 50 пикселей MC.Free; end;

Разумеется, все методы, доставшиеся классу TMyCanvas в наследство от TCanvas, так же можно использовать, включая те же Create и Free, чем мы и воспользовались. Применительно к остальным свойствам и методам можно делать то же самое, например, установить толщину и цвет линии, вывести линию при помощи MoveTo и т.д.:

MC.Pen.Width:=3; MC.Pen.Color:=clRed; MC.MoveTo(10,10); MC.LineTo(200,10); MC.Brush.Style:=bsHorizontal;

Таким образом, можно оформить вывод фигур, при помощи заполнения, штриховкой, а линию сделать толще и изменить ее цвет (рис. 9.1).


Рис. 9.1. Вывод графики на холст окна

Законченный код программы можно найти в каталоге DemoPart2Canvas. В нем же приведен еще один вариант использования метода Circle — для создания кольца из окружностей.

Вывод на печать

Вывод текста и графики возможен не только на дисплей, но и на принтер. Для этого так же используется свойство Canvas, но только не формы, а специального объекта Printer. Чтобы задействовать этот объект, необходимо подключить к программе модуль printers, указав его в списке используемых модулей, т.е. в uses. При этом не требуется ни создавать экземпляр класса TPrinter, ни заботиться о его удалении — достаточно просто использовать переменную Printer, которая создается для программы автоматически, если указан модуль Printers.

Помимо свойства Canvas, объект Printer имеет ряд иных свойств и методов, необходимых для осуществления печати. Среди методов этого объекта следует отметить, прежде всего, BeginDoc и EndDoc. Эти методы используются, соответственно, для начала и окончания процесса печати. Отметим так же метод NewPage, используемый для обозначения начала новой страницы, а так же метод Abort, прерывающий процесс печати. Что касается свойств, то они приведены в таблице 9.2.

Таблица 9.2. Свойства класса TPrinter

Свойство Тип Описание
Aborted Boolean Указывает, остановлена или нет печать пользователем
Canvas TCanvas Представляет холст листа
Copies Integer Определяет число копий для печати
Orientation TPrinterOrientation Определяет формат расположения бумаги – портретный (poPortrait), или ландшафтный (poLandscape)
PageHeight Integer Указывает на высоту страницы в пикселях
PageNumber Integer Указывает на текущую печатаемую страницу
PageWidth Integer Указывает на ширину страницы в пикселях
Printing Boolean Указывает, выполняется или нет печать в данный момент
Title String Определяет текст, идентифицирующий задание печати в менеджере принтеров Windows

Прежде, чем что-либо выводить не печать, необходимо проделать подготовительную работу. Это вызвано рядом причин, в частности, тем, что принтер не может печатать под обрез — следовательно, надо определить поля. Кроме того, у разных принтеров различное выходное разрешение, которое зависит как от модели, так и от настроек качества печати. В случае вывода текста так же следует определиться с количеством строк, помещающихся на странице. Тем не менее, в простейшем случае для вывода на печать бывает достаточно просто открыть документ для печати при помощи метода BeginDoc и назначить свойству Canvas принтера необходимое содержимое:

Printer.BeginDoc; Printer.Canvas.TextOut(150, 150, ‘Текст для печати’); Printer.EndDoc;

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

В то же время, если надо вывести только текст, причем его оформление не принципиально, то можно воспользоваться стандартной процедурой writeln, указав для нее вывод на принтер. Делается это при помощи процедуры AssignPrn:

var F: TextFile; . AssignPrn(F); Rewrite(F); writeln(F,’Текст для печати.’); CloseFile(F);

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

Чтобы посмотреть, как работают оба этих метода, можно обратиться к примеру, находящемуся в каталоге DemoPart2Print.

Читайте также:  Как отменить приглашение в скайпе

Но вернемся к графическому выводу на принтер. Как уже было отмечено, для начала следует определиться с областью, доступной для печати и с ее размерами в пикселях. Для удобства бывает полезным определить переменные, отвечающие за размер полей с каждой из сторон документа. В случае вывода строк текса так же необходима переменная, определяющая положение ввода текущей строки. Что касается предмета для вывода, то попробуем нарисовать рамку для всей страницы, проходящую по ее полям, а так же текст разного размера и начертания, и какую-либо еще геометрическую фигуру. Все это мы можем разместить в функции, которую назовем PrintAny (см. листинг 9.1).

Листинг 9.1. Печать текста и графики

procedure PrintAny; var LMargin, RMargin, TMargin, BMargin: integer; fH, HPos: integer; begin with Printer, Printer.Canvas do begin LMargin:=PageWidth div 10; // поле слева 10% от ширины страницы RMargin:=PageWidth div 20; // поле справа 5% от ширины страницы TMargin:=PageHeight div 20; // поле сверху 5% от высоты страницы BMargin:=PageHeight div 10; // поле снизу 10% от высоты страницы Title:=’Пробная печать’; // заголовок печати BeginDoc; Pen.Width:=3; Rectangle(LMargin,TMargin,PageWidth-RMargin,PageHeight-BMargin); // рамка Font.Name:=’Arial’; Font.Style:=[fsBold,fsUnderline]; Font.Size:=24; fH:=abs(Font.Height); // получаем высоту шрифта HPos:=TMargin+fH; // вычисляем отступ сверху для вывода текста TextOut(LMargin,Hpos,’ Заголовок ‘); Font.Style:=[]; Font.Size:=10; fH:=abs(Font.Height); HPos:=HPos+TMargin+fh; // вновь вычисляем отступ для дальнейшего вывода TextOut(LMargin,Hpos,’ Текст абзаца.’); Ellipse(LMargin*2,Hpos+LMargin,LMargin*4,Hpos+LMargin*3); // рисуем круг EndDoc; end; // конец width end; // конец процедуры PrintAny

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

Пример работы этой функции можно посмотреть в программе AnyPrint, которая расположена в каталоге DemoPart2Print2.

Жаргон GDI.

GDI расшифровывается как Graphics Device Interface, и представляет собой интерфейс, который Windows использует для рисования 2D графики. Также это самый медленный способ отображения графики из существующих, однако самый простой для понимания основ. Итак, для начала, поговорим об основных понятиях и терминах в GDI.

Начнём с того, что GDI обычно не используют для создания крутых графических эффектов, для этого есть DirectX, OpenGL, или любые графические библиотеки (такие как: DelphiX, FastLib, DIBUltra, Graphics32. ). Однако, для создание простых эффектов с минимальными усилиями GDI вполне сгодится.

С GDI тесно связана ещё одна аббревиатура — DC ("Device Context" — контекст устройства). Это то, на чём мы рисуем, и в Delphi контекст устройства представлен как TCanvas. Идея контекста устройства заключается в том, что это универсальное устройство вывода, поэтому можно использовать одинаковые функции как для экрана, так и для принтера.

Все графические функции в Delphi являются надстройками над стандартными GDI функциями Windows. Позже мы поговорим об этих функциях.

А теперь самое время приступить к рассмотрению того, как устроен GDI. Ниже, в таблице, представлены некоторые важные классы:

Имя Описание
Pen Используется для рисования простых линий. Обычно применяется для функции LineTo или при рисовании рамки для определённой фигуры (например для функции Rectangle).
Brush Кисть используется для заполнения области определённым цветом. Применяется в функциях Rectangle, FillRect или FloodFill.
Font Используется для задания шрифта, которым будет нарисован текст. Можно указать имя шрифта, размер и т.д.
Region Позволяет задать регион (замкнутое пространство). Регионом может быть круг, квадрат или произвольная фигура. Позволяет так же делать дырки в фигурах.

Однако, пора переходить от слов к делу, а именно, начать рисовать линии и фигуры.

Рисование линий

Сперва необходимо чётко уяснить, что координата (0,0) это верхний левый угол экрана. То есть значения по оси y увеличиваются вниз экрана. Соответственно, координата (0, 50) означает, что мы просто отступили на 50 пикселей от верха экрана.

Самое главное, что надо знать при рисовании линий и фигур, это различие между пером (Pen) и кистью (Brush). Всё очень просто: перо (Pen) используется при рисовании линий или рамок, а кисть (Brush) для заполнения фигуры.

Ниже приведены две функции, которые используются для рисования линий и обе принадлежат TCanvas:

Имя Описание Пример
MoveTo Перемещает точку начала рисования линии в указанные координаты x и y Canvas.MoveTo(50, 100);
LineTo Рисует линию начиная с текущей позиции (см. MoveTo) до указанных координат x и y. Canvas.LineTo(50, 100);

Эффект перемещения точки начала рисования линии так же достигается при помощи установки своства PenPos в канвасе. например, "Canvas.PenPos.x := 20;", "Canvas.PenPos.y := 50", или "Canvas.PenPos := Point(20,50);".

По умолчанию, точка начала рисования установлена в (0,0), то есть, если сразу вызвать "Canvas.LineTo(100,100);" то будет нарисована линия из точки (0,0) в точку (100, 100). Точка начала рисования автоматически переместится в (100, 100), то есть, если выполнить команду "Canvas.LineTo(200, 100);", то следующая линия будет нарисована из точки (100, 100) в (200, 100). Поэтому, если мы хотим рисовать линии несоединённые друг с другом, то придётся воспользоваться методом MoveTo.

Линия, нарисованная при помощи LineTo использует текущее перо канваса (типа TPen). Основные свойства пера, это ширина — "Canvas.Pen.Width := 4;" (при помощи которого можно задавать различную ширину линий), и цвет "Canvas.Pen.Color := clLime;".

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

Процедура DrawLines вызывается из обработчика кнопки OnClick. Количество линий задаётся в константе NUM_LINES. Между прочим, функция RGB, составляет цвет каждой линии из трёх основных составляющих: красного, зелёного и синего (значения от 0 до 255) и возвращает нам цвет в виде TColor. О цветах поговорим немного позже, а вот так выглядит нарисованный пейзаж:

Теперь, когда линии нарисованы, попробуйте немножко подвигать форму. Если форму переместить за края экрана, то Вы увидите, что линии частично стёрлись. Это не глюк, и решается эта проблема очень просто. Но не сейчас ;-). Сперва посмотрим, как рисовать различные фигуры.

Рисование фигур

Для рисования фигур, в TCanvas предусмотрены следующие функции:

ИМЯ ОПИСАНИЕ ПРИМЕР
Ellipse Рисует элипс, вписанный в невидимый квадрат с координатами верхнего левого угла и правого нижнего. Если координаты х и y у углов будут совпадать, то получится круг. Canvas.Ellipse(0,0,50,50);
FillRect Заполняет прямоугольник цветом текущей кисти (brush), но никак не за пределами него. Canvas.FillRect( Bounds(0,0,100,100));
FloodFill Заполняет данную область цветом текущей кисти, до тех пор пока не будет достигнут край. Canvas.FloodFill(10, 10, clBlack, fsBorder);
Rectangle Рисует прямоугольник (или квадрат), заполненный цветом текущей кисти и обрамлённый цветом текущего пера Canvas.Rectangle( Bounds(20, 20, 50, 50));
RoundRect Тоже, что и Rectangle, но с загруглёнными углами. Canvas.RoundRect( 20, 20, 50, 50, 3, 3);

Ещё есть очень нужная функция TextOut, которая позволяет рисовать текст, используя шрифт, заданный в канвасе:

ИМЯ ОПИСАНИЕ ПРИМЕР
TextOut Рисует данную строку на канвасе начиная с координат (x,y) — фон текста заполняется текущим цветом кисти. Canvas.TextOut(10, 10, ‘Some text’);

Кстати, функция позволяет рисовать текст, не заполняя его фон. Если Вам необходимо изменить шрифт, используемый в TextOut, то необходимо изменить свойство Font канваса (это свойство имеет тип TFont) — например "Canvas.Font.Name := ‘Verdana’;", "Canvas.Font.Size := 24;" или "Canvas.Font.Color := clRed;".

Читайте также:  Как добавить игру в браузере стим

Вкратце хотелось бы обратить Ваше внимание на довольно полезный класс TRect, который умеет хранить в себе значения лево, право, верха и низа (кстати, в Windows API это RECT). То ест, достаточно указать левую и верхнюю координату и ширину и высоту области, а TRect автоматически подставит в виде (лево, верх, лево + ширина, верх + высота). Ещё есть другая функция Rect(), которая делает тоже самое, но координаты в ней задаются напрямую как лево, право, верх и низ. Ну и по желанию, можно использовать API функцию SetRect.

Ниже представлен пример, который рисует случайным образом различные фигуры:

Как Вы уже успели заметить, некоторые фигурки имеют цвет рамки, отличающийся от того цвета, которым заполнена фигура. Это как раз тот момент, о котором я упоминал выше. Кистью мы заполняем объекты, а пером обрамляем. Если цвет кисти (brush) меняется случайным образом, то цвет пера(pen) остаётся постоянным. Из-за этого и получается такая картина.

Перерисовка окна

Теперь давайте разберёмся, почему в самом первом примере у нас стирались линии при перемещении формы за границы экрана. А именно, нам нужно выяснить разницу между "рисованием" и "перерисовкой".

Рисование, это то, что мы делали выше. То есть, рисовали любые линии и графические фигуры. Однако, рисунок сохранялся до тех пор, пока окно(форма) не было обновлено.

Перерисовка несколько отличается от понятия "рисование". Когда окну необходимо перерисоваться, то Windows посылает определённое сообщение. Это сообщение поступает в обработчик события "OnPaint". Любой код, который поместить в обработчик OnPaint будет вызван каждый раз, когда форме необходимо обновиться.

Для примера, поместите следующий код в проект:

Если поместить на форму кнопку и вызывать DrawSomeText из обработчика кнопки OnClick, то проблема с исчезновением текста при перемещении формы останется. ОДНАКО, если вызвать DrawSomeText из обработчика формы OnPaint, то текст останется на своём месте окончательно.

Дескрипторы, или как пользоваться аналогичными API функциями

Итак, мы научились рисовать линии, различные фигуры, научились делать так, чтобы наше творение не стиралось при перемещении формы, и проделали мы всё это при помощи стандартных функций VCL (таких как Canvas.TextOut и т.д.). Однако, что делать, если Вы не хотите пользоваться графическими функциями VCL, которые всего навсего являются надстройками над аналогичными функциями из Windows API? Пожалуйста! Никто нам не запрещает пользоваться API функциями напрямую! Но постойте-ка, все они требуют какого-то HDC! Что такое HDC?

Почти всё в Windows использует "Дескриптор" (Handle). Дескриптор, это способ идентификации Вашего объекта в системе. У каждого окна есть свой дескриптор, у каждой кнопки тоже есть свой дескриптор и т.д. Именно поэтому все наши объекты имеют дескриптор в качестве свойства — например, "MyForm.Canvas.Handle".

Тип HDC это Дескриптор(Handle) Контекста Устройства (Device Context). Я уже говорил в самом начале, что TCanvas включает в себя большинство функций DC. Поэтому, мы спокойно можем подставлять свойство канваса Handle везде, где нам это потребуется.

Ради интереса можно взглянуть на таблицу, в которой представлены примеры вызовов некоторых функций из VCL и их аналогов из Windows API.

Так же можно использовать разные дескрипторы, чтобы рисовать в разных местах. Например, можно использовать "SomeBmp.Canvas.Handle" для рисования на картинке (битмапе), либо "Form1.Canvas.Handle", чтобы рисовать на форме.

В API версии функции TextOut необходимо передавать строку завершённую нулём. Это значит, что вместо того, чтобы передать строку в функцию напрямую, необходимо передать её как PChar. Так же не забывайте передавать в функцию длину строки. Для этого можно воспользоваться функцией Length.

Ну что, Вам уже захотелось поместить на форму какую-нибудь красивую картинку ?

Что такое Битмапы (Bitmaps)?

Рисование линий, это, конечно, хорошо, но рано или поздно Вам понадобится нарисовать более реалистичную картнику в своём приложении. Поэтому совершенно необходимо научиться работать с растровыми изображениями, или как их называют в среде программистов — битмапами.

Битмап, это графический объект, который содержит заголовок, необходимую информацию о картинке (такую как высота, ширина, цвета и т.д.) и, собственно, само изображение (большой массив, содержащий цвет каждой точки). В Delphi для этой цели уже предусмотрен класс TBitmap.

Битмапы можно рисовать не только на форме, но и по всему экрану. Может это и может показаться немного странным, но иногда это бывает полезно, особенно при создании скринсейвера. Однако, сначала нам необходимо разобраться с тем, как работать с битмапами. Вот небольшой пример:

Эта функция пытается загрузить и показать картинку, (с именем Filename, например ‘myBitmap.bmp’) начиная с точки (x,y).

Сразу скажу, что эта функция довольно неэффективна. Она создаёт и уничтожает битмап каждый раз когда вызывается, а так же каждый раз проверяет существование файла. Лучше объявлять объект TBitmap как часть формы, создавать и загружать картинку в FormCreate, а освобождать её в FormDestroy.

Функции рисования в GDI

TCanvas имеет несколько полезных функций, которые работают с типом TGraphic. Тип TGraphic является базовым классом для графических объектов в Delphi, таких как: битмапы (TBitmap), иконки (TIcon), метафайлы (TMetafile) и JPEG-и (TJPEGImage). Все они используют одни и те же функции, которые приведены в таблице:

Все эти функции являются методами TCanvas.

ИМЯ ОПИСАНИЕ ПРИМЕР
Draw Рисует TGraphic на канвасе так как он есть, не растягивая. Canvas.Draw(5,10,MyGraphic);
StrechDraw Рисует TGraphic на канвасе, подгоняя (растягивая) его под заданную область. Canvas.StretchDraw( Bounds(0,0,32,32), MyGraphic);
CopyRect Копирует часть TCanvas-а в другой, при необходимости растягивая его. Canvas.CopyRect( Bounds(0,0,32,32), MyBmp.Canvas, Bounds(0, 0, 640, 480));

TCanvas.Draw является обёрткой для API функции BitBlt:

Описанный выше способ позволяет рисовать битмап в run-time. Конечно, проще поместить на форму TImage и установить в ней картинку. Изображение будет постоянно оставаться на том месте, где Вы его поместили, но это скучно ;-). Куда интереснее сделать при помощи битмапов анимацию.

С другой стороны, поняв принципы работы с битмапами, Вам будет легче перейти к другим графическим библиотекам (например DirectX).

Программирование. Теория и практика.

Здравствуйте уважаемые коллеги!

Как рисовать на канве TCanvas компонента TPanel — вопрос, на который я постараюсь дать ответ в данной статье.
Известно, что компонент TPanel не позволяет рисовать на своей канве, но есть способ обойти это ограничение…

Компонент TPanel в качестве родительского класса использует TCustomControl, у которого присутствует свойство Canvas и процедура Paint. Оба они находятся в разделе Protected, что означает что мы не можем использовать его напрямую, но можем получить доступ в дочернем классе.

Создадим собственный класс, унаследовав его от стандартного TPanel:

Вынесем свойство Canvas в раздел public что бы мы могли использовать его в созданных экземплярах данного класса.
Заменяем виртуальный метод Paint.
И добавляем событие OnPaint, которое будет вызываться в методе Paint, который в свою очередь срабатывает при перерисовке компонента.

В разделе implementation опишем метод Paint:

if Assigned(FOnPaint) then — Если присвоено событие OnPaint, то вызовем его, передав себя (ключевое слово Self) в качестве параметра.

После запуска можем наблюдать нарисованные кружки на панели:

Ссылка на основную публикацию
Регулятор громкости для автомагнитолы
Бывший хозяин видимо пытаясь снять магнитолу за рукоятку громкости, сломал её. В результате громкость не регулировалась, а отпаявшиеся контакты энкодера...
Работа с far manager
Фар менеджер - один из самых удобных файловых менеджеров, рассчитанный на работу с файлами и папками на дисках, прежде всего,...
Работа с классами python
Серия контента: Этот контент является частью # из серии # статей: Этот контент является частью серии: Следите за выходом новых...
Регулярные выражения perl примеры
Regular expressions, или регулярные выражения - способ определения символьной маски для последующего сравнения с ней строки символов или для обработки...
Adblock detector