Основы офисного программирования и документы Word

Организация диалога. Объект Assistant

Разбить на страницы
Показывать лекцию целиком

Организация диалога. Объект Assistant

Помощник, ведущий диалог

Всякий раз, когда разработчик создает очередное решение, одна из серьезных проблем, стоящих перед ним, состоит в организации интерфейса своей системы. Хороший интерфейс, - привлекательный и понятный пользователю, во многом определяет успех предлагаемого решения. Диалог с пользователем - важная часть интерфейса. Во многих случаях для организации диалога достаточно обычных диалоговых окон, открываемых в нужный момент с выдачей подходящего сообщения. Зачастую для организации диалога предпочтительнее более выразительные средства и тут незаменим Помощник (объект Assistant ), хорошо знакомый пользователям Office 2000, поскольку именно он обеспечивает диалог со справочной системой, может организовать подсказки и выдачу советов. Давайте познакомимся с объектом Assistant поближе и научимся использовать его в своих решениях. Объект Assistant, задающий Помощника, появился в предыдущей версии Office 97. В новой версии он сохранил свои основные свойства и поведение.

Вначале несколько слов о Помощнике. Идея Помощников (Мастеров, Агентов) в программировании не нова. Сегодня эта технология приобрела широкую популярность. В любом достаточно сложном приложении, в котором пользователю отводится активная роль, полезно создать некоторую совокупность Помощников пользователя. Пользователь будет выбирать, какую задачу он хочет решить в тот или иной момент, а соответствующий Помощник поможет ему на этом пути, проводя пользователя через все этапы решения задачи, снабжая необходимой информацией, информируя о возникших ошибках, позволяя сделать откат и вернуться к предыдущему этапу. В программных продуктах Microsoft, например, подобные Помощники или Мастера (Assistants, Wizards) сопровождают нас на каждом шагу, начиная с этапа инсталляции приложения. Кроме того, что Помощники предназначены для обеспечения помощи в решении некоторой конкретной задачи и могут вести диалог с пользователем, они могут обладать еще двумя важными качествами:

  • Иметь видимый образ, возможно допускающий анимацию. Помощник с анимацией, делает приложение одушевленнее. Замечу, что из всех образов, в которых может предстать Помощник, заданный объектом Assistant, я предпочитаю Rocky и позволяю себе в минуты отдыха играться с ним, заставляя его выполнять различные движения. Жаль только, что его анимация не подчиняется голосовым командам, например, "Принеси палку".
  • Обладать определенной интеллектуальностью. Интеллектуальный" Помощник должен уметь собирать факты в процессе работы пользователя, иметь базу знаний, содержащую факты и правила, и иметь встроенную машину вывода. Такой Помощник может делать собственные выводы, брать на себя часть творческой работы, например, по заданию части параметров, или приходить на помощь в нужный, по его мнению, момент.
  • В последнем предложении я не поставил запятые в обороте "по его мнению". Интеллектуальный Помощник, каковым, несомненно, является встроенная в Word система проверки правописания, тут же выдала мне соответствующую подсказку.

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

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

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

    (рис 7.1) Структура объекта Assistant

    В объект Assistant вложен объект Balloon. В свою очередь в объект Balloon вложены две коллекции - CheckBoxes (кнопки выбора) и Labels (метки) с элементами классов CheckBox и Label соответственно. Обратите внимание, коллекции называются именно так и не имеют приставки Balloon, как показано на рисунке, взятом из документации, и не изменившимся в новой версии.

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

    Свойства объекта Assistant

    Как это мы уже не раз делали, зададим сводку основных свойств таблицей:

    Основные свойства объекта Assistant
    Свойство Назначение
    Animation Возвращает или устанавливает тип анимации образа Assistant. Если свойство применяется к объекту Assistant, то он "оживает" сразу же при включении. Если же оно применяется к объекту Balloon, то анимация возникает только при появлении баллончика. Может быть значением одной из 34-х констант типа MsoAnimationType.
    AssistWithAlerts, AssistWithHelp, AssistWithWizards Булевы свойства, имеющие значение True, если Assistant используется для выдачи предупреждений (заменяя окно MsgBox ), в ответ на нажатие клавиши F1 (Help), и при выдаче справочных сообщений, когда работают различные Мастера
    BalloonError Возвращает значение, указывающее на тип последней ошибки объекта Balloon.
    FeatureTips Булево свойство, которому дается значение True, когда желательно получать советы о наиболее эффективных способах использования свойств приложения.
    FileName Возвращает или устанавливает имя файла, содержащего графический образ Assistant. Файл имеет уточнение act, например файл со скрепкой - Clippit.act. Заметим, что могут быть заданы только стандартные для Office 97 файлы. Собственные образы задавать нельзя, но число стандартных образов расширяется.
    GuessHelp Это именно то булево свойство, установив значение которого, равным True, Вы получаете контекстную подсказку с именами разделов электронной документации при обращении за помощью. Хотите сами искать - отключите это свойство.
    HighPriorityTips, KeyboardShortcutTips, MouseTips Советы имеют разный приоритет. Если свойство имеет значение True, то будут выдаваться советы только наивысшего приоритета. Следующие два булевы свойства включают возможность выдачи информации о горячих клавишах и наиболее эффективном использовании мыши.
    NewBalloon Является по существу центральным свойством, поскольку позволяет создать новый объект Balloon. После чего можно нужным образом определить свойства этого объекта. Напомним, что баллончик определяет основные возможности Assistant.
    Sounds Булево свойство, включающее звук в процессе анимации.
    TipOfDay Булево свойство, включающее или отключающее "Совет дня" при открытии приложения Office 97.
    Visible Делает видимым или невидимым объект Assistant, сворачивая его в кнопку на панели инструментов.
    Новые свойства в Office 2000 Назначение
    On Новое булево свойство позволяет включать и выключать Помощника.

    Методы объекта Assistant

    В Office 2000 не произошло изменений в методах объекта Assistant. Он по-прежнему имеет следующие методы: StartWizard, ActivateWizard, EndWizard, Help, Move и ResetTips. Методы этого объекта используются реже, чем свойства и я ограничусь их кратким описанием.

    Методы StartWizard, ActivateWizard, EndWizard применяются при создании пользовательских Мастеров. Первым должен быть запущен метод StartWizard, возвращающий идентификатор (длинное целое) Помощника. Этот идентификатор затем используется в методах ActivateWizard и EndWizard, соответственно активизирующих и деактивирующих Помощника.

    Метод Help выводит стандартное сообщение Помощника справочной системы Office 2000 с заголовком "What would you like to do?"

    Метод Move перемещает Помощника в указанную параметрами left и top позицию на экране

    Метод ResetTips очищает журнал советов, в связи с чем могут вновь появляться уже данные советы.

    В заключение рассказа о свойствах и методах объекта Assistant приведем пример, в котором поменяем образ объекта Assistant и некоторые его свойства:

    Public Sub ChooseAss()
    With Assistant
    	Debug.Print .FileName
    	'Задаем образ Помощника
    		'.FileName = "dot.acs"
    		.FileName = "Offcat.acs"
    		'.FileName = "Rocky.acs"
    		
    	'Его анимационное поведение
    		.Animation = msoAnimationGreeting
    		.Animation = msoAnimationGetAttentionMinor
    	'Другие свойства
    		.AssistWithHelp = True
    		.FeatureTips = True
    		.GuessHelp = True
    		.HighPriorityTips = True
    		.Visible = True
    	End With
    End Sub

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

    (рис 7.2) "Мурка" в роли Помощника (объекта Assistant)

    Обратите внимание, - на вопрос, заданный на естественном русском языке, выдана точная справка. Этого не было в предыдущей версии.

    Объект Balloon

    Можно изменить свойства объекта Assistant, но в каждый момент существует только один такой объект. C ним можно связать произвольное число объектов Balloon, которые я называю баллончиками. Поясним происхождение термина. Реплики рисованных персонажей комиксов или карикатур художники нередко помещают в кружок - "баллончик", выдуваемый изо рта.

    У объекта Assistant нет коллекции объектов Balloon (а жаль), но можно создать необходимое число переменных этого класса или массив из таких объектов. Вот пример:

    Public Sub Balls()
    	Dim i As Integer
    	'Создание объектов Balloons
    		Dim FirstBall As Balloon, LastBall As Balloon
    		Dim ArrOfBall(3) As Balloon
    	With Assistant
    		.FileName = "OffCat.acs"
    		Set FirstBall = .NewBalloon
    		FirstBall.Show
    		.FileName = "Rocky.acs"
    		Set LastBall = .NewBalloon
    		LastBall.Show
    		For i = 1 To 3
    			Set ArrOfBall(i) = .NewBalloon
    			ArrOfBall(i).Show
    		Next i
    		FirstBall.Show
    	End With
    End Sub

    Здесь созданы две переменные и массив из трех элементов класса Balloon. По ходу дела внешний вид объекта Assistant меняется, но все баллончики одинаковы, в момент рождения они пусты и имеют единственную кнопку "ОК". Рассмотрим, как можно наполнить содержанием эти объекты и задать их свойства.

    Модальные и немодальные баллончики

    Объекты Balloon предназначены для ведения диалога с пользователем и фактически являются специальным видом диалоговых окон. Любое диалоговое окно, а значит и объект Balloon может быть модальным и немодальным. Из модальных окон нельзя выйти, не закончив диалог. Обычно, для этого нужно щелкнуть одну из кнопок этого окна - Ok или Cancel. В модальном объекте Balloon эти кнопки, как правило, присутствуют, но их наличие не является обязательным. Если щелкнуть любую кнопку в модальном окне, то диалог оканчивается и окно закрывается. До тех пор, пока модальное окно не будет закрыто, нельзя начать работать с другим окном. Немодальные окна можно покидать, в этот момент они перестают быть активными, но остаются на экране и не закрываются. При необходимости в них можно вернуться и продолжить работу с ними. Позже мы рассмотрим механизм закрытия немодальных окон и специальный механизм CallBack функций, позволяющий организовать реакцию на выбор, сделанный пользователем в немодальном окне.

    Объект Balloon имеет свойство Mode с тремя возможными значениями:

  • MsoModeModal - в этом случае диалог с объектом Balloon является модальным. Его обычно используют для вывода предупреждений, требующих особого внимания или получения ответа от пользователя, без которого дальнейшая работа не может быть продолжена.
  • MsoModeModeless - в этом случае окно становится немодальным и оно может оставаться открытым, в то время как продолжается работа над приложением в других его окнах. Такие объекты удобны, например, при выдаче справочной информации, которая должна быть все время под рукой.
  • MsoModeAutoDown - задает специальный вид модального окна, в котором не обязательны кнопки. Окно закрывается автоматически, как только пользователь введет символ с клавиатуры или щелкнет кнопку мыши, где - либо вне модального окна. Такие окна полезны при выводе сообщений, не носящих критический характер, например советов.
  • Терминальные свойства объекта Balloon

    С двумя свойствами этого объекта: Animation и Mode мы уже знакомы. Первое из них задает анимацию объекта Assistant при вызове его метода Show, в тот момент, когда показывается объект Balloon. Рассмотрим подробнее другие свойства

  • Heading - позволяет прочесть или установить строку, задающую текст заголовка.
  • Text - На вершине объекта Balloon сразу после заголовка может появляться некоторый текст. Его и устанавливает свойство Text. Оба элемента являются необязательными. Заметьте, что Heading и Text могут включать и графику. Последняя задается строкой, имеющей следующий синтаксис: {<type> <location> [<factor>]}. Первый параметр задает тип графического файла (bmp или wmf), второй - его расположение, третий позволяет согласовать размер wmf-файла (Windows metafile), но не bmp-файла.
  • Icon - Слева от заголовка можно добавить специальный значок для привлечения внимания. Возможные значки задаются следующими константами: msoIconAlert, msoIconNone, или msoIconTip.
  • Button - Внутрь баллончика можно поместить некоторое количество кнопок заранее предустановленного типа. К ним, конечно, относятся кнопки: Ok, Cancel, Next, Close, Retry и им подобные. Значениями свойства могут быть константы, задающие соответствующее подмножество кнопок.
  • Это не все свойства объекта Balloon. Есть еще несколько важных для понимания свойств, но мы расскажем о них чуть позднее. А сейчас небольшой пример конструирования объекта Balloon с некоторыми из рассмотренных свойств:

    Public Sub OneBall()
    	Dim Text1 As String, Text2 As String, Text3 As String
    	Dim Text4 As String, Text5 As String
    	Dim myPath As String
    	myPath = ActiveDocument.Path
    	'Формирование свойства Text
    		Text1 = "Хочешь знать, как перевезти с берега на берег"
        'Вставка графики в середину текста
    		Text2 ="{wmf "  myPath  "\wolf.wmf}";  " Волка,"  vbCrLf
    		Text3 = "{wmf "  myPath  "\goat.wmf}"  " Козу"  "	И "
    		Text4 = "{wmf "  myPath  "\cabbage.wmf}"  " Капусту"  vbCrLf  vbCrLf
    		Text5 = "Соблюдая 3 правила?"
    	Dim FirstBall As Balloon
    	Set FirstBall = Assistant.NewBalloon
    	With FirstBall
    		.Heading = "Волк, Коза и Капуста"
    		.Icon = msoIconAlert
    		.Text = Text1  Text2  Text3  Text4  Text5
    		.Button = msoButtonSetYesNo
    		.Show
    	End With
    End Sub

    Вот как выглядит это диалоговое окно баллончика с картинками, вставленными в текст:

    (рис 7.3) Объект Balloon с заданными свойствами

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

    Метки и флажки

    У объекта Balloon есть две коллекции - Labels с элементами Label и CheckBoxes с элементами CheckBox. В каждой из коллекций может содержаться не более пяти элементов. Элементами Labels являются метки, для которых, как правило, задается свойство Text, определяющее метку. Метки имеют тип, задающий их оформление. Все метки должны быть одного типа, так что настала пора рассказать еще об одном свойстве объекта Balloon. Тип меток задается свойством BalloonType объекта Balloon и имеет три возможных значения:

  • msoBalloonTypeNumbers - нумерованный список меток,
  • msoBalloonTypeBullets- список-бюллетень меток,
  • msoBalloonTypeButtons - список кнопок
  • Списки первых двух типов позволяют проинформировать пользователя о тех или иных предоставляемых возможностях. Конечно, для этой цели можно также использовать свойство Text самого объекта Balloon, но метки удобнее, поскольку информация предоставляется в структурированном виде.

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

    Вместе или вместо меток третьего типа можно использовать свойство Button, благодаря которому в баллончике также появляются кнопки, а метод Show и в этом случае возвращает номер нажатой кнопки. Кнопки со стандартными именами, задаваемые Button, часто бывают полезными, но, конечно, не всегда приемлемы. Благодаря свойству Text у кнопок - меток, можно задать "свои" кнопки со своими именами.

    Совместное использование меток третьего типа и свойства Button стало теперь возможным - я приведу пример такого использования.

    Флажки (кнопки выбора), задаваемые элементами CheckBox, используются для той же цели, что и кнопки - они позволяют определить выбор пользователя. Существенное отличие состоит в том, что пользователь может выбрать не одну из предоставляемых ему возможностей, а несколько, взводя соответствующие флажки. Когда флажок взведен, то свойство Checked соответствующего элемента из коллекции CheckBoxes получает значение True. Каждое из этих свойств можно затем проверить и использовать при выборе последующих действий в программе.

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

    Public Sub CheckingHobbies()
    	Dim FirstBall As Balloon, LastBall As Balloon
    	Dim i As Integer
    'Первый баллончик выясняет увлечения
    	Assistant.FileName = "Rocky.acs"
    	Set FirstBall = Assistant.NewBalloon
    	With FirstBall
    		.Heading = "Ваши увлечения"
    		.Checkboxes(1).Text = "Футбол"
    		.Checkboxes(2).Text = "Теннис"
    		.Checkboxes(3).Text = "Шахматы"
    		.Checkboxes(4).Text = "Плавание"
    		.Checkboxes(5).Text = "Горные лыжи"
    		.Show
    	End With
    'Второй баллончик уведомляет об увлечениях
    	Assistant.FileName = "OffCat.acs"
    	Set LastBall = Assistant.NewBalloon
    	Dim Count As Integer
    	Count = 0
    	With LastBall
    		.Heading = "Ваши увлечения"
    		.BalloonType = msoBalloonTypeBullets
    		For i = 1 To 5
    			If FirstBall.Checkboxes(i).Checked Then
    				Count = Count + 1
    				.Labels(Count).Text = FirstBall.Checkboxes(i).Text
    			End If
    		Next i
    		If Count > 0 Then
    			.Text = "Вы любите:"
    		Else
    			.Text = "Вы ничего не любите"
    		End If
    		.Show
    	End With
    End Sub

    А теперь взгляните на картинки, которые будут появляться в процессе выполнения этой процедуры.

    (рис 7.5) Объект Balloon выясняет увлечения(рис 7.4) Объект Balloon уведомляет об увлечениях

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

    Public Sub CheckingHobbies1()
    	'В данном примере для задания предпочтений используются метки
    	'и возможности анализа результата работы метода Show
    	Dim FirstBall As Balloon, LastBall As Balloon
    	Dim i As Integer
    	Dim Answer As MsoBalloonButtonType
    'баллончик выясняет увлечения
    	Set FirstBall = Assistant.NewBalloon
    	With FirstBall
    		.Heading = "Ваш любимый вид спорта?"
    		.BalloonType = msoBalloonTypeButtons
    		.Labels(1).Text = "Футбол"
    		.Labels(2).Text = "Теннис"
    		.Labels(3).Text = "Шахматы"
    		.Labels(4).Text = "Плавание"
    		.Labels(5).Text = "Горные лыжи"
    		.Button = msoButtonSetBackNextClose
    		Answer = .Show
    	End With
    	'Анализ пользовательского выбора
    	Select Case Answer
    		Case 1
    			MsgBox ("Футбол - любимая игра миллионов.")
    		Case 2
    			MsgBox ("Теннис -	красивый вид спорта.")
    		Case 3
    			MsgBox ("Шахматы - игра мыслителей.")
    		Case 4
    			MsgBox ("Плавание - нет ничего полезнее.")
    		Case 5
    			MsgBox ("Горные лыжи	- спорт избранных.")
    		Case msoBalloonButtonBack
    			MsgBox ("Показать предыдущий список игр?")
    		Case msoBalloonButtonNext
    			MsgBox ("Показать следующий список игр?")
    		Case Else
    			 MsgBox ("Вы совсем не спортсмен!")
    			 
    	End Select
    End Sub

    В нашем диалоговом окне три командные кнопки с фиксированными именами и пять меток, также имеющих тип кнопок. Пользователь может нажать каждую из этих 8 кнопок, и выбор пользователя можно затем проанализировать. Обратите внимание на тип переменной Answer, получающей результат метода Show, и на то, как она используется в операторе выбора Select. На следующем рисунке показан момент выбора пользователем одной из кнопок:

    (рис 7.6) Организация выбора одной из многих возможностей

    CallBack процедура в немодальном диалоге

    Процедура обратного вызова (CallBack)- это такая процедура, которая вызывается системными, а не написанными самим программистом процедурами. Типичная ситуация такова: Программист явно или неявно вызывает системную процедуру, а та, в свою очередь, вызывает CallBack процедуру программиста. Естественно, что для CallBack процедур система определяет форму их вызова - имя процедуры, число и типы формальных параметров (но не их имена, которые могут быть произвольными).

    CallBack процедуры необходимы при немодальном диалоге, организованном объектами Balloon. Система вызывает CallBack процедуру, передавая ей в качестве одного из параметров номер кнопки, которую выбрал пользователь в окне немодального диалога. Напомним, что при модальном диалоге этот номер возвращает метод Show. Организовать модальный диалог достаточно просто, а с не модальным всегда возникают некоторые сложности. В данном случае они преодолеваются за счет использования процедуры обратного вызова. Эту процедуру пишет сам программист, но вызывает ее система, передавая в процедуру номер кнопки, известный ей в момент вызова. Используя полученный параметр, конечно, нетрудно написать тело самой процедуры так, чтобы она правильно реагировала на выбор, сделанный пользователем.

    Теперь, когда общая идея понятна, уточним некоторые детали. Прежде всего заметим, что объект Balloon имеет еще одно ранее не описанное важное свойство CallBack. Значением этого свойства является строка, задающая имя CallBack процедуры. Заметьте, что в данном случае Вы сами определяете имя процедуры и сообщаете его системе. Но число параметров и их типы все-таки фиксированы. Процедура, имя которой Вы указали в свойстве CallBack, должна иметь следующий синтаксис:

    < имя процедуры> (Ball As Balloon, NumberOfButton As Long, iPriv As Long)

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

    Public Sub UnModal()
    	Dim FirstBall As Balloon
    	Dim Text1 As String, Text2 As String
    	Dim Text3 As String, Text4 As String
    	Dim myPath As String
    	myPath = ActiveDocument.Path
    'Формирование свойства Text
    'Вставка графики в начало текста
    	Text1 = "{wmf "  myPath  " /Cabbage.wmf}"
    	Text2 = "Вы уже перевезли на другой берег "
    	Text3 = "Волка и Козу! Осталось съездить за капустой."
    	Text4 = "Отправляясь назад, Вы возьмете с собой: "
    	Set FirstBall = Assistant.NewBalloon
    	With FirstBall
    		.Mode = msoModeModeless
    		.Callback = "Answer"
    		.Icon = msoIconAlert
    		.Heading = "ВОЛК, КОЗА И КАПУСТА"
    		.Text = Text1  Text2  Text3  Text4
    		.BalloonType = msoBalloonTypeButtons
    		.Button = msoButtonSetNone
    		.Labels(1).Text = "Волка"
    		.Labels(2).Text = "Козу"
    		.Labels(3).Text = "Капусту"
    		.Labels(4).Text = "Никого"
    		.Show
    	End With
    End Sub
    
    Public Sub Answer(Ball As Balloon, Count As Long, iPriv As Long)
    'Анализ принятого решения
    Select Case Count
    	Case 1
    		Call Explain("Это возможное, но не лучшее решение!")
    	Case 2
    		Call Explain("Это правильно!")
    	Case 3
    		Call Explain("Это невозможно!")
    	Case 4
    		Call Explain("Ужасная трагедия: Волк съест Козу!")
    	Case Else
    		'Пропускаем
    End Select
    ' При желании можно закрыть окно диалога
    	Ball.Close
    End Sub
    
    
    Public Sub Explain(Txt As String)
    	Dim ExplainBall As Balloon
    	Set ExplainBall = Assistant.NewBalloon
    	With ExplainBall
    		.Heading = "ВОЛК, КОЗА И КАПУСТА"
    		.Text = Txt
    		.Show
    	End With
    End Sub

    Здесь, как Вы видите, вместо переменной Answer появилась CallBack процедура Answer, которая и определяет реакцию на выбор пользователя. Заметьте, что в конце этой процедуры метод Close закрывает диалог. Если этого не делать, то после выдачи сообщения о неудачном решении, можно вернуться в окно немодального диалога и изменить свой выбор! В этом сила немодального диалога. Тем не менее, следует быть весьма аккуратным и во время закрыть окно немодального диалога. В противном случае это окно будет постоянно (до перезагрузки компьютера) сопровождать Помощника на экране. Сложность состоит в том, что локальная переменная, определяющая объект Balloon, может прекратить свое существование, а немодальное окно будет продолжать существовать. Поэтому лучше такие переменные определять как глобальные переменные модуля, тогда метод Close может быть вызван в любой из процедур, завершающих работу приложения.

    Несерьезный интерфейс для серьезных задач

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

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

    Не возникло никаких принципиальных трудностей с добавлением объекта Assistant к уже имеющейся реализации игры. Понятно, что пришлось слегка изменить интерфейс, - в игре появились еще два визуальных объекта. Одним из них является Помощник, роль которого играет Рокки, вторым - остров, где живет Рокки. Чтобы дать представление о том, как теперь выглядит интерфейс игры, как выглядит диалог, приведу пару рисунков, отображающих некоторые моменты общения с Помощником "Рокки" в процессе игры:

    (рис 7.7) Приветствие Рокки в момент начала игры

    На следующих двух рисунках Рокки рассказывает о правилах игры и дает совет по поводу очередного хода:

    (рис 7.9) Рокки сообщает о правилах игры(рис 7.8) Рокки дает совет

    Как Рокки ведет диалог?

    Я уже сказал, что никаких серьезных трудностей не возникло при введении Помощника для организации диалога. Достаточно просто, заменить сообщение, выдаваемое функцией MsgBox на сообщение, выдаваемое Помощником, используя его баллончики. Но здесь есть одно "но"! При работе с Помощником появляется больше возможностей и, поневоле, хочется организовать более живой и интересный диалог - использовать картинки, дать пользователю возможность выбора, проявить интеллект и предлагать подсказки в возникающих ситуациях.

    О том, как в сообщения, появляющиеся в баллончиках, включать рисунки, было уже рассказано в этой лекции. Было также достаточно подробно рассказано и о том, как дать возможность пользователю выбирать и как затем анализировать его выбор. Поэтому давайте поговорим об "интеллекте" Помощника. Это трудная задача. Но в нашем простом примере она решаема. Давайте возложим на Помощника обязанность не только следить за соблюдением правил игры и выдавать сообщения при их нарушениях, но и пусть он дает советы, подсказывая, какой ход следует сделать в той или иной ситуации.

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

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

    Вот какие изменения пришлось сделать в реализации игры. Во-первых, я добавил новый модуль Dialogs, в который поместил процедуры и константы, необходимые для ведения диалога. Некоторые изменения пришлось ввести и в текст модуля WGC. В раздел объявлений этого модуля добавлены следующие строчки:

    Public StateOfPlay As String 'Состояние игры
    Public Answer As MsoBalloonButtonType	'Выбор пользователя
    'Другие общие параметры
    Public WidthOfRiver	'Ширина реки
    Public MyPath As String	 'каталог, хранящий исходный документ и другие файлы игры

    Изменения внесены и в процедуру инициализации:

    Public Sub InitialStates()
    	'Задаем начальные состояния объектов и их образов
    	StateOfMan = "LeftBank"
    	StateOfWolf = "LeftBank"
    	StateOfGoat = "LeftBank"
    	StateOfCabbage = "LeftBank"
    	StateOfBoat = "LeftBank"
    	CountInBoat = 0
    	StateOfPlay = "InitState"
    	'Инициализация объектов формы
    	With WGCForm
    		.Man.Top = .LeftBank.Top + 15: .Man.Left = .LeftBank.Left + 10
    		.Man.Visible = True
    		.Wolf.Top = .LeftBank.Top + 80: .Wolf.Left = .LeftBank.Left + 10
    		.Wolf.Visible = True
    		.Goat.Top = .LeftBank.Top + 140: .Goat.Left = .LeftBank.Left + 10
    		.Goat.Visible = True
    		.Cabbage.Top = .LeftBank.Top + 200: .Cabbage.Left = .LeftBank.Left + 10
    		.Cabbage.Visible = True
    		
    		.Boat.Top = .LeftBank.Top + 130: .Boat.Left = .LeftBank.Left + .LeftBank.Width
    		.Boat.Visible = True
    		WidthOfRiver = .Width - .LeftBank.Width - .RightBank.Width _
    			- .Boat.Width
    		'Поместить Рокки на остров
    		Assistant.FileName = "Rocky.acs"
    		'Debug.Print Assistant.Left, Assistant.Top
    		Assistant.Move XLeft:=.Left + .Island.Left + .Island.Width / 2, _
    			YTop:=.Top + .Island.Top + .Island.Height - 10
    		Assistant.Animation = msoAnimationCharacterSuccessMajor
    		'Assistant.AssistWithAlerts = False
    		'Assistant.AssistWithHelp = False
    		'Debug.Print Assistant.Left, Assistant.Top
    
    	 
    	    End With
    	'Путь к каталогу
    	MyPath = ActiveDocument.Path
    	'Сформировать баллончики - диалоговые окна
    	Call FormBalloons
    	'Инициализировать диалог
    	 Call Dialog1
    
    End Sub

    Я улучшил инициализацию, задав относительное расположение объектов, что позволяет менять размеры игрового поля, сохраняя взаимное расположение объектов. Наиболее серьезные дополнения выделены цветом фона. Как видите, здесь вводится объект Assistant и, используя метод Move, он помещается на свое место - остров, при этом задается его анимационное поведение. Далее вызываются две процедуры модуля Dialogs. В первой из них формируются объекты - баллончики разного типа, во второй - инициализируется начальный диалог Помощника, приглашающий к началу игры.

    Других изменений в процедурах этого модуля не было, если не считать замены вызовов функции MsgBox на вызовы соответствующих функций модуля Dialogs, как, например, в процедуре TestingState:

    Public Sub TestingState()
    	'Тестирование состояний
    	With WGCForm
    	'Волк съел козу
    	If (StateOfWolf = StateOfGoat) And (StateOfWolf  < > StateOfMan) Then
    		.Goat.Visible = False
    		'MsgBox Prompt:=Mes1 + vbCrLf + Mes3, Buttons:=vbCritical + vbOKOnly, Title:=Mes13
    		Call Dialog5
    		InitialStates
    	End If
    	'Коза съела капусту
    	If (StateOfCabbage = StateOfGoat) And (StateOfCabbage  < < StateOfMan) Then
    		.Cabbage.Visible = False
    		'MsgBox Prompt:=Mes1 + vbCrLf + Mes4, Buttons:=vbCritical + vbOKOnly, Title:=Mes13
    		Call Dialog6
    		InitialStates
    	End If
    	'Слишком много пассажиров!
    	If (CountInBoat > 2) Then
    		If StateOfMan = "InBoat" Then .Man.Visible = False
    		If StateOfWolf = "InBoat" Then .Wolf.Visible = False
    		If StateOfGoat = "InBoat" Then .Goat.Visible = False
    		If StateOfCabbage = "InBoat" Then .Cabbage.Visible = False
    		'MsgBox Prompt:=Mes1 + vbCrLf + Mes5, Buttons:=vbCritical + vbOKOnly, Title:=Mes13
    		Call Dialog7
    		InitialStates
    	End If
    	'Конец игры - Все пассажиры собрались на правом берегу
    	If (StateOfMan = "RightBank") And (StateOfWolf = "RightBank") And _
    		(StateOfGoat = "RightBank") And (StateOfCabbage = "RightBank") Then
    		
    		'MsgBox Prompt:=Mes2 + vbCrLf + Mes6, Buttons:=vbExclamation + vbOKOnly, Title:=Mes14
    		Call Dialog8
    	End If
    	End With
    End Sub

    Приведем теперь текст модуля Dialogs:

    Option Explicit
    'Константы для организации диалогов
    Public Const Mes1 = "Ужасно, нелепо и грустно! "
    Public Const Mes2 = "Прекрасно, как славно,отлично! "
    Public Const Mes3 = " Волк съел козу! "
    Public Const Mes4 = " Коза съела капусту! "
    Public Const Mes5 = " Лодка перевернулась и все утонули! "
    Public Const Mes6 = " Вам это удалось! Все переправились!"
    Public Const Mes7 = " Не удалось дотащить "
    Public Const Mes8 = " Человека! "
    Public Const Mes9 = " Волка! "
    Public Const Mes10 = " Козу! "
    Public Const Mes11 = " Капусту! "
    Public Const Mes12 = " Повторите попытку! "
    Public Const Mes13 = " Беда!"
    Public Const Mes14 = " Радость! "
    Public Const Mes15 = " Лодку! "
    Public Const Txt1 = "Привет! Я Рокки."  vbCrLf _
    	 "Щелкни по острову, если захочешь поговорить со мной."
    Public Const Txt2 = "Волк, Коза и Капуста!"
    'Public Const Txt3 = "{wmf "  MyPath  "\goat.wmf}"
    'Public Const Txt4 = "{wmf "  MyPath  "\cabbage.wmf}"
    Public Const Txt5 = ""
    
    'Массив баллончиков - диалоговых окон Рокки
    Public RockyBalloons(1 To 10) As Balloon
    Public Sub Dialog()
    	'Начальный диалог при открытии игры
    	 'Анализ состояния игры
    	 Select Case StateOfPlay
    		Case "InitState"
    			Call Dialog1
    		Case "State1"
    			Call Dialog2
    		Case "State2"
    			Call Dialog9
    		Case "StateFinish"
    			Call Dialog10
    		Case Else
    	 End Select
    		
    End Sub
    Public Sub OneBall()
    	Dim Text1 As String, Text2 As String, Text3 As String
    	Dim Text4 As String, Text5 As String
    	Dim MyPath As String
    	MyPath = ActiveDocument.Path
    	'Формирование свойства Text
    		Text1 = "Хочешь знать, как перевезти с берега на берег"
    '		Вставка графики в середину текста
    		Text2 = "{wmf "  MyPath  "\wolf.wmf}"  " Волка,"  vbCrLf
    		Text3 = "{wmf " MyPath  "\goat.wmf}"  " Козу"  "	И "
    		Text4 = "{wmf "  MyPath  "\cabbage.wmf}"  " Капусту?"  vbCrLf  vbCrLf
    		'Text5 = "Соблюдая 3 правила?"
    	Dim FirstBall As Balloon
    	Set FirstBall = Assistant.NewBalloon
    	With FirstBall
    		.Heading = "Волк, Коза и Капуста"
    		.Icon = msoIconAlert
    		.Text = Text1  Text2  Text3  Text4
    		.Button = msoButtonSetYesNo
    		.Show
    	End With
    End Sub
    
    
    Public Sub FormBalloons()
    	'Инициализация баллончиков
    	Dim I As Integer
    	For I = 1 To 10
    		Set RockyBalloons(I) = Assistant.NewBalloon
    		RockyBalloons(I).Heading = Txt2
    		RockyBalloons(I).Icon = msoIconAlertInfo
    	Next I
    	FormBall1
    	FormBall2
    	FormBall3
    	FormBall4
    	FormBall5
    	FormBall6
    	FormBall7
    	'FormBall8
    End Sub
    Public Sub FormBall1()
    		'Формирование свойства Text - знакомство
    		With RockyBalloons(1)
    			.Text = Txt1
    			.Button = msoButtonSetOK
    		End With
    End Sub
    
    Public Sub Dialog1()
    	 RockyBalloons(1).Show
    	 StateOfPlay = "State1"	 'Игра началась
    End Sub
    Public Sub FormBall2()
    	Dim Text1 As String, Text2 As String, Text3 As String
    	Dim Text4 As String, Text5 As String
    	'Формирование свойства Text
    		Text1 = "Нужно срочно перевезти с берега на берег"
    '		Вставка графики в середину текста
    		Text2 = "{wmf "  MyPath  "\wolf.wmf}"  " Волка,"  vbCrLf
    		Text3 = "{wmf "  MyPath "\goat.wmf}"  " Козу"  "	И "
    		Text4 = "{wmf "  MyPath  "\cabbage.wmf}"  " Капусту?"  vbCrLf  vbCrLf
    		Text5 = "Хочешь знать правила игры?"
    		With RockyBalloons(2)
    			.Text = Text1  Text2  Text3  Text4  Text5
    			.Button = msoButtonSetYesNo
    		End With
    End Sub
    
    Public Sub Dialog2()
    	Answer = RockyBalloons(2).Show
    	Select Case Answer
    		Case msoBalloonButtonYes	'Нажата кнопка Yes
    			'Показать правила игры
    			Call Dialog3
    		Case msoBalloonButtonNo	'Нажата кнопка No
    			'Предложить начать играть
    			Call Dialog4
    	End Select
    End Sub
    
    
    Public Sub FormBall3()
    	Dim Text1 As String, Text2 As String, Text3 As String
    	Dim Text4 As String, Text5 As String
    	'Формирование переменных Text
    	Text1 = "В лодке, используемой для перевоза,"  _
    		" может находиться не более двух путников"  _
    		" (человек, волк, коза и капуста - это путники)."  vbCrLf _
    		 "При попытке посадить большее число путников лодка перевернется. "
    	Text2 = "Если оставить	в лодке или на берегу волка и козу без присмотра человека,"  _
    		vbCrLf "то волк немедленно съест козу."
    	Text3 = "Если оставить в лодке или на берегу капусту и козу без присмотра человека,"  _
    		vbCrLf  "то коза немедленно съест капусту."
    	Text4 = "Без человека лодка не может переплыть на другой берег."
    	Text5 = "Начинайте играть! Желаю успеха!"
    	With RockyBalloons(3)
    		.BalloonType = msoBalloonTypeNumbers
    		.Labels(1).Text = Text1
    		.Labels(2).Text = Text2
    		.Labels(3).Text = Text3
    		.Labels(4).Text = Text4
    		.Labels(5).Text = Text5
    	End With
    End Sub
    
    Public Sub Dialog3()
    	RockyBalloons(3).Show
    	StateOfPlay = "State2"	 'Правила заданы
    End Sub
    
    Public Sub FormBall4()
    	RockyBalloons(4).Text = "Начинайте играть! Желаю успеха!"
    End Sub
    Public Sub Dialog4()
    	RockyBalloons(4).Show
    	StateOfPlay = "State2"	 'Правила заданы
    End Sub
    
    Public Sub FormBall5()
    	RockyBalloons(5).Icon = msoIconAlertCritical
    	
    End Sub
    Public Sub Dialog5()
    	RockyBalloons(5).Text = Mes1 + vbCrLf + Mes3
    	RockyBalloons(5).Show
    	StateOfPlay = "State1"	 'Начало игры
    End Sub
    
    Public Sub Dialog6()
    	RockyBalloons(5).Text = Mes1 + vbCrLf + Mes4
    	RockyBalloons(5).Show
    	StateOfPlay = "State1"	 'Начало игры
    End Sub
    Public Sub Dialog7()
    	RockyBalloons(5).Text = Mes1 + vbCrLf + Mes5
    	RockyBalloons(5).Show
    	StateOfPlay = "State1"	 'Начало игры
    End Sub
    Public Sub FormBall6()
    	RockyBalloons(6).Icon = msoIconAlert
    	RockyBalloons(6).Text = Mes2 + vbCrLf + Mes6
    End Sub
    Public Sub Dialog8()
    	RockyBalloons(6).Show
    	StateOfPlay = "StateFinish"	 'Конец игры
    End Sub
    
    
    Public Sub Dialog9()
    	'Совет!
    	
    	'Rule1: Если волк и коза на одном берегу, то увези козу.
    	'Rule2: Если капуста и коза на одном берегу, то увези капусту.
    		If (StateOfWolf = StateOfGoat) Then
    			RockyBalloons(7).Text = "Увези козу!"
    		ElseIf (StateOfCabbage = StateOfGoat) Then
    			 RockyBalloons(7).Text = "Увези капусту!"
    		Else
    			RockyBalloons(7).Text = "Тут моя помощь не нужна!"
    		End If
    	RockyBalloons(7).Show
    	
    End Sub
    
    Public Sub FormBall7()
    	RockyBalloons(7).Icon = msoIconTip
    End Sub
    Public Sub Dialog10()
    	RockyBalloons(6).Text = "Приходите, поиграем еще раз! Рокки будет ждать."
    	RockyBalloons(6).Show
    	StateOfPlay = "StateFinish"	 'Конец игры
    End Sub

    Я не буду комментировать процедуры этого модуля. Все что нужно было сказать, уже сказано. Отмечу только процедуру Dialog9, которая вызывается, когда Рокки должен дать совет. Заметьте, его интеллектуальность определяется двумя правилами типа "если… то". Если не выполняются условия ни одного из этих правил, то Рокки полагает, что ситуация очень простая и его советы не нужны, поскольку можно принимать любое решение, допустимое правилами игры.

    На этом мы и закончим разговор об организации диалогов с использованием возможностей объекта Assistant.

    Страницы:

    Организация диалога. Объект Assistant

    Помощник, ведущий диалог

    Всякий раз, когда разработчик создает очередное решение, одна из серьезных проблем, стоящих перед ним, состоит в организации интерфейса своей системы. Хороший интерфейс, - привлекательный и понятный пользователю, во многом определяет успех предлагаемого решения. Диалог с пользователем - важная часть интерфейса. Во многих случаях для организации диалога достаточно обычных диалоговых окон, открываемых в нужный момент с выдачей подходящего сообщения. Зачастую для организации диалога предпочтительнее более выразительные средства и тут незаменим Помощник (объект Assistant ), хорошо знакомый пользователям Office 2000, поскольку именно он обеспечивает диалог со справочной системой, может организовать подсказки и выдачу советов. Давайте познакомимся с объектом Assistant поближе и научимся использовать его в своих решениях. Объект Assistant, задающий Помощника, появился в предыдущей версии Office 97. В новой версии он сохранил свои основные свойства и поведение.

    Вначале несколько слов о Помощнике. Идея Помощников (Мастеров, Агентов) в программировании не нова. Сегодня эта технология приобрела широкую популярность. В любом достаточно сложном приложении, в котором пользователю отводится активная роль, полезно создать некоторую совокупность Помощников пользователя. Пользователь будет выбирать, какую задачу он хочет решить в тот или иной момент, а соответствующий Помощник поможет ему на этом пути, проводя пользователя через все этапы решения задачи, снабжая необходимой информацией, информируя о возникших ошибках, позволяя сделать откат и вернуться к предыдущему этапу. В программных продуктах Microsoft, например, подобные Помощники или Мастера (Assistants, Wizards) сопровождают нас на каждом шагу, начиная с этапа инсталляции приложения. Кроме того, что Помощники предназначены для обеспечения помощи в решении некоторой конкретной задачи и могут вести диалог с пользователем, они могут обладать еще двумя важными качествами:

  • Иметь видимый образ, возможно допускающий анимацию. Помощник с анимацией, делает приложение одушевленнее. Замечу, что из всех образов, в которых может предстать Помощник, заданный объектом Assistant, я предпочитаю Rocky и позволяю себе в минуты отдыха играться с ним, заставляя его выполнять различные движения. Жаль только, что его анимация не подчиняется голосовым командам, например, "Принеси палку".
  • Обладать определенной интеллектуальностью. Интеллектуальный" Помощник должен уметь собирать факты в процессе работы пользователя, иметь базу знаний, содержащую факты и правила, и иметь встроенную машину вывода. Такой Помощник может делать собственные выводы, брать на себя часть творческой работы, например, по заданию части параметров, или приходить на помощь в нужный, по его мнению, момент.
  • В последнем предложении я не поставил запятые в обороте "по его мнению". Интеллектуальный Помощник, каковым, несомненно, является встроенная в Word система проверки правописания, тут же выдала мне соответствующую подсказку.

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

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

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

    (рис 7.1) Структура объекта Assistant

    В объект Assistant вложен объект Balloon. В свою очередь в объект Balloon вложены две коллекции - CheckBoxes (кнопки выбора) и Labels (метки) с элементами классов CheckBox и Label соответственно. Обратите внимание, коллекции называются именно так и не имеют приставки Balloon, как показано на рисунке, взятом из документации, и не изменившимся в новой версии.

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

    Свойства объекта Assistant

    Как это мы уже не раз делали, зададим сводку основных свойств таблицей:

    Основные свойства объекта Assistant
    Свойство Назначение
    Animation Возвращает или устанавливает тип анимации образа Assistant. Если свойство применяется к объекту Assistant, то он "оживает" сразу же при включении. Если же оно применяется к объекту Balloon, то анимация возникает только при появлении баллончика. Может быть значением одной из 34-х констант типа MsoAnimationType.
    AssistWithAlerts, AssistWithHelp, AssistWithWizards Булевы свойства, имеющие значение True, если Assistant используется для выдачи предупреждений (заменяя окно MsgBox ), в ответ на нажатие клавиши F1 (Help), и при выдаче справочных сообщений, когда работают различные Мастера
    BalloonError Возвращает значение, указывающее на тип последней ошибки объекта Balloon.
    FeatureTips Булево свойство, которому дается значение True, когда желательно получать советы о наиболее эффективных способах использования свойств приложения.
    FileName Возвращает или устанавливает имя файла, содержащего графический образ Assistant. Файл имеет уточнение act, например файл со скрепкой - Clippit.act. Заметим, что могут быть заданы только стандартные для Office 97 файлы. Собственные образы задавать нельзя, но число стандартных образов расширяется.
    GuessHelp Это именно то булево свойство, установив значение которого, равным True, Вы получаете контекстную подсказку с именами разделов электронной документации при обращении за помощью. Хотите сами искать - отключите это свойство.
    HighPriorityTips, KeyboardShortcutTips, MouseTips Советы имеют разный приоритет. Если свойство имеет значение True, то будут выдаваться советы только наивысшего приоритета. Следующие два булевы свойства включают возможность выдачи информации о горячих клавишах и наиболее эффективном использовании мыши.
    NewBalloon Является по существу центральным свойством, поскольку позволяет создать новый объект Balloon. После чего можно нужным образом определить свойства этого объекта. Напомним, что баллончик определяет основные возможности Assistant.
    Sounds Булево свойство, включающее звук в процессе анимации.
    TipOfDay Булево свойство, включающее или отключающее "Совет дня" при открытии приложения Office 97.
    Visible Делает видимым или невидимым объект Assistant, сворачивая его в кнопку на панели инструментов.
    Новые свойства в Office 2000 Назначение
    On Новое булево свойство позволяет включать и выключать Помощника.

    Методы объекта Assistant

    В Office 2000 не произошло изменений в методах объекта Assistant. Он по-прежнему имеет следующие методы: StartWizard, ActivateWizard, EndWizard, Help, Move и ResetTips. Методы этого объекта используются реже, чем свойства и я ограничусь их кратким описанием.

    Методы StartWizard, ActivateWizard, EndWizard применяются при создании пользовательских Мастеров. Первым должен быть запущен метод StartWizard, возвращающий идентификатор (длинное целое) Помощника. Этот идентификатор затем используется в методах ActivateWizard и EndWizard, соответственно активизирующих и деактивирующих Помощника.

    Метод Help выводит стандартное сообщение Помощника справочной системы Office 2000 с заголовком "What would you like to do?"

    Метод Move перемещает Помощника в указанную параметрами left и top позицию на экране

    Метод ResetTips очищает журнал советов, в связи с чем могут вновь появляться уже данные советы.

    В заключение рассказа о свойствах и методах объекта Assistant приведем пример, в котором поменяем образ объекта Assistant и некоторые его свойства:

    Public Sub ChooseAss()
    With Assistant
    	Debug.Print .FileName
    	'Задаем образ Помощника
    		'.FileName = "dot.acs"
    		.FileName = "Offcat.acs"
    		'.FileName = "Rocky.acs"
    		
    	'Его анимационное поведение
    		.Animation = msoAnimationGreeting
    		.Animation = msoAnimationGetAttentionMinor
    	'Другие свойства
    		.AssistWithHelp = True
    		.FeatureTips = True
    		.GuessHelp = True
    		.HighPriorityTips = True
    		.Visible = True
    	End With
    End Sub

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

    (рис 7.2) "Мурка" в роли Помощника (объекта Assistant)

    Обратите внимание, - на вопрос, заданный на естественном русском языке, выдана точная справка. Этого не было в предыдущей версии.

    Объект Balloon

    Можно изменить свойства объекта Assistant, но в каждый момент существует только один такой объект. C ним можно связать произвольное число объектов Balloon, которые я называю баллончиками. Поясним происхождение термина. Реплики рисованных персонажей комиксов или карикатур художники нередко помещают в кружок - "баллончик", выдуваемый изо рта.

    У объекта Assistant нет коллекции объектов Balloon (а жаль), но можно создать необходимое число переменных этого класса или массив из таких объектов. Вот пример:

    Public Sub Balls()
    	Dim i As Integer
    	'Создание объектов Balloons
    		Dim FirstBall As Balloon, LastBall As Balloon
    		Dim ArrOfBall(3) As Balloon
    	With Assistant
    		.FileName = "OffCat.acs"
    		Set FirstBall = .NewBalloon
    		FirstBall.Show
    		.FileName = "Rocky.acs"
    		Set LastBall = .NewBalloon
    		LastBall.Show
    		For i = 1 To 3
    			Set ArrOfBall(i) = .NewBalloon
    			ArrOfBall(i).Show
    		Next i
    		FirstBall.Show
    	End With
    End Sub

    Здесь созданы две переменные и массив из трех элементов класса Balloon. По ходу дела внешний вид объекта Assistant меняется, но все баллончики одинаковы, в момент рождения они пусты и имеют единственную кнопку "ОК". Рассмотрим, как можно наполнить содержанием эти объекты и задать их свойства.

    Модальные и немодальные баллончики

    Объекты Balloon предназначены для ведения диалога с пользователем и фактически являются специальным видом диалоговых окон. Любое диалоговое окно, а значит и объект Balloon может быть модальным и немодальным. Из модальных окон нельзя выйти, не закончив диалог. Обычно, для этого нужно щелкнуть одну из кнопок этого окна - Ok или Cancel. В модальном объекте Balloon эти кнопки, как правило, присутствуют, но их наличие не является обязательным. Если щелкнуть любую кнопку в модальном окне, то диалог оканчивается и окно закрывается. До тех пор, пока модальное окно не будет закрыто, нельзя начать работать с другим окном. Немодальные окна можно покидать, в этот момент они перестают быть активными, но остаются на экране и не закрываются. При необходимости в них можно вернуться и продолжить работу с ними. Позже мы рассмотрим механизм закрытия немодальных окон и специальный механизм CallBack функций, позволяющий организовать реакцию на выбор, сделанный пользователем в немодальном окне.

    Объект Balloon имеет свойство Mode с тремя возможными значениями:

  • MsoModeModal - в этом случае диалог с объектом Balloon является модальным. Его обычно используют для вывода предупреждений, требующих особого внимания или получения ответа от пользователя, без которого дальнейшая работа не может быть продолжена.
  • MsoModeModeless - в этом случае окно становится немодальным и оно может оставаться открытым, в то время как продолжается работа над приложением в других его окнах. Такие объекты удобны, например, при выдаче справочной информации, которая должна быть все время под рукой.
  • MsoModeAutoDown - задает специальный вид модального окна, в котором не обязательны кнопки. Окно закрывается автоматически, как только пользователь введет символ с клавиатуры или щелкнет кнопку мыши, где - либо вне модального окна. Такие окна полезны при выводе сообщений, не носящих критический характер, например советов.
  • Терминальные свойства объекта Balloon

    С двумя свойствами этого объекта: Animation и Mode мы уже знакомы. Первое из них задает анимацию объекта Assistant при вызове его метода Show, в тот момент, когда показывается объект Balloon. Рассмотрим подробнее другие свойства

  • Heading - позволяет прочесть или установить строку, задающую текст заголовка.
  • Text - На вершине объекта Balloon сразу после заголовка может появляться некоторый текст. Его и устанавливает свойство Text. Оба элемента являются необязательными. Заметьте, что Heading и Text могут включать и графику. Последняя задается строкой, имеющей следующий синтаксис: {<type> <location> [<factor>]}. Первый параметр задает тип графического файла (bmp или wmf), второй - его расположение, третий позволяет согласовать размер wmf-файла (Windows metafile), но не bmp-файла.
  • Icon - Слева от заголовка можно добавить специальный значок для привлечения внимания. Возможные значки задаются следующими константами: msoIconAlert, msoIconNone, или msoIconTip.
  • Button - Внутрь баллончика можно поместить некоторое количество кнопок заранее предустановленного типа. К ним, конечно, относятся кнопки: Ok, Cancel, Next, Close, Retry и им подобные. Значениями свойства могут быть константы, задающие соответствующее подмножество кнопок.
  • Это не все свойства объекта Balloon. Есть еще несколько важных для понимания свойств, но мы расскажем о них чуть позднее. А сейчас небольшой пример конструирования объекта Balloon с некоторыми из рассмотренных свойств:

    Public Sub OneBall()
    	Dim Text1 As String, Text2 As String, Text3 As String
    	Dim Text4 As String, Text5 As String
    	Dim myPath As String
    	myPath = ActiveDocument.Path
    	'Формирование свойства Text
    		Text1 = "Хочешь знать, как перевезти с берега на берег"
        'Вставка графики в середину текста
    		Text2 ="{wmf "  myPath  "\wolf.wmf}";  " Волка,"  vbCrLf
    		Text3 = "{wmf "  myPath  "\goat.wmf}"  " Козу"  "	И "
    		Text4 = "{wmf "  myPath  "\cabbage.wmf}"  " Капусту"  vbCrLf  vbCrLf
    		Text5 = "Соблюдая 3 правила?"
    	Dim FirstBall As Balloon
    	Set FirstBall = Assistant.NewBalloon
    	With FirstBall
    		.Heading = "Волк, Коза и Капуста"
    		.Icon = msoIconAlert
    		.Text = Text1  Text2  Text3  Text4  Text5
    		.Button = msoButtonSetYesNo
    		.Show
    	End With
    End Sub

    Вот как выглядит это диалоговое окно баллончика с картинками, вставленными в текст:

    (рис 7.3) Объект Balloon с заданными свойствами

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

    Метки и флажки

    У объекта Balloon есть две коллекции - Labels с элементами Label и CheckBoxes с элементами CheckBox. В каждой из коллекций может содержаться не более пяти элементов. Элементами Labels являются метки, для которых, как правило, задается свойство Text, определяющее метку. Метки имеют тип, задающий их оформление. Все метки должны быть одного типа, так что настала пора рассказать еще об одном свойстве объекта Balloon. Тип меток задается свойством BalloonType объекта Balloon и имеет три возможных значения:

  • msoBalloonTypeNumbers - нумерованный список меток,
  • msoBalloonTypeBullets- список-бюллетень меток,
  • msoBalloonTypeButtons - список кнопок
  • Списки первых двух типов позволяют проинформировать пользователя о тех или иных предоставляемых возможностях. Конечно, для этой цели можно также использовать свойство Text самого объекта Balloon, но метки удобнее, поскольку информация предоставляется в структурированном виде.

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

    Вместе или вместо меток третьего типа можно использовать свойство Button, благодаря которому в баллончике также появляются кнопки, а метод Show и в этом случае возвращает номер нажатой кнопки. Кнопки со стандартными именами, задаваемые Button, часто бывают полезными, но, конечно, не всегда приемлемы. Благодаря свойству Text у кнопок - меток, можно задать "свои" кнопки со своими именами.

    Совместное использование меток третьего типа и свойства Button стало теперь возможным - я приведу пример такого использования.

    Флажки (кнопки выбора), задаваемые элементами CheckBox, используются для той же цели, что и кнопки - они позволяют определить выбор пользователя. Существенное отличие состоит в том, что пользователь может выбрать не одну из предоставляемых ему возможностей, а несколько, взводя соответствующие флажки. Когда флажок взведен, то свойство Checked соответствующего элемента из коллекции CheckBoxes получает значение True. Каждое из этих свойств можно затем проверить и использовать при выборе последующих действий в программе.

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

    Public Sub CheckingHobbies()
    	Dim FirstBall As Balloon, LastBall As Balloon
    	Dim i As Integer
    'Первый баллончик выясняет увлечения
    	Assistant.FileName = "Rocky.acs"
    	Set FirstBall = Assistant.NewBalloon
    	With FirstBall
    		.Heading = "Ваши увлечения"
    		.Checkboxes(1).Text = "Футбол"
    		.Checkboxes(2).Text = "Теннис"
    		.Checkboxes(3).Text = "Шахматы"
    		.Checkboxes(4).Text = "Плавание"
    		.Checkboxes(5).Text = "Горные лыжи"
    		.Show
    	End With
    'Второй баллончик уведомляет об увлечениях
    	Assistant.FileName = "OffCat.acs"
    	Set LastBall = Assistant.NewBalloon
    	Dim Count As Integer
    	Count = 0
    	With LastBall
    		.Heading = "Ваши увлечения"
    		.BalloonType = msoBalloonTypeBullets
    		For i = 1 To 5
    			If FirstBall.Checkboxes(i).Checked Then
    				Count = Count + 1
    				.Labels(Count).Text = FirstBall.Checkboxes(i).Text
    			End If
    		Next i
    		If Count > 0 Then
    			.Text = "Вы любите:"
    		Else
    			.Text = "Вы ничего не любите"
    		End If
    		.Show
    	End With
    End Sub

    А теперь взгляните на картинки, которые будут появляться в процессе выполнения этой процедуры.

    (рис 7.5) Объект Balloon выясняет увлечения(рис 7.4) Объект Balloon уведомляет об увлечениях

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

    Public Sub CheckingHobbies1()
    	'В данном примере для задания предпочтений используются метки
    	'и возможности анализа результата работы метода Show
    	Dim FirstBall As Balloon, LastBall As Balloon
    	Dim i As Integer
    	Dim Answer As MsoBalloonButtonType
    'баллончик выясняет увлечения
    	Set FirstBall = Assistant.NewBalloon
    	With FirstBall
    		.Heading = "Ваш любимый вид спорта?"
    		.BalloonType = msoBalloonTypeButtons
    		.Labels(1).Text = "Футбол"
    		.Labels(2).Text = "Теннис"
    		.Labels(3).Text = "Шахматы"
    		.Labels(4).Text = "Плавание"
    		.Labels(5).Text = "Горные лыжи"
    		.Button = msoButtonSetBackNextClose
    		Answer = .Show
    	End With
    	'Анализ пользовательского выбора
    	Select Case Answer
    		Case 1
    			MsgBox ("Футбол - любимая игра миллионов.")
    		Case 2
    			MsgBox ("Теннис -	красивый вид спорта.")
    		Case 3
    			MsgBox ("Шахматы - игра мыслителей.")
    		Case 4
    			MsgBox ("Плавание - нет ничего полезнее.")
    		Case 5
    			MsgBox ("Горные лыжи	- спорт избранных.")
    		Case msoBalloonButtonBack
    			MsgBox ("Показать предыдущий список игр?")
    		Case msoBalloonButtonNext
    			MsgBox ("Показать следующий список игр?")
    		Case Else
    			 MsgBox ("Вы совсем не спортсмен!")
    			 
    	End Select
    End Sub

    В нашем диалоговом окне три командные кнопки с фиксированными именами и пять меток, также имеющих тип кнопок. Пользователь может нажать каждую из этих 8 кнопок, и выбор пользователя можно затем проанализировать. Обратите внимание на тип переменной Answer, получающей результат метода Show, и на то, как она используется в операторе выбора Select. На следующем рисунке показан момент выбора пользователем одной из кнопок:

    (рис 7.6) Организация выбора одной из многих возможностей

    CallBack процедура в немодальном диалоге

    Процедура обратного вызова (CallBack)- это такая процедура, которая вызывается системными, а не написанными самим программистом процедурами. Типичная ситуация такова: Программист явно или неявно вызывает системную процедуру, а та, в свою очередь, вызывает CallBack процедуру программиста. Естественно, что для CallBack процедур система определяет форму их вызова - имя процедуры, число и типы формальных параметров (но не их имена, которые могут быть произвольными).

    CallBack процедуры необходимы при немодальном диалоге, организованном объектами Balloon. Система вызывает CallBack процедуру, передавая ей в качестве одного из параметров номер кнопки, которую выбрал пользователь в окне немодального диалога. Напомним, что при модальном диалоге этот номер возвращает метод Show. Организовать модальный диалог достаточно просто, а с не модальным всегда возникают некоторые сложности. В данном случае они преодолеваются за счет использования процедуры обратного вызова. Эту процедуру пишет сам программист, но вызывает ее система, передавая в процедуру номер кнопки, известный ей в момент вызова. Используя полученный параметр, конечно, нетрудно написать тело самой процедуры так, чтобы она правильно реагировала на выбор, сделанный пользователем.

    Теперь, когда общая идея понятна, уточним некоторые детали. Прежде всего заметим, что объект Balloon имеет еще одно ранее не описанное важное свойство CallBack. Значением этого свойства является строка, задающая имя CallBack процедуры. Заметьте, что в данном случае Вы сами определяете имя процедуры и сообщаете его системе. Но число параметров и их типы все-таки фиксированы. Процедура, имя которой Вы указали в свойстве CallBack, должна иметь следующий синтаксис:

    < имя процедуры> (Ball As Balloon, NumberOfButton As Long, iPriv As Long)

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

    Public Sub UnModal()
    	Dim FirstBall As Balloon
    	Dim Text1 As String, Text2 As String
    	Dim Text3 As String, Text4 As String
    	Dim myPath As String
    	myPath = ActiveDocument.Path
    'Формирование свойства Text
    'Вставка графики в начало текста
    	Text1 = "{wmf "  myPath  " /Cabbage.wmf}"
    	Text2 = "Вы уже перевезли на другой берег "
    	Text3 = "Волка и Козу! Осталось съездить за капустой."
    	Text4 = "Отправляясь назад, Вы возьмете с собой: "
    	Set FirstBall = Assistant.NewBalloon
    	With FirstBall
    		.Mode = msoModeModeless
    		.Callback = "Answer"
    		.Icon = msoIconAlert
    		.Heading = "ВОЛК, КОЗА И КАПУСТА"
    		.Text = Text1  Text2  Text3  Text4
    		.BalloonType = msoBalloonTypeButtons
    		.Button = msoButtonSetNone
    		.Labels(1).Text = "Волка"
    		.Labels(2).Text = "Козу"
    		.Labels(3).Text = "Капусту"
    		.Labels(4).Text = "Никого"
    		.Show
    	End With
    End Sub
    
    Public Sub Answer(Ball As Balloon, Count As Long, iPriv As Long)
    'Анализ принятого решения
    Select Case Count
    	Case 1
    		Call Explain("Это возможное, но не лучшее решение!")
    	Case 2
    		Call Explain("Это правильно!")
    	Case 3
    		Call Explain("Это невозможно!")
    	Case 4
    		Call Explain("Ужасная трагедия: Волк съест Козу!")
    	Case Else
    		'Пропускаем
    End Select
    ' При желании можно закрыть окно диалога
    	Ball.Close
    End Sub
    
    
    Public Sub Explain(Txt As String)
    	Dim ExplainBall As Balloon
    	Set ExplainBall = Assistant.NewBalloon
    	With ExplainBall
    		.Heading = "ВОЛК, КОЗА И КАПУСТА"
    		.Text = Txt
    		.Show
    	End With
    End Sub

    Здесь, как Вы видите, вместо переменной Answer появилась CallBack процедура Answer, которая и определяет реакцию на выбор пользователя. Заметьте, что в конце этой процедуры метод Close закрывает диалог. Если этого не делать, то после выдачи сообщения о неудачном решении, можно вернуться в окно немодального диалога и изменить свой выбор! В этом сила немодального диалога. Тем не менее, следует быть весьма аккуратным и во время закрыть окно немодального диалога. В противном случае это окно будет постоянно (до перезагрузки компьютера) сопровождать Помощника на экране. Сложность состоит в том, что локальная переменная, определяющая объект Balloon, может прекратить свое существование, а немодальное окно будет продолжать существовать. Поэтому лучше такие переменные определять как глобальные переменные модуля, тогда метод Close может быть вызван в любой из процедур, завершающих работу приложения.

    Несерьезный интерфейс для серьезных задач

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

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

    Не возникло никаких принципиальных трудностей с добавлением объекта Assistant к уже имеющейся реализации игры. Понятно, что пришлось слегка изменить интерфейс, - в игре появились еще два визуальных объекта. Одним из них является Помощник, роль которого играет Рокки, вторым - остров, где живет Рокки. Чтобы дать представление о том, как теперь выглядит интерфейс игры, как выглядит диалог, приведу пару рисунков, отображающих некоторые моменты общения с Помощником "Рокки" в процессе игры:

    (рис 7.7) Приветствие Рокки в момент начала игры

    На следующих двух рисунках Рокки рассказывает о правилах игры и дает совет по поводу очередного хода:

    (рис 7.9) Рокки сообщает о правилах игры(рис 7.8) Рокки дает совет

    Как Рокки ведет диалог?

    Я уже сказал, что никаких серьезных трудностей не возникло при введении Помощника для организации диалога. Достаточно просто, заменить сообщение, выдаваемое функцией MsgBox на сообщение, выдаваемое Помощником, используя его баллончики. Но здесь есть одно "но"! При работе с Помощником появляется больше возможностей и, поневоле, хочется организовать более живой и интересный диалог - использовать картинки, дать пользователю возможность выбора, проявить интеллект и предлагать подсказки в возникающих ситуациях.

    О том, как в сообщения, появляющиеся в баллончиках, включать рисунки, было уже рассказано в этой лекции. Было также достаточно подробно рассказано и о том, как дать возможность пользователю выбирать и как затем анализировать его выбор. Поэтому давайте поговорим об "интеллекте" Помощника. Это трудная задача. Но в нашем простом примере она решаема. Давайте возложим на Помощника обязанность не только следить за соблюдением правил игры и выдавать сообщения при их нарушениях, но и пусть он дает советы, подсказывая, какой ход следует сделать в той или иной ситуации.

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

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

    Вот какие изменения пришлось сделать в реализации игры. Во-первых, я добавил новый модуль Dialogs, в который поместил процедуры и константы, необходимые для ведения диалога. Некоторые изменения пришлось ввести и в текст модуля WGC. В раздел объявлений этого модуля добавлены следующие строчки:

    Public StateOfPlay As String 'Состояние игры
    Public Answer As MsoBalloonButtonType	'Выбор пользователя
    'Другие общие параметры
    Public WidthOfRiver	'Ширина реки
    Public MyPath As String	 'каталог, хранящий исходный документ и другие файлы игры

    Изменения внесены и в процедуру инициализации:

    Public Sub InitialStates()
    	'Задаем начальные состояния объектов и их образов
    	StateOfMan = "LeftBank"
    	StateOfWolf = "LeftBank"
    	StateOfGoat = "LeftBank"
    	StateOfCabbage = "LeftBank"
    	StateOfBoat = "LeftBank"
    	CountInBoat = 0
    	StateOfPlay = "InitState"
    	'Инициализация объектов формы
    	With WGCForm
    		.Man.Top = .LeftBank.Top + 15: .Man.Left = .LeftBank.Left + 10
    		.Man.Visible = True
    		.Wolf.Top = .LeftBank.Top + 80: .Wolf.Left = .LeftBank.Left + 10
    		.Wolf.Visible = True
    		.Goat.Top = .LeftBank.Top + 140: .Goat.Left = .LeftBank.Left + 10
    		.Goat.Visible = True
    		.Cabbage.Top = .LeftBank.Top + 200: .Cabbage.Left = .LeftBank.Left + 10
    		.Cabbage.Visible = True
    		
    		.Boat.Top = .LeftBank.Top + 130: .Boat.Left = .LeftBank.Left + .LeftBank.Width
    		.Boat.Visible = True
    		WidthOfRiver = .Width - .LeftBank.Width - .RightBank.Width _
    			- .Boat.Width
    		'Поместить Рокки на остров
    		Assistant.FileName = "Rocky.acs"
    		'Debug.Print Assistant.Left, Assistant.Top
    		Assistant.Move XLeft:=.Left + .Island.Left + .Island.Width / 2, _
    			YTop:=.Top + .Island.Top + .Island.Height - 10
    		Assistant.Animation = msoAnimationCharacterSuccessMajor
    		'Assistant.AssistWithAlerts = False
    		'Assistant.AssistWithHelp = False
    		'Debug.Print Assistant.Left, Assistant.Top
    
    	 
    	    End With
    	'Путь к каталогу
    	MyPath = ActiveDocument.Path
    	'Сформировать баллончики - диалоговые окна
    	Call FormBalloons
    	'Инициализировать диалог
    	 Call Dialog1
    
    End Sub

    Я улучшил инициализацию, задав относительное расположение объектов, что позволяет менять размеры игрового поля, сохраняя взаимное расположение объектов. Наиболее серьезные дополнения выделены цветом фона. Как видите, здесь вводится объект Assistant и, используя метод Move, он помещается на свое место - остров, при этом задается его анимационное поведение. Далее вызываются две процедуры модуля Dialogs. В первой из них формируются объекты - баллончики разного типа, во второй - инициализируется начальный диалог Помощника, приглашающий к началу игры.

    Других изменений в процедурах этого модуля не было, если не считать замены вызовов функции MsgBox на вызовы соответствующих функций модуля Dialogs, как, например, в процедуре TestingState:

    Public Sub TestingState()
    	'Тестирование состояний
    	With WGCForm
    	'Волк съел козу
    	If (StateOfWolf = StateOfGoat) And (StateOfWolf  < > StateOfMan) Then
    		.Goat.Visible = False
    		'MsgBox Prompt:=Mes1 + vbCrLf + Mes3, Buttons:=vbCritical + vbOKOnly, Title:=Mes13
    		Call Dialog5
    		InitialStates
    	End If
    	'Коза съела капусту
    	If (StateOfCabbage = StateOfGoat) And (StateOfCabbage  < < StateOfMan) Then
    		.Cabbage.Visible = False
    		'MsgBox Prompt:=Mes1 + vbCrLf + Mes4, Buttons:=vbCritical + vbOKOnly, Title:=Mes13
    		Call Dialog6
    		InitialStates
    	End If
    	'Слишком много пассажиров!
    	If (CountInBoat > 2) Then
    		If StateOfMan = "InBoat" Then .Man.Visible = False
    		If StateOfWolf = "InBoat" Then .Wolf.Visible = False
    		If StateOfGoat = "InBoat" Then .Goat.Visible = False
    		If StateOfCabbage = "InBoat" Then .Cabbage.Visible = False
    		'MsgBox Prompt:=Mes1 + vbCrLf + Mes5, Buttons:=vbCritical + vbOKOnly, Title:=Mes13
    		Call Dialog7
    		InitialStates
    	End If
    	'Конец игры - Все пассажиры собрались на правом берегу
    	If (StateOfMan = "RightBank") And (StateOfWolf = "RightBank") And _
    		(StateOfGoat = "RightBank") And (StateOfCabbage = "RightBank") Then
    		
    		'MsgBox Prompt:=Mes2 + vbCrLf + Mes6, Buttons:=vbExclamation + vbOKOnly, Title:=Mes14
    		Call Dialog8
    	End If
    	End With
    End Sub

    Приведем теперь текст модуля Dialogs:

    Option Explicit
    'Константы для организации диалогов
    Public Const Mes1 = "Ужасно, нелепо и грустно! "
    Public Const Mes2 = "Прекрасно, как славно,отлично! "
    Public Const Mes3 = " Волк съел козу! "
    Public Const Mes4 = " Коза съела капусту! "
    Public Const Mes5 = " Лодка перевернулась и все утонули! "
    Public Const Mes6 = " Вам это удалось! Все переправились!"
    Public Const Mes7 = " Не удалось дотащить "
    Public Const Mes8 = " Человека! "
    Public Const Mes9 = " Волка! "
    Public Const Mes10 = " Козу! "
    Public Const Mes11 = " Капусту! "
    Public Const Mes12 = " Повторите попытку! "
    Public Const Mes13 = " Беда!"
    Public Const Mes14 = " Радость! "
    Public Const Mes15 = " Лодку! "
    Public Const Txt1 = "Привет! Я Рокки."  vbCrLf _
    	 "Щелкни по острову, если захочешь поговорить со мной."
    Public Const Txt2 = "Волк, Коза и Капуста!"
    'Public Const Txt3 = "{wmf "  MyPath  "\goat.wmf}"
    'Public Const Txt4 = "{wmf "  MyPath  "\cabbage.wmf}"
    Public Const Txt5 = ""
    
    'Массив баллончиков - диалоговых окон Рокки
    Public RockyBalloons(1 To 10) As Balloon
    Public Sub Dialog()
    	'Начальный диалог при открытии игры
    	 'Анализ состояния игры
    	 Select Case StateOfPlay
    		Case "InitState"
    			Call Dialog1
    		Case "State1"
    			Call Dialog2
    		Case "State2"
    			Call Dialog9
    		Case "StateFinish"
    			Call Dialog10
    		Case Else
    	 End Select
    		
    End Sub
    Public Sub OneBall()
    	Dim Text1 As String, Text2 As String, Text3 As String
    	Dim Text4 As String, Text5 As String
    	Dim MyPath As String
    	MyPath = ActiveDocument.Path
    	'Формирование свойства Text
    		Text1 = "Хочешь знать, как перевезти с берега на берег"
    '		Вставка графики в середину текста
    		Text2 = "{wmf "  MyPath  "\wolf.wmf}"  " Волка,"  vbCrLf
    		Text3 = "{wmf " MyPath  "\goat.wmf}"  " Козу"  "	И "
    		Text4 = "{wmf "  MyPath  "\cabbage.wmf}"  " Капусту?"  vbCrLf  vbCrLf
    		'Text5 = "Соблюдая 3 правила?"
    	Dim FirstBall As Balloon
    	Set FirstBall = Assistant.NewBalloon
    	With FirstBall
    		.Heading = "Волк, Коза и Капуста"
    		.Icon = msoIconAlert
    		.Text = Text1  Text2  Text3  Text4
    		.Button = msoButtonSetYesNo
    		.Show
    	End With
    End Sub
    
    
    Public Sub FormBalloons()
    	'Инициализация баллончиков
    	Dim I As Integer
    	For I = 1 To 10
    		Set RockyBalloons(I) = Assistant.NewBalloon
    		RockyBalloons(I).Heading = Txt2
    		RockyBalloons(I).Icon = msoIconAlertInfo
    	Next I
    	FormBall1
    	FormBall2
    	FormBall3
    	FormBall4
    	FormBall5
    	FormBall6
    	FormBall7
    	'FormBall8
    End Sub
    Public Sub FormBall1()
    		'Формирование свойства Text - знакомство
    		With RockyBalloons(1)
    			.Text = Txt1
    			.Button = msoButtonSetOK
    		End With
    End Sub
    
    Public Sub Dialog1()
    	 RockyBalloons(1).Show
    	 StateOfPlay = "State1"	 'Игра началась
    End Sub
    Public Sub FormBall2()
    	Dim Text1 As String, Text2 As String, Text3 As String
    	Dim Text4 As String, Text5 As String
    	'Формирование свойства Text
    		Text1 = "Нужно срочно перевезти с берега на берег"
    '		Вставка графики в середину текста
    		Text2 = "{wmf "  MyPath  "\wolf.wmf}"  " Волка,"  vbCrLf
    		Text3 = "{wmf "  MyPath "\goat.wmf}"  " Козу"  "	И "
    		Text4 = "{wmf "  MyPath  "\cabbage.wmf}"  " Капусту?"  vbCrLf  vbCrLf
    		Text5 = "Хочешь знать правила игры?"
    		With RockyBalloons(2)
    			.Text = Text1  Text2  Text3  Text4  Text5
    			.Button = msoButtonSetYesNo
    		End With
    End Sub
    
    Public Sub Dialog2()
    	Answer = RockyBalloons(2).Show
    	Select Case Answer
    		Case msoBalloonButtonYes	'Нажата кнопка Yes
    			'Показать правила игры
    			Call Dialog3
    		Case msoBalloonButtonNo	'Нажата кнопка No
    			'Предложить начать играть
    			Call Dialog4
    	End Select
    End Sub
    
    
    Public Sub FormBall3()
    	Dim Text1 As String, Text2 As String, Text3 As String
    	Dim Text4 As String, Text5 As String
    	'Формирование переменных Text
    	Text1 = "В лодке, используемой для перевоза,"  _
    		" может находиться не более двух путников"  _
    		" (человек, волк, коза и капуста - это путники)."  vbCrLf _
    		 "При попытке посадить большее число путников лодка перевернется. "
    	Text2 = "Если оставить	в лодке или на берегу волка и козу без присмотра человека,"  _
    		vbCrLf "то волк немедленно съест козу."
    	Text3 = "Если оставить в лодке или на берегу капусту и козу без присмотра человека,"  _
    		vbCrLf  "то коза немедленно съест капусту."
    	Text4 = "Без человека лодка не может переплыть на другой берег."
    	Text5 = "Начинайте играть! Желаю успеха!"
    	With RockyBalloons(3)
    		.BalloonType = msoBalloonTypeNumbers
    		.Labels(1).Text = Text1
    		.Labels(2).Text = Text2
    		.Labels(3).Text = Text3
    		.Labels(4).Text = Text4
    		.Labels(5).Text = Text5
    	End With
    End Sub
    
    Public Sub Dialog3()
    	RockyBalloons(3).Show
    	StateOfPlay = "State2"	 'Правила заданы
    End Sub
    
    Public Sub FormBall4()
    	RockyBalloons(4).Text = "Начинайте играть! Желаю успеха!"
    End Sub
    Public Sub Dialog4()
    	RockyBalloons(4).Show
    	StateOfPlay = "State2"	 'Правила заданы
    End Sub
    
    Public Sub FormBall5()
    	RockyBalloons(5).Icon = msoIconAlertCritical
    	
    End Sub
    Public Sub Dialog5()
    	RockyBalloons(5).Text = Mes1 + vbCrLf + Mes3
    	RockyBalloons(5).Show
    	StateOfPlay = "State1"	 'Начало игры
    End Sub
    
    Public Sub Dialog6()
    	RockyBalloons(5).Text = Mes1 + vbCrLf + Mes4
    	RockyBalloons(5).Show
    	StateOfPlay = "State1"	 'Начало игры
    End Sub
    Public Sub Dialog7()
    	RockyBalloons(5).Text = Mes1 + vbCrLf + Mes5
    	RockyBalloons(5).Show
    	StateOfPlay = "State1"	 'Начало игры
    End Sub
    Public Sub FormBall6()
    	RockyBalloons(6).Icon = msoIconAlert
    	RockyBalloons(6).Text = Mes2 + vbCrLf + Mes6
    End Sub
    Public Sub Dialog8()
    	RockyBalloons(6).Show
    	StateOfPlay = "StateFinish"	 'Конец игры
    End Sub
    
    
    Public Sub Dialog9()
    	'Совет!
    	
    	'Rule1: Если волк и коза на одном берегу, то увези козу.
    	'Rule2: Если капуста и коза на одном берегу, то увези капусту.
    		If (StateOfWolf = StateOfGoat) Then
    			RockyBalloons(7).Text = "Увези козу!"
    		ElseIf (StateOfCabbage = StateOfGoat) Then
    			 RockyBalloons(7).Text = "Увези капусту!"
    		Else
    			RockyBalloons(7).Text = "Тут моя помощь не нужна!"
    		End If
    	RockyBalloons(7).Show
    	
    End Sub
    
    Public Sub FormBall7()
    	RockyBalloons(7).Icon = msoIconTip
    End Sub
    Public Sub Dialog10()
    	RockyBalloons(6).Text = "Приходите, поиграем еще раз! Рокки будет ждать."
    	RockyBalloons(6).Show
    	StateOfPlay = "StateFinish"	 'Конец игры
    End Sub

    Я не буду комментировать процедуры этого модуля. Все что нужно было сказать, уже сказано. Отмечу только процедуру Dialog9, которая вызывается, когда Рокки должен дать совет. Заметьте, его интеллектуальность определяется двумя правилами типа "если… то". Если не выполняются условия ни одного из этих правил, то Рокки полагает, что ситуация очень простая и его советы не нужны, поскольку можно принимать любое решение, допустимое правилами игры.

    На этом мы и закончим разговор об организации диалогов с использованием возможностей объекта Assistant.

    Вернуться к учебному плану