Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛАБ_ПОА_2005_Builder.doc
Скачиваний:
7
Добавлен:
03.05.2019
Размер:
1.26 Mб
Скачать

Компонент Image

Компонент Image находится на странице Дополнительно библиотеки компонентов. Он имеет свойство Canvas (канва, холст), представляющее собой область компонента, на которой можно рисовать или отображать готовые изображения. Канва содержит свойства и методы, существенно упрощающие графику C++Builder.

Каждая точка канвы имеет координаты X и Y. Система координат канвы, как и везде в C++Builder, имеет началом левый верхний угол канвы. Координата X возрастает при перемещении слева направо, а координата Y − при перемещении сверху вниз.

Координаты измеряются в пикселах. Пиксел − это наименьший элемент поверхности рисунка, с которым можно манипулировать. Важнейшее свойство пиксела − его цвет. Для описания цвета используется тип TColor. В C++Builder определено множество констант типа TColor. Одни из них непосредственно определяют цвета (например, clBlue − синий), другие определяют цвета элементов окон, которые могут меняться в зависимости от выбранной пользователем палитры цветов Windows (например, clBtnFace − цвет поверхности кнопок).

Рисование по пикселам

Для рисования по пикселам используется свойство канвы Pixels. Это свойство представляет собой двумерный массив Canvas->Pixels[int X][int Y], который отвечает за цвета канвы. Например, Canvas->Pixels[10][20] соответствует цвету пиксела, 10-го слева и 20-го сверху. С массивом пикселов можно обращаться как с любым свойством: изменять цвет, задавая пикселу новое значение, или определять его цвет по хранящемуся в нем значению. Например, Canvas->Pixels[10][20]=clBlackэто задание пикселу черного цвета.

Предположим, нужно нарисовать график некоторой функции F(X) на канве компонента Image1, если известен диапазон ее изменения Ymax и Ymin и диапазон изменения аргумента Xmin и Xmax. Это можно сделать так:

float X,Y; // координаты функции

int PX,PY; // координаты пикселов

for(PX=0;PX<=Image1->Width;PX++)

{

// X - координата, соответствующая пикселу с координатой PX

X=Xmin+PX*(Xmax-Xmin)/Image1->Width;

Y=F(X);

// PY - координата пиксела, соответствующая координате Y

PY=Image1->Height-(Y-Ymin)* Image1->Height/(Ymax-Ymin);

// Устанавливается красный цвет выбранного пиксела

Image1->Canvas->Pixels[PX][PY]=clRed;

}

Цикл выполняется по всем значениям горизонтальной координаты пикселов PX компонента Image1. Сначала выбранное значение PX пересчитывается в соответствующее значение X. Затем производится вызов функции и определяется ее значение Y. Это значение пересчитывается в вертикальную координату пиксела PY. И в заключение цвет пиксела с координатами (PX, PY) устанавливается красным.

Ниже приведено приложение для функции sin(X), для которой Xmin=0, Xmax=4 (2 периода), Ymin=-1 и Ymax=1.

Рисование пером

У канвы есть свойство − Pen − перо. Это объект, в свою очередь имеющий ряд свойств. Одно из них Color − цвет, которым наносится рисунок. Второе свойство − Width (ширина линии). Ширина задается в пикселах. По умолчанию ширина равна 1.

Свойство Style определяет вид линии и может принимать следующие значения:

psSolid

Сплошная линия

psDash

Штриховая линия

psDot

Пунктирная линия

psDashDot

Штрих-пунктирная линия

psDashDotDot

Линия, чередующая штрих и два пунктира

psClear

Отсутствие линии

psInsideFrame

Сплошная линия, но при Width>1 допускающая цвета, отличные от палитры Windows

Все стили со штрихами и пунктирами доступны только при Width=1. В противном случае линии этих стилей рисуются как сплошные.

Стиль psInsideFrameединственный, который допускает произвольные цвета. Цвет линии при остальных стилях округляется до ближайшего из палитры Windows.

У канвы имеется свойство PenPos. Это свойство определяет в координатах канвы текущую позицию пера. Перемещение пера без прорисовки линии, т.е. изменение PenPos, производится методом канвы MoveTo(X,Y). Здесь (X,Y) − координаты точки, в которую перемещается перо. Эта текущая точка становится исходной, от которой методом LineTo(X,Y) можно провести линию в точку с координатами (X,Y). При этом текущая точка перемещается в конечную точку линии, и новый вызов LineTo будет проводить линию из этой новой текущей точки.

Нарисуем по пикселам и пером графики синуса и сравним качество графиков.

  1. Создайте для проекта приложения каталог (папку Windows), запустите C++Builder 6, создайте новый проект, назовите форму ДЕМОНСТРАЦИЯ КОМПОНЕНТА IMAGE и командой Сохранить все сразу сохраните файл модуля и проект под разными именами.

  2. На пустую форму перенесите два компонента Image и разместите их по горизонтали рядом. Размеры обоих компонентов сделайте абсолютно одинаковыми, так как на этом для экономии размера кода основана программа. Сделать размеры компонентов абсолютно одинаковыми можно, выделив их оба и воспользовавшись командой всплывающего меню Size.

  3. Над первым, левым компонентом поместите первую метку Label1 и назовите ее рисунок по пикселам, над вторым − Label2, с названием рисунок пером.

  4. В правом верхнем углу поместите кнопку Button1 и назовите ее КОНЕЦ. В обработчик щелчка кнопки впишите Close();.

  5. Под компонентами поместите вторую кнопку Button2, назовите ее НАРИСОВАТЬ, а в обработчик щелчка впишите:

void __fastcall TForm1::Button2Click(TObject *Sender)

