Для создания деревьев можно использовать два подхода — строить дерево в виде терма или использовать объектную модель (последнее возможно только для пользователей
Подготовим изображения, которые будут размещаться в вершинах дерева — для терминальных вершин, для открытых и закрытых узлов, а также для выделенных вершин (терминальных, открытых и закрытых), всего шесть изображений.
Выделим папку ).
(рис 6.1) Изображения для терминальной вершины: (a) обычной; (b) выделенной
Аналогично следует создать изображения (.
Откроем редактор страницы ).
(рис 6.2) Редактор страницы treePage
Кроме этого, добавим пользовательский элемент управления (). Пользователям Personal Edition следует сразу создать еще один элемент управления (Custom Control) для отображения дерева потомков (Class: treeViewControl; Name: descendtree_ctl).
Закроем редактор страницы и выберем команду компиляции пакета treePage.pack.
В раздел open имплементации класса treePage слeдует добавить имена классов resourceIdentifiers и treeViewControl:
open core, vpiDomains, resourceIdentifiers, treeViewControl
Далее необходимо изменить определение конструктора new/0 и добавить объявление констант.
clauses
new():-
userControlSupport::new(),
generatedInitialize(),
%
db := familyForm::familyForm:db.
facts
db : dbrel.
constants
closed : bitmapId = resid(idb_closed).
closedSel : bitmapId = resid(idb_closedsel).
opened : bitmapId = resid(idb_opened).
openedSel : bitmapId = resid(idb_openedsel).
terminal : bitmapId = resid(idb_terminal).
terminalSel : bitmapId = resid(idb_terminalsel).
ancestors = 0.
descendants = 1.
Добавим обработчик событий ShowListener. Ниже приведено его определение.
clauses
onShow(_Source, _Data):-
some(Person) = db:selectedPerson,
!,
AncTree = createTree(Person:id, ancestors),
anctree_ctl:insertTree(wcc_null, sorted(), AncTree),
DescTree = createTree(Person:id, descendants), % для PE
descendtree_ctl:insertTree(wcc_null, sorted(), DescTree).
onShow(_Source, _Data).
Предикат insertTree/3 размещает дерево в окне treeViewControl. Параметр sorted означает, что поддеревья упорядочиваются по надписям, помещенным в корнях этих поддеревьев.
Предикат createTree/2 строит дерево. Дерево строится в виде терма — шестиместной структуры с функтором tree (см. ниже). Первый аргумент хранит идентификатор, второй — список свойств узла (например, он может быть развернутым — expanded), третий и четвертый — изображения для невыделенных и выделенных вершин, пятый — текст (надпись) и шестой — список поддеревьев.
predicates
createTree: (unsigned, positive AncOrDesc) -> tree.
clauses
createTree(Id, Type) =
tree(uncheckedConvert(itemId, Id), [], Pict, PictSel,
Person:legend(),
list::map(ChildList, {(I) = createTree(I, Type)})):-
Person = getPerson(Id),
ChildList = childList(Person, Type),
nodeBitmap(toBoolean([] = ChildList), true, Pict, PictSel).
predicates
getPerson: (unsigned Id) -> person.
clauses
getPerson(Id) = Person:-
Person = db:getPerson(Id),
!.
getPerson(_) = _:-
exception::raise_error().
predicates
childList: (person, positive Type) -> unsigned* IdList.
clauses
childList(Person, descendants) = Person:children:- !.
childList(Person, _) =
list::filter([Person:idFather, Person:idMother], {(I):- I > 0}).
predicates
nodeBitmap: (boolean IsTerminal, boolean IsNotExpanded,
bitmapId NewBmp [out], bitmapId NewSelBmp [out]).
clauses
nodeBitmap(true, _, terminal, terminalSel):- !.
nodeBitmap(_, true, closed, closedSel):- !.
nodeBitmap(_, _, opened, openedSel).
Предикат nodeBitmap/4 возвращает изображения для вершины (невыделенной и выделенной).
Сделаем так, чтобы при открывании или закрывании узла дерева менялось изображение. В редакторе страницы treePage выделим в списке окна Properties элемент anctree_ctl и добавим обработчик событий ExpandBeginResponder. Ниже приведено его определение.
predicates
onAnctreeExpandBegin : treeViewControl::expandBeginResponder.
clauses
onAnctreeExpandBegin(Source, ItemId, IsExpanded) =
treeViewControl::acceptExpand:-
Source:getItem(ItemId, Text, StateList, Bmp, _SelBmp),
nodeBitmap(toBoolean(terminal = Bmp), IsExpanded,
NewBmp, NewSelBmp),
Source:setItem(ItemId, Text, StateList, NewBmp, NewSelBmp),
Source:unselect().
Далее (в .
(рис 6.3) Деревья предков и потомков
Для построения дерева потомков в ). В таблице свойств установим следующие значения для приведенных ниже свойств:
Name: desctree_ctl;@Node: treeNode_std;Border: True.Изменим определение конструктора new/0 так, как показано ниже.
clauses
new():-
userControlSupport::new(),
generatedInitialize(),
%
db := familyForm::familyForm:db,
descTreeControl_ctl:imageList := imageList::new(16, 16),
closedIdx := desctree_ctl:imageList:addResource(idb_closed),
closedSelIdx :=
desctree_ctl:imageList:addResource(idb_closedsel),
terminalIdx :=
desctree_ctl:imageList:addResource(idb_terminal),
terminalSelIdx :=
desctree_ctl:imageList:addResource(idb_terminalsel),
if some(Person) = db:selectedPerson then
Root = treeNode_std::new(Person:legend()),
Root:bitmapIdx := closedIdx,
Root:selectedBitmapIdx := closedSelIdx,
getTree(Root, Person:id, descendants),
TreeModel = treeModel_std::new(),
TreeModel:addTree(Root),
desctree_ctl:model := TreeModel,
desctree_ctl:nodeRenderer := TreeModel:nodeRenderer
end if.
Ниже приведено определение предиката getTree/3, который строит дерево, а также объявление фактов-переменных.
facts
closedIdx : integer := 0.
closedSelIdx : integer := 0.
terminalIdx : integer := 0.
terminalSelIdx : integer := 0.
predicates
getTree: (treeNode_std, unsigned, positive Type).
clauses
getTree(ParentNode, Id, Type):-
Person = getPerson(Id),
List = childList(Person, Type),
Idx = if [] = List then terminalIdx else closedIdx end if,
SelIdx = if []= List then terminalSelIdx else closedSelIdx end if,
ParentNode:bitmapIdx := Idx,
ParentNode:selectedBitmapIdx := SelIdx,
list::forAll(List, {(IdChild):-
Child = getPerson(IdChild),
Node = treeNode_std::new(ParentNode, Child:legend()),
getTree(Node, IdChild, Type)}).
При выделении вершины будем изменять цвет надписи. Добавим для элемента управления treeControl обработчики событий SelectBeginResponder и SelectEndListener.
Ниже приведено определение предиката onDesctreeSelectBegin.
predicates
onDesctreeSelectBegin :
treeControl{treeNode_std}::selectBeginResponder.
clauses
onDesctreeSelectBegin(_Source, _Unselected, Selected) =
treeControl{treeNode_std}::acceptSelect:-
Selected = treeControl{treeNode_std}::node(Node),
!,
Node:textColor := color_DarkBlue,
desctree_ctl:refresh(Node).
onDesctreeSelectBegin(_Source, _Unselected, _Selected) =
treeControl{treeNode_std}::acceptSelect.
Далее приведено определение предиката onDesctreeSelectEnd.
predicates
onDesctreeSelectEnd :
treeControl{treeNode_std}::selectEndListener.
clauses
onDesctreeSelectEnd(_Source, Unselected, _Selected):-
Unselected = treeControl{treeNode_std}::node(Node),
!,
Node:textColor := color_Black,
desctree_ctl:refresh(Node).
onDesctreeSelectEnd(_Source, _Unselected, _Selected).
Результат показан справа на рис. 6.3 рис 6.3.
В настоящем параграфе создается форма, в которой в виде таблицы отображаются сводные сведения из базы данных.
Cоздадим форму listViewForm и поместим в нее следующие элементы управления (рис. 6.4 рис 6.4):
пользовательский элемент управления (Custom Control):
Class: listViewControl; Right Anchor: True, Bottom Anchor: True;
поле редактирования (Edit Control):
Text: <пустое поле> Top Anchor: False, Right Anchor: True, Bottom Anchor: True; VScroll: True, AutoVScroll: True, AutoHScroll: False.
(рис 6.4) Редактор формы listViewForm
Закроем редактор окна и выберем команду компиляции пакета listViewForm.pack.
Затем в пакете listViewForm создадим изображения (Bitmap) male (idb_male) и female (idb_female) размером 16 х 16.
В раздел open имплементации класса listViewForm добавим имена классов resourceIdentifiers и listViewControl:
open core, vpiDomains, resourceIdentifiers, listViewControl
После этого изменим определение конструктора, а также определим факты-переменные.
clauses
new(Parent):-
formWindow::new(Parent),
generatedInitialize(),
%
db := familyForm::familyForm:db,
ImageList = imageList::new(16, 16),
maleIdx := ImageList:addResource(idb_male),
femaleIdx := ImageList:addResource(idb_female),
listViewControl_ctl:imageList := ImageList.
facts
db : dbrel.
maleIdx : integer := 0.
femaleIdx : integer := 0.
Далее следует определить предикаты, которые используются для формирования строк в ячейках таблицы.
predicates
getLegend: (unsigned Id) -> string Name.
clauses
getLegend(Id) = Person:legend():-
Person = db:getPerson(Id),
!.
getLegend(_Id) = "".
predicates
getPict: (person) -> integer Idx.
clauses
getPict(Person) = maleIdx:-
dbrel::male = Person:sex,
!.
getPict(_Person) = femaleIdx.
predicates
getSpouses: (person) -> string.
clauses
getSpouses(P) = string::concatWithDelimiter(
[S:legend() || Id in P:spouses, S = db:getPerson(Id)], ", ").
Предикат getLegend/1 возвращает строку, состоящую из имени и фамилии родителя, либо пустую строку, если сведения о родителе отсутствуют в базе данных. Предикат getPict/1 возвращает изображение, которое отображается в строке таблицы. Предикат getSpouses/1 собирает строку, состоящую из имен и фамилий супругов.
Таблица создается при открытии окна ). Изначально строки упорядочиваются по идентификаторам.
(рис 6.5) Окно listViewForm
Добавим в редакторе формы listViewForm обработчик событий ShowListener. Его определение приведено ниже.
clauses
onShow(_Source, _Data):-
ColumnList = [
column("Имя", 100, alignLeft),
column("Фамилия", 80, alignLeft),
column("Пол", 50, alignCenter),
column("Отец", 100, alignLeft),
column("Мать", 110, alignLeft),
column("Супруги", 120, alignLeft)
],
Comparator = {(X, Y) = compare(X:id, Y:id)},
PersonList = list::sortBy(Comparator, db:personList),
ItemList = [
item(
uncheckedConvert(itemId, Person:id),
Person:name, Pict, [],
[Person:surname, Person:sex, Father, Mother, Spouses])
||
Person in PersonList,
Pict = getPict(Person),
Father = getLegend(Person:idFather),
Mother = getLegend(Person:idMother),
Spouses = getSpouses(Person)
],
listViewControl_ctl:insertColumnList(1, ColumnList),
listViewControl_ctl:insertItemList(ItemList),
listViewControl_ctl:setLVType(lvs_report),
listViewControl_ctl:setStyle([lvs_singlesel]).
Список ColumnList содержит параметры столбцов таблицы — название, ширину столбца и тип выравнивания элементов в столбце.
Строка таблицы хранится в виде терма item/5. Первый аргумент содержит идентификатор, второй — значение в первом столбце, третий — изображение, четвертый — список свойств, пятый — список значений в остальных столбцах. Если изображение не требуется, то значение параметра Pict можно положить равным (– 1).
Форма listViewForm открывается при нажатии на кнопку "Таблица" окна familyForm. В редакторе формы familyForm добавим обработчик события нажатия на эту кнопку. Ниже приведено его определение.
clauses
onTableClick(_Source) = button::defaultAction:-
familyForm := This,
_ = listViewForm::display(getParent()).
Добавим операцию сортировки списка по столбцу при выделении столбца. Для этого следует открыть редактор формы listViewForm, выделить элемент listViewControl и добавить обработчик события ColumnClickListener. Он определяется ниже.
predicates
onListViewControlColumnClick :
listViewControl::columnClickListener.
clauses
onListViewControlColumnClick(S, ColumnNumber):-
S:sortItems(listViewControl::ascending(), ColumnNumber).
В результате строки таблицы будут упорядочены по значениям элементов выделенного столбца.
При выделении строки таблицы, описание о члене семьи из файла, который указан в базе данных (первым), должно отобразиться в поле редактирования (см. рис. 6.5 рис 6.5). Если файл с описанием отсутствует в базе данных, то в поле редактирования должно отобразиться имя человека. В редакторе формы listViewForm добавим для списка обработчик событий SelectBeginResponder.
predicates
onListViewControlSelectBegin :
listViewControl::selectBeginResponder.
clauses
onListViewControlSelectBegin(S, ItemId, true) =
listViewControl::acceptSelect:-
item(_, Name, _, _, [Surname | _]) = S:getItem(ItemId),
Id = uncheckedConvert(unsigned, ItemId),
Person = db:getPerson(Id),
!,
Text = getDescription(Person, Name, Surname),
edit_ctl:setText(Text).
onListViewControlSelectBegin(_, _, _) = acceptSelect:-
edit_ctl:setText("").
Ниже приведено определение предиката getDescription/3.
predicates
getDescription: (person, string Name, string Surname) -> string.
clauses
getDescription(Person, _, _) = Text:-
[FileName | _] = Person:descriptions,
FilePath = dbrel::descriptionsFolder(),
FullName = fileName::setPath(FileName, FilePath),
file::existFile(FullName),
try Text = file::readString(FullName, _)
catch _ do
fail
end try,
!.
getDescription(_, Name, S) = string::concat(Name, " ", S).
Существует четыре способа отображения списка — таблица (см. выше), список, значки и плитка (рис. 6.6 рис 6.6).
(рис 6.6) Способы отображения списка: (a) список; (b) значки; (c) плитка
Создадим всплывающее меню, которое будет использоваться для изменения способа отображения списка (см. рис. 6.5 рис 6.5).
В папке listViewForm создадим меню listViewPopUpMenu с пунктами:
id_report);id_list);id_icon);id_smallicon).После этого добавим обработчик событий MouseRightClickListener для списка и обработчик событий MenuItemListener для формы. Ниже приведено определение предиката onListViewControlMouseRightClick.
predicates
onListViewControlMouseRightClick :
listViewControl::mouseRightClickListener.
clauses
onListViewControlMouseRightClick(_Source, Point):-
Menu = vpi::menuGetRes(id_listviewpopupmenu),
menuPopUp(Menu, Point, align_left).
Далее определяется предикат onMenuItem.
predicates
onMenuItem : window::menuItemListener.
clauses
onMenuItem(_Source, id_report):- !,
listViewControl_ctl:setLVType(lvs_report).
onMenuItem(_Source, id_list):- !,
listViewControl_ctl:setLVType(lvs_list).
onMenuItem(_Source, id_icon):- !,
listViewControl_ctl:setLVType(lvs_icon).
onMenuItem(_Source, id_smallicon):- !,
listViewControl_ctl:setLVType(lvs_smallicon).
onMenuItem(_Source, _MenuTAG).
Высплывающее меню можно создать непосредственно в окне списка. Для этого нужно изменить определение предиката ):
onListViewControlMouseRightClick(_Source, Point):-
Menu = vpi::menuGetRes(id_listviewpopupmenu),
listViewControl_ctl:menuPopUp(Menu, Point, align_left).
В этом случае придется использовать другой обработчик событий выбора пункта меню. В редакторе окна ).
Упражнения
6.1. Создайте отдельное окно для просмотра изображения выделенного члена семьи. Оно должно открываться с помощью двойного щелчка по изображению на форме familyForm и на форме tabForm.
6.2. Создайте окно для поиска ответов на запросы к базе данных на языке, близком к естественному языку. Для вывода ответа на запрос используйте список (listBox или listViewControl).
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.