Методические указания для проведения практических и лабораторных занятий по дисциплине "Программирование на языке высокого уровня" для студентов специальностей 220200 Автоматизированные системы обработки информации и управления

Вид материалаМетодические указания

Содержание


Привязка к родительским свойствам
Класс TCanvas
3. Работа с компонентами
Компонент TMenuItem
Подобный материал:
1   2   3   4   5   6   7   8   9   10   11

Привязка к родительским свойствам


Для придания приложению строгого внешнего вида требуется, чтобы все визу­альные компоненты имели единый стиль. Чтобы избавиться от необходимости изменять код элементов-потомков при изменении внешнего вида предка, в них нужно правильно установить свойства:

(pdi property ParentColor: boolean;

@ property ParentCtl3D: boolean;

(Pb) property ParentFont: boolean;

(pS) property ParentShowHint: boolean;

Все четыре свойства отвечают за наличие связи между соответствующими свойствами в родительских и дочерних элементах. Если какое-то из них у элемента установлено в True, это означает, что он наследует свойство от родителя и меняет цвет, трехмерность, шрифт или показ ярлычков вместе и вслед за ним. Но если само свойство дочернего элемента (например, Color или ParentColor) переустановить явно, то связь с родительским свойством разрьюается.


2.8. Графическая подсистема

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

Другой бич работы с графикой в Windows — проблема рационального исполь­зования ресурсов. Для больших программных комплексов она стала в по­следнее время нешуточной (это касается, по крайней мере, версий Windows до 3.11 включительно). Такие монстры, как Microsoft Office, потребляют во время работы львиную долю ресурсов. В Delphi ресурсами GDI незримо для пользователя "заведуют" специальные менеджеры, ведущие списки всех разме­щенных кистей, перьев, шрифтов и т. п. и управляющие их использованием.

Обязательным для любого объекта, связанного с графикой в Delphi является событие

property OnChange: TNotifyEvent;

Его обработчик вызывается всякий раз, когда изменились какие-то харак­теристики объекта, влияющие на его внешний вид.

В стандартном GDI основой для рисования служит дескриптор контекста устройства hDC и связанные с ним шрифт, перо и кисть. В состав VCL входят объектно-ориентированные надстройки над последними, назначением которых является удобный доступ к свойствам инструментов и прозрачная для поль­зователя обработка всех их изменений. Сначала опишем три этих класса.


Класс TCanvas

TCanvas = class(TPersistent)

Этот класс — сердцевина графической подсистемы Delphi. Он объединяет в себе и "холст" (контекст конкретного устройства GDI), и "рабочие инстру­менты" (перо, кисть, шрифт) и даже "подмастерьев" (набор функций по рисованию типовых геометрических фигур).

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

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

Дескриптор контекста устройства, над которьм "построена" канва, может быть востребован для различных низкоуровневых операций. Он задается свой­ством:

property Handle: HDC;

Для рисования канва включает в себя шрифт, перо и кисть:

(р) property Font: TFont ;

(Pt property Pen: TPen;

(РЙ property Brush: TBrush;

Кроме того, можно рисовать и поточечно, получив доступ к каждому пикселу. Значение свойства

property Pixels[X, Y: Integer]: TColor;

соответствует цвету точки с координатами (X,Y).

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

procedure Arc (XI, Yl, Х2, Y2, ХЗ, Y3, Х4, Y4: Integer) ;

Метод рисует сегмент эллипса. Эллипс определяется описывающим прямоуголь­ником (X1,Y1) — (X2,Y2); его размеры должны лежать в диапазоне от 2 до 32767 точек. Начальная точка сегмента лежит на пересечении эллипса и луча, проведенного из его центра через точку (X3.Y3). Конечная точка сегмента лежит на пересечении эллипса и луча, проведенного из его центра через точку (X4.Y4). Сегмент рисуется против часовой стрелки.

procedure Chord(Xl, Yl, Х2, Y2, ХЗ, Y3, Х4, Y4: Integer);

Рисует хорду и заливает отсекаемую ею часть эллипса. Эллипс, начальная и конеч­ная точки определяются, как в методе Arc.

procedure EllipsefXl, Yl, Х2, Y2: Integer) ;

Рисует и закрашивает эллипс, вписанный в прямоугольник (X1.Y1) — (X2.Y2).

procedure LineTo(X, Y: Integer);

Проводит линию текущим пером из текущей точки в (X,Y).

procedure MoveTo(X, Y: Integer);

Перемещает текущее положение пера (свойство PenPos) в точку (X,Y).

procedure BrushCopy(const Dest: TRect; Bitmap: TBitmap; const Source: TRect; Color: TColor);

Производит специальное копирование. Прямоугольник Source из битовой карты Bitmap копируется в прямоугольник Dest на канве; при этом цвет Color заменяется на цвет текущей кисти (Brush.Color). С помощью этого метода можно нарисо­вать "прозрачную" картинку. Для этого нужно выбрать соответствующий фону цвет кисти и затем заменить на него фоновый или наиболее часто встреча­ющийся цвет битовой карты (см. Bitmap. TransparentColor).




procedure CopyRect(const Dest: TRect; Canvas: TCanvas; const Source: TRect) ;

Производит копирование прямоугольника Source из канвы Canvas в прямоугольник Dest в области самого объекта.

procedure FillRect(const Rect: TRect) ;

Производит заливку прямоугольника (текущей кистью).

procedure FrameRectfconst Rect: TRect);

Производит оконтуривание прямоуголь­ника цветом текущей кисти (без заполнения).

procedure Draw(X, Y: Integer; Graphic: TGraphic) ;

Осуществляет рисование графического объекта Graphic (точнее, вызов метода его рисования) в области с верхним левым углом (X,Y).

procedure StretchDraw(const Rect: TRect; Graphic: TGraphic);

Осуществляет рисование объекта Graphic в заданном прямоугольнике Rect. Если размеры их не совпадают, Graphic масштабируется.

procedure DrawFocusRect(const Rect: TRect);

Производит отрисовку прямоугольной рамки из точек (как на элементе, имеющем фокус ввода). Поскольку метод использует логическую операцию XOR (исключающее ИЛИ), повторный вызов для того же прямоугольника приводит изображение к начальному виду.

procedure FloodFilKX, Y: Integer; Color: TColor; FillStyle: TFillStyle); TFillStyle = (fsSurface, fsBorder) ;