{

#define Pi 3.14159

float X,Y; // координаты функции

int PX,PY; // координаты пикселов

// Переводится перо в начало координат второго графика -

// на левый край канвы в середину ее высоты

Image2->Canvas->MoveTo(0,Image2->Height/2);

// Устанавливается красный цвет рисования пером

Image2->Canvas->Pen->Color=clRed;

// Устанавливается ширина линии рисования в три пиксела

Image2->Canvas->Pen->Width=3;

for(PX=0;PX<=Image1->Width;PX++)

{

// X - координата, соответствующая пикселу с координатой PX

X=PX*4*Pi/Image1->Width;

Y=sin(X);

// PY - координата пиксела, соответствующая координате Y

PY=Image1->Height-(Y+1)* Image1->Height/2;

// Устанавливается красный цвет выбранного пиксела

Image1->Canvas->Pixels[PX][PY]=clRed;

// Проводится линия на втором графике

Image2->Canvas->LineTo(PX,PY);

}

}

  1. В заголовочный файл модуля впишите #include <math.h>. Сохраните проект и запустите на выполнение. Нетрудно видеть, что качество графиков сильно различается . В левом на крутых участках сплошной линии нет − она распадается на отдельные точки − пикселы. А правый график весь сплошной. Это показывает, что при прочих равных условиях рисовать лучше не по пикселам, а пером.

Отметим еще одно ценное свойство компонента Image и его канвы − можно задавать координаты пикселов, выходящие за пределы размеров канвы. Это позволяет не заботиться о том, какая часть рисунка попадает в рамку Image, а какая нет. Например, соответствующий оператор изменим так: Y=2*sin(X);. Сохраним проект и выполним. Увидим, что изобразилась только та часть рисунка, которая помещается в рамку канвы. Это позволяет без затруднений осуществлять приложения, в которых пользователю предоставляется возможность увеличивать и просматривать в деталях какие-то фрагменты графиков.

Библиографический список

  1. Архангельский АЯ Программирование в C++Builder 6. – М: ЗАО «Издательство БИНОМ», 2003 – 1152 с – С 189–194, 384−388.

ЛАБОРАТОРНАЯ РАБОТА 6

Список изображений.

Компоненты отображения иерархических данных.

Полоса состояния.

Перетаскивание объектов – технология Drag&Drop

Список изображений – компонент ImageList (находится на странице Win32 библиотеки компонентов) представляет собой набор изображений одинаковых размеров (например, пиктограмм), на которые можно ссылаться по индексам, начинающимся с нуля. Во многих компонентах, в том числе и в компонентах отображения иерархических данных, имеются свойства, представляющие собой ссылки на компонент ImageList.

Изображения в компонент ImageList могут быть загружены в процессе проектирования с помощью редактора списков изображений. Окно редактора вызывается двойным щелчком на компоненте ImageList или щелчком правой кнопки мыши и выбором команды контекстного меню Редактор ImageList. В окне редактора можно добавить в списки изображения (кнопка Добавить), удалить изображение из списка кнопкой Удалить, очистить весь список кнопкой Очистить.

При добавлении изображения в список, которое начинается с нажатия кнопки Добавить, открывается окно открытия файлов изображений, в котором можно выбрать нужный файл. Множество изображений, размещаемых обычно на кнопках, содержится в папке …\Program Files\Common Files\Borland Shared\Images\Buttons.

Следует помнить, что размер всех изображений в списке должен быть одинаковым. Как правило, это размер, используемый для пиктограмм в меню, списках, кнопках. При добавлении в список изображений для кнопок надо иметь в виду, что они часто содержат не одно, а два и более изображений. В этих случаях после выбора имени файла изображений при щелчке на кнопке Открыть задается вопрос: Bitmap dimensions forare greater then imagelist dimensions. Separate into … separate bitmaps?” (“Размерность изображения … больше размерности списка. Разделить на … отдельные изображения?”). Если ответить отрицательно, то все изображения уменьшатся в горизонтальном размере и лягут как одно изображение. Использовать его в дальнейшем будет невозможно. Поэтому на заданный вопрос надо ответить положительно. Тогда загружаемая битовая матрица автоматически разделится на отдельные изображения, а затем те из них, которые не нужны, удаляют.

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

В редакторе списков изображений, выделив то или иное изображение, можно установить его свойства: Прозрачный цвет и Цвет за. Для пиктограмм эти свойства устанавливаются в clNone.

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

TreeView

(окно дерева данных)

Win32

Просмотр структуры иерархических данных в виде дерева в стиле Windows 95/98/2000

Outline

(окно дерева данных)

Win3.1

Просмотр структуры иерархических данных в виде дерева в стиле Windows 3.x

ListView

(список данных в стиле Windows 95)

Win32

Отображение в стиле папок Windows списков в виде колонок или пиктограмм

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

Основным свойством TreeView, содержащим информацию об узлах дерева, является Items. Свойство Items объектного типа TTreeNodes содержит список узлов дерева. Доступ к информации об отдельных узлах осуществляется через свойство Items->Item[int Index]. Например, TreeView1–> Items–>Item[0] – это узел дерева с индексом 0 (первый узел дерева). Каждый узел является объектом типа TTreeNodes, обладающим своими свойствами и методами.

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

Сначала рассмотрим формирование дерева в процессе проектирования.

  1. Создайте для проекта приложения каталог (папку Windows), запустите C++Builder 6, создайте новый проект, назовите форму ДЕМОНСТРАЦИЯ КОМПОНЕНТА TREEVIEW_1 и командой Сохранить все сразу сохраните файл модуля и проект под разными именами.

  2. Разместите на пустой форме компонент TreeView1 со страницы Win32 и просмотрите открывшиеся в Инспекторе Объектов свойства.

  3. Во время проектирования формирование дерева осуществляется в окне редактора элементов компонента TreeView1 (узлов дерева). Вызовите окно двойным щелчком на компоненте или нажатием кнопки с многоточием около свойства Items в окне Инспектора Объектов. Окно редактора содержит две панели: Элементы и Свойства элемента. Панель Элементы содержит группу кнопок.

