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

Содержание
1. Программирование для Windows: особенности
1.1 Новый интерфейс — новые возможности
1.1.1 Окна и их компоненты
1.1.2 Управляющие элементы окна
1.1.3 Другие особенности интерфейса
1.2 DOS и Windows: разные подходы к программированию
1.2.1 Особенности работы с базами данных
1.3 Структура программ в CA-Visual Objects
1.3.1 Объекты. Связи типа “владение”
1.3.2 Генерация и обработка событий
1.3.3 Другие типы связей в программах
1.3.4 Как все-таки работает программа в CA-Visual Objects?
1. Программирование для Windows: особенности
Возможности, предлагаемые системой Windows конечным пользователям, весьма впечатляющи, если их сравнивать с возможностями старой доброй DOS: дружелюбный графический интерфейс, многозадачная среда, вездесущая мышка… В то же время для программистов-разработчиков коммерческих приложений эти возможности трансформируются в дополнительную головную боль, поскольку их реализация на практике сопряжена с довольно существенным усложнением программ, а в иных случаях попросту невозможна без использования новых средств и методов разработки.
Тем не менее, не все так страшно, как может показаться в начале пути. Система программирования CA-Visual Objects — чрезвычайно мощный инструмент, способный снять с разработчика большинство проблем, не связанных напрямую с логикой работы создаваемых приложений. Надо только научиться грамотно пользоваться этим инструментом…
Попробуем прежде всего разобраться в основных отличиях Windows от DOS, непосредственно определяющих как новые требования к разрабатываемым приложениям, так и новые подходы к программированию.
1.1 Новый интерфейс — новые возможности
Первое, что бросается в глаза при переходе от DOS к Windows, это графическая операционная среда. Действительно, графический интерфейс пользователя (Graphical User Interface — GUI) составляет сердцевину Windows. Необходимость графического интерфейса продиктована не только и не столько эстетическими соображениями. Основное его назначение заключается в повышении уровня дружелюбности и информативности экрана дисплея, а также в предоставлении пользователю более широких возможностей по оперативному вмешательству в вычислительный процесс. Эти цели в GUI достигаются как за счет широкого использования графических шрифтов и цветовой гаммы, так и за счет введения новых типов элементов управления интерфейсом.
Основу графического интерфейса в Windows составляют окна. Окна и их компоненты — «альфа» и «омега» GUI. Через окна и их элементы приложение, с одной стороны, осуществляет интерфейс с пользователем, а с другой — взаимодействует с Windows. Любое приложение, работающее в среде Windows, должно быть представлено как минимум одним окном.
1.1.1 Окна и их компоненты
В CA-Visual Objects различают три базовых типа окон:
1. Окно приложения — главное или единственное окно работающей программы. В соответствии со стандартом GUI, окно приложения может быть двух видов: однодокументным (Single Document Interface — SDI) и многодокументным (Multiple Document Interface — MDI). Основное различие между этими видами окон состоит в том, что MDI-окна могут содержать в себе несколько дочерних окон, каждое из которых может работать независимо от других, в то время как SDI-окно является единственным на все приложение.
Классическим примером MDI-приложения является текстовый процессор WORD фирмы Microsoft (рис.1.1). Запустив это приложение в работу, пользователь имеет возможность одновременной работы с несколькими документами, каждый из которых представляется самостоятельным дочерним окном.
/>
Рис 1.1 Пример MDI-приложения (в главном окне Microsoft Word открыты два независимых дочерних окна — BOOK1. DOC и BOOK2. DOC)
Примером SDI-приложения является игровая программа “Пасьянс”, входящая в комплект поставки Windows (рис.1.2). В этом приложении открывается единственное окно, и пользователь одновременно может “раскладывать” на компьютере всего один пасьянс.
/>
Рис 1.2 Пример SDI-приложения
Ясно, что MDI-стандарт предлагает пользователю гораздо более богатые возможности. Именно он в полной мере реализует “способности” Windows и наиболее подходит для разработки сложных приложений, обслуживающих базы данных. По этой причине мы и возьмем его за основу во всех дальнейших рассуждениях.
В MDI-приложениях окно приложения называется также главным окном или окном-оболочкой. Это окно должно быть пустым, т.е. не содержать в себе никаких элементов управления, за исключением меню (см. ниже).
2. Окно данных — специфический вид окна, наилучшим образом приспособленный для работы с базами данных. Оно может содержать в себе любые элементы управления, обеспечивающие удобные средства работы с данными. С учетом сказанного в п.1, окно данных — одно из дочерних окон главного окна приложения. И именно поэтому окно данных в общем случае немодально, т.е. допускает возможность активизации любых других окон. Все окна данных размещаются в пределах главного окна приложения.
3. Диалоговое окно — окно с небольшим набором внутренних компонентов, основная цель которого состоит в выдаче пользователю сообщений и/или запросов и прием от него небольшого числа команд и параметров. В отличие от окна данных, диалоговое окно в общем случае модально, т.е. не позволяет активизировать другие окна до того, как оно будет закрыто. Вместе с тем, в практике программирования используют и немодальные диалоговые окна, например, для поиска информации или отображения динамики процессов с помощью прогресс-индикаторов.
В общем случае окно состоит из следующих компонентов:
область (панель) заголовка;
область (панель) меню;
область (панель) инструментов;
область (панель) состояния:
кнопка системного меню;
кнопки максимизации и минимизации окна;
рамка окна;
рабочая область окна.
Панель заголовка говорит сама за себя — на ней отображается заголовок данного окна. В многодокументном приложении заголовки окон играют важную роль, позволяя пользователю быстрее ориентироваться в отображаемой информации.
Панель меню находится в верхней части окна. Она предназначена для хранения заголовков главного меню (меню первого уровня). Если заголовки не умещаются в одной строке, они переносятся на новую строку (т.е. панель меню расширяется).
Панель меню имеется только у главного окна приложения. Если это окно пустое, то на панели меню отображаются заголовки меню главного окна. Если же главное окно имеет хотя бы одно дочернее окно (окно данных), то на его панели меню отображаются заголовки меню активного в данный момент дочернего окна. Диалоговые окна не имеют собственного меню.
Панель инструментов содержит в себе кнопки с характерными пиктограммами. Эти кнопки доступны только для мышки и служат для запуска наиболее часто используемых программных компонентов. В CA-Visual Objects эта панель называется панелью управления, и кнопки на ней дублируют важнейшие варианты меню. Как правило, панель инструментов располагается вверху, непосредственно под панелью меню. Однако допускается также размещение этой панели в левой, правой или нижней частях окна. CA-Visual Objects позволяет пользователю динамически с помощью мышки перемещать эту панель в удобное для него место.
Панель состояния располагается у нижней кромки окна и служит для вывода сообщений о состоянии приложения, состоянии клавиатуры, а также, при желании, — времени и даты.
Кнопка системного меню окна активизируется любо мышкой, либо клавишей Alt. Системное меню содержит варианты управления окном, в том числе и вариант его закрытия. Закрытие окна означает завершение всех связанных с ним процессов. Закрытие главного окна приложения приводит к завершению этого приложения.
Кнопка максимизации окна доступна только для мышки и служит для увеличения размеров окна до максимально возможных. Дочерние окна увеличиваются до размеров главного окна приложения, главное окно — до размеров экрана.
Кнопка минимизации окна также доступна только для мышки и служит для свертывания окна до размеров иконки — пиктограммы стандартного размера (как правило, 32х32 точки).
/>
Рис.1.3 Стандартные компонеты окна в Windows
Рамка окна служит его визуальной границей. Кроме того, по виду рамки пользователь может судить, допускает ли данное окно плавное динамическое изменение своих размеров с помощью мышки или клавиатуры.
Рабочая область — это та часть окна, в которую не входит ни один из вышеперечисленных элементов. Именно в рабочей области разработчик располагает все необходимые для диалога с пользователем управляющие элементы.
1.1.2 Управляющие элементы окна
Стандарт GUI, реализованный в Windows 3.1 и 3.11, предполагает наличие некоторого единого для всех приложений минимального набора управляющих элементов. В этот набор входят:
командные кнопки (PushButton);
переключатели (CheckBox);
радиокнопки (RadioButton) и их группы (RadioButtonGroup);
однострочный элемент ввода (SingleLineEdit);
многострочный элемент ввода (MultiLineEdit);
блок списка (ListBox);
комбинированный блок списка (ComboBox);
текстовое поле (FixedText);
панель вертикальной прокрутки или вертикальный лифт (VerticalScrollBar);
панель горизонтальной прокрутки или горизонтальный лифт (HorisontalScrollBar);
элемент типа “группа” или рамка (GroupBox);
иконка или пиктограмма (Icon).
В любой момент времени в активном окне непосредственно готов к действию лишь один из его управляющих элементов. Говорят, что этот элемент имеетфокус (или фокус ввода). Передача фокуса конкретному элементу осуществляется щелчком мышки на его изображении. Другой способ — с использованием клавиатуры. Он основан на том факте, что в любом окне имеется строго упорядоченный список всех его элементов. (Упорядоченность списка определяется разработчиком). Нажатие клавиши Tab на клавиатуре приводит к передаче фокуса очередному элементу управления окна, а нажатие комбинации клавиш Shift+Tab — предыдущему.
Командные кнопки.
Командная кнопка (рис.1.4) — это такой элемент окна, “нажатие” на который вызывает вполне определенное действие. “Нажатие” на кнопку осуществляется либо перемещением на нее указателя мышки и щелчком левой кнопки, либо нажатием “горячей” клавиши (т.е. одновременным нажатием клавиши Alt и клавиши, соответствующей подчеркнутой букве в названии кнопки), либо нажатием клавиши пробела, если кнопка в данный момент имеет фокус (наименование такой кнопки обведено штриховой линией — на рис.1.4 это кнопка “Да”).
/>
Рис.1.4 Диалоговое окно с четырьмя командными кнопками
Переключатели.
Переключатель (рис.1.5) — элемент окна, позволяющий включать или отключать некоторые дополнительные возможности приложения. Переключатель имеет два состояния: включен и выключен1. Управление переключателем со стороны пользователя осуществляется также, как и управление командной кнопкой. Важно подчеркнуть, что независимо от того, сколько переключателей расположено в окне, сгруппированы они или нет, каждый переключатель работает независимо от других.
/>
Рис.1.5 Фрагмент окна с переключателями
Радиокнопки.
Радиокнопка (рис.1.6) как элемент управления окна в некотором роде близка переключателю. Этот элемент также имеет всего два состояния: включен/выключен. Принципиальное отличие от переключателей состоит в том, что радиокнопки, как правило, используются только группами. При этом включение одной радиокнопки в группе приводит к автоматическому выключению всех других кнопок этой группы. Иначе говоря, все радиокнопки в группе взаимозависимы. Так например, включение кнопки “Все” на рис.1.6 автоматически выключит кнопку “Страницы”. Управление радиокнопками осуществляется аналогично управлению переключателями, за исключением того, что передача фокуса от одной кнопки к другой осуществляется не клавишей Tab, а клавишами-стрелками.–PAGE_BREAK–
/>
Рис.1.6 Фрагмент окна с группой радиокнопок
Однострочный и многострочный элементы ввода
Однострочный элемент ввода (см. Рис.6.1, справа от радиокнопки “Страницы”) — это графический аналог GET-элемента в Clipper’e. Назначение его то же — ввод и корректировка однострочных данных. Многострочный элемент ввода (рис.1.7) предназначен для обработки сложных текстовых данных (например, мемо-полей), содержащих символы “возврат каретки”. В Clipper’е, как изветно, для этих целей используется функция MemoEdit ().
/>
Рис.1.7 Фрагмент окна с многострочным элементом ввода
Блоки списка
Блок списка — чрезвычайно мощный и полезный элемент управления окна. С его помощью пользователь может выбрать (пометить) из предлагаемого перечня, насчитывающего до 8000 элементов, одну или несколько необходимых ему строк. Различают простые и выпадающие блоки списков.
Простой блок (рис.1.8) представляет собой прямоугольник с заголовком, в рамках которого отображается несколько строк-вариантов. Если весь перечень вариантов не размещается в пределах этого прямоугольника, справа он дополняется вертикальным лифтом, обеспечивающим прокрутку всего перечня. Блок может дополняться и горизонтальным лифтом в случаях, когда строки не размещаются в нем целиком. Пользуясь мышкой или клавишами-стрелками, пользователь подсвечивает требуемую строку. В некоторых случаях блоки допускают выбор сразу нескольких элементов. Множественный выбор осуществляется мышкой (либо непосредственно, либо при одновременном удержании в нажатом состоянии клавиши Shift или Ctrl — в зависимости от свойств блока).
В практике чаще используются блоки выпадающих списков. Такие блоки нормально пребывают в так называемом закрытом состоянии, отображая лишь выбранный на текущий момент времени вариант (рис.1.9а). Тем самым экономится рабочая область окна, которую можно использовать для других управляющих элементов. Раскрытие блока осуществляется только в момент выбора щелчком мышки на стрелке />, после чего работа с ним производится в том же порядке, что и с обычным блоком. При переходе фокуса к другому элементу окна блок автоматически закрывается.
/>
Рис.1.8 Фрагмент окна с простым блоком списка
/>/>
а) б)
Рис.1.9 Блок выпадающего списка в закрытом (а) и открытом (б) состоянии
Комбинированные блоки списка.
Комбинированный блок списка объединяет блок списка с однострочным полем ввода. Пользователь либо выбирает необходимую ему строку из предлагаемого перечня, либо попросту вводит ее с клавиатуры. Комбинированные блоки также бывают простыми (рис.1.10а) и выпадающими (рис.1.10б).
/>/>
а) б)
Рис.1.10 Фрагменты окон с простым (а) и выпадающим (б) комбинированными блоками
Поля текста.
Поле текста — простейший элемент управления, необходимый для размещения в окне поясняющего текста. Этот элемент относится к категории пассивных — он не может получить фокус ввода.
Панели вертикальной и горизонтальной прокрутки
Панели вертикальной и горизонтальной прокрутки обеспечивают возможность скроллинга рабочей области окна в случаях, когда эта область выходит за его текущие границы. Панель вертикальной прокрутки располагается у правой границы окна, панель горизонтальной прокрутки — у нижней. На рис.1.11 представлен пример панели горизонтальной прокрутки. Управление панелями осуществляется с помощью мышки тремя способами. Первый состоит в “нажатии” мышкой требуемой кнопки скроллинга, второй — в “буксировке” мышкой лифта в нужном направлении. Третий способ реализуется щелчком мышки в некоторой области непосредственно на панели прокрутки.
/>
Рис.1.11 Панель горизонтальной прокрутки
Элементы типа “группа”.
Элемент “группа” в CA-Visual Objects имеет две разновидности: простая группа и группа радиокнопок. Простая группа имеет чисто эстетическое значение, позволяя очерчивать рамкой любые функционально близкие друг другу элементы окна. Группа радиокнопок — рамка, очерчивающая только взаимосвязанные радиокнопки. Чисто внешне обе разновидности групп никак не отличаются друг от друга (рис.1.12). В то же время разница между ними есть. Простая группа — пассивный компонент окна (а следовательно, и приложения), в то время как группа радиокнопок — активный компонент, позволяющий упростить управление радиокнопками из программы.
/>
Рис.1.12. Фрагмент окна с группами
Иконки (пиктограммы)
Иконка — это небольшое по размерам изображение (32х32 точки), которое может быть размещено в рабочей области окна в оформительских целях. Иконка — пассивный элемент окна, не получающий фокуса ввода.
/>
Рис.1.13. Фрагмент окна с иконкой.
1.1.3 Другие особенности интерфейса
Наряду с окнами и их элементами управления, стандарт интерфейса GUI предполагает наличие у приложения и других атрибутов. Вот лишь некоторые из них:
Безусловная и полная поддержка мышки.
Полный отказ от модальных меню, в которых выбор одного варианта полностью исключает другие варианты. Пользователь в любой момент времени должен иметь возможность выполнить любую функцию из общего набора, предоставляемого приложением, независимо от того, что конкретно в данный момент происходит в программе.
Полная “прозрачность” всех элементов интерфейса для пользователя с точки зрения их назначения и выполняемых функций. При малейшем затруднении пользователь должен получить контекстно-чувствительную справку через известный ему стандартный механизм помощи.
Как видно, интерфейс с пользователем, предлагаемый и поддерживаемый Windows, существенно более богат и сложен в сравнении с тем, что имеет место в DOS. Ясно, что непосредственное программирование такого интерфейса — задача весьма и весьма сложная. К счастью, CA-Visual Objects имеет достаточный набор средств, позволяющих автоматизировать и, в конечном итоге, максимально упростить процесс разработки интерфейса. В частности, все описанные выше окна, их компоненты и элементы управления в полной мере поддерживаются как встроенными средствами визуального программирования (оконным редактором, редактором меню), так и развитыми средствами языка программирования.
1.2 DOS и Windows: разные подходы к программированию
Графический интерфейс — не самое главное нововведение в Windows, по сравнению c DOS. Гораздо более важным является то, что Windows — мультизадачная операционная среда, призванная обеспечить одновременную работу нескольких программ. Это важнейшее свойство Windows обусловливает еще один уровень требований как непосредственно к прикладным программам, так и к системам их разработки. И первое среди таких требований — отказ от процедурного программирования.
Большинство приложений, написанных под DOS, имеют в принципе одинаковую иерархическую структуру. На самом верху этой структуры находится некая головная процедура или функция. Она отображает на экране меню и в зависимости от выбора пользователя, вызывает одну из функций второго уровня или завершает работу программы. В функциях второго уровня пользователю также могут быть предложены для выбора новые меню, в соответствии с которыми он может “спуститься” на один уровень ниже, еще более конкретизируя и детализируя вычислительный процесс, и т.д. На любом из уровней пользователю могут предлагаться окна для просмотра, ввода или корректировки информации, обрабатываемой данной программой. Во всех случаях, требующих вмешательства пользователя в вычислительный процесс (выбор из меню, ввод/корректировка данных и т.д.), программа переходит в режим ожидания.
В Clipper’е основные средства диалога с пользователем реализуются такими командами и функциями, как MENU TO, ACHOICE (), READ. Для всех них общим является модальный режим работы, т.е. такой режим, при котором программа своими средствами анализирует любую реакцию пользователя и не продолжает вычислительный процесс до тех пор, пока пользователь не предпримет заранее обусловленного программой действия (например, нажмет клавишу Esс). Модальный режим диалогов в DOS ограничивает возможности пользователя по управлению вычислительным процессом. Например, пользователь не может прервать на время ввод одного документа в базу данных и выбрать из меню вариант ввода или печати нового документа.
Иными словами, в DOS программа в большей степени руководит пользователем, нежели пользователь — программой. Программа как бы ведет пользователя за руку по своим “лабиринтам”, предоставляя ему весьма ограниченный спектр возможностей по дальнейшим действиям на каждом “перекрестке”. В более общем плане можно сказать следующим образом: в DOS программа управляет событиями, а не события программой.
Иерархическая структура программ и реализованная в них схема взаимосвязи программных компонентов вполне удовлетворяет пользователей, работающих в DOS, но не способна удовлетворить пользователей Windows. Один из важнейших принципов Windows состоит в том, что пользователь должен всегда быть хозяином положения и в любой момент иметь самый широкий спектр полномочий по управлению вычислительным процессом. Например, пользователь, а не программа должен определять последовательность заполнения полей при вводе/корректировке данных. Более того, он должен иметь возможность вообще прервать на время процесс ввода/корректировки данных и обратиться к любой другой возможности из числа тех, которые предоставляются текущей или даже другой программой! Ведь Windows, в отличие от DOS, — многозадачная операционная среда.
Для реализации этого принципа программы, работающие под управлением Windows, не должны сами ожидать тех или иных действий от пользователя и заниматься их первичной обработкой, т.е. не должны быть модальными. Выполнение этой задачи берет на себя среда Windows, которая предоставляет такого рода “сервис” централизованно для всех программ.
В Windows все, что происходит во время работы программ и так или иначе может повлиять на дальнейший алгоритм их работы, называется событием. Нажатие или отпускание клавиши на клавиатуре, перемещение мышки или нажатие на ней кнопки, выбор варианта из меню — все это и многое другое представляет собой для Windows события. С учетом этого термина, говорят, что программы, работающие под управлением Windows, должны быть событийно-управляемыми. Такие программы, в противоположность “досовским”, управляются внешними событиями, а не управляют ими.
Событийно-управляемая программа должна быть представлена каким-то набором небольших программных единиц, работающих совершенно независимо друг от друга. Назначение каждой такой единицы заключается в функциональной (т.е. вторичной по отношению к Windows) обработке одного конкретного события, которое когда-то в силу каких-то причин может произойти. Программа, получив от Windows сообщение о происшедшем событии, должна быстро “отыскать” в своем наборе ту конкретную программную единицу, которая отвечает за его обработку, и отдать ей управление. Последняя, в свою очередь, должна максимально быстро выполнить необходимые действия и вернуть управление Windows. Требование максимальной быстроты обусловлено тем фактом, что в процессе работы каждой такой программной единицы Windows оказывается как бы “глухой” и невосприимчивой к любым новым событиям, которые могут произойти как в данной программе, так и в любой другой, работающей с ней параллельно2.
Таким образом, работающая под управлением Windows программа с момента своего запуска и до момента завершения не имеет непрерывного времени жизни: она периодически активизируется сигналом от Windows, вызывает соответствующий обработчик события и снова “засыпает”.
Новая схема функционирования программы требует от ее создателей ярко выраженного модульного подхода к программированию. Каждый обработчик событий должен быть строго изолирован от любого другого. В противном случае чрезвычайно трудно предсказать реакцию программы в целом на одну из возможных комбинаций событий и гарантировать отсутствие нежелательных побочных эффектов.
При такой схеме работы программы с точки зрения разработчика появляется довольно неприятный побочный эффект: программа как бы утрачивает свою динамическую целостность. Действительно, если в DOS одним из важнейших программных компонентов для разработчика является стек вызовов, по которому всегда можно отследить историю вызовов или траекторию потока управлений в программе, то в Windows такой стек в подавляющем большинстве случаев оказывается практически непригодным, ибо не содержит в себе полезной информации.
1.2.1 Особенности работы с базами данных
Другой аспект, представляющийся весьма важным для разработчика при переходе от DOS к Windows, состоит в том, что программировать в новых условиях приходится с учетом возможности множественного одновременного доступа к файлам даже в том случае, когда программа задумана как однопользовательская.    продолжение
–PAGE_BREAK–
При программировании в среде DOS сложилась весьма четкая классификация программ на однопользовательские и многопользовательские. Однопользовательская программа рассчитана на одного пользователя и может работать с файлами в простейшем монопольном режиме доступа. Многопользовательская программа пишется для локальной сети и обязана учитывать возможность одновременного доступа к файлам со стороны нескольких пользователей. Естественно, вторую категорию программ разрабатывать значительно труднее, особенно для случаев сложных транзакций. Выбрав однопользовательский вариант для своей программы, разработчик с самого начала руководствуется двумя соображениями:
“DOS работает в монозадачном режиме, следовательно никакая другая программа во время работы моей не будет иметь возможности обращаться к обрабатываемым файлам”;
“Структура моей программы мною же и определяется, поэтому я всегда могу построить ее таким образом, что никогда один и тот же файл не будет открыт дважды”.
В среде Windows про однопользовательский режим работы приходится забыть хотя бы потому, что одну и ту же программу пользователь может запустить одновременно в двух “экземплярах”. Кроме того, имеются и другие факторы, побуждающие всегда разрабатывать только многопользовательские приложения. Для примера рассмотрим следующую, достаточно типовую для Windows-приложений, ситуацию. Допустим, в какой-то момент времени пользователь выбирает из меню вариант работы с файлом документов и в открывшемся окне приступает к выписке новой накладной на отпуск товара. Выше уже отмечалось, что по принятым в Windows стандартам хорошая программа должна в любых ситуациях предоставлять ему максимум своих функциональных возможностей, общий перечень которых заложен в меню. Поскольку меню в Windows не модально и доступно пользователю всегда, он может в силу соображений срочности приостановить ввод текущей накладной и приступить к вводу следующей, повторно выбрав из меню тот же вариант. Ясно, что в обеспечение этого разработчик не только должен предусмотреть возможность множественного доступа к файлам программы, но и позаботиться о том, чтобы эти файлы открывались в различных рабочих областях.
Данный пример приводит к следующим размышлениям. Оба окна и обслуживающие их программные коды должны быть вполне самостоятельными и самодостаточными компонентами общей программы, полностью реализующими принцип реентерабельности (т.е. допускающими свое существование во многих независимых копиях). Кроме того, необходимо позаботиться о том, чтобы при каждом новом открытии окна соответствующий файл открывался в новой рабочей области с уникальным алиасом (псевдонимом). И, наконец, окна должны иметь средства коммуникации друг с другом, поскольку каждое из них должно отражать реальную на данный момент времени информацию.
Таким образом, немодальный, многозадачный и многооконный режимы работы Windows добавляют разработчикам новые хлопоты. Каким образом создать приложение, способное устойчиво работать в столь сложной операционной среде? Ответ на этот вопрос следующий: успех ждет только на пути объектно-ориентированного программирования (ООП). И система CA-Visual Objects такое программирование обеспечивает в полной мере!
1.3 Структура программ в CA-Visual Objects
1.3.1 Объекты. Связи типа “владение”
Подробно реализация принципов ООП в CA-Visual Objects рассматривается в главе 3. Сейчас же мы коснемся этих вопросов лишь в той мере, в какой это необходимо для уяснения структуры приложений, создаваемых с помощью CA-Visual Objects, и их основных особенностей.
Программа в CA-Visual Objects — это совокупность объектов, способных взаимодействовать друг с другом посредством сигналов (сообщений).
Объект — некоторый функционально-полный компонент программы, обладающий вполне определенным набором свойств. Объект способен принимать сигналы (сообщения) от других объектов, реагировать на них и генерировать собственные сигналы (сообщения).
Нормально, объект пребывает в пассивном состоянии, ожидая получения предназначенных ему сообщений.
Получив сообщение X (см. рис.2.1), объект может изменить одно или несколько своих свойств (например, размеры, цвет) и сгенерировать одно или несколько сообщений Y для других объектов.
Характер реакции объекта определяется содержанием входного сообщения X. Отреагировав на очередное сообщение, объект снова переходит в пассивное состояние до тех пор, пока не получит извне новый сигнал.
/>
Рис 1.14. Схематическое представление объекта
Объекты, имеющие общие “родовые” характеристики (т.е. сходные свойства и реакции на входные сообщения), объединяются в классы.
В ООП все возможные сообщения принято делить на две большие группы:
простые сообщения — те, которые имеют отношение к одному конкретному свойству объекта;
сложные сообщения — те, которые затрагивают одновременно несколько свойств объекта и/или побуждают его генерировать свои собственные сообщения.
В CA-Visual Objects, как и в Clipper’е версий 5. х, факт посылки сообщения объекту обозначается символом “: ” (двоеточие). Простые сообщения формируются указанием имени объекта и его конкретного свойства, например:
cColor: = oBar: Color // значение свойства Color объекта oBar
// присвоить переменной cColor
oBox: Width: = 10 // свойству Width объекта oBox
// присвоить значение 10
Сложные сообщения в программах реализуются методами и синтаксически характеризуются наличием пары круглых скобок — “ () ”:
oWindow: Repaint () // ОбъектуoWindowвыполнитьметод// Repaint ()
Реакция объекта на получение сложного сообщения должна быть явно определена в описании соответствующего метода.
Для обеспечения конкретного (адресного) взаимодействия объектов друг с другом посредством сообщений в программе должна быть определена схема их связей. Конечно, описывать связи в виде обобщенной сетевой структуры, когда каждый конкретный объект может непосредственно сообщаться с любым другим, — задача весьма и весьма сложная. Для упрощения процесса программирования в CA-Visual Objects принята существенно более простая, но в то же время весьма гибкаяиерархическая структура связей.
Суть иерархической структуры связей в CA-Visual Objects раскрывается следующим основополагающим положением: любой объект программы имеет своего владельца. Эта концепция чрезвычайно важна, поскольку не только позволяет весьма просто организовывать систему связей объектов, но и обеспечивает поддержание динамической целостности программы как единого функционирующего организма. Рассмотрим ее более подробно применительно к среде Windows.
Как уже отмечалось, типовое приложение в Windows визуально представляется главным окном (или, иначе, окном-оболочкой), в рамках которого это приложение может открывать сколь угодно много дочерних окон. Любое дочернее окно содержит в себе те или иные элементы управления. Описанная цепочка легко и естественно укладывается в иерархическую структуру (рис.1.15):
/>
Рис.1.15. Иерархическая структура связей объектов в CA-Visual Objects
Иерархические связи объектов в CA-Visual Objects фиксируются следующим образом. Исходя из принципа владения, в наборе свойств любого объекта всегда имеется свойство с именем Owner (“владелец” — англ), в котором содержится ссылка на объект, владеющий данным объектом. Пользуясь этой ссылкой, каждый объект может связаться с любым другим, в том числе и с равным себе по рангу (в последнем случае — транслируя свое сообщение через своего владельца).
Связи типа “владение” — становой хребет программ, разрабатываемых средствами CA-Visual Objects. Именно с использованием этих связей осуществляется маршрутизация сообщений, формирование подсказок и диагностики и обработка ошибок. Эти связи в объектно-ориентированной программе выполняют роль, аналогичную той, которые играют стеки вызовов в процедурно-ориентированных программах.
1.3.2 Генерация и обработка событий
Рассмотрим более предметно схему генерации и обработки событий, принятую в CA-Visual Objects.
Любые манипуляции пользователя с клавиатурой или мышкой являются для программы в CA-Visual Objects событиями. Важным в схеме обработки событий является то, что первичная обработка любого события осуществляется системой Windows. Она распознает событие и направляет информацию о нем диспетчеру событий системы времени исполнения CA-Visual Objects, которая автоматически подключается к приложению во время его компоновки. Диспетчер событий в соответствии с полученной от Windows информацией определяет окно, в рамках которого событие произошло, и посылает окну соответствующе сообщение. Окно должно своими средствами распознать это сообщение и выполнить необходимые действия.
В терминах объектно-ориентированного подхода эта схема интерпретируется следующим образом: все оконные классы объектов должны обладать функционально-полным набором методов, способным обеспечить обработку любого события. Поскольку спектр возможных событий достаточно широк, для удобства разработчиков в CA-Visual Objects в нем выделяется особая группа так называемых командных событий. Командные события возникают в системе в четырех ситуациях:
при выборе пользователем из меню какого либо варианта (независимо от того, осуществлен выбор с помощью клавиатуры или мышки);
при “нажатии” пользователем с помощью мышки кнопки, изображенной на панели управления окна;
при нажатии пользователем клавиш-акселераторов;
при “нажатии” пользователем командной кнопки, изображенной в рабочей области окна.
Командные события выделяются среди всех прочих тем, что средства их функциональной обработки должны быть определены разработчиком программы. При обработке такого рода событий диспетчер программы действует по следующему алгоритму:
Определяется идентификатор события (который назначается разработчиком в виде одного из свойств всем объектам, способным генерировать командные события).
Вначале в программе ищется подкласс окон, имя которого совпадает с идентификатором командного события. Если такой подкласс определен разработчиком, то автоматически создается и отображается на экране новое окно данного подкласса.
Если такого подкласса нет, диспетчер пытается найти подкласс отчетов с тем же именем.
Если и такого подкласса нет, диспетчер приступает к поиску метода с аналогичным именем для окна, которому принадлежит данный управляющий элемент.
Если и в этом случае поиск оказывается безуспешным, диспетчер определяет окно-владелец и, если оно существует, пытается отыскать метод у этого окна. И так далее — вверх по цепочке владения.
Если метод обнаружен, он немедленно запускается на выполнение. В противном случае диспетчер считает, что случившееся командное событие в функциональной обработке приложения не нуждается, и это событие им игнорируется.
Что касается всех прочих событий, то для каждого из них в стандартных оконных классах предусмотрены специальные встроенные методы, обеспечивающие их обработку по умолчанию. Разработчик, пользуясь механизмом наследования классов, всегда может модифицировать эти методы так, чтобы они удовлетворяли конкретным требованиям его приложения.
Поясним сказанное на примере. Допустим, пользователь работает в дочернем окне “Расходная накладная: корректировка” приложения “Корпорация SuperStocks: запасы и взаиморасчеты” (рис.1.16). Разработчик присвоил подклассу таких окон имя DocsOut. Предположим также, что в процессе корректировки отображаемой в дочернем окне накладной ему потребовалось уточнить содержание картотеки учета товарно-материальных ценностей. Для этого он в меню “Файлы” выбирает вариант “Картотека”. Пусть разработчик данного приложения связал этот вариант с командным событием Cards. В этом случае диспетчер приложения вначале попытается отыскать в работающей программе описание оконного подкласса с тем же именем. Если разработчик предусмотрел подкласс таких окон, то система времени исполнения автоматически создает экземпляр этого окна, отображает его поверх окна “Расходная накладная: корректировка”и делает активным (рис.1.17). Новое окно с названием “Картотека” имеет собственные меню и элементы управления и полностью готово к работе.
Вернемся к окну, изображенному на рис.1.16, и рассмотрим другой вариант. Пусть теперь пользователь вместо выбора из меню того или иного варианта “нажмет” командную кнопку “Отказ” в правом нижнем углу этого окна. Допустим, разработчик связал эту кнопку с командным событием CancelButton, и по замыслу нажатие этой кнопки должно приводить к отказу от всех сделанных в базе данных изменений и закрытию окна “Расходная накладная: корректировка”. Для этого он разработал метод с именем CancelButton () в классе окон DocsOut. После “нажатия” клавиши “Отказ” диспетчер программы попытается найти сначала подкласс окон с именем CancelButton. Потерпев неудачу, диспетчер попытается далее найти подкласс отчетов с тем же именем. Не найдя отчета “CancelButton”, диспетчер приступит к поиску метода CancelButton () в классе активного окна (DocsOut). Теперь ему будет сопутствовать удача, поскольку в данном классе метод с таким именем предусмотрен разработчиком. Отыскав метод, диспетчер запустит его на выполнение.
/>    продолжение
–PAGE_BREAK–
Рис.1.16. Пример окна “Расходная накладная… ”
/>
Рис 1.17. Пример окна “Картотека”
1.3.3 Другие типы связей в программах
Помимо связей типа “владение” CA-Visual Objects поддерживает еще четыре их разновидности:
связь по наследованию;
реляционная связь таблиц (файлов) баз данных;
связь окон с серверами данных (связь по использованию);
связь с другими приложениями (связь “клиент-сервер”).
Связь по наследованию
Наследственные связи также играют в CA-Visual Objects чрезвычайно важную роль, поскольку именно через них реализуются мощь и гибкость объктно-ориентированного программирования. Осознанное владение механизмом наследственных связей — ключ к успеху при разработке сложных приложений. Эти связи подробно рассматриваются в главе 3.
Реляционные связи файлов баз данных.
Реляционные связи файлов баз данных получили в CA-Visual Objects свое дальнейшее развитие. Как известно, Clipper в этом плане ограничивается поддержкой только связи типа “1: 1″ (“один к одному”), предлагая в качестве инструмента функцию DBSetRelation () (или, что то же, оператор SET RELATION TO). Установка такой связи от одного файла (ведущего) к другому (ведомому) предполагает автоматическое перемещение указателя в ведомом файле при любых навигационных операциях на ведущем при условии, что ведомый файл упорядочен должным образом по соответствующему ключевому полю (полям). Этот простейший вид реляционной связи иллюстрируется на рис.1.18.
/>
Рис.1.18. Типовая схема реляцонной связи “1: 1”
Связь “1: 1″ (как и связь «М: 1») является традиционной при программировани на Xbase-языках. Являясь основой для построения сложных реляционных баз данных, она тем не менее предлагает лишь частичное решение задачи: гарантируя автоматическое перемещение указателя к требуемой строке в ведомой таблице, она не накладывает никаких ограничений на ведение операций над этой таблицей. В частности, для нашего примера, эта связь никак не помешает перевести указатель в файле-классификаторе партнеров явным образом, скажем, на одну строку вверх или вниз. Иначе говоря, ответственность за нарушение целостности такой связки целиком лежит на программисте.
Учитывая это, в CA-Visual Objects реализована также поддержка и более мощного типа связей, а именно — связей типа “1: M” (“один ко многим”). Эта связь в CA-Visual Objects получила название селективной или связи “мастер-детали”. Селективная связь поддерживается на уровне серверов данных (т.е. на уровне объектов) стандартным методом SetSelectiveRelation (). Установка данной связи от ведущего файла к ведомому гарантирует, что в последнем (при условии его соответствующей упорядоченности) отфильтровываются все записи, значения ключевых полей которых не соответствуют значению управляющих полей в ведущем файле. Ведомый файл как бы усекается до группы последовательных записей с требуемым значением ключа, получая при этом новые логические признаки начала и конца файла. Соответственно, такие операции, как переход в начало файла (GoTop) и в его конец (GoBottom), выполняются в пределах выбранной последовательности. Селективная связь иллюстрируется на рис.1.19:
/>
Рис.1.19. Типовая схема реляционной связи “1: M”
Селективная связь значительно упрощает программирование многих фрагментов реальных приложений. В частности, последний пример в приложении может быть весьма эффектно представлен, например, следующим окном данных:
/>
Рис.1.20. Пример реализации селективной связи в окне данных CA-Visual Objects
Заметим попутно, что для реализации этого окна в CA-Visual Objects автору пришлось вручную написать всего одну строку программного кода, задающую заголовок таблицы. Все остальное выполнено средствами визуальных редакторов системы!
Связь по использованию
Связь по использованию является одной из “изюминок” CA-Visual Objects. Обеспечивают эту связь чрезвычайно мощные скрытые механизмы системы. Данная связь может устанавливаться только между объектами двух классов: окнами и серверами данных. Суть ее вкратце заключается в том, что окно данных, используя сервер данных, становится как бы его витриной, приобретая при этом не только возможность отображать, добавлять и корректировать содержащуюся в сервере информацию, но и целый набор стандартных операций (методов), характерных только для сервера (например, операции навигации по файлу базы данных).
Окно данных и сервер данных имеют весьма схожие параллельные структуры. И тот, и другой объекты в каждую единицу времени работают с одним и тем же фрагментом файла базы данных (записью). И тот, и другой объекты способны выделять в текущей записи ее поля. При установке между окном данных и сервером данных связи типа “использует” каждый элемент управления окна, способный получать, хранить и обрабатывать информацию, автоматически привязывается к полям сервера, а значит, и к полям моделируемого им реального файла базы данных (при условии эквивалентности имен элементов управления и полей).
/>
Рис.1.21 Схема взаимодействия сервера и окна данных
Связь по владению реализуется методом Use () окна данных. Использование этого мощного и универсального метода позволяет разработчику сосредоточиться на прикладной логике своей программы и абстрагироваться от множества деталей, связанных с непосредственной работой с файлами. Для примера предположим, что в программе открыт сервер базы данных oServer с полями данных Name и Code и окно данных oWnd с полями ввода, имеющими те же имена. Тогда сказанное можно проиллюстрировать следующим фрагментом программного кода:
Function Test ()