Производит заливку области текущей кистью. Процесс начинается с точки (X,Y). Если режим FillStyle равен fsSurface, то он продолжается до тех пор, пока есть соседние точки с цветом Color. В режиме fsBorder закрашивание, наоборот, прекращается при выходе на границу с цветом Color.

procedure Pie (XI, Yl, Х2, Y2, ХЗ, Y3, Х4, Y4: Integers-

Рисует сектор эллипса, описываемого прямоугольником (X1,Y1) — (X2,Y2). Стороны сектора лежат на лучах, проходящих из центра эллипса через точки (X3.Y3) и (X4,Y4).

procedure Polygon(const Points: array of TPoint) ;

Строит многоугольник, используя массив координат точек Points. При этом последняя точка соединяется с первой и внутренняя область закрашивается.

procedure Polyline(const Points: array of TPoint) ;

Строит ломаную линию, используя массив координат точек Points.

procedure Rectangle(XI, Yl, Х2, Y2 : Integer) ;

Рисует прямоугольник с верхним левым углом в (XI ,Y1) и нижним правым в (X2.Y2).

procedure RoundRect (XI, Yl, Х2, Y2, ХЗ, Y3: Integer);

Рисует прямоугольник с закругленными углами. Координаты вершин — те же, что и в методе Rectangle. Закругления рисуются как сегменты эллипса с размерами осей по горизонтали и вертикали ХЗ и Y3.




function. TextHeight(const Text: string): Integer;

Возвращает высоту строки Text в пикселах.

function TextWidth(const Text: string): Integer;

Возвращает ширину строки Text в пиксе­лах.

procedure TextOut(X, Y: Integer; const Text: string);

Производит вывод строки Text. Левый верхний угол помещается в точку канвы (X,Y).

procedure TextRect(Rect: TRect; X, Y: Integer; const Text: stringi ;

Производит вывод текста с отсечением. Как и в TextOut, строка Text выводится с позиции (X,Y); при этом часть текста, лежащая вне пределов прямоугольника Rect, отсекается и не будет видна.

(Ro) property ClipRect: TRect;

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

property PenPos: TPoint;

Содержит текущую позицию пера канвы (изменяется посредством метода MoveTo).


Метод

procedure Refresh;

сбрасывает текущие шрифт, перо и кисть, заменяя их на стандартные, заимство­ванные из Windows (BLACK.PEN, HOLLOW_BRUSH, SYSTEM.FONT).

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

property OnChange: TNotifyEvent;

property OnChanging: TNotifyEvent;

Эти события возникают при изменениях свойств и вызовах методов TCanvas, меняющих вид канвы (то есть при любом рисовании. В MoveTo, например, они не возникают). Отличие их в том, что OnChanging вызывается до начала изменений, a OnChange — после их завершения.

Идентификатор (код) растровой операции при копировании прямоугольных блоков содержится в свойстве

(Pb) property CopyMode: TCopyMode;

TCopyMode = Longint;

и определяет правило сочетания пикселов, копируемых на канву, с ее текущим содержимым. При этом можно создавать разные изобразительные эффекты. В Delphi определены следующие константы кодов: cmBlackness, cmDstInvert, cmMergeCopy, cmMergePaint, cmNotSrcCopy, cmNotSrcErase, cmPatCopy, cmPatInvert, cmPatPaint, cmSrcAnd, cmSrcCopy, cmSrcErase, cmSrcInvert, cmSrcPaint, cmWhiteness.

Все они стандартно определены в Windows, и подробное их описание можно найти в документации по GDI. Значением CopyMode по умолчанию является cmSrcCopy — копирование пикселов источника поверх существующих.

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


3. РАБОТА С КОМПОНЕНТАМИ

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

Для каждого из компонентов приводятся все методы и свойства, которые доступны программисту, работающему с этим компонентом, то есть описанные как public и published (в т. ч. недокументированные). Мы попытались проиллюстрировать некоторые неочевидные вещи хотя бы коротким фрагмен­том кода. В развернутом виде примеры использования компонентов можно найти на дискете, прилагаемой к книге.


3.1. Работа с меню


В приложениях, написанных на Delphi, могут быть реализованы меню двух основных видов:

• Главное меню. Такое меню принадлежит форме и отображается вместе с ней под ее панелью заголовка. Если в приложении несколько форм, то для удобства можно объединять меню всех активных форм в одном.

• Всплывающее меню. Такое меню предусмотрено почти у всех компонен­тов — элементов управления Windows. Оно возникает (всплывает) при нажатии правой кнопки мыши на этом компоненте. Предусмотрено такое меню и у формы.

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

На нижнем уровне лежат команды меню — пункты, с выбором которых должна быть связана та или иная реакция приложения. Команда! объединяются в подменю. Подменю — это пункты, выбор которых означает показ или свертывание списка входящих в него команд и подменю.

Принципы создания и работы с меню в Delphi очень просты. Каждому пункту меню соответствует свой компонент класса TMenuItem. Вы добавляете к меню новые пункты (а к форме — новые компоненты) либо во время разработки (при помощи Конструктора меню), либо во время исполнения. При выбо­ре пункта меню для описывающего его компонента инициируется событие OnClick, в обработчике которого и нужно предусмотреть соответствующие действия.


Компонент TMenuItem


TObject—>TPersistent—”TComponent—>TMenuItein

Модуль MENUS

В Палитру компонентов не входит

Этот компонент, который является основой системы меню в Delphi, вы не встретите в Палитре компонентов — он входит в состав имеющихся там компонентов TMainMenu и TPopupMenu.

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

(Pb) property Caption: string;

Помимо основной, он несет еще две дополнительные нагрузки. Во-первых, если в строке имеется амперсанд ('&'), то он вместе с следующим за ним символом является акселератором. Например, для строки '&File' нажатие + означает выбор этого пункта. Во-вторых, если текст состоит из

одного символа '-', то этот пункт служит в меню разделителем (имеет стиль MFJSEPARATOR);

Помимо акселератора может быть описана еще одна комбинация клавиш, нажатие которой равнозначно выбору пункта. Она должна содержаться в свойстве: •

(Pb) property Shortcut: TShortCut;

TShortCut = Low(Word)..High(Word);

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

procedure Click;

приводят к возникновению события:

(Р1э) property OnClick: TNotifyEvent;

Компонент TMenuItem может различать только это событие, с которьм до­лжны быть связаны действия, ради которых вы ввели данный пункт в меню. Воспринимают это событие те пункты меню, которые в данный момент активны, что означает-установленное в True свойство:

(РЬ) property Enabled: Boolean;

Если Enabled равно False, пункт изображается серьм цветом и не воспринимает сообщений.

Часто пункты меню используются для переключения каких-либо режимов рабо­ты программы. При этом они могут быть отмечены "галочкой" перед началом текста. Свойство

(Pb) property Checked: Boolean;

отвечает за то, является ли этот пункт отмеченным.

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

(Pb) property Break: TMenuBreak;

TMenuBreak = (mbNone, mbBreak, mbBarBreak) ;

призвано решить эту проблему. Если оно установлено в mbBreak, то ко­манды меню, начиная с этой, располагаются в новом — соседнем с преж­ним — столбце (при этом их принадлежность не изменяется). Если оно равно mbBarBreak, столбцы при этом разделяются вертикальной чертой. В Delphi все компоненты меню типа TMenuItem могут быть как простыми командами, так и подменю, имеющими собственный список пунктов. В случае, если у компонента дочерних подменю и пунктов нет, для него имеет смысл свойство:

(Ro) property Command: Word;

Прежде при написании меню нужно было выдумывать и присваивать уникаль­ный идентификатор каждому его пункту — то есть собственно код команды, который посылался в качестве параметра сообщения WM.COMMAND. Сейчас эта задача возложена на Delphi — программист не только не определяет, но может и не знать кода команды, связанного с этим пунктом меню. Система выберет уникальное значение автоматически и присвоит это значение свойству Command. Изменять его не разрешается.

Интерпретация сообщений меню скрыта от программиста. Система сама опре­деляет, какой пункт выбран, и вызывает его обработчик события OnClick.

Если для каких-то целей понадобился код команды, можно воспользоваться вышеуказанным свойством (см. пример в описании компонента TMenu).

Если у компонента TMenuItem имеются дочерние пункты, то он является подменю, имеет статус MF_POPUP и дескриптор меню Windows, доступный для чтения через свойство:

(ro) property Handle: HMENU;

Пункты меню иерархически связаны. Методы и свойства для работы с до­черними пунктами меню приведены в таблице.

(До) property Parent: TMenuItem;

Содержит указатель на родительское подменю.

(Ro) property I terns[Index: Integer]: TMenuItem;

Содержит список дочерних пунктов меню.

fRo) property Count: Integer;

Содержит количество дочерних пунктов меню.

procedure Insert(Index: Integer; Item: TMenuItem) ;

Вставляет пункт Item в меню на место Index. Поскольку структура меню строго иерархическая, вставляемый пункт не должен быть частью другого меню (его свойство Parent должно быть равно nil).

procedure Delete(Index: Integer) ;

Удаляет пункт с индексом Index из меню.

function IndexOf(Item: TMenuItem): Integer;

Возвращает индекс пункта Item.

procedure Add(Item: TMenuItem);

Добавляет пункт Item в конец меню.

procedure Remove(Item: TMenuItem);

Удаляет пункт Item из меню.


Если пункт меню находится в фокусе, нажатие вызовет систему помощи с контекстом, определенным в свойстве:

(Pb) property HelpContext: THelpContext;

Свойство

(Pb) property Grouplndex: Byte;

используется при объединении нескольких меню между собой. Подробное объяснение его назначения см. в описании компонента TMainMenu.

Компонент TMenu

TObject—”TPersistent->TComponent->TMenu

Модуль MENUS

В Палитру компонентов не входит

Этот компонент отсутствует в Палитре компонентов, но содержит методы и свойства, приведенные в таблице, общие для двух потомков — TMainMenu и TPopupMenu, которые туда входят.

(Ro) property Handle: HMENU;

Содержит дескриптор меню.

property WindowHandle: HWND;

Содержит дескриптор окна Windows (формы или оконного элемента управления), с кото­рым связано меню.

(Ro) property Items: TMenuItem;

Содержит список элементов меню. На самом верху иерархии меню есть единственный элемент (со статусом MFPOPUP), чей список и используется.

function DispatchCoinn>and(ACommand: Word): Boolean;

Отыскивает пункт меню с заданной командой, в случае успеха вызывает его метод Click и возвращает True.

function DispatchPopupfAHandle: HMENU): Boolean;