Кнопка Новый элемент позволяет добавить в дерево новый узел. Он будет расположен на том же уровне, на котором расположен узел, выделенный курсором в момент щелчка на кнопке Новый элемент.

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

Кнопка Удалить удаляет выделенный узел дерева.

Кнопка Загрузить позволяет загрузить структуру дерева из файла. Файл, хранящий структуру дерева – это обычный текстовый файл, содержащий тексты узлов. Уровни узлов обозначаются отступами. Например, файл проектируемого дерева должен иметь вид

Кафедра АТ

ИСУ

ИСУ-11

ИСУ-12

У

Кафедра ЭВМ

ВМ

Для каждого нового узла в панели Свойства элемента можно указать ряд свойств. Свойство Текст – это надпись, появляющаяся в дереве около данного узла. Свойства Индекс образа и Выделенный индекс определяют индекс пиктограммы, отображаемой для узла, который соответственно не выделен и выделен пользователем в данный момент. Эти индексы соответствуют списку пиктограмм (в общем случае – изображений, образов), хранящихся в отдельном компоненте ImageList. Указание на этот компонент задается в свойстве Images компонента TreeView. Индексы начинаются с нуля. Если указать индекс -1 (значение по умолчанию), пиктограммы изображаться не будут. Последнее свойство – Индекс статус-образа позволяет добавить еще одну пиктограмму в данный узел, не зависящую от состояния узла. Подобная пиктограмма может просто служить дополнительной характеристикой узла. Индекс, указанный как Индекс статус-образа, соответствует списку пиктограмм, хранящихся в отдельном компоненте ImageList, указанном в свойстве StateImages компонента TreeView.

  1. Разместите на форме два компонента – ImageList1 и ImageList2. Загрузите в первый компонент не менее 14 пиктограмм, во второй – не менее 7 пиктограмм.

  2. Выделите компонент TreeView1. В свойстве Images задайте ImageList1, а в свойстве StateImagesImageList2.

  3. Спроектируйте дерево согласно содержимому приведенного выше файла, задавая для каждого узла по 3 пиктограммы. Следует учесть, что Индекс статус-образа не должен быть равным 0. Например, для первого узла можно задать индексы пиктограмм – 0, 1, 1, для второго узла – 2, 3, 2 и т.д.

  4. В правом верхнем углу формы поместите кнопку Button1 и назовите ее КОНЕЦ. В обработчик щелчка кнопки впишите Close();.

  5. Сохраните все и запустите приложение на выполнение. Убедитесь в работоспособности приложения.

Теперь рассмотрим формирование дерева во время выполнения приложения. Для этого имеется ряд методов объектов типа TTreeNodes.

Следующие методы позволяют вставлять в дерево новые узлы:

Add(TTreeNode* Node,

const System::AnsiString S)

Добавляет новый узел с текстом S как последний узел уровня, на котором расположен Node

AddFirst(TTreeNode* Node,

const System::AnsiString S)

Вставляет новый узел с текстом S как первый из узлов уровня, на котором находится Node. Индексы последую-щих узлов увеличиваются на 1

Insert(TTreeNode* Node,

const System::AnsiString S)

Вставляет новый узел с текстом S сразу после узла Node на тот же уро-вень. Индексы последующих узлов увеличиваются на 1

AddChild(TTreeNode* Node,

const System::AnsiString S)

Добавляет узел с текстом S как последний дочерний узла Node

AddChildFirst(TTreeNode* Node,

const System::AnsiString S)

Вставляет новый узел с текстом S как первый из дочерних узлов узла Node. Индексы последующих узлов увели-чиваются на 1

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

AddObject(TTreeNode* Node,

const System::AnsiString S, void* Ptr)

Добавляет новый узел с текстом S и объектом Ptr как последний узел уровня, на котором расположен Node

AddObjectFirst(TTreeNode* Node,

const System::AnsiString S, void* Ptr)

Вставляет новый узел с текстом S и объектом Ptr как первый из уз-лов уровня, на котором находится Node. Индексы последующих уз-лов увеличиваются на 1

InsertObject(TTreeNode* Node,

const System::AnsiString S, void* Ptr)

Вставляет новый узел с текстом S и объектом Ptr сразу после узла Node на тот же уровень. Индексы последующих узлов увеличивают-ся на 1

AddChildObject(TTreeNode* Node,

const System::AnsiString S, void* Ptr)

Добавляет узел с текстом S и объ-ектом Ptr как последний дочерний узла Node

AddChildObjectFirst(TTreeNode* Node,

const System::AnsiString S, void* Ptr)

Вставляет новый узел с текстом S и объектом Ptr как первый из до-черних узлов узла Node. Индексы последующих узлов увеличивают-ся на 1

Каждый из приведенных выше методов возвращает вставленный узел.

  1. Откройте новый проект и командой Сохранить все сразу сохраните файл модуля и проект под разными именами. Назовите форму ДЕМОНСТРАЦИЯ КОМПОНЕНТА TREEVIEW_2. На форму перенесите компоненты TreeView1, Button1 (назовите КОНЕЦ) и Button2 (назовите ЗАДАТЬ ДЕРЕВО).

  2. Обработчики щелчков кнопок задайте соответственно такими:

void __fastcall TForm1::Button1Click(TObject *Sender)