// “Привязка” сервера к окну данных
oWnd: Use (oServer)
? oWnd: Name // “Иванов Иван Иванович”
? oWnd: Code // 0034
// Заполнение поле ввода Name новой строкой символов
// прямым присваиванием (то же можно выполнить с клавиатуры)
oWnd: Name: = “Иванов Иван Петрович”
? oWnd: Name // “Иванов Иван Петрович”
// Поле сервера (а значит, и поле файла базы данных)
// также изменилось:
? oServer: Name // “Иванов Иван Петрович”
// Переход к очередной записи:
oWnd: Skip (1)
? oWnd: Name // “Петров Сергей Дмитриевич”

Return nil
Однако, мощь связи по использованию этим не ограничивается. Метод Use () позволяет нескольким окнам использовать один и тот же сервер одновременно. Такого рода ситуации в практике программирования возникают довольно часто: например, одно окно служит для отображения в табличной форме информации, записанной в файле, а другое — для корректировки и/или добавления записей в этот файл в бланковой форме. Если оба окна используют один и тот же сервер данных, то любые изменения данных в одном окне автоматически отображаются в другом! Сервер данных и использующие его окна постоянно “общаются” друг с другом, не оставляя без внимания ни одного происходящего с ними события!
Связь “клиент-сервер”
Windows как мультизадачная среда устанавливает механизм общения двух параллельно исполняемых приложений и обеспечивает необходимые для этого средства. Это механизм известен под аббревиатурой DDE (Dynamic Data Exchange — Динамический Обмен Данными). Суть этого механизма состоит в том, что одно приложение, зарегистрировав себя в операционной системе в качестве сервера, способно обслуживать заранее определенные запросы другого приложения, зарегистрировавшего себя в качестве клиента. И наоборот.
Подробное описание реализации интерфейса с этим механизмом в CA-Visual Objects выходит за рамки данной брошюры. Поэтому мы просто констатируем, что этот интерфейс в системе есть, весьма просто реализован, и рекомендуем его широкое использование после освоения основ программирования в CA-Visual Objects.
1.3.4 Как все-таки работает программа в CA-Visual Objects?
Итак, попытаемся теперь, с учетом сказанного, представить потоки управления в типовой программе, написанной в системе CA-Visual Objects. Структурная схема головного модуля такой программы представлена на рис.1.8 Как видно, она довольно проста.
Первое, что в ней делается — это создается объект ShellWnd, принадлежащий классу главных окон приложения. В качестве одного из своих свойств этот объект имеет объект класса меню, свойства которого описаны заранее программистом с помощью специального редактора. Допустим, в объекте-меню есть два подменю с заголовками “Файл” и “Помощь”, при этом подменю “Файл” предлагает на выбор три варианта: “Открыть” (с идентификатором командного события File_Open), “Закрыть” (с идентификатором командного события File_Close) и “Выход” (с идентификатором командного события File_Exit).
/>
Рис.1.22 Структура головного модуля программы
Далее созданное окно отображается на экране, после чего запускается внутренний диспетчер событий. Как уже отмечалось, задача диспетчера состоит в ожидании события (т.е. сигнала от Windows), дешифровке его и инициализации требуемого объекта или метода.
После фактического выполнения описанных трех блоков (кстати, представляемых всего тремя строками программного кода) на экране отобразится окно с панелью меню. Пусть пользователь выберет из меню открывшегося окна с помощью клавиатуры или мышки вариант “Файл-Открыть”. Windows в ответ на это событие пошлет диспетчеру соответствующий сигнал. Диспетчер распознает этот сигнал как событие командного типа и запустит ранее описанный стандартный алгоритм поиска обработчика данного события по его идентификатору File_Open. Если такой обработчик будет найден (в виде дочернего окна или отчета с таким же именем, или метода окна ShellWnd с этим именем), то он немедленно запустится в работу. Пусть под событием File_Open скрывается новое (дочернее) окно. В этом случае оно будет создано и показано на экране. Это окно становится активным. Оно имеет одним из своих свойств собственное меню и владеет некоторым числом элементов управления. Все эти элементы окна — потенциальные генераторы новых событий, обработка которых будет осуществляться аналогично.
Этот циклический процесс будет продолжаться до тех пор, пока одно из событий не приведет явно или неявно к закрытию главного окна приложения. Одновременно с его закрытием завершит свою работу диспетчер событий, а следовательно, и все приложение в целом.