Работает как Di spatchCommand, но отыскивает пункт меню с дескриптором AHandle.

function Findltem(Value: Word; Kind: TFindItemKind): TMenuItem; TFindItemKind = (fkComrriand, fkHandle, fkShortCut);

Возвращает указатель на объект, соответ­ствующий заданному пункту меню. Параметр Value должен содержать величину, которая интерпретируется в соответствии с одним из трех способов поиска (по команде, дескрип­тору или комбинации горячих клавиш).

function GetHelpContext(Value: Word; ByComniand: Boolean) : THelpContext;

Возвращает значение контекста помощи элемента меню. Если параметр ByCommand установлен в True, Value содержит связанную с пунктом команду, в противном случае — дескриптор. Если контекст у пункта отсут­ствует (равен 0), то отыскивается ближайший родительский ненулевой контекст. Если и он не найден, возвращается 0.

function IsShortCut(var Message: TWMKey): Boolean;

Определяет, какая комбинация горячих клавиш ShortCut нажата, и отыскивает соот­ветствующий пункт меню. Если пункт с таким значением ShortCut найден, и его метод Click отработал успешно, метод возвращает True.


В следующем примере метод обрабатывает сообщение Windows WM_MENUSELECT, которое возникает при перемещении фокуса между пунк­тами меню. В зависимости от типа пункта показывается его дескриптор или команда:

procedure TFormI.wmMenuSelect(var Msg :TWMMenuSelect) ;

var Anitem : TMenuItem;

begin

with Msg do

begin

if (MenuFlag and MF_POPUP <>0 )

then

begin

Anitem := Formi.Menu.Findltem(Idltem, fkHandle);

if Anitemonil then Labell .Caption :=

'Handle:'+IntToHex(Anitem.Handle,4) ;

end

else

begin

Anitem := Formi.Menu.Findltem(Idltem, fkCommand);

if Anitemonil then Labell .Caption :=

'Command:'+IntToHex(Anitem.Command,4) ;

end;

end;

inherited;

end;