{

Close();

}

//---------------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)

{

TreeView1->Items->Clear();

TreeView1->Items->Add(NULL,"Кафедра АТ");

TreeView1->Items->AddChild(TreeView1->Items->Item[0],"ИСУ");

TreeView1->Items->AddChild(TreeView1->Items->Item[0],"У");

TreeView1->Items->Add(TreeView1->Items->Item[0],"Кафедра ЭВМ");

TreeView1->Items->AddChild(TreeView1->Items->Item[3],"ВМ");

TreeView1->Items->AddChild(TreeView1->Items->Item[1],"ИСУ-11");

TreeView1->Items->AddChild(TreeView1->Items->Item[1],"ИСУ-12");

}

  1. Запустите приложение на выполнение и убедитесь в его работоспособности. Сохраните приложение.

Текст, связанный с некоторым узлом, можно найти с помощью его свойства Text. Например, TreeView1->Items->Item[1]->Textэто надпись ”ИСУ".

Объект, связанный с некоторым узлом, можно найти с помощью его свойства Data. Например, TreeView1->Items->Item[1]->Data.

Для удаления узлов есть два метода: Clear(void), очищающий все дерево, и Delete(TTreeNode* Node), удаляющий указанный узел Node и все его узлы-потомки. При удалении узлов, связанных с объектами, объекты не удаляются.

Реорганизация дерева, связанная с созданием или удалением многих узлов, может вызывать неприятное мерцание изображения. Избежать этого можно с помощью методов BeginUpdate (запрещает перерисовку дерева) и EndUpdate (разрешает перерисовку дерева). Таким образом, изменение структуры дерева может осуществляться так:

TreeView1->Items->BeginUpdate();

<операторы изменения дерева>

TreeView1->Items->EndUpdate();

Если метод BeginUpdate применен подряд несколько раз, то перерисовка дерева произойдет только после того, как столько же раз будет применен метод EndUpdate.

Свойство узла Count – это число узлов, управляемых данным, т.е. дочерних узлов, их дочерних узлов и т.п. Если значение Count равно 0, узел является листом дерева.

Важным свойством компонента TreeView является Selected. Это свойство указывает узел, который выделен пользователем. Пользуясь этим свойством, можно запрограммировать операции, которые надо выполнить для выбранного пользователем узла. Если ни один узел не выделен, значение Selected равно NULL.

При выделении пользователем нового узла происходят события OnChanging (перед изменением выделения) и OnChange – после выделения. В обработчик события OnChanging передаются параметры TTreeNode* Node – узел, который выделен в данный момент, и bool &AllowChange – разрешение на перенос выделения. Если в обработчике задать AllowChange=false, то переключение выделения не произойдет. В обработчик события OnChange передается параметр TTreeNode* Node – выделенный узел. В этом обработчике предусматривают действия, которые должны производиться при выделении узла.

Ряд событий компонента TreeView связан с развертыванием и свертыванием узлов. При развертывании узла происходят события OnExpanding (перед развертыванием) и OnExpanded (после развертывания). В обработчики этих событий передается параметр TTreeNode* Node – развертываемый узел. Кроме того, в обработчик OnExpanding передается параметр bool &AllowExpansion, который нужно задать равным false, чтобы запретить развертывание. При свертывании узла происходят события OnCollapsing (перед свертыванием) и OnCollapsed (после свертывания). Так же, как и в событиях, связанных с развертыванием, в обработчики передается параметр TTreeNode* Node – свертываемый узел, а в обработчик OnCollapsing дополнительно передается параметр bool &AllowCollapse, разрешающий или запрещающий свертывание.

Свойство ReadOnly компонента TreeView позволяет запретить пользователю редактировать отображаемые данные. Если редактирование разрешено, то при редактировании возникают события OnEditing и OnEdited, аналогичные рассмотренным ранее (в обработчике OnEditing параметр bool &AllowEdit позволяет запретить редактирование).

Ряд свойств компонента TreeView: ShowButtons, ShowLines, ShowRootпозволяют отображать или убирать из дерева кнопки, показывающие раскрытия узла, линии, связывающие узлы, и корневой узел.

Свойство SortType позволяет автоматически сортировать ветви и узлы дерева. По умолчанию это свойство равно stNone, что означает, что дерево не сортируется. Если установить SortType равным stText, то узлы будут автоматически сортироваться по алфавиту. Возможно также проводить сортировку по связанным с узлами объектам Data (значение SortType равно stData), одновременно по тексту и объектам Data (значение SortType равно stBoth) или любым иным способом.

Для использования этих возможностей сортировки надо написать обработчик события OnCompare, в который передаются параметры TTreeNode*Node1 и TTreeNode*Node2 – сравниваемые узлы, и параметр int &Compare, в который надо заносить результат сравнения: отрицательное число, если узел Node1 должен располагаться ранее Node2, нуль, если эти узлы считаются эквивалентными, и положительное число, если узел Node1 должен располагаться в дереве после Node2. Например, следующий оператор в обработчике события OnCompare обеспечивает обратный алфавитный порядок расположения узлов:

OnCompare = -AnsiStrIComp(Node1->Text.c_str(),Node2->Text.c_str());

События OnCompare наступают после задания любого значения SortType, отличного от stNone, и при изменении пользователем свойств узла (например, при редактировании им надписи узла), если значение SortType не равно stNone. После сортировки первоначальная последовательность узлов в дереве теряется. Поэтому последующее задание SortType=stNone не восстанавливает начальное расположение узлов, но исключает дальнейшую генерацию событий OnCompare, т.е. автоматическую перестановку узлов, например, при редактировании их надписей. Если же требуется изменить характер сортировки или провести сортировку с учетом новых созданных узлов, то надо сначала задать значение SortType=stNone, а затем задать любое значение SortType, отличное от stNone. При этом будут сгенерированы новые обращения к обработчику событий OnCompare.

