Введение в DELPHI

в освоении. Однако при изменении


Программа SHAPEDEM проста в написании и в освоении. Однако при изменении пользователем размера окна она будет выглядеть "некрасиво". Давайте изменим ее таким образом, чтобы программа сама обрабатывала изменение размера окна, а заодно изучим компонент меню. Для достижения этих целей сделаем следующее:
  • Кнопки и выпадающий список уберем с экрана и вместо них поместим на форму компонент меню (MainMenu)
  • "Заставим" полосы прокрутки изменять свое положение в зависимости от размера окна
  • "Заставим" свойство Position полос прокрутки изменяться, чтобы правильно отражать размер формы.


Взглянув на рис.8, Вы сможете увидеть, как будет выглядеть программа после этих изменений.



Рис. 8: Программа SHAPDEM2 имеет возможность реагировать на изменение пользователем размера окна

Листинг B: Программа SHAPDEM2 включает метод FormOnResize. Представлен главный модуль. unit Main; interface uses WinTypes, WinProcs, Classes, Graphics, Forms, Controls, ColorDlg, StdCtrls, Menus, Dialogs, ExtCtrls; type TForm1 = class(TForm) Shape1: TShape; ColorDialog1: TColorDialog; ScrollBar1: TScrollBar; ScrollBar2: TScrollBar; MainMenu1: TMainMenu; Shapes1: TMenuItem; ShapeColor1: TMenuItem; FormColor1: TMenuItem; Shapes2: TMenuItem; Rectangle1: TMenuItem; Square1: TMenuItem; RoundRect1: TMenuItem; RoundSquare1: TMenuItem; Ellipes1: TMenuItem; Circle1: TMenuItem; Exit1: TMenuItem; procedure NewShapeClick(Sender: TObject); procedure ShapeColorClick(Sender: TObject); procedure FormColorClick(Sender: TObject); procedure ScrollBar2Change(Sender: TObject); procedure ScrollBar1Change(Sender: TObject); procedure FormResize(Sender: TObject); procedure Exit1Click(Sender: TObject); private { Private declarations } public

{ Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.NewShapeClick(Sender: TObject); begin Shape1.Shape := TShapeType((Sender as TMenuItem).Tag); end; procedure TForm1.ShapeColorClick(Sender: TObject); begin if ColorDialog1.Execute then Shape1.Brush.Color := ColorDialog1.Color; end; procedure TForm1.FormColorClick(Sender: TObject); begin if ColorDialog1.Execute then Form1.Color := ColorDialog1.Color; end; procedure TForm1.ScrollBar2Change(Sender: TObject); begin Shape1.Height := ScrollBar2.Position; end; procedure TForm1.ScrollBar1Change(Sender: TObject); begin Shape1.Width := ScrollBar1.Position; end; procedure TForm1.FormResize(Sender: TObject); var Menu, Caption, Frame: Integer; begin Caption := GetSystemMetrics(sm_cyCaption); Frame := GetSystemMetrics(sm_cxFrame) * 2; Menu := GetSystemMetrics(sm_cyMenu); Scrollbar1.Max := Width; Scrollbar2.Max := Height; Scrollbar2.Left := Width - Frame - Scrollbar2.Width; Scrollbar1.Top := Height - ScrollBar2.Width - Frame - Caption - Menu; Scrollbar1.Width := Width - Scrollbar2.Width - Frame; Scrollbar2.Height := Height - Frame - Caption - Menu - Scrollbar1.Height; end; procedure TForm1.Exit1Click(Sender: TObject); begin Close; end; end.

Главное меню для программы создается с помощью компонента MainMenu (находится на страничке "Standard" палитры компонентов). Поместив его на форму, дважды щелкните по нему мышкой - откроется редактор меню, в котором Вы сможете ввести нужные Вам названия пунктов меню и, при желании, изменить их имена (задаваемые Delphi по умолчанию) для удобочитаемости. Создадим меню программы SHAPEDEM2 с тремя главными пунктами: "Цвета", "Фигуры", "Выход".

Для первого пункта создадим следующие подпункты:
  • Цвет фигуры
  • Цвет окна


Для второго:
  • Прямоугольник
  • Квадрат
  • Закругленный прямоугольник
  • Закругленный квадрат
  • Эллипс
  • Окружность


Третий пункт меню не будет содержать никаких подпунктов.

После создания всех пунктов и подпунктов меню для работы программы SHAPEDEM2 нужно назначить номера для каждого из подпунктов меню, связанных с типом фигуры. Для этого воспользуемся свойством Tag, имеющимся у каждого пункта меню. Свойство Tag (типа Integer) специально введено в каждый компонент Delphi с тем, чтобы программисты могли использовать его по своему усмотрению. Назначим 0 свойству Tag пункта "Прямоугольник", 1 - пункту "Квадрат", 2 - пункту "Закругленный прямоугольник" и т.д. Цель такого назначения будет объяснена позднее.

Два метода, созданные для подпунктов изменения цвета аналогичны тем, которые были в программе SHAPEDEM: procedure TForm1.ShapeColorClick(Sender: TObject); begin if ColorDialog1.Execute then Shape1.Brush.Color := ColorDialog1.Color; end; procedure TForm1.FormColorClick(Sender: TObject); begin if ColorDialog1.Execute then Form1.Color := ColorDialog1.Color; end;

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

Аналогично, методы, реализующие реакцию на выбор подпунктов меню изменения вида фигуры также очень похожи на методы выбора фигуры через выпадающий список: procedure TForm1.NewShapeClick(Sender: TObject); begin Shape1.Shape := TShapeType((Sender as TMenuItem).Tag); end;

Этот код "работает" правильно благодаря тому, что перечислимый тип TShapeType в качестве начального имеет значение 0 и в свойство Tag подпунктов меню мы также записали порядковые номера, начинающиеся с нуля.

Отметим, что мы использовали оператор as, который позволяет надежно преобразовывать типы из одного в другой: в частности, преобразовать параметр Sender (имеющий общий тип TObject) в тип TMenuItem. Как правило, параметр Sender в Delphi - это управляющий элемент, посылающий сообщения функции, в которой он фигурирует. В данном случае, Sender является пунктом меню, и, следовательно, Вы можете работать с этим параметром как если бы он был декларирован с типом TMenuItem.

Главная причина использования оператора as состоит в том, что он обеспечивает очень ясный синтаксис, даже если Вы проводите сложное двухуровневое преобразование типов. Более того, оператор as обеспечивает проверку преобразования в режиме выполнения программы. Когда Вы используете оператор as, Вы можете быть уверены в том, что преобразование Sender в TMenuItem реально будет произведено лишь в том случае, если Sender действительно имеет тип TMenuItem.

Две полосы прокрутки в программе SHAPEDEM2 всегда будут располагаться возле границ окна, независимо от его размеров. Выполнение этих действий требует от Вас написания несколько более сложного программирования, чем было ранее. Как было указано ранее, Delphi, хотя и скрывает от программиста детали Windows-программирования, однако не запрещает обращаться к функциям Windows API (прикладного пользовательского интерфейса). Таким образом, Delphi поддерживает низкоуровневое программирование на уровне Windows API. Короче говоря, если Вам нужно углубиться в дебри низкоуровневого программирования - пожалуйста! procedure TForm1.FormResize(Sender: TObject); var Menu, Caption, Frame: Integer; begin Caption := GetSystemMetrics(sm_cyCaption); Frame := GetSystemMetrics(sm_cxFrame) * 2; Menu := GetSystemMetrics(sm_cyMenu); Scrollbar1.Max := Width; Scrollbar2.Max := Height; Scrollbar2.Left := Width - Frame - Scrollbar2.Width; Scrollbar2.Height := Height - Frame - Caption - Menu; Scrollbar1.Top := Height - Scrollbar2.Width - Frame - Caption - Menu; Scrollbar1.Width := Width - Scrollbar2.Width - Frame; end;

Код, показанный здесь, является реакцией на событие OnResize. Это событие перечислено среди других на страничке "Events" Инспектора Объектов в состоянии, когда выбрана форма (окно). Как Вы можете ожидать, событие (сообщение) OnResize посылается форме (окну) каждый раз, когда пользователь "захватывает" мышкой за какой-либо край окна и делает размер окна большим или меньшим. Однако, это же сообщение (событие) посылается окну и тогда, когда происходит максимизация окна (но не минимизация).

Первое, что делается в данном методе - запрашиваются системные параметры, определяющие размеры заголовка окна, огибающей его рамки и меню. Эта информация "добывается" путем вызова функции GetSystemMetrics, являющейся частью Windows API. Функции GetSystemMetrics передается один аргумент в виде константы, определяющей вид запрашиваемой информации. Например, если Вы передадите функции константу sm_cyCaption, получите в качестве результата высоту заголовка окна (в пикселах). Полный список этих констант имеется в on-line справочнике Delphi (Help|Windows API|Alphabetical functions|User functions|GetSystemMetrics), здесь же мы приведем небольшую выдержку из справочника:
SM_CXBORDERШирина огибающей окно рамки, размер которой не может быть изменен.
SM_CYBORDERВысота огибающей окно рамки, размер которой не может быть изменен.
SM_CYCAPTIONВысота заголовка окна, включая высоту огибающей окно рамки, размер которой не может быть изменен (SM_CYBORDER).
SM_CXCURSORШирина курсора.
SM_CYCURSORВысота курсора.
SM_CXFRAMEШирина огибающей окно рамки, размер которой может быть изменен.
SM_CYFRAMEВысота огибающей окно рамки, размер которой может быть изменен.
SM_CXFULLSCREENШирина клиентской части для полноэкранного окна.
SM_CYFULLSCREENВысота клиентской части для полноэкранного окна (эквивалентна высоте экрана за вычетом высоты заголовка окна).
SM_CXICONШирина иконки.
SM_CYICONВысота иконки.
SM_CYMENUВысота полосы меню в одну строку. Это высота меню за вычетом высоты огибающей окно рамки, размер которой не может быть изменен (SM_CYBORDER).
SM_CXMINМинимальная ширина окна.
SM_CYMINМинимальная высота окна.
vSM_CXSCREENШирина экрана.
SM_CYSCREENВысота экрана.
SM_MOUSEPRESENTНе 0, если мышь установлена.
В методе FormResize программа вычисляет новые размеры полос прокрутки: Scrollbar1.Max := Width; Scrollbar2.Max := Height; Scrollbar2.Left := Width - Frame - Scrollbar2.Width; Scrollbar2.Height := Height - Frame - Caption - Menu; Scrollbar1.Top := Height - Scrollbar2.Width - Frame - Caption - Menu; Scrollbar1.Width := Width - Scrollbar2.Width - Frame;

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

В программе SHAPEDEM свойство Max каждой полосы прокрутки оставалось равным значению по умолчанию - 100; это означало, что после того как бегунок полосы прокрутки пройдет все доступное расстояние (как для вертикальной, так и для горизонтальной полосы прокрутки), свойство Position будет установлено в 100. Если бегунок возвращался к началу, свойство Position устанавливалось равным свойству Min, которое, по умолчанию, 0.

В программе SHAPEDEM2 Вы можете изменять значения свойств Min и Max так, чтобы диапазон значений Position полос прокрутки отражал текущий размер окна (формы), даже при изменении формой своего размера в режиме выполнения. Здесь приведены соответствующие строки из метода FormResize. procedure TForm1.FormResize(Sender: TObject); begin ... Scrollbar1.Max := Width; Scrollbar2.Max := Height; ... end;

Две строчки кода, показанные выше, просто устанавливают максимальные значения полос прокрутки равными ширине и высоте формы соответственно. После этого Вы всегда сможете сделать помещенную на форму фигуру такой же "большой", как и сама форма. После введения таких изменений Вам больше не потребуется умножать свойство Position на какой-либо множитель. procedure TForm1.Scrollbar2Change (Sender: TObject); begin Shape1.Height := Scrollbar2.Position; end;

Если Вы после этого запустите программу SHAPDEM2 на выполнение, Вы увидите, что она работает корректно при любом изменении размера формы. Более того, теперь Вы можете выбирать фигуры и цвета из меню, что придает программе более строгий вид.

В конце хотелось бы сделать одно маленькое замечание. Как Вы, возможно, уже заметили, каждая форма, по умолчанию, имеет две полосы прокрутки (HorzScrollbar и VertScrollbar), которые появляются автоматически всякий раз, когда размер формы становится меньше, чем область, занимаемая управляющими элементами, расположенными на этой форме. Иногда эти полосы прокрутки могут быть очень полезными, но в нашей ситуации они сделают совсем не то, что хотелось бы. Поэтому, для надежности, Вы можете установить их вложенные свойства Visible в False.


Содержание раздела