Создание САПР на базе продуктов Autodesk
Информационный Канал Subscribe.Ru |
Информационная рассылка сайта [CadDev.Narod.Ru]
(с) 2004, Калугин Сергей СергеевичПо просьбам активистов ...
Сегодняшняя и несколько последующих рассылок будут связаны не совсем с тематикой
разработки CAD.
Будут рассмотрены вопросы интеграции приложений, что тоже относится к некторым
подсистемам САПР.
В этом номере:
Компоненты ADO
Дмитрий Ю. Сидоров
В Delphi 5.0 появились компоненты для работы с Microsoft® ActiveX® Data Objects (далее ADO). ADO это технология стандартного обращения к реляционным данным от Microsoft. Эта технология аналогична BDE по назначению и довольно близка по возможностям.
Следует отличать компоненты Delphi, являющиеся частью библиотеки визуальных компонентов Delphi (VCL), и интерфейсы и объекты ADO, которые в них инкапсулированы. В дальнейшем, когда упоминается компонент – это компонент Delphi, а когда объект или интерфейс – это объект или интерфейс ADO.
Обзор компонент
Для работы с ADO на вкладке компонентов ADO есть шесть компонентов: TADOConnection, TADOCommand, TADODataSet, TADOTable, TADOQuery, TADOStoredProc.
Рис. 0. Палитра компонент ADO
- TADOConnection аналогичен компоненту BDE TDatabase и используется для указания базы данных и работы транзакциями.
- TADOTable – таблица доступная через ADO.
- TADOQuery – запрос к базе данных. Это может быть как запрос, в результате которого возвращаются данные и базы (например, SELECT), так и запрос, не возвращающий данных (например, INSERT).
- TADOStoredProc – вызов хранимой процедуры. В отличие от BDE и InterBase хранимые процедуры в ADO могут возвращать набор данных, поэтому компонент данного типа является потомком от TDataSet, и может выступать источником данных в компонентах типа TDataSource*.
- TADOCommand и TADODataSet являются наиболее общими компонентами для работы с ADO, но и наиболее сложными в работе. Оба компонента позволяют выполнять команды на языке провайдера данных (так в ADO называется драйвер базы данных).
Разница между ними в том, что команда, исполняемая через TADODataSet, должна возвращать набор данных и этот компонент позволяет работать с ними средствами Delphi (например, привязать компонент типа TDataSource). А компонент TADOCommand позволяет исполнять команды не возвращающие набор данных, но не имеет штатных средств Delphi для последующего использования возвращенного набора данных.
Очевидно, что все компоненты должны связываться с базой данных. Делается это двумя способами либо через компонент TADOConnection либо прямым указанием базы данных в остальных компонентах. К TADOConnection остальные компоненты привязываются с помощью свойства Connection, к базе данных напрямую через свойство ConnectionString.
База данных может быть указана двумя способами через файл линка к данным (файл в формате Microsoft Data Link, расширение UDL), либо прямым заданием параметров соединения.
Значение свойства всех ConnectionString этих компонент могут быть введены напрямую в текстовой форме, но куда проще вызвать редактор свойства нажав на кнопку “…” в конце поля ввода. Окно этого свойства выглядит так:
Рис. 1.
При выборе “Use data link file” и нажатии на кнопку “Browse…” появляется стандартный диалог выбора файла. Этот файл можно создать в любом окне explorer-а (в этом окне открытия файла, в самом explorer, на desktop и т.д.) вызвав контекстное меню и выбрав пункт “New/Microsoft Data Link”. Потом вызовите локальное меню для созданного файла и выберите в нем пункт “Open”. После этого появится property sheet описанный чуть ниже. Эти же вкладки содержит и property sheet, вызываемый через пункт “Property” локального меню UDL файла, но в нем еще есть вкладки относящиеся к самому файлу.
Использование файлов Microsoft Data Link упрощает поддержку приложений, так как возможно использовать средства Windows для настройки приложения.
При выборе в редакторе свойства “Use connection string” и нажатии на кнопку “Build…” появляется такой же property sheet, как и при выборе “Open” для Microsoft Data Link файла.
В этом окне выбирается тип базы данных, местоположение базы и параметры соединения.
На первой странице выбирается тип базы данных или Provider, в терминах ADO.
Рис. 2.
Базы MS Access доступны как через “Microsoft Jet OLE DB Provider”, так и через “Microsoft OLE DB Provider for ODBC”.
Следующая страница зависит от выбранного типа базы, однако для всех типов есть кнопка “Test connection” позволяющая проверить правильность и полноту параметров.
Для “Microsoft Jet OLE DB Provider” она выглядит так:
Рис. 3.
Checkbox “Blank password” подавляет диалог ввода идентификатора и пароля пользователя при установлении соединения, если поле пароля пустое.
Checkbox “Allow saving password” сохраняет пароль в строке параметров соединения. Если он не отмечен, то введенный пароль будет использоваться только при выполнении тестового соединения.
Для “Microsoft OLE DB Provider for ODBC” эта страница выглядит так:
Рис. 4.
Радиокнопка “Use data source name” позволяет ввести предустановленный алиас ODBC, а через “Use connection string” вводится как алиасы так и тип ODBC драйвера и параметры соединения.
Параметры идентификации пользователя аналогичны выше описанным.
На странице “Advanced” расположены дополнительные параметры, с помощью которых устанавливается уровень доступа к файлу базы данных, таймаут сетевого соединения (то есть время через которое связь будет считаться потерянной, если сервер не отвечает) и уровень глубины проверки секретности соединения.
Рис. 5.
На странице “All” можно отредактировать все параметры с предыдущих страниц и параметры зависящие от провайдера, но не вошедшие на страницу “Connection”. Редактирование осуществляется в виде параметр – значение, причем в текстовой форме, никаких диалогов нет. Помощи то же нет, эти параметры описаны только в документации на провайдер. Ее можно найти в MSDN Data Access Services/Microsoft Data Access Components (MDAC) SDK/Microsoft ActiveX Data Objects (ADO)/Microsoft ADO Programmer's Reference/Using Providers with ADO.
Рис. 6.
В компоненте TADOConnection есть свойства Provider, DefaultDatabase и Mode которые являются альтернативным методом задания частей строки параметров соединения – провайдера, базы данных (например, пути до базы MS Access) и режима совместного использования файлов базы данных. Эти значение этих свойств автоматически включаются в строку соединения, если были заданы до активизации компонента и автоматически выставляются после соединения.
* Прим. ред. Компоненты StoredProc (и BDE и IB) могут возвращать набор данных, являются потомками TDataSet и могут выступать источником данных в компонентах типа TdataSource.
По волнам интеграции…
Я родом из DOS. Кто-нибудь помнит, что это такое? Кто-нибудь помнит те компьютеры,
на которых это крутилось? А какие усилия прилагались для того, чтобы сделать
программу с минимальными требованиями к памяти и диску. Как использовали сначала
EMS, а потом XMS с одной единственной целью - оптимизация. Много времени с
тех пор прошло (старею что ли?).
Сейчас другие времена (наконец-то!). Кругом Win32, OLE, пара-тройка гигабайт
на процесс, «безразмерные» диски. Кто сейчас придает значение лишним четырем
килобайтам? Сотня килобайт - туда, сотня - сюда. Вот и я сейчас буду утверждать,
что интеграция приложений (мегабайты потерь оперативной памяти) - это правильно.
Да, наверно это правильно, когда ты начинаешь использовать функциональность
программ, которых ты не писал. Просто, эти самые программы умеют больше, чем
можешь ты сам. А аналог написать слабо - пару лет попыхтишь и на пенсию по
несостоятельности (мне уже давно пора!).
А зачем оно нужно? |
Собственно, цель этой статьи мне понятна - поделиться своим опытом с народом. Делюсь…
Итак, зачем нам, лучшим в мире программистам, нужен Excel, порождение "злого" гения Microsoft? Конечно, часто это лишнее - «юзать» Excel для отчетов. Напечатать «платежку» можно и в QReport-е. Но…
Есть заказчики, готовые отдать «кучищи» денег за то, что они будут знать все и всегда о своем предприятии. Да еще, чтоб это было красиво и со вкусом.
Приезжает один из моих заказчиков (немец - они повсюду! курорты Испании просто куплены ими - это знаю наверняка) на свое местное предприятие и начинает задавать интересные вопросы. Как трудились за время его отсутствия, сколько продукции выпустили, кому сколько отгрузили, в разных валютах, итого в USD и пр.? А я ему в ответ открываю отчет, неслабый такой, - сводная таблица по движению готовой продукции (посвященные знают, что это 40-ой счет в бухгалтерии). А в ней одних PageField-ов десяток. И на каждый его вопрос я начинаю отвечать не напрягаясь, потихоньку перетаскивая поля таблицы туда-сюда, фильтрую кое-что, строю диаграммы. Что, вы думаете, было потом? Он, как маленький ребенок, сидел за этой сводной таблицей несколько часов, все восхищался. И правильно, наши программисты круче ихних! Заодно и мы спокойно поработали (ему занятие нашлось). О деньгах тут вообще не говорим.
Потом я ему показал, как эту самую сводную таблицу в Сеть можно опубликовать. Сейчас просит, чтоб ему доступ из Германии сделали к этой табличке. Мы, конечно, рады стараться.
Я бы привел еще несколько примеров, но, думаю, читатели уже поняли меня. Excel - вещь практически незаменимая во всяческих анализах (не путать с поликлиникой). А для тех, кто не понял, я еще напишу. Отдельно.
Так как же с ним работать? |
А просто. Создал "Excel.Application", использовал его по назначению, "убил" и готово. Вот именно об этом я и попытаюсь написать здесь.
Важно!
Параллельно с написанием статьи создавался демо-проект (точнее два - для Delphi
4 и 5), где вы сможете найти весь код примеров статьи. Проект для Delphi 4.0
использует импортированную Type Library из Excel 97. Здесь я использую ранее
связывание, ибо CreateOLEObject отлично описал мой любимый классик в "Delphi
4 Unleashed" (мне ли с ним тягаться?). Кроме того, обращайтесь к комментариям
в исходных текстах этого проекта. Местами там написано намного понятней, нежели
здесь. Delphi 5 содержит более удобный механизм импорта библиотек типов с
поддержкой событий и прекрасной генерацией ко-классов. Специально для счастливых
обладателей Delphi 5 (я тоже им являюсь) я создал проект, но уже применительно
к TexcelApplication (правда ли, что импортированный MS Office есть только
в версии Enterprise?). Примеры кода я буду приводить сначала для Delphi 4,
потом для Delphi 5. Заранее приношу прощения за дублирование информации в
комментариях и в статье - писал сразу везде.
И еще. Эффективная работа с Excel-ом из Delphi-приложений немыслима без знания
одной важной вещи. И имя ей - интерфейс. Мне, конечно, хотелось бы написать
о принципах работы с интерфейсами здесь, в этой статье. Более того, я обещал
сделать это самой Королеве. Но…
Мне ли (совсем еще не профессионалу - и это так!) пытаться сделать это лучше,
чем классики этой области. Я честно признаюсь, что не смогу этого сделать
быстро (в небольшом объеме) и качественно. Поэтому всякого, не знакомого еще
с этой областью программирования, я с глубочайшими извинениями отсылаю к книге
Чеппела "OLE Inside".
Достойную помощь (уже применительно к Delphi) может вам оказать "Delphi
4 Unleashed" Чарльза Калверта.
Создание экземпляра Excel.Application. |
Модуль импортированной Excel TLB (неважно, для D4 или D5) содержит описания всех интерфейсов, которые правильные программисты из Microsoft решили выставить наружу. Там есть все необходимое: типы, константы и интерфейсы. Этого вполне достаточно для работы с Excel-ом из Delphi-приложения (во написал! а что еще нужно-то?). Я создаю Excel для последующего его использования с помощью такого кода:
Delphi 4.0
|
Этот достаточно простой код вы найдете практически во всех книгах, посвященных работе с интерфейсами. Как и везде, я напишу, что в результате выполнения этого кода создастся объект COM с CLSID-ом «{00024500-0000-0000-C000-000000000046}» (читайте и перечитывайте Калверта, это не только укрепляет сон!).
Delphi 5.0
|
В отличие от предыдущих версий, Delphi 5.0 предоставляет более удобный сервис при импорте библиотек типов. Большой шаг вперед - появление класса ToleServer с поддержкой событий. Теперь работа с существующими и создание новых OLE-серверов стала намного удобней. Как видите, не приходится обращаться к низкоуровневым функциям. Впрочем, в Delphi 4.0 тоже существовал этот класс, только не от Borland. Отличная библиотека была создана Бином Ли (Binh Ly) в COM Nodes - это Threading COM Library. С легкой руки Алексея Вуколова (специальное спасибо!) я использовал ее для построения масштабируемых COM-серверов в сервисах WinNT.
Обращу ваше внимание только на параметр NewInstance. Он позволяет создать новый процесс. Я часто задаю себе вопрос - "А нужен ли NewInstance?". Одна копия процесса, все ж, требует меньше памяти. Но еще чаще я думаю - "Боже, как хорошо я сделал, когда создал новый процесс!". Почему? Если вы не хотите потерять уже открытые, но еще не сохраненные книги, экспериментируя даже с моими примерами, создавайте новый процесс. Печальный опыт научил меня использовать GetActiveObject только в случае полной уверенности в коде, который будет выполняться после. Поэтому, мой вам совет, тестируйте свои приложения только с NewInstance. Или закрывайте важные книги пред этим. Excel - хитрая программа, бывает, улетает в неизвестность, ни слова не сказав. Это не вина Microsoft. Это неудачное расположение звезд.
Как показать Excel, если он, разумеется, создан? |
Вот здесь начинаются хитрости. Любой, читавший помощь по Excel VBA, скажет, что достаточно написать FIXLSApp.Visible := true. Не тут-то было. Я делаю так:
Delphi 4.0 / 5.0
|
Зачем здесь условие на минимайз и какой-то ScreenUpdating? Давайте попробуем закомментировать эти строки, остаиви только Visible, запустить проект, создать Excel (кнопка CreateExcel), показать его (кнопка ShowExcel), минимизировать, вернуться в приложение и сделать снова ShowExcel. Да-да, Visible = true переводит фокус в минимизированный Excel, не восстанавливая размеры окна. Это ситуация, с которой я борюсь условием на xlMinimized. Но ScreenUpdating зачем?
Знающие люди говорят, что это свойство отвечает за перерисовку окон Excel. Это все равно, что DisableControls у TDataSet. Добавляет скорости, если в нем false. И это правда что, если выключить его во время длительных пересчетов, то быстрее пересчитается. Но мы, ведь, не выключали его. Зачем тогда эта строка?
Делаем так: комметируем эту строку, запускаем демо, CreateExcel, ShowExcel, закрываем его (можно кнопкой с крестиком в правом верхнем углу окна, кому нравится - через меню "Файл/Выход"). Знающие люди скажут, что Excel на самом деле не закрыт. Интерфейс мы не освободили, поэтому в TaskManager мы его и увидим. Итак, Excel по-прежнему у нас в руках. Мы имеем право сделать ему снова Show.
После такого действия у меня возникает ощущение, что я переплатил за свою видеокарту. Фокус в Excel-е, но я по-прежнему наблюдаю форму демо-проекта. Видимо, программисты из MS не рассчитывали на то, что кто-то закроет Excel, вызванный через создание Excel.Application, а потом захочет увидеть его снова. Но я-то захотел?!
Свойства Visible, WindowState и ScreenUpdating вызываются с каким-то непонятным индексом массива - 0. В модуле Excel TLB во многих свойствах и методах вы можете встретить параметр или индекс lcid. Не помню, у кого я это прочитал (Калверт или Канту), но с тех пор я туда передаю всегда 0. И все работает. LCID - это что-то насчет локализации. В MSDN написано "Indicates that the parameter is a locale ID (LCID)".
Спрячем Excel от посторонних глаз! |
На свой процесс я всегда создаю один экземпляр Excel.Application. Уже пару лет все отчеты у меня - это отчеты Excel. Я написал несколько классов, которые мне очень помогают в этом. Сегодня у меня целая «отчетная» подсистема, зашитая в класс и обслуживающая непомерно большие запросы моих пользователей. В промежутках между работой с отчетами нет необходимости «мозолить глаза» лишним окном в TaskBar-е. Вот и прячу я этот Excel. Это очень просто и комментариев, думаю, не требует:
Delphi 4.0 / 5.0
|
Закроем Excel корректно! |
Собственно говоря, при закрытии приложения Excel сам будет закрыт, если вы там не устели чего-нибудь отредактировать. И это правильно. Программисты Borland (Inprise до сих пор мне режет слух, да и некоторым в Inprise, судя по всему, тоже) позаботились об этом. Но я еще с Delphi 3 заимел дурную привычку освобождать все самостоятельно. Освобождать обычным присваиванием в nil (это касается проекта для D4). Труда это не составляет, да и проверка на Assigned удобна. Поэтому, и еще из кое-каких соображений, я делаю так:
Delphi 4.0
|
Ну вот, написал только
про nil, а кода - на полстраницы. Опишу ситуацию.
Вы не запускали новый процесс, вы «законнектились» к уже существовавшему.
В нем была открыта книга. Попробуйте: CreateExcel, ShowExcel, HideExcel (имеем
право), ReleaseExcel. Если оставить только присваивание в nil, то существовавший
процесс не будет выгружен (он же существовал до запуска нашего демо), но будет
спрятан от пользователя с его открытой книгой.
Delphi 5.0
|
Практически тот же код. Только в D5 вы работаете уже не с интерфейсом напрямую, а с экземпляром класса TexcelApplcation. Если посмотреть его предков, то можно увидеть, что это настоящий класс, освободить который просто необходимо. Поэтому вместо присваивания в nil там написано FreeAndNil (помните такую процедуру?).
Лучшее решение - шаблоны |
Excel, интегрированный с моими приложениями, хорош (для меня - программиста) только по одной причине. Я всегда создаю шаблоны и использую их потом при построении отчетов. Шаблоны позволяют мне избежать ручного (в исходном тексте) форматирования. В общем случае, алгоритм выглядит просто: по шаблону создается книга, каким-то образом помеченные области заполняются данными и… (а дальше все уже готово). Как я создаю книгу по шаблону:
Delphi 4.0 / 5.0
|
В этом коде нет ничего сложного. В принципе при работе с Excel я мало находил мест, где что-либо сделать было бы сложно. Чаще достаточно прочитать справку по VBA или записать макрос (благо, Microsoft встроила в Excel хороший пишущий player). После выполнения этого метода будет добавлена книга, близнец шаблона, с именем шаблона и порядковым номером (как "Книга1.xls" или "Книга228.xls"). Правда здесь есть одна тонкость. Эти «циферки» в имя книги Excel добавляет после поиска книг с таким же названием в каталоге по умолчанию. Я несколько раз наступал на грабли (больно!), когда пытался сохранять книги в другом каталоге и создавать новую - по этому же шаблону. К сожалению, не может эта «злобная» программа держать открытыми несколько книг с одинаковыми названиями, несмотря на то, что они лежат в разных каталогах.
Как я помечаю области, в которые необходимо разместить данные? В Excel существует возможность объединить ячейки в группу и поименовать эту группу. В терминах Microsoft это объект Range (область). Для своего проекта я создал тестовую книгу "Test.xls", в которой на листе "Лист1" разместил область "TestRange" (см. рисунок). Более того, для ячеек этой области я указал форматы вывода (Field4 - дата, Field3 - красный цвет шрифта). Я надеюсь, что после переноса тестовых данных форматы сохранятся.
Что есть шаблон без данных в нем? |
Существует масса способов передать данные в Excel, начиная с DDE и заканчивая обычным присваиванием (типа Cell.Value := NewValue ). Конечно, максимальную скорость передачи данных можно получить, только используя DDE. Но я отказался от этого пути из-за некоторых ограничений и давно смущающего меня флажка в настройках Excel ("Игнорировать DDE-запросы"). Поэтому здесь я опишу менее эффективный, но работоспособный, путь решения этой проблемы. Итак, после нажатия кнопки CreateExcel имеем открытый шаблон с листом "Лист1" и областью с именем "TestRange". Для чистоты эксперимента (скорей из лени, великая вещь - собственная лень) я описал константный массив с тестовыми данными - TestDataArray. Именно эти данные я и передаю в ячейки области:
Delphi 4.0
|
Delphi 5.0
|
Я знаю, что многие профессионалы (к коим, к сожалению, я не принадлежу) взвоют от негодования при виде такого кода. Их можно понять, они знают намного более эффективные решения. Именно об этих решениях я и собираюсь написать в следующий раз. А вы пока не забудьте почитать комментарии в проекте-примере.
To be continue… |
Excel - занимательная программа. Я давно с ней. Библиотека типов Excel громадна, как «Титаник» (хорошо, что не тонет). Я отдаю должное программистам, создавшим этот не менее замечательный, чем Delphi, продукт. И в одну статью все, что хочется написать, не вместишь (почему-то у меня уже шесть листов? Знаю, я слишком многословен). Поэтому ругайте меня и ждите продолжения…
Проект для Delphi 4. -
D4Sample.zip (133 K)
Проект
для Delphi 5. -
D5Sample.zip (8 K)
http://subscribe.ru/
E-mail: ask@subscribe.ru |
Отписаться
Убрать рекламу |
В избранное | ||