Имеются и другие возможности сортировки. Например, метод AlphaSort(void) обеспечивает алфавитную последовательность узлов независимо от значения SortType, но при отсутствии обработчика событий OnCompare (если обработчик есть, то при выполнении метода AlphaSort происходит обращение к этому обработчику). Отличие метода AlphaSort от задания значения SortType=stText заключается в том, что изменение надписей узлов приводит к автоматической пересортировке дерева только при SortType=stText.

При разработке дополнения в нашем проекте удобно использовать обработчики событий OnKeyDown и OnKeyUp. Событие OnKeyDown/OnKeyUp наступает, если компонент находится в фокусе, при нажатии/отжатии пользователем любой клавиши, включая функциональные и вспомогательные, такие, как Shift, Alt и Ctrl. В обработчики событий передаются, кроме обычного параметра Sender, указывающего на компонент, в котором произошло событие, параметры Key и Shift. Параметр Key определяет нажатую/отжатую клавишу клавиатуры. Параметр Shift является множеством, которое может быть пустым или включать в себя следующие элементы: ssShift, ssAlt, ssCtrl (нажата клавиша Shift, Alt, Ctrl соответственно).

Компонент StatusBar (находится на странице Win32) представляет собой ряд панелей, отображающих полосу состояния в стиле Windows. Обычно эта полоса размещается внизу формы.

Свойство SimplePanel определяет, включает ли полоса состояния одну или множество панелей. Если SimplePanel = true, то вся полоса состояния представляет собой единственную панель, текст которой задается свойством SimpleText. Если же SimplePanel = false, то полоса состояния является набором панелей, задаваемых свойством Panels. В этом случае свойство SizeGrip определяет, может ли пользователь изменять размеры панелей в процессе выполнения приложения.

Каждая панель полосы состояния является объектом типа TStatusPanels. Свойства панелей задают специальным редактором наборов, который можно вызвать тремя способами: из Инспектора Объектов кнопкой с многоточием около свойства Panels, двойным щелчком на компоненте StatusBar или из контекстного меню, выбрав команду Panels Editor. В окне редактора можно перемещаться по панелям, добавлять новые или уничтожать существующие панели. При этом в окне Инспектора Объектов будут видны их свойства.

Основное свойство каждой панели – Text, в который заносится отображаемый в панели текст. Его можно занести в процессе проектирования, а затем можно изменять программно во время выполнения. Другое существенное свойство – Width (ширина).

Программный доступ к текстам отдельных панелей возможен через свойство Panels и его индексированное подсвойство Items. Например, оператор:

StatusBar1->Panels->Items[0]->Text=”текст 1”;

выведет текст “текст1” в первую панель.

Количество панелей полосы состояния можно определить из подсвойства Count свойства Panels. Поэтому тексты всех панелей можно очистить так:

for(int i=0; i<StatusBar1->Panels->Count; i++)

{ StatusBar1->Panels->Items[i]->Text=””;}

  1. Вернемся к сохраненному выше проекту. Перенесем на форму компонент StatusBar1, его свойство SimplePanel установим равным true. В код модуля добавим глобальную переменную bool ShiftPressed и обработчики событий OnChange, OnKeyDown, OnKeyUp:

void __fastcall TForm1::TreeView1Change(TObject *Sender, TTreeNode *Node)

{

String pn="",cn="";

TTreeNode*ParentNode=Node->Parent;

if(ParentNode) pn="..Родитель: "+ParentNode->Text;

TTreeNode*ChildNode=Node->getFirstChild();

if(ChildNode) cn="..Наследник:.."+ChildNode->Text;

Caption=pn+cn;

}

//---------------------------------------------------------------------------

void __fastcall TForm1::TreeView1KeyDown(TObject *Sender, WORD &Key,

TShiftState Shift)

{

TTreeNode*Node=TreeView1->Selected;

switch(Key)

{ case VK_DELETE:

if(Node)

{ StatusBar1->SimpleText="Удалить узел: "+Node->Text;

Node->Delete();

} ShiftPressed=false; break;

case VK_INSERT:

if(Node)

{ StatusBar1->SimpleText="Создать узел: "+Node->Text;

TreeView1->Items->Insert(Node,"Новый узел");

} ShiftPressed=false; break;

case VK_SHIFT:

ShiftPressed=true; return;

}

TreeView1->Update();

}

//---------------------------------------------------------------------------

void __fastcall TForm1::TreeView1KeyUp(TObject *Sender, WORD &Key,

TShiftState Shift)

{

ShiftPressed=false;

}

//---------------------------------------------------------------------------

  1. Убедитесь в работоспособности дополненного приложения, добавляя новые узлы клавишей Insert и удаляя выделенный узел клавишей Delete. Сохраните приложение.

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

Все свойства, методы и события, связанные с процессом перетаскивания, определены в классе TControl, являющемся прародителем всех визуальных компонентов C++Builder. Поэтому они являются общими для всех компонентов.

Начало процесса перетаскивания определяется свойством DragMode, которое может устанавливаться в процессе проектирования или программно равным dmManual или dmAutomatic. Значение dmAutomatic (автоматическое) определяет автоматическое начало процесса перетаскивания при нажатии пользователем кнопки мыши над компонентом. Значение же dmManual (ручное) говорит о том, что начало процесса перетаскивания должен определять программист. Для этого он должен в соответствующий момент вызвать метод BeginDrag. Например, он может поместить вызов этого метода в обработчик события OnMouseDown, наступающего в момент нажатия кнопки мыши. В этом обработчике он может проверить предварительно какие-то условия (режим работы приложения, нажатие тех или иных кнопок мыши и вспомогательных клавиш) и при выполнении этих условий вызвать BeginDrag.

Во время перетаскивания объекта обычный вид курсора изменяется. Пока курсор перемещается над формой или компонентами, которые не могут принять информацию из перетаскиваемого объекта, он обычно имеет тип crNoDrop: «кольцо с перемычкой». Если же курсор перемещается над компонентом, готовым принять информацию из перетаскиваемого объекта, то он приобретает вид, определяемый свойством перетаскиваемого объекта DragCursor. По умолчанию это свойство равно crDrag, что соответствует изображению «стрелка из квадрата». Подчеркнем, что вид курсора определяется свойством DragCursor перетаскиваемого объекта, а не того объекта, над которым перемещается курсор.

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

Значение параметра Accept, задаваемое в обработчике события OnDragOver, определяет вид курсора, перемещающегося при перетаскивании над данным компонентом. Если в компоненте не описан обработчик события OnDragOver, то считается, что данный компонент не может принять информацию перетаскиваемого объекта.

Процедура приема информации от перетаскиваемого объекта записывается в обработчике события OnDragDrop принимающего компонента. Это событие наступает, если после перетаскивания пользователь отпустил кнопку мыши над данным компонентом. В обработчик этого события передаются параметры Source (объект-источник) и X и Y координаты курсора.

После завершения или прерывания перетаскивания наступает событие OnEndDrag, в обработчике которого можно предусмотреть какие-то дополнительные действия. Имеется также связанное с перетаскиванием событие OnStartDrag, которое позволяет произвести какие-то операции в начале перетаскивания. Это событие полезно при автоматическом начале перетаскивания, когда иным способом этот момент нельзя зафиксировать.

Вернемся к дополненному выше проекту.

  1. Свойство DragMode компонента TreeView1 установим равным dmAutomatic.

  2. В код модуля добавим обработчики событий OnDragOver, OnDragDrop:

void __fastcall TForm1::TreeView1DragOver(TObject *Sender, TObject *Source,

int X, int Y, TDragState State, bool &Accept)

{

Accept=Source->ClassNameIs("TTreeView");

}

//---------------------------------------------------------------------------

void __fastcall TForm1::TreeView1DragDrop(TObject *Sender, TObject *Source,

int X, int Y)

{

if(TreeView1->Selected==NULL) return;

THitTests HT=TreeView1->GetHitTestInfoAt(X,Y);

TNodeAttachMode AttachMode;

TTreeNode*Node=TreeView1->GetNodeAt(X,Y);

if(HT.Contains(htOnItem)) AttachMode=naAddChild;

else if(HT.Contains(htNowhere)) AttachMode=naAdd;

else if(HT.Contains(htOnIndent)) AttachMode=naInsert;

else return;

if(ShiftPressed)

{ StatusBar1->SimpleText="Копировать узел: "+ TreeView1->Selected->Text;

Node->Assign(TreeView1->Selected);

}

else

{ StatusBar1->SimpleText="Переместить узел: "+ TreeView1->Selected->Text;

TreeView1->Selected->MoveTo(Node,AttachMode);

}

TreeView1->Update();

}

  1. Убедитесь в работоспособности дополненного приложения, используя для перемещения узлов левую кнопку мыши, а для копирования узлов – левую кнопку мыши и нажатую клавишу Shift.

Компонент ListView позволяет отображать в стиле Windows данные в виде списков, таблиц, крупных и мелких пиктограмм. Стиль отображения определяется свойством ViewStyle, которое может устанавливаться в процессе проектирования или программно во время выполнения. Свойство может принимать значения: vsIcon – крупные значки, vsSmallIcon – мелкие значки, vsList – список, vsReport – таблица.

Рассмотрим использование компонента ListView в процессе проектирования.

  1. Создайте новый проект, назовите форму ДЕМОНСТРАЦИЯ КОМПОНЕНТА LISTVIEW и командой Сохранить все сразу сохраните файл модуля и проект под разными именами.

  2. Разместите на форме два компонента – ImageList1 и ImageList2. Загрузите в первый компонент не менее 11 пиктограмм, во второй – не менее 2 пиктограмм.

  3. Разместите на пустой форме компонент ListView1 со страницы Win32 и просмотрите открывшиеся в Инспекторе Объектов свойства.

  4. Основное свойство компонента, описывающее состав отображаемой информации – Items. Рядом с этим свойством в окне Инспекторе Объектов имеется кнопка с многоточием, щелчком по которой вызовем Редактор элементов ListView.

  5. В редакторе задайте структуру:

ИСУ

ИСУ-11

ИСУ-12

У

У-11

У-12

У-13,

устанавливая индексы образа равными 0, 1, …6, а индексы статус-образа (для узлов ИСУ и У) – 0 и 1. Для перехода из одного окна в другое пользуйтесь клавишей Tab.

  1. Выделите ListView1. Свойствам LargeImages и SmallImages задайте значение ImageList1, а свойству StateImages ImageList2.

  2. Свойство Columns определяет список заголовков таблицы в режиме vsReport. Двойным щелчком но компоненте ListView1 или щелчком на кнопке с многоточием рядом со свойством Columns вызовите редактор заголовков (Правка List). Крайняя левая кнопка позволяет добавить новую секцию в заголовок, вторая слева – удалить секцию, а две кнопки со стрелками позволяют изменять последовательность секций. После того, как секция добавлена и на ней установлен курсор, в окне Инспектора Объектов появится множество свойств этого объекта. В свойстве Caption последовательно задавайте тексты секций заголовка – специальность, группы 1, группы 2, группы 3, а в свойстве ImageIndex укажите индексы пиктограмм, которые появятся перед текстами секций заголовка – 7, 8, 9, 10 соответственно. Свойства MinWidth и MaxWidth определяют соответственно минимальную и максимальную ширину заголовка в пикселах. Только в этих пределах пользователь может изменять ширину заголовка курсором мыши. Для всех заголовков значение MaxWidth поставьте равным 300. Значение ширины по умолчанию задается значением свойства Width.

  3. Выполните приложение при значениях свойства ViewStyle: vsIcon – крупные значки, vsSmallIcon – мелкие значки, vsList – список, vsReport – таблица. Курсором мыши поварьируйте шириной заголовков. Сохраните приложение для последующего дополнения.

Дополненное приложение предоставит пользователю возможность изменять вид списка в окне ListView1 и, кроме того, позволит при стилях vsIcon и vsSmallIcon перетаскивать пиктограммы мышью в любое место окна.

  1. На форму сохраненного приложения со страницы Стандарт перенесите компонент MainMenu1. Это, как и ImageList, невизуальный компонент, т.е. место его размещения на форме в процессе проектирования не имеет никакого значения для пользователя – во время выполнения приложения он увидит не сам компонент, а только меню, сгенерированное им.

  2. Основное свойство компонента MainMenu1 – Items. Его заполнение производится с помощью Конструктора Меню, вызываемого двойным щелчком на компоненте MainMenu или нажатием кнопки с многоточием рядом со свойством Items в окне Инспектора Объектов. В открывшемся окне нужно спроектировать меню с разделами Крупные значки (имя MIcon), Мелкие значки (имя MSmallIcon), Список (имя MList), Таблица (имя MReport). Название раздела (курсив) заносится в свойство Caption, а имя – в свойство Name соответствующего раздела. Новые разделы можно вводить, помещая курсор в рамку из точек, обозначающую место расположения нового раздела. Если раздел ввелся не на нужном месте, его можно отбуксировать мышью в нужное место.

  1. Установите во всех разделах одинаковый, не равный нулю, индекс GroupIndex и свойства RadioItem в true, чтобы обеспечить работу каждого из разделов в режиме радиокнопки с другими разделами.

  2. Впишите обработчики щелчков для разделов меню и для событий OnDragOver, OnDragDrop компонента ListView1:

void __fastcall TForm1::MIconClick(TObject *Sender)

{

ListView1->ViewStyle=vsIcon;

MIcon->Checked=true;

ListView1->DragMode=dmAutomatic;

}

//---------------------------------------------------------------------------

void __fastcall TForm1::MSmallIconClick(TObject *Sender)

{

ListView1->ViewStyle=vsSmallIcon;

MSmallIcon->Checked=true;

ListView1->DragMode=dmAutomatic;

}

//---------------------------------------------------------------------------

void __fastcall TForm1::MListClick(TObject *Sender)

{

ListView1->ViewStyle=vsList;

MList->Checked=true;

ListView1->DragMode=dmAutomatic;

}

//---------------------------------------------------------------------------

void __fastcall TForm1::MReportClick(TObject *Sender)

{

ListView1->ViewStyle=vsReport;

MReport->Checked=true;

ListView1->DragMode=dmAutomatic;

}

//---------------------------------------------------------------------------

void __fastcall TForm1::ListView1DragOver(TObject *Sender, TObject *Source,

int X, int Y, TDragState State, bool &Accept)

{

Accept=(Source=ListView1);

}

//---------------------------------------------------------------------------

void __fastcall TForm1::ListView1DragDrop(TObject *Sender, TObject *Source,

int X, int Y)

{

((TListView*)Sender)->Selected->Position=Point(X,Y);

}

  1. Выполните построенное приложение. Убедитесь, что с помощью меню можно изменять вид списка в окне ListView1 и, кроме того, при стилях vsIcon и vsSmallIcon можно перемещать пиктограммы мышью в любое место окна.

  2. Метод Arrange:

void _fastcall Arrange(TListArrangement Code);

позволяет упорядочить пиктограммы в режимах vsIcon и vsSmallIcon. Параметр Code определяет способ упорядочивания:

arAlignBottom

выравнивание вдоль нижнего края области

arAlignLeft

выравнивание вдоль левого края области

arAlignRight

выравнивание вдоль правого края области

arAlignTop

выравнивание вдоль верхнего края области

arDefault

выравнивание (по умолчанию) вдоль верхнего края области

arSnapToGrid

размещение каждой пиктограммы в ближайшем узле сетки

Добавьте в меню раздел Выравнивание и в обработчик щелчка на нем запишите оператор:

ListView1->Arrange(arAlignTop);

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

Библиографический список

  1. Архангельский АЯ Программирование в C++Builder 6. – М: ЗАО «Издательство БИНОМ», 2003 – 1152 с – С 176–186, 209–214, 229–230, 325–328.

  2. Шамис В.А. Borland C++ Builder 6. Для профессионалов / В.А. Шамис.− СПб.: Питер, 2003. − 798 с. – С. 340−345.

ЛАБОРАТОРНАЯ РАБОТА 7

Главное меню.

Контекстное всплывающее меню.

Горячие клавиши

Меню представляют два компонента, расположенные на странице Стандарт: MainMenuглавное меню и PopupMenuвсплывающее меню.

Компонент MainMenu является невизуальным компонентом, т.е. место его размещения на форме в процессе проектирования не имеет значения для пользователя – во время выполнения он увидит не сам компонент, а только меню, сгенерированное компонентом.

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

Основное свойство компонента MainMenuItems. Его заполнение производится с помощью Конструктора Меню, вызываемого двойным щелчком на компоненте MainMenu или нажатием кнопки с многоточием рядом со свойством Items в окне Инспектора Объектов. При работе в окне Конструктора Меню вводят новые разделы и помещают их в нужное место.

При выборе нового раздела (щелчком на разделе) в Инспекторе Объектов появится множество свойств данного раздела, поскольку каждый раздел меню, т.е. каждый элемент свойства Items является объектом типа TMenuItem, обладающим своими свойствами, методами, событиями. Рассмотрим основные свойства раздела.

Свойство Caption обозначает надпись раздела. Правила заполнения этого свойства следующие.

В надписи можно предусмотреть использование клавиши ускоренного доступа, выделяя для этого один из символов надписи. Перед символом, который должен соответствовать клавише ускоренного доступа, ставится символ амперсанда '&’. Этот символ не появляется в надписи, а следующий за ним символ оказывается подчеркнутым. Тогда пользователь может вместо щелчка на кнопке нажать в любой момент клавишу Alt совместно с клавишей выделенного символа.

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

Свойство Name задает имя объекта, соответствующего разделу меню. Рекомендуется давать этим объектам осмысленные имена.

Свойство ShortCut определяет клавиши быстрого доступа к разделу меню – «горячие» клавиши, с помощью которых пользователь, даже не заходя в меню, может в любой момент вызвать выполнение действий, связанных с данным разделом. Чтобы определить клавиши быстрого доступа, надо открыть выпадающий список свойства ShortCut в окне Инспектора Объектов и выбрать из него нужную комбинацию клавиш. Эта комбинация появится в строке раздела меню.

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

Свойство Break используется в длинных меню, чтобы разбить список разделов на несколько столбцов. Возможные значения Break: mbNone – отсутствие разбиения меню (это значение принято по умолчанию), mbBarBreak и mbBreak – в меню вводится новый столбец разделов, отделенный от предыдущего полосой (mbBarBreak) или пробелами (mbBreak).

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

<имя_раздела>->Checked =! <имя_раздела>->Checked;

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

Еще одним свойством, позволяющим вводить маркеры в разделы меню, является RadioItem. Это свойство, установленное в true, определяет, что данный раздел должен работать в режиме радиокнопки совместно с другими разделами, имеющими то же значение свойства GroupIndex. По умолчанию значение GroupIndex равно нулю. Если же при RadioItem = true для нескольких разделов задать значение GroupIndex большим нуля и одинаковым, то все эти разделы могут быть отмечены маркерами флажков, но только в выбранном разделе появится маркер флажка. Если задать программно в одном из этих разделов Checked = true, то в остальных разделах Checked автоматически сбросится в false.

Для подобных групп разделов, работающих как радиокнопки, можно установить в true свойство AutoCheck. Тогда при щелчке пользователя на невыбранном разделе все будет работать нормально: этот раздел включится, а ранее включенный выключится. Но если пользователь щелкнет на выбранном разделе, то он выключится и окажется, что все разделы данной группы выключены. Если по смыслу это допустимое состояние, то все можно оставить без изменений. Но если в любом случае один из разделов должен быть включен, то надо отказаться от использования свойства AutoCheck (установить его в false) и переключать свойство Checked программно. Например, в обработчики щелчков этих разделов можно ввести оператор:

if(! ((TMenuItem *) Sender)->Checked)

((TMenuItem *) Sender)->Checked) = true;

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

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

Для каждого раздела могут быть установлены пользователем во время проектирования или программно во время выполнения свойства Enabled (доступен) и Visible (видимый). Если установить Enabled = false, то раздел будет изображаться серой надписью и не будет реагировать на щелчок пользователя. Если же задать Visible = false, то раздел вообще не будет виден, а остальные разделы сомкнутся, заняв место невидимого. Свойства Enabled и Visible используются для того, чтобы изменять состав доступных пользователю разделов в зависимости от режима работы приложения.

Имеется также возможность ввода в разделы меню изображений. Для этого используют свойства разделов Bitmap и ImageIndex. Первое из них позволяет непосредственно ввести изображение в раздел, выбрав его из указанного пользователем файла. Второе позволяет указать индекс изображения, хранящегося во внешнем компоненте ImageList. Указание на этот компонент задается в свойстве Images компонента MainMenu. Индексы начинаются с нуля. Если указать индекс -1 (значение по умолчанию), изображения не будет.

Основное событие раздела – OnClick, возникающее при щелчке пользователя на разделе или при нажатии «горячих» клавиш быстрого доступа.

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

Наличие или отсутствие объединения определяется свойством AutoMerge компонентов MainMenu. Если требуется, чтобы меню вспомогательных форм объединялись с меню главной формы, то в каждой такой вспомогательной форме надо установить AutoMerge в true. При этом свойство AutoMerge главной формы должно оставаться в false.

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

Форма 1 Форма 2

2 – 4 1 – 3

| | | |

2 4 1 3

| | |

2 4 1

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

1 – 2 – 3 – 4

| | | |

1 2 3 4

| | |

1 2 4

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

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

Рассмотрим пример использования компонента MainMenu и варианты объединения главного меню вспомогательной формы с главным меню главной формы.

  1. Создайте новое приложение и командой Сохранить все сохраните файл модуля и проект под предложенными по умолчанию именами – Unit1 и Project1 в созданной для приложения папке (каталоге).

  2. В свойство Caption формы Form1 впишите ГЛАВНАЯ ФОРМА.

  3. Со страницы Стандарт на форму перенесите компонент MainMenu1, двойным щелчком на нем перейдите в Конструктор Меню (окно Form1-> MainMenu1) и сконструируйте меню с двумя головными разделами Формирование квадратных матриц, Операции с матрицей.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]