Книга
Книга
УДК 681.3.06
ББК 32.973.26-018.1
П58
Попов С. А.
Delphi и 1С:Предприятие. Программирование информационного обмена. — СПб.: БХВ-Петербург, 2007. — 592 с.: ил. + CD-ROM — (Профессиональное программирование)
ISBN 978-5-9775-0041-8
Рассмот])сны вопросы, связанные с программированием информационного обмена между системой 1С:Прсдприятис и внешними приложениями, разработанными в Delphi. Приведены общие сведения о конфигурации системы 1 С:Предприятие. На конкретных примерах показаны приемы программирования и доступ к информационной структуре системы 1С:Прсдприятис с использованием механизма OLE Automation, а также прямой доступ к данным с помощью SQL-janjxxoB. Уделено внимание вопросам внешнего администрирования системы 1 С:Предприятие. Материал сопровождается большим количеством практических примеров, размешенных на прилагаемом компакт-диске.
Для программистов
УДК 681.3.06
ББК 32.973.26-018.1
Группа подготовки издания:
Главный редактор Зам. главного редактора Зав. редакцией Редактор Компьютерная верстка КорректорДизайн серии Оформление обложки Зав. производствомГлавный редактор Зам. главного редактора Зав. редакцией Редактор Компьютерная верстка КорректорДизайн серии Оформление обложки Зав. производствомЕкатерина Кондукова Игорь Шишигин Григорий Добин Татьяна ТемкинаНатальи Караваевой Наталия Перишкова Инны Таниной Е/ены Беляевой Николай ТверскихЕкатерина Кондукова Игорь Шишигин Григорий Добин Татьяна ТемкинаНатальи Караваевой Наталия Перишкова Инны Таниной Е/ены Беляевой Николай Тверских
Главный редактор Зам. главного редактора Зав. редакцией Редактор Компьютерная верстка Корректор
Дизайн серии Оформление обложки Зав. производством
Главный редактор Зам. главного редактора Зав. редакцией Редактор Компьютерная верстка Корректор
Дизайн серии Оформление обложки Зав. производством
Екатерина Кондукова Игорь Шишигин Григорий Добин Татьяна Темкина
Натальи Караваевой Наталия Перишкова Инны Таниной Е/ены Беляевой Николай Тверских
Екатерина Кондукова Игорь Шишигин Григорий Добин Татьяна Темкина
Натальи Караваевой Наталия Перишкова Инны Таниной Е/ены Беляевой Николай Тверских
Лицензия ИД f* 02429 от 24.07.00. Подписано • печать 27.02.07.
Формат 70x100’715. Печать офсетная. Усл. печ. л. 47,73.
Тираж 2000 эка. Заказ Ne 1064
•БХВ-Петербург", 194354. Санкт-Петербург, ул. Есенина, 56.
Санитарно-эпидемиологическое заключение на продукцию
Ne 77.99.02.953.Д.006421.11.04 от 11.11.2004 г. выдано Федеральной службойпо надзору в сфере защиты прав потребителей и благополучия человека.
ISBN 978-5-9775-0041-8ISBN 978-5-9775-0041-8Отпечатано с готовых диапозитивовв ГУП Типография "Наука"199034. Санкт-Петербург. 9 линия, 12
ISBN 978-5-9775-0041-8
ISBN 978-5-9775-0041-8
С Попова А.. 1007
С Оформление. кштельстао "БХВ-Петсрбург-, 2007
Оглавление
ЧАСТЬ 1.1С И МЕХАНИЗМ OLE AUTOMATION1
Глава 1. Общие сведения.......3
Глава 2. Подготовка к изучению материала этой части. Конфигурация 1С 4
Глава 3. Подключение к 1С ееееееееееееее»еее«ее«ееееееееееееееееееееееее*ее««ееееееееееееееееееее*евееее 19
Первый этап19
Второй этап25
Глава 4. Доступ к информации 1С из внешних приложений29
Считывание информации из справочников31
Реквизит справочника типа Перечисление32
Реквизит справочника типа Строки неограниченной длины42
Реквизит справочника типа Справочник51
Обобщение пройденного материала62
Периодические реквизиты справочников86
Считывание информации из документов123
Считывание информации из регистров157
Доступ к информационной структуре базы данных 1С187
Доступ к информационной структуре с использованием механизма OLE Automation187
Doc-файлы (хранилища структурированной информации). Файл конфигурации системы 1С:Предприятие —1Cv7.MD215
Метод EvalExpr.............................................................................................228
Метод ExecuteBatch 243
Изменение информации в базе данных 1С266
Редактирование элементов справочников266
Редактирование документов?.'..•333
Синхронизация баз данных 1С342
IV Оглавление
Глава 5. Расширение функционала 1С„359
Общие сведения360
Внутрипроцессный сервер автоматизации362
Внепроцессный сервер автоматизации433
ЧАСТЬ II. ДОСТУП К БАЗЕ ДАННЫХ 1С БЕЗ ПРОГРАММЫ 1С:ПРЕДПРИЯТИЕ451
Глава 6. Файлы формата DBF453
Общая информация о DBF-формате453
Доступ к информации в DBF-файлах456
Глава 7. Обработка словаря базы данных 1С (файл 1Cv7.DD)462
Глава 8. Доступ к таблицам базы данных с учетом информации в файле 1Cv7.DD468
Глава 9. Дополнительные данные об информационном содержании таблиц, полученные с помощью механизма OLE Automation.......479
Глава 10. Дополнительные данные об информационном содержании таблиц, полученные из файла !Cv7.MD483
Глава 11. Остатки ТМЦ на складах. Пример526
ЧАСТЬ III. ПРОГРАММА 1С:ПРЕДПРИЯТИЕ В СРЕДЕ WINDOWS551
Глава 12. Список зарегистрированных баз данпных системы 1С:Предприятие553
Глава 13. Список активных пользователей базы данных 1С:Предприятие558
Глава 14. Отслеживание регламента системного обслуживания баз данных 1С:Преднриятие566
Глава 15. Программа 1С:Предприятне в качестве DDE-сервера570
Приложение. Описание компакт-диска573
Структура содержимого компакт-диска573
Предметный указатель575
Часть 1
1С и механизмOLE Automation
2Часть I. 1C и механизм OLE Automation
Эта часть посвящена вопросам программирования информационного обмена между системой 1С и внешними приложениями с применением механизма OLE Automation.
Общие сведения
OLE Automation представляет собой механизм управления приложением извне с помощью соответствующих сервисов, предоставляемых самим приложением. Для реализации этих сервисов приложение использует интерфейсы COM-объектов. которые располагаются внутри его адресного пространства. Такое приложение называется сервером OLE Automation. или сервером автоматизации.
Приложение, использующее эти сервисы, называется контроллером автоматизации. или клиентам автоматизации. Сервер автоматизации может выполняться как в собственном адресном пространстве (в виде приложения), так и в адресном пространстве клиента (в виде DLL-библиотеки). В первом случае сервер называется внешним (out-of-process — внепроцессный), а во втором случае — встроенным (in-process — внутрипроцессный).
Любой сервер OLE Automation, а также COM-объект. идентифицируется уникальным 128-битовым (16-байтным) кодом QUID (Global Unique Identifier — глобально уникальный идентификатор). Информация обо всех серверах OLE Automation и СОМ-объектах хранится в системном реестре. Сервисные возможности сервера автоматизации определяются объектами, методами и свойствами. которые разработчики сервера предусмотрели для использования во внешних приложениях.
Если сервер и клиент выполняются на разных компьютерах, то сервер называется удаленным. В рамках данной книги такие серверы рассматриваться не будут.
В качестве примера серверов OLE Automation можно привести такие приложения. как Microsoft Office (Word. Excel и т. д.), Microsoft Internet Explorer и др. Система IC также поддерживает механизм OLE Automation в качестве как сервера, так и клиента. Следовательно, здесь применимы все приемы и способы программирования, разработанные для использования этой технологии в других приложениях.
Подготовка к изучению материала
этой части. Конфигурация 1С
Те, у кого есть опыт работы в среде Конфигуратора системы 1 С: Предприятие, могут пропустить эту главу.
Для того чтобы можно было уделить максимум внимания процессу программирования. не отвлекаясь на нюансы конфигураций 1С, доступные читателям. создадим свою, простую конфигурацию 1С.
Примечание
Создаваемая конфигурация носит отвлеченный от реалий характер и не претендует на какую-либо практическую ценность для ее использования в иных целях, кроме учебных.
Примечание
Конфигурация размещена на сопроводительном компакт-диске книги в папке \1C_example.DBV
Рассмотрим весь процесс создания конфигурации 1С достаточно подробно, чтобы читатели, не имеющие опыта работы с 1С, получили представление об этом процессе.
В данном случае будет создана локальная конфигурация на основе файлов формата DBF. Для этого необходимо создать папку на каком-либо логическом диске компьютера (например, E:\lC_exaniple.DB\) и запустить Конфигуратор системы 1С:Предприятие, выбрав его в программном меню Windows (рис. 2.1) или щелкнув на его ярлыке (рис. 2.2). ч
• На экране появится диалоговое окно со списком конфигураций 1С (рис. 2.3).
Здесь (в данном случае) нужно нажать кнопку Добавить. На экране появится диалоговое окно (рис. 2.4), где следует ввести наименование конфигурации и папку, где будут размещены файлы конфигурации и базы данных 1С.
Глава 2. Подготовка к изучению материала этой части. Конфигурация 1С
5
^ 1С Предприятие
^ 1С Предприятие Монопольно
^ Readme - Дополнительная информация
Монитор пользователей
^
Отладчик
Переход с версии 7.5
м
Сервер защиты
□
Удаление драйвера защиты
□
Установка драйвера защиты
Конфигуратор
Рис. 2.1. Запуск конфигуратора из программного меню Windows
Рис. 2.2. Ярлык конфигуратора
155 Запуск 1С:Предприятия
В режиме.
S
Конфигуратор
Мснолз^ьн:-
ОК
х
Информационные Базы:
2003-06-10 - РАБОЧАЯ
2003-07-15. Complex
2004-03-10-НУ
Smple.l
Информационная База Й2
Отмена |
Изменить |
| Добавить |Удалить
Помощь |
Рис. 2.3. Диалоговое окно выбора базы данных 1С
•^Регистрация Информационной Базы
Название: (Учебная конфигурация
Путь; |EA1C_exampteDB\
■В
ок |
Отмена [
Рис. 2.4. Диалоговое окно ввода информации о новой конфигурации
о
После этого новая конфигурация появится в списке конфигураций (рис. 2.5). Следует отметить, что при обращении к 1С через механизм OLE Automation это диалоговое окно появляется только в том случае, если запрашиваемая конфигурация не найдена.
Рис. 2.5. Диалоговое окно выбора базы данных 1С (появилась новая конфигурация)
Чтобы можно было настроить (реорганизовать) конфигурацию, следует выбрать ее в списке (см. рис. 2.5) и нажать кнопку ОК.
Если конфигурация новая, на экране появится диалоговое окно для выбора типа базы данных: локальная (на основе DBF-файлов) или удаленная ("клиент- сервер") в среде MS SQL Server (рис. 2.6).
В нашем случае необходимо указать вариант локальной базы данных: Файлы *.DBF; *.CDX, а также формат кодировки кириллицы (1251).
На рис. 2.7 показан список файлов и папок, созданных программой 1С для пустой конфигурации.
Примечание
Информационная модель конфигураций 1С в недостаточной степени документирована. И это представляет трудности в случаях, когда требуется обеспечить доступ к данным из других приложений, вне контекста системы 1 (^Предприятие. Эти вопросы будут более подробно рассмотрены в части II.
Чтобы изменить конфигурацию (реорганизовать базу данных), необходимо ее открыть. Это можно сделать из меню Конфигуратора или нажав на соответствующую кнопку (рис. 2.8).
Рис. 2.6. Диалоговое окно выбора типа базы данных 1С
Рис. 2.7. Список файлов в папке E:\lC_exarnple.ОВ\ (пустая конфигурация)
^Конфигуратор - Задача
Файл Действия Конфигурация Конструкторы Дднииистр.фоваиие
jO gSQ y ^Й!€
^ {:* Э С А[
Нажжт* для редактирования аоифигурац*
I i ^5 ® е ; ,j £ ; Й Й ; ifo ^ & 1
Рис. 2.8. Панель инструментов конфигуратора 1С (кнопка редактирования)
простой справочник "Список физических лиц".
Примечание
В терминологии 1С справочником называется объект программы, позволяющий пользователю вводить, хранить и получать информацию, структурируя ее в виде дерева. Справочник представляется списком древовидной структуры, в узлах которого хранится информация о различных объектах. Информация хранится в виде записей, все узлы дерева хранят записи одной структуры, содержащей различные величины. Набор этих величин для каждого справочника произволен за исключением двух строковых величин: кода объекта и значе-
ния объекта. Код объекта является уникальным для данного справочника и пл зволяет ссылаться на этот объект из других местпрограммы Значке объек объекта) °ЛЬНаЯ СТР0Ка' введенная пользователем (обычно это название
спра-спра-Для создания нового справочника следует в конфигурации выделить . воч^ик ("иТ".5. ВЫЗВаВ ВСПЛЬ'ВаЮЩее МеНЮ’ вь,бРать ПУ^ Новый
спра-
спра-
Рис. 2.9. Всплывающее меню конфигуратораРис. 2.9. Всплывающее меню конфигуратора
Рис. 2.9. Всплывающее меню конфигуратора
Рис. 2.9. Всплывающее меню конфигуратора
На экране появится диалоговое окно настройки справочника (рис. 2.10).
XXКонструктор Справочника
X
X
Идентификатор. [физЛица
СинонимСиноним[Слисок Физических лит[Слисок Физических лит
Синоним
Синоним
[Слисок Физических лит
[Слисок Физических лит
Комментарий [Пример
Обязательно укажите итентификатор справочника. Поле "Синоним" может быть заполнено для представления вида справочника в режиме запуска "1 СПредгриятие" В пола "комментарий" можно ввести поясняющую информацию.
17 Использовать конструкторы для создания новых объектов
^Незац | flaneg> | Гпто^ | Отмена [ Помощь |
Рис. 2.10. Диалоговое окно создания нового справочника(идентификатор справочника)
-авИ
Глава 2. Подготовка к изучению материала этой части. Конфигурация 1С 9 Идентификатор справочника должен быть уникальным в контексте данной конфигурации.
Примечание
В терминологии 1С идентификатор — краткое наименование объекта метаданных. Идентификатор используется для обозначения объекта метаданных в списках и диалогах, а также служит для обращения к объекту метаданных в программных модулях.
Все обращения через механизм OLE Automation к этому справочнику также производятся с использованием этого идентификатора.
ххЧтобы продолжить создание справочника, нажмите кнопку Далее (рис. 2.10). На экране поочередно появятся диалоговые окна (рис. 2.11 и 2.12). Здесь также нужно нажать кнопки Далее и Готово соответственно, ничего не меняя.
х
х
Конструктор Справочника
Г |СоаДОТЬ НО»1Й ВИД-Й&'онГС!Идентификатор l.vw cytiKOfflo: fГ |СоаДОТЬ НО»1Й ВИД-Й&'онГС!Идентификатор l.vw cytiKOfflo: f
Г |СоаДОТЬ НО»1Й ВИД-Й&'онГС!
Идентификатор l.vw cytiKOfflo: f
Г |СоаДОТЬ НО»1Й ВИД-Й&'онГС!
Идентификатор l.vw cytiKOfflo: f
Отмена | Помощь |Отмена | Помощь |< Назад< НазадДале$ >Дале$ >ГотовоГотовоРис. 2.11. Диалоговое окно создания нового справочника (продолжение)Рис. 2.11. Диалоговое окно создания нового справочника (продолжение)
Отмена | Помощь |
Отмена | Помощь |
< Назад
< Назад
Дале$ >
Дале$ >
Готово
Готово
Рис. 2.11. Диалоговое окно создания нового справочника (продолжение)
Рис. 2.11. Диалоговое окно создания нового справочника (продолжение)
Если справочник предполагается использовать для ведения аналитического учета по бухгалтерским счетам, то необходимо создать вид субконто имеющий тип данного справочника. Конструктор предлагает автоматически создать такой вид субконто
На рис. 2.13 представлено диалоговое окно настройки справочника. Создаваемый справочник прост, потому что предназначен для тренировочных целей. Значения всех полей, кроме Длина наименования, можно оставить установленными по умолчанию.
Рис. 2.12. Диалоговое окно создания нового справочника (продолжение)
Рис. 2.13. Диалоговое окно создания нового справочника (свойства и реквизиты справочника)
Поле Длина наименования представляет интерес потому, что в свойстве Наименование будут храниться фамилия, имя и отчество физического лица. Поэтому необходимо увеличить значение его длины относительно принятого по умолчанию. Здесь следует отметить, что код и наименование являются общими свойствами всех справочников конфигурации 1С. Максимальная длина кода элемента справочника — 24 символа.
Если в справочнике нужно хранить дополнительную информацию, то для этого используются реквизиты справочника. Расширим справочник дополнительной информацией:
Дата рождения (тип дата);
Домашний адрес (тип Строка).
Чтобы внести новый реквизит в справочник, нужно нажать кнопку Новый в группе Реквизиты (см. рис. 2.13). Затем в диалоговом окне настройки реквизита (рис. 2.14 и 2.15) следует указать идентификатор реквизита, его синоним и тип. В контексте данного справочника идентификатор реквизита должен быть уникальным. В зависимости от типа реквизита может потребоваться внести дополнительную информацию о реквизите, например: Длина (для типа Строка или Число). Точность (для типа число) и другие данные (на вкладке Дополнительные).
Рис. 2.14. Диалоговое окно создания нового справочника (новый реквизит типа Дата)
Идентификатор: (физЛицаКомментарий: (ПримерКол-ва уровней: |1 -г|Идентификатор: (физЛицаКомментарий: (ПримерКол-ва уровней: |1 -г|Подчинен:Подчинен:СинонимСиноним| |не подчинено)(Слисок Физических лиц| |не подчинено)(Слисок Физических лицДлина кдда Длина наименованияДлина кдда Длина наименования556464Разметать гг^ты сверху Автоматическая нумерация Контроль уникальностиРазметать гг^ты сверху Автоматическая нумерация Контроль уникальностиFFI7I7г Серии кодов ; О Во всем справочнике | ^ В пределах подчиненияг Серии кодов ; О Во всем справочнике | ^ В пределах подчиненияРеквизитыI | ДатаРожденияРеквизитыI | ДатаРожденияновый!новый!IIIIТип кода — ^ Числова О ТекстовеТип кода — ^ Числова О ТекстовеСвойства РеквизитаСвойства РеквизитаОбщие | Дополнительные |Общие | Дополнительные |□□- Основное пр Г В виде кс<• В виде н<- Основное пр Г В виде кс<• В виде н<Идентификатор:Синоним:Идентификатор:Синоним:] ДомашнийАдрес (Домашний адрес] ДомашнийАдрес (Домашний адрес§1§1Г ОднафогГ ОднафогКомментарий:Тип значенияКомментарий:Тип значения[«Строка»[«Строка»ОКОКДлина-Длина-Точность: |0Точность: |0ОтменаОтменаОбновитьОбновить
Идентификатор: (физЛица
Комментарий: (Пример
Кол-ва уровней: |1 -г|
Идентификатор: (физЛица
Комментарий: (Пример
Кол-ва уровней: |1 -г|
Подчинен:
Подчинен:
Синоним
Синоним
| |не подчинено)
(Слисок Физических лиц
| |не подчинено)
(Слисок Физических лиц
Длина кдда Длина наименования
Длина кдда Длина наименования
5
5
64
64
Разметать гг^ты сверху Автоматическая нумерация Контроль уникальности
Разметать гг^ты сверху Автоматическая нумерация Контроль уникальности
F
F
I7
I7
г Серии кодов ; О Во всем справочнике | ^ В пределах подчинения
г Серии кодов ; О Во всем справочнике | ^ В пределах подчинения
Реквизиты
I | ДатаРождения
Реквизиты
I | ДатаРождения
новый!
новый!
II
II
Тип кода — ^ Числова О Текстове
Тип кода — ^ Числова О Текстове
Свойства Реквизита
Свойства Реквизита
Общие | Дополнительные |
Общие | Дополнительные |
□
□
- Основное пр Г В виде кс
<• В виде н<
- Основное пр Г В виде кс
<• В виде н<
Идентификатор:
Синоним:
Идентификатор:
Синоним:
] ДомашнийАдрес (Домашний адрес
] ДомашнийАдрес (Домашний адрес
§1
§1
Г Однафог
Г Однафог
Комментарий:
Тип значения
Комментарий:
Тип значения
[«Строка»
[«Строка»
ОК
ОК
Длина-
Длина-
Точность: |0
Точность: |0
Отмена
Отмена
Обновить
Обновить
ВВЕЗВВЕЗ"■' Справочник ФизЛица
ВВЕЗ
ВВЕЗ
1
Рис. 2.15. Диалоговое окно создания нового справочника (новый реквизит типа Строка)
В задачу данной книги не входит детальное описание возможностей 1С, поэтому ограничимся простым справочником.
На рис. 2.16 представлено дерево конфигурации, где отражен новый справочник.
В 1^1 Задача
Г S Константы
5S Справочники
ФизЛица
ДатаРождения
ДомашнийАдрес
Рис. 2.16. Новый справочник в списке конфигурации 1С
Чтобы сохранить сделанные в конфигурации изменения, нужно нажать соответствующую кнопку на панели Конфигуратора 1С (рис. 2.17).
Глава 2. Подготовка к изучению материала этой части. Конфигурация 1С
Сохранить изменения в конфигурацииСохранить изменения в конфигурацииРис. 2.17. Панель инструментов конфигуратора 1С (кнопка сохранения конфигурации)Рис. 2.17. Панель инструментов конфигуратора 1С (кнопка сохранения конфигурации)Рис. 2.18. Запрос на подтверждение сохранения изменений в конфигурацииРис. 2.18. Запрос на подтверждение сохранения изменений в конфигурации
Сохранить изменения в конфигурации
Сохранить изменения в конфигурации
Рис. 2.17. Панель инструментов конфигуратора 1С (кнопка сохранения конфигурации)
Рис. 2.17. Панель инструментов конфигуратора 1С (кнопка сохранения конфигурации)
Рис. 2.18. Запрос на подтверждение сохранения изменений в конфигурации
Рис. 2.18. Запрос на подтверждение сохранения изменений в конфигурации
Далее следует запрос на подтверждение (рис. 2.18).
На рис. 2.19 представлен запрос, характерный для новой конфигурации или для случаев, когда по каким-то причинам отсутствует файл 1Cv7.DD.
(Конфигуратор
Отсутствует старый словаре данных! Продолжить?
Да ] Нет |
Рис. 2.19. Запрос на создание файла 1Cv7.DD
Здесь следует отметить, что текстовый файл 1Cv7.DD — это словарь данных. Имя этого файла зависит от формата хранения таблиц базы данных (см. рис. 2.6). Для локальной базы данных (формат DBF) имя файла: 1Cv7.DD. В случае, если база данных размещается в среде MS SQL Server, имя этого файла: 1Cv7.DDS.
Примечание
Более детально структура словаря данных (1Cv7.DD) будет рассмотрена в части II.
Имя -
| Размер
Тип
I Изменен|
OSY5L06
Папка с файлами
12.06.2006 И:27
Й 1CV7.LCK
ОКБ
Файл "LCK"
12.06.2006 И:27
ONEW.STRU
Палка с файлами
12.06.2006 15:06
^!Cv7.DD
9 КБ
Файл "DD"
12.06.2006 15:06
®jllSBLOB
5 КБ
Active Server Docu...
12.06.2006 15:07
У 1SBL0B.DBF
1КБ
Файл"DBF"
12.06.2006 15:07
$1SCON5T
6 КБ
Active Server Docu...
12.06.2006 15:07
5 15CONST.D6F
1КБ
Файл"DBF"
12.06.2006 15:07
$15CRDOC
6 КБ
Active Server Docu...
12.06.2006 15:07
5 15CRDOC.DBF
1КБ
Файл"DBF"
12.06.2006 15:07
^ISDNLOCK
5 КБ
Active Server Docu...
12.06.2006 15:07
51SDM.OCK.D8F
1КБ
Файл"DBF"
12.06.2006 15:07
ф 1SJOURN
ЦКБ
Active Server Docu...
12.06.2006 15:07
S ISJOURN.DBF
1КБ
Файл "DBF"
12.06.2006 15:07
315SYSTEM.DBF
1КБ
Файл"DBF"
12.06.2006 15:07
§?15UIDCTL
5 КБ
Active Server Docu...
12.06.2006 15:07
515UIDCTL.DBF
1КБ
Файл"DBF"
12.06.2006 15:07
15U5ER5.D8F
1 КБ
Файл "DBF"
12.06.2006 15:07
a 1CV7.MD
63 КБ
Файл "MD"
12.06.2006 15:07
5$SC12
8 КБ
Active Server Docu...
12.06.2006 15:07
@)5C12.DBF
1КБ
Файл"DBF"
12.06.2006 15:07
Далее Конфигуратор представит список сделанных изменений. Если эти изменения корректны, их следует принять, нажав соответствующую кнопку (рис. 2.20).Далее Конфигуратор представит список сделанных изменений. Если эти изменения корректны, их следует принять, нажав соответствующую кнопку (рис. 2.20).После реорганизации структуры на экран выводится соответствующее сообПосле реорганизации структуры на экран выводится соответствующее сообщение (рис. 2.21).щение (рис. 2.21).ЦРеоргакизация информацииЦРеоргакизация информациихх- Изменения в структуре информацииАнализ изменений е структуре информацииНовый справочник - ФизЛицаОбработка справочника: ФизЛица- Изменения в структуре информацииАнализ изменений е структуре информацииНовый справочник - ФизЛицаОбработка справочника: ФизЛицаПринятьПринятьОтменаОтменаРис. 2.20. Список изменений в конфигурации, которые будут сохраненыРис. 2.20. Список изменений в конфигурации, которые будут сохраненыРис. 2.21. Сообщение об окончании реорганизации конфигурацииРис. 2.21. Сообщение об окончании реорганизации конфигурации
Далее Конфигуратор представит список сделанных изменений. Если эти изменения корректны, их следует принять, нажав соответствующую кнопку (рис. 2.20).
Далее Конфигуратор представит список сделанных изменений. Если эти изменения корректны, их следует принять, нажав соответствующую кнопку (рис. 2.20).
После реорганизации структуры на экран выводится соответствующее сооб
После реорганизации структуры на экран выводится соответствующее сооб
щение (рис. 2.21).
щение (рис. 2.21).
ЦРеоргакизация информации
ЦРеоргакизация информации
х
х
- Изменения в структуре информации
Анализ изменений е структуре информации
Новый справочник - ФизЛица
Обработка справочника: ФизЛица
- Изменения в структуре информации
Анализ изменений е структуре информации
Новый справочник - ФизЛица
Обработка справочника: ФизЛица
Принять
Принять
Отмена
Отмена
Рис. 2.20. Список изменений в конфигурации, которые будут сохранены
Рис. 2.20. Список изменений в конфигурации, которые будут сохранены
Рис. 2.21. Сообщение об окончании реорганизации конфигурации
Рис. 2.21. Сообщение об окончании реорганизации конфигурации
Рис. 2.22. Список файлов в папке E:\1C_example.DB\ (после реорганизации)
■■*6 ■ --•. - ^- . .
На этом простом примере рассмотрение вопроса создания и изменения конфигурации 1 С:Предприятие заканчивается. Те, кто желает ознакомиться с этим процессом более детально, должны использовать соответствующую специальную литературу.
В дальнейшем, по ходу изложения, мы будем неоднократно наращивать конфигурацию, дополняя ее другими объектами метаданных.
Определенный интерес для программиста может представлять содержание папки, где размещена созданная конфигурация (E:\lC_example.DB\).
На рис. 2.22 показан список файлов и папок, созданных программой 1С после того, как был создан справочник "Список физических лиц".
Назначение некоторых файлов приведено в табл. 2.1.
Таблица 2.1. Файлы в папке конфигурации системы 1 (^Предприятие
Файл
Назначение
1CV7.MD
Файл конфигурации. Здесь хранится вся информационная структура данных. Редактирование этого файла осуществляется Конфигуратором 1С
1CV7.DD
Словарь данных (текстовый файл). Содержит описания структуры таблиц и индексов базы данных программы ^Предприятие. Этот файл генерируется автоматически
1Cv7.LCK
Появляется в том случае, если конфигурация открыта программой 1С:Предприятие или Конфигуратором
1SBLOB.*
Здесь хранятся значения реквизитов справочников, документов и счетов имеющих тип Строка неограниченной длины
1SCONST.*
Здесь хранятся значения констант, периодических реквизитов справочников и бухгалтерских счетов
1SCRDOC.*
Здесь хранятся вхождения документов в графы отбора, списки подчиненных документов, вхождения документов в общие журналы, для которых определен состав документов
1SDNLOCK."
Здесь хранится временный список номеров документов, которые вводятся в данный момент
JSJOURN.*
1SSYSTEM.DBF
Здесь хранятся журналы документов
Содержит общие параметры информационной базы (точка актуальности, рассчитанный период бухгалтерских итогов, периодичность оперативных итогов и т. п.)
1SUIDCTL*
Здесь хранятся уникальности (дополнительный контроль уникальности внутренней идентификации объектов)
1SUSERS.DBF
Содержит число соединений с базой данных, счетчик изменений данных пользователями
SC12."
Справочник "Список физических лиц" (в нашем случае)
Чтобы заполнить созданный справочник "Список физических лиц" информацией. нужно запустить программу 1С:Предприятие. Сделать это можно из Конфигуратора, нажав соответствующую кнопку (рис. 2.23).
£*Конфигуратор - Задача - [Конфигурация]
8^ Файл Действия Конфигурация Конструкторы Администрирование
jo ^ Ы ! * ^ р ^i' с$ Я з с м|“~«
^■^X'^^»® ':fi ;gg :j!»№№®|
'^Запустить программу 1С для работы с базой данных
Рис. 2.23. Панель инструментов конфигуратора 1С (кнопка запуска 1С:Предприятия)
Когда программа 1С:Предприятие запустится, откроем список доступных справочников с помощью меню (рис. 2.24).
В списке доступных справочников выберем строку Список физических лиц (Пример) и нажмем кнопку ОК (рИс. 2.25).
Рис. 2.24. Меню 1С:Предлриятие (выбор списка справочников для редактирования)Рис. 2.24. Меню 1С:Предлриятие (выбор списка справочников для редактирования)Рис. 2.25. Список справочников для выбораРис. 2.25. Список справочников для выбора
Рис. 2.24. Меню 1С:Предлриятие (выбор списка справочников для редактирования)
Рис. 2.24. Меню 1С:Предлриятие (выбор списка справочников для редактирования)
Рис. 2.25. Список справочников для выбора
Рис. 2.25. Список справочников для выбора
На экране появится окно, отражающее содержание справочника. В данном случае справочник пуст. Чтобы внести информацию, вызовем всплывающее меню и выберем пункт Новый (рис. 2.26).
Рис. 2.26. Всплывающее меню для работы со справочникомРис. 2.26. Всплывающее меню для работы со справочником
Рис. 2.26. Всплывающее меню для работы со справочником
Рис. 2.26. Всплывающее меню для работы со справочником
Затем внесем фамилию, имя, отчество, домашний адрес и дату рождения для физического лица, как показано на рис. 2.27.
Повторяя эту процедуру, внесем информацию о других физических лицах.
Рис. 2.27. Ввод данных в справочник ФизЛицаРис. 2.27. Ввод данных в справочник ФизЛица
Рис. 2.27. Ввод данных в справочник ФизЛица
Рис. 2.27. Ввод данных в справочник ФизЛица
На рис. 2.28 представлен список введенных физических лиц.
Как видим, список отсортирован не в том порядке, как данные вводились. Следует отметить, что в данном случае порядок сортировки был определен выбором переключателя в группе Основное представление (см. рис. 2.13). По умолчанию в этой группе выбран переключатель В виде наименования, что и определило порядок сортировки.
Созданный нами справочник отражается в словаре данных (файл !Cv7.DD) так, как показано на рис. 2.29. ГОУ 00 СПО «ТЭЕ»
.^ БИБЛИОТЕКА
Код
Намменование
Дата...
Домашний адрес
Аксакалов Аксакал Аксакапович
01 01.70
Россия, г.Б. ул Б. д.00
1
Иванов Иван Иванович
01.01.71
Россия. г.Неизвестный. ул.А. д.01
Aj
2
Петров Петр Петрович
01 01 72
Россия, г Неизвестный, улА. д.02
3
Сидоров Сидор Сидорович
01 01 73
Россия, г Неизвестньй, ул.А. д.03
4
Федоров Федор Федорович
01.01.74
Россия, г Известный. ул.Б. д.001
Г
Рис. 2.28. Содержание справочника ФизЛица после редактирования(сортировка по наименованию)
#—ТАВЫ по 8: Слраеоххих ♦ихЛкца
• Наае T-SC12
IDescr|Type|A/S/U) IDBTebleNaaeI Reusable
|С пр a soi км* •мвЛицдIXISC1211
IFields
# Naae 7-ID F-CQDX F"DISCR ?-ISlU№
leaser1 Type 1 LengthI Precision
1 ID objectIC19|0
(Object code|C15(0
(object descriptionIC|6410
(Flag ObjectisHarkelC|1|0
F-VIR3TABP I Version st марIC 1610
F-SP15
F-SP16
I (ПХмеаРохдакиаID(8(0
НР)Домаша«АМресIC164(0
I-Indexes
t Naae I-IDD I-CODI I-DZSCR
IDescr| Uni c^uel Indexed fields(DBNaae
lof ID10IIPHDD
lot ССФ110iCaDKUPMR)ICODI
lof DISC»10IDISCR(UPPIR)IDKSCR
Рис. 2.29. Содержание файла 1Cv7.DD
Эта информация будет полезна при рассмотрении вопросов доступа к базе; данных 1С без использования механизма OLE Automation.
Для того чтобы подробнее изучить доступ к информации базы данных 1С,| в дальнейшем нужно будет расширить созданную конфигурацию. Мы будем; делать это по ходу изложения материала.
В следующей главе рассматриваются вопросы подключения к системе- 1С:Предприятие как к серверу OLE Automation.
лШ/ ;
Глава 3
Подключение к 1С
Для иллюстрации механизма подключения к программе 1 С:Предприятие создадим в среде Delphi простое приложение, которое будет считывать информацию из справочника "Список физических лиц", созданного в предыдущей главе.
Первый этап
Примечание
Исходные тексты содержатся на сопроводительном компакт-диске книги в файле Part_1\Chapter_03\Topic_3_1\sp_Connectjo_lC_01.PAS.
Создадим новый проект.
Поместим в форму два компонента трапе! (свойство Align компонента Panell установим равным AlTop, а компонента Рапе12 —AlClient).
На панель Panell добавим кнопку Buttoni (TButton) и установим для нее свойство Caption = "Соединить".
Добавим на панель Panell еще 4 компонента — Labeii, Editi. Labels,
Edits — и установим их свойства:
Labell.Caption = "Имя 1С-сервера = ”
Labels.Caption = "Строка инициализации = "
Editi.Text = "V77.Application"
Edits.Text = " /DE:\lC_example.DB "
Поместим на панель Panels компонент ListBoxi (TListBox); его свойство Align установим равным AlClient.
Внешний вид созданной формы представлен на рис. 3.1.
Рис. 3.1. Форма примера подключения к 1С (первый этап)
Поле Editi.Text содержит имя 1С как сервера OLE Automation (мы указали V77 .Application). Возможные значения (согласно документации по 1С):
VICEnterprise.Application—независимый КЛЮЧ;
77 .Application — зависимый ключ;
77s. Application — зависимый ключ, SQL-версия;
77L.Application — зависимый ключ, локальная версия;
77м. Application — зависимый ключ, сетевая версия.
Поле Edit2.Text содержит строку инициализации 1С. Мы указали /DE: \lc_example.DB, т. е. местонахождение базы данных, к которой желаем подключиться.
Некоторые возможные значения ключей (согласно документации по 1С):
/о папка — имя каталога (папки), где располагается база данных;
/м — монопольный доступ;
/N Имя пользователя".
/РПароль доступа.
Пример: /DE:\lC_example.DB /ЫАдмин /Р123.
Дополним исходный текст программы (в листинге 3.1 изменения выделены полужирным).
t™^.,™..^...,.....,..,,.„...,...._,,.v^^ ,,..,_ .,._„,„._,,_
рЛистинг 3.1. Изменения в исходном тексте программы
uses
CcoObj,
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls;
type
TForml = class (TForm)
Panel1: TPanel;
Panel2: TPanel;
Buttonl: TButton;
Label1: TLabel;
Label2: TLabel;
Editl: TEdit;
Edit2: TEdit;
ListBoxl: TListBox;
procedure ButtonlClick(Sender: TObject); private
( Private declarations }
OlelC: Olevariant;
public
{ Public declarations }
end;
Переменная oleic (типа olevariant) будет использована в дальнейшем, как указатель на объект 1С (сервер OLE Automation).
Сделаем двойной щелчок на компоненте Buttonl и изменим стандартный обработчик события (нажатия кнопки), как показано в листинге 3.2.
procedure TForml.ButtonlClick(Sender: TObject);
Var
ResOpen: integer;
begin
OlelC:= CreateOleObject(Editl.Text);
ResOpen:=OlelC.Initialize(OlelC.RMTrade, Edit2.Text, '*); end;
Здесь следует сделать некоторые пояснения.
Строка
OlelC:= CraateOleObject(Editl.Text);
собственно, "запускает" программу 1С как OLE-сервер автоматизации (ИМЯ указано В Editl. Text).
Строка
ResOpen:=01elC.Initialize(OlelC.RMTrade, Edit2.Text, '');
инициализирует программу IC согласно информации, содержащейся в Edit2.Text.
Примечание
Подробную информацию можно найти в соответствующей документации по 1 С.
Сохраним проект под именем sp_Connect_to_lC_01.DPR (или любым другим, на усмотрение читателя), откомпилируем его и запустим приложение sp_Connect_to_ 1 С_01 .EXE.
Нажмем кнопку Соединить. Если все указано корректно (поля Editi.Text и Edit2.Text), то программа 1С запустится как сервер OLE Automation.
Если на компьютере не установлена программа 1С:Предприятие, появится сообщение (рис. 3.2).
Рис. 3.2. Сообщение, появляющееся в случае, если изданном компьютере программа 1С не установлена
На рис. 3.3 показан внешний вид окна программы 1С:Предприятие в момент загрузки конфигурации.
Если в строке инициализации не указаны имя пользователя и (или) пароль доступа, то может последовать запрос на авторизацию (рис. 3.4).
Если некорректно указан каталог конфигурации (базы данных), то появится соответствующий запрос (рис. 3.5).
•Г Пример использования 1С, как OLE - сервера авто... ВЕИ
С1998 1999 фирме 1б. Все проев заироиены»
Загрузка структуры данных программы
Лицею*» не программ! принадлежит;
Sergey/у' г ■
■Ноте:; М:/у V
Строка инициализации = | /О Е: \1 C_example.DВ
1С:Предприятие
Версия 7^7:
Рис. 3.3. Программа 1С:Предприятие запустилась, как сервер OLE Automation
'Авторизация доступа
^ Пользователь: |Админ
VT Пароль:I
Предприятие
Версия 7.7
х
tlS
OK | Отмена | Помощь |
ГО В
'iwweirHriwPswrr'pwnQVT^^~—Г”
yat$L^LZ/ > ,';'Л, '• е 1996-1999 фирме 1 с. Воепрееаее
**■
Рис. 3.4. Запрос на авторизацию пользователя
Рис. 3.5. Диалоговое окно выбора базы данных 1С
После загрузки и инициализации программы 1С ссылка на нее хранится в переменной oieic.
Следует помнить, что программа 1С:Предприятие (как и все создаваемые объекты OLE Automation), выступающая в качестве объекта OLE Automation в другой программе, будет находиться в памяти компьютера до удаления или изменения значения переменной, содержащей ее в качестве указателя на объект. Именно поэтому мы вынесли объявление переменной oleic "за пределы" обработчика TForml. ButtonlClick.
Явных (видимых) признаков того, что мы запустили 1С, нет. Это связано с тем, что программа 1С:Предприятие в режиме сервера OLE Automation скрывает свое окно. В дальнейшем будут рассмотрены способы визуализации окна 1С.
Удостовериться в том. что программа 1С запущена, можно, запустив диспетчер задач (комбинация <Ctrl>+<Alt>+<E>el>). В списке процессов (вкладка Процессы) можно увидеть строку lcv7s.exe (рис. 3.6) — это свидетельствует о том, что программа 1С активна.
После закрытия программы sp_Connect_to_lC_01.EXE автоматически выгрузится из памяти и программа 1С.
^ Диспетчер задач Windows
Файл Параметры Вид Завершение работы СправгПриложения Процессы | Быстродействие ] Сеть | Г
Имя образа svchost.exe tasl-mgr.exeИмя образа svchost.exe tasl-mgr.exePIP | Имя n~4056 SYSTEM3180 SergeyPIP | Имя n~4056 SYSTEM3180 Sergeysp Connect to IC 01.exesp Connect to IC 01.exe314Э Sergey314Э Sergey3144 Sergey |3144 Sergey |
Имя образа svchost.exe tasl-mgr.exe
Имя образа svchost.exe tasl-mgr.exe
PIP | Имя n~
4056 SYSTEM
3180 Sergey
PIP | Имя n~
4056 SYSTEM
3180 Sergey
sp Connect to IC 01.exe
sp Connect to IC 01.exe
314Э Sergey
314Э Sergey
3144 Sergey |
3144 Sergey |
Рис. 3.6. Отображение программы 1 С: Предприятие в списке запущенных процессов
Второй этап
Возьмем за основу предыдущий проект и дополним его.
Примечание
Исходные тексты находятся на сопроводительном компакт-диске книги в файле \Part_1 \Chapter_03\Topic_3_2\sp_Connect_to_1 C_02.PAS.
Поместим на панель Paneli еще одну кнопку Buttons (TButton) и текстовое Поле Edit3 (TEdit).
Установим значения свойств:
Buttons.Caption = "Справочник*
Edit3.Text = "ФизЛица"
IS Пример использования 1С, как OLE - сервера авто... ВВЕЗ|
■ Соединить I Справочник ^ФизЛица ) Имя 1С-сервера (OLE Automation) - |V77.Applicalion I Строка инициализации = (/DE \ic_exampte DB
Рис. 3.7. Форма примера подключения к 1С (второй этап)
Сделаем двойной щелчок на кнопке Buttons и изменим стандартный обработчик события (нажатия кнопки), как показано в листинге 3.3.
Листинг 3.3. Считывание информации из справочника ФиаЛина . ;
procedure TForml.Button2Click(Sender: TObject) ;
Var
OleFizLica: OleVariant;
begin
OleFizLica:= OBaseigned; //1
ListBoxl.Items.Clear;
if not VarlsBvty(OlelC) then begin //2
OleFizLica:=OlelC.CreateObject('Справочник.’♦Edit3.Text); //3
if not VarleEnpty(OleFizLica) then begin //4
if OleFizLica.Выбрать Элементно then begin //5
while OleFizLica.ПолучитьЭлемакт>0 do //6
begin
ListBoxl.Itens.Add(
Trim(01eFizLica.Koд)+'1 //7
+ TrimfOleFizLica.Наименование)+' ' //8
+ TriIn(01eFizLica.ДaтaPoждeния)+• ' //9
* Trim(OleFizLica.ДомашнийАдрес) //10
);
Application.ProcessMessages;
end;
end;
end;
end;
OleFizLica:= Unassigned; //11 end;
Переменная OleFizLica (типа OleVariant) служит указателем на объект 1С Справочник.ФизЛица.
Строки 1 и И (номера строк указаны в комментариях листинга):
OleFizLica:= □naaeigned;
Здесь "обнуляется" значение переменной OleFizLica. Тем самым, если ранее был создан какой-либо OLE-объект, на который ссылалась эта переменная, он будет уничтожен. В данном случае это излишки кода обработчика; эти строки оставлены лишь в качестве иллюстрации.
Строка 2:
if not VarlsEnpty (OlelC) then begin
Это проверка: значение переменной oleic не должно быть "пустым". То есть "непустое" значение переменной oleic означает (в контексте нашего проекта), что программа 1С запущена (как сервер OLE Automation) и связь с ней установлена.
Строка 3:
OleFizLica:=01е1С.CreateObject(•Справочник.'+Edit3.Text);
Здесь создается объект, который ссылается на спавочник с идентификатором Физлица. Если такой справочник существует, то в дальнейшем переменная OleFizLica будет содержать ссылку на него.
Строка 4:
if not VarlaBnpty (OleFizLica) then begin
Это проверка: значение переменной OleFizLica не должно быть "пустым". То есть "непустое" значение переменной OleFizLica означает (в контексте нашего проекта), что объект 1С Справочник.Физлица создан и можно обращаться к его свойствам и методам.
Строки 5 и 6:
if OleFizLica.ВыбратьЭлементы>0 then begin
while OleFizLica.Получить3лемент>0 do
Здесь вызываются методы объекта типа Справочник:
Выбрать элементы — осуществляет выборку элементов справочника;
получитьЭлемент — осуществляет позиционирование на каждом элементе справочника поочередно в цикле до тех пор, пока не вернет значение 0.
Строки 7—10 организуют обращение к свойствам и реквизитам текущего элемента справочника.
Примечание
Функция Trim О используется для того, чтобы конвертировать значение типа Variant (возвращаемое через механизм OLE) в строковое значение. Если не предусмотреть этого, то может последовать исключение (рис. 3.8 и 3.9).
Рис. 3.8. Сообщение об исключении, вызванном некорректной операцией с переменной типа Variant
Лея»
Рис. 3.9. Сообщение об исключении, вызванном некорректной операцией с переменной типа Vari ап с
Сохраним проект в файле с именем sp_Connect_to_lC_02.DPR (или любым другим, на усмотрение читателя), откомпилируем его и запустим приложение sp_Connect_to_lC_02.EXE.
Нажмем кнопку Соединить, а после того как программа 1С загрузится (см. предыдущий пример), — кнопку Справочник.
Если все указано корректно (поле Edic3.Text). программа 1С создаст объект типа справочник.Физлица, ссылка на который будет размещена в переменной oleFizLica. Затем информация из справочника будет считана и размещена в списке ListBoxi (рис. 3.10).
-Г Пример использования LC, как OLE - сервера автомати... BBI3
; Соединить |[ Справ'очник]| (ФизЛица
| Имя 10-сервера (OLE Automation]- |V77.Application j Строка инициализации - |/DE \1C_exarnple.D8
5 Аксакалов Аксакал Аксакалович 01.01.1970 Россия. г.Б, ул Б. д 00
Иванов Иваи Иванович 01.01 1971 Россия, г Неизвестный. ул А. д.01
Петров Петр Петрович 01 01 1972 Россия, г Неизвестный. улА.д 02
Сидоров Сидор С^орович 01.01.1973 Россия, г.Неизвестный. ул.А, д.03
Федоров Федор Федорович 01.01 1974 Россия. г.Известный. ул.Б .д.001
Рис. 3.10. Результат считывания информации из справочника "Список физических лиц"
Примечание
Порядок считывания элементов справочника (при обращении к методу получить Элемент) определяется порядком сортировки справочника "Список физических лиц", указанным в Конфигураторе (см. рис. 2.13).
В следующей главе более подробно рассмотрены вопросы считывания информации из базы данных 1С.
Глава 4
Доступ к информации 1С из внешних приложений
Прежде чем приступить к программированию, рассмотрим основные типы данных, применяемые в системе 1С для формирования информационных структур конфигураций (отражения свойств и методов объектов в предметной области).
Поддерживаются следующие типы данных:
базовые типы данных:
Числовой
Строковый
Дата
агрегатные типы данных — это специализированные типы данных системы 1 С: Предприятие. К агрегатным типам данных, участвующим в формировании информационной структуры, относятся:
Константа
Справочник
Перечисление
Документ
Регистр
ПланСчетов
Счет
ВидСубконто
Операция
БУхгалтерскиеИтоги
^УрналРасчетов
2 Ък. 1064
ВидРасчета
ГруппаРасчетов
Календарь
Периодический
У агрегатных типов данных есть атрибуты (свойства агрегатного типа данных) и .методы (действия, которые может выполнять агрегатный тип данных). Например, в главе 3 мы обращались к методам выбратьЭлементы] и ПолучитьЭлемент агрегатного типа данных справочникI
Примечание।
В системе 1С:Предприятие можно обращаться к именам типов данных, им атрибутам и методам как в русском, так и англоязычном написании (табл. 4.1). I
Таблица 4.1. Агрегатные типы данных и их англоязычные синонимьА в системе 1 (^Предприятию
Агрегатный тип данных
Англоязычный синоним
Константа
Const
Справочник
Reference
Перечисление
Enum
Документ
Document
Регистр
Register
ПланСчетов
ChartOfAccounts
Счет
Account
ВидСуОконто
SubcontoKind
Операция
Operation
БухгалтерекиеИтоги
BookkeepingTotals
ЖурналРасчетов
CalcJournal
ВидРасчета
CalculationKind
ГруппаРасчетов
CalculationGroup
Календарь
Calendar
Периодический
Periodic
Типы данных в системе 1С:Предприятие имеют числовой эквивалент, или код (табл. 4.2).
Таблица 4.2. Коды типов данных в системе 1 (^Предприятие
Тип данных
Код
Неопределенный
0
Числовой,
1
Строковый
2
дата
3
Перечисление
10
Справочник
11
документ
12
Календарь
13
ВидРасчета
14
Счет
15
ВидСубконто
16
ПланСчетов
17
Внешний объект (прочие агрегатные объекты)
100
Примечание
Более подробную характеристику и назначение всех указанных выше типов данных можно найти в любой специальной литературе по системе 1С:Предприятие (здесь не приводится).
В рамках данной книги мы рассмотрим способы обращения к информации различных типов данных 1С:Предприятие на конкретных примерах.
Примечание
Представленные ниже примеры исходных текстов — упрощенная иллюстрация к рассматриваемым вопросам. Назначение этих примеров — дать представление о возможном подходе при решении задач информационного обмена с системой 1С:Предприятие. При работе с реальными базами 1С может потребоваться их дальнейшая доработка.
Считывание информации из справочников
Используя созданную ранее конфигурацию 1С. рассмотрим вопросы доступа к Информации из базы данных 1С с использованием механизма OLE Automation.
Реквизит справочника типа Перечисление
Опираясь на информацию, полученную в главе 2. запустим Конфигуратор 1 и откроем нашу конфигурацию (lC_example.DB).
Добавим в конфигурацию новое перечисление — "Принадлежность к пол; (с идентификатором Пол).
Примечание
В терминологии 1С перечисления — это списки значений, задаваемые на эта, конфигурирования, которые не могут быть изменены при выполнении задачи.
Для создания нового перечисления нужно в конфигурации выделить с пом шью мыши строку Перечисления и, вызвав всплывающее меню, выбра’ в нем пункт Новое Перечисление (рис. 4.1).
На экране появится диалоговое окно настройки перечисления (рис. 4.2).
Pi Задача
а Константы
Справочники
ф Документы
ф И Журналы документов
Перечне ;1ениэдНННН^^Н9Н^ИВ1ЕЕЕЯ Л^Яноьсе Перечисление
L : IF4 ^,, , -- - — I
Рис. 4.1. Всплывающее меню Конфигуратора (новое перечисление)
Рис. 4.2. Диалоговое окно настройки перечисления
Примечание
Идентификатор перечисления должен быть уникальным в контексте данной конфигурации. Все обращения через механизм OLE Automation к этому перечислению производятся с использованием этого уникального идентификатора.
Чтобы внести новое значение перечисления, нужно нажать кнопку Новый (см. рис. 4.2). На экране появится диалоговое окно настройки значения перечисления (рис. 4.3).
Примечание
Идентификатор каждого значения в контексте перечисления должен быть уникальным.
Л Перечисление Пол
Идентификатор: (Пол комментарий: (ПримерИдентификатор: (Пол комментарий: (ПримерСиноним: (ПолСиноним: (ПолЗнамениЗнамениСвойства ЗначенияСвойства ЗначенияН06ЫЙ1Н06ЫЙ1Общие |Идентификатор:Общие |Идентификатор:(Мужской(Мужской
Идентификатор: (Пол комментарий: (Пример
Идентификатор: (Пол комментарий: (Пример
Синоним: (Пол
Синоним: (Пол
Знамени
Знамени
Свойства Значения
Свойства Значения
Н06ЫЙ1
Н06ЫЙ1
Общие |
Идентификатор:
Общие |
Идентификатор:
(Мужской
(Мужской
Комментарий:Комментарий:ОКОК
Комментарий:
Комментарий:
ОК
ОК
Представление:Представление:(Мужской(МужскойОтменаОтмена
Представление:
Представление:
(Мужской
(Мужской
Отмена
Отмена
НовьиНовьиОбновить
Новьи
Новьи
Qписание
Рис. 4.3. Диалоговое окно ввода нового значения перечисления
В перечисление вида пол внесем два значения:
Мужской
Женский
Точно так же создадим еще одно перечисление вида семейноеположение. Заполним его значениями:
НикогдаНеСостоялВБраке
СостоитВЗарегистрированномБраке
СостоитВНеЗарегистрированномБраке
гРажданскийБрак
Новые реквизиты (пол и семейноеположение) были размещены в справочник Физлица (файл таблицы SC12.DBF). Имена полей в DBF-файле формируютс системой 1С на основе внутреннего алгоритма. Как видите, здесь нет ника ких указаний на то, каким образом связаны поля таблицы (sp29 и зрзо) с структурой данных, хранящейся в файле 1Cv7.MD, а также не отражена иг формация о том, какой именно тип данных имеют эти поля в контексте иг формационной структуры конфигурации 1С.
На рис. 4.9 представлена структура таблицы SC12.DBF, если открыть е в Database Desktop (Delphi).
Рис. 4.9: Структура файл SC12.DBF в Database Desktop
Чтобы внести значения новых реквизитов, нужно запустить программ 1 С:Предприятие (см. рис. 2.23). На рис. 4.10 отображено представление вве денных данных в среде 1С.
Код
Наименование
Дата.,. || Домашний адрес
Пол
Семейное положение .
5
.Аксакалов Аксакал Аксакалович
01 01 70
Россия, г Б. улБ д 00
Мужской
Разведен(разведена)
Иванов Иван Иванович
01 01 71
Россия, г Неизвестный, ул
Мужской
Состоит в зарегистрировав
□
2
Петров Петр Петрович
01.01 72
Россия, г Неизвестны',, ул
Мужской
Г ражданскии бра-;
3
Сидоров Сидор Сидорович
01.01 73
Россия, г Неизвестный ул
Мужской
Вдовец (вдова)
У
4
Федоров Федор Федорович
01 01 74
Россия, г Известный, ул Б
Мужском
Разошелся (разошлась)
У
6
Криогенова Фекла Маринад овна
15 03 65
Россия.гN ул . У. д 005
Ж ВМС [^2
Никогда не состоял (не соС
|Му*ско>
Рис. 4.10. Справочник ФизЛица. Новые реквизиты типа Перечисление
На рис. 4.11 отображено представление введенных данных в DBF-файл (SC12.DBF), который соответствует справочнику Физлица. Как видите, по со
держанию полей SP29 и SP30, которые соответствуют данным типа перечисление, невозможно сделать какие-либо выводы о реальной информации по каждому физическому лицу. Мы можем сделать предположения, лишь руководствуясь известной нам информацией о структуре, поскольку сами создали эту конфигурацию. В разд. 4.4 мы рассмотрим вопрос идентификации значений перечислений вне контекста программы 1С:Предприятие.
\1 (^..example DB \SC12. D В Г
SC12
10
CODE-OESCR
SMARK VERSTAMP SP15SP1B
SP29
SP30
1
1
Иванов Иван Иванович
Б
01.01.1971 Россия, г.Неювестный, у;
J
N :
2
2
Петров Петр Петрович
4
01.01 1972 Россия.г Неизвестный, ут
J
р
3
3
3
Сидоров Сидор Сидорович
9
01 01 1973 Россия, г. Неизвестный, ул
J
s i
4
4
4
Федоров Федор Федорович
5
01.01 1974 Россия, г.Иэвестный, ул Е
J
я.:
5
5
5
; Аксакалов Аксакал Аксакал:
5
01.01.1970 Россия, г.Б.ул.Б.д.ОО
J
°:
Б
6
6
। Криогенова Фекла Маринад
■: о
15.03.1965; Россия, r.N. ул,, У. д 005
к
М'
Рис. 4.11. Справочник ФизЛица — так отражена информация в файле SC12.DBF,если открыть его в Database Desktop
Рассмотрим пример, иллюстрирующий считывание и анализ информации с использованием данных типа перечисление в среде Delphi.
Создадим новый проект с именем sp_LoadEnumFromRef.DPR (или любым другим, на усмотрение читателя). За основу проекта можно взять последний пример из предыдущей главы.
Примечание
Исходный текст проекта представлен на сопроводительном компакт-диске книги в файле \Part_1\Chapter_04\Topic_4_1\ltem_4_1_1\sp_LoadEnumFromRef.PAS.
На рис. 4.12 приведена Delphi-форма примера.
Способ соединения с 1С в качестве сервера OLE Automation был рассмотрен в предыдущей главе и более на этом не будем акцентрировать внимание.
Прежде чем приступить к написанию кода, примем к сведению, что в качестве имени значения перечисления обязательно должно выступать полное имя конкретного вида и значения перечисления, как оно объявлено в Конфигураторе. Вид и значение перечисления записываются через точку после ключевого слова Перечисление, т. е. полное имя значения перечисления записывается следующим образом:
Перечисление.<1С_Переч>.< Ю_ЗначенияПереч>
где <то_переч> — идентификатор перечисления, <1о_3наченияпереч> — идентификатор конкретного значения данного перечисления.
Рис. 4.12. Форма примера, иллюстрирующего работу сданными типа ПеречислениеРис. 4.12. Форма примера, иллюстрирующего работу сданными типа Перечисление
Рис. 4.12. Форма примера, иллюстрирующего работу сданными типа Перечисление
Рис. 4.12. Форма примера, иллюстрирующего работу сданными типа Перечисление
Объект перечисление является частью глобального контекста систе, 1С:Предприятие. Это значит, что мы можем обратиться к этому типу ме данных через ссылку на программу 1С как сервер OLE Automation (перем, ная oleic).
Примечание
Англоязычный синоним ключевого слова Перечисление — Епшп.
Поставим перед собой задачу прочитать информацию из справочника физЛи, только о тех физических лицах, кто никогда не состоял в браке. Вспомни что для этих целей в Конфигураторе было создано перечисление семейн. Положение, ОДНО ИЗ Значений которого — НикогдаНеСостоялВБраке (см. рк 4.4). Вспомним также, что в справочнике Физлица для отражения этой hi формации был введен специальный реквизит СемейноеПоложение (не путать одноименным перечислением как объектом метаданных), см. рис. 4.7.
В контексте встроенного языка 1С можно сравнивать значения одного thi непосредственно, например, как показано в листинге 4.1.
Если
Clip.СемейноеПоложение=Перечислание.СемейноеПоложение.НикогдаНеСостоялВ ке Тогда
КонецЕсли;
При доступе через OLE Automation такой подход будет некорректным. Нуж- н0 сравнивать уникальные идентификаторы, которые представляют собой строки или целые числа.
Вооружившись этими сведениями, изменим обработчик события (см. листинг 3.3) "нажатие кнопки Выбрать из справочника (Button2)", как показано в листинге 4.2.
(Листинг 4.2. Выбор из справочника информации о лицах, никогда [ле состоявшиеся браке,.S
procedure TForml.Button2Click(Sender: TObject);
Var
OleBuf, // Вспомогательная переменная
OleFizLica: OleVariant; // Ссылка на справочник "ФизЛица*
// Идентификатор реквизита значения справочника "СемейноеПоложение": idEnumX,
// Идентификатор значения перечисления "СемейноеПоложение" (метаданные): idEnumMeta: string;
begin
ListBoxl.Items.Clear;
if not VarlsEmpty(OlelC) then begin
// Получаем ссылку на перечисление СемейноеПоложение
OleBuf:= OlelC.Перечисление.СемейноеПоложение;
// Читаем идентификатор соответствующего значения
// соответствующего перечисления
idEnuneteta:=Trim(OleBuf.НихогдаНеСостонлВБраке.Идентификатор);
// Создаем справочник "ФизЛица" и получаем на него ссылку
OleFizLica:=OlelC.CreateObject('Справочник.*+Edit3.Text);
if not VarlsBnpty(OleFizLica) then begin
if OleFizLica.ВыбратьЭлементы>0 then begin
while OleFizLica.ПалучитьЭлемент>0 do begin
// Читаем идентификатор значения реквизита
11 справочника "СемейноеПоложение"
IdEnumX:=Trim(OleFizLica.СемейноеПоложение.Идентификатор);
// Сравниваем идентификаторы
if idEnumX = IdEnunHeta then begin
ListBoxl.Items.Add(
Trim(OleFizLica.Код)+' | *
+ TrimtOleFizLica.Наименование)+' | 1
+ TrimtOleFizLica.ДатаРождения}*' | 1
* TrimtOleFizLica.Пол.Идентификатор)+' | 1
+ TrimtOleFizLica.ДомашнийАдрес)
);
end;
Application.ProcessMessages;
end;
end;
end;
end;
end;
Поясним текст обработчика.
В строке
OleBuf:= OlelC.Перечисление.СемейноеПоложение;
получаем ссылку на перечисление СемейноеПоложение как объект.
В строке
IdEnunetetа:=Trim(01eBuf.НикогдаНеСостоялВВрахе.Идентификатор);
считывается идентификатор соответствующего значения перечисления (ю объекта) из глобального контекста конфигурации.
В строке
IdRnuniX:=Tr im (01eFi zLica.СемейноеПоложение.Идентификатор);
считывается идентификатор значения реквизита справочника (как объекта).
В строке
if idEnunflC = IdEnunMeta then begin
сравнивается идентификатор значения реквизита СемейноеПоложение спр, вочника Физлица с идентификатором значения НикогдаНеСостоялВБраке го речисления СемейноеПоложение.
В строке
+ TrimtOleFizLica.Пол.Идентификатор)+' | '
выполняется обращение к идентификатору значения реквизита Пол (как об) екта) справочника Физлица.
На рис. 4.13 показан результат считывания информации из справочник
ФизЛица.
^1риме^<спользования 1С, как OLE - сервераавтоматизацииМИВ_||
Соединить с 1С j
' Имя IC-сервера (OLE Automation) - |V77 Application Строка инициализации ■ |7DE:\1C_example.DB
; Выбрать тех. кто никогда не сост. в брасе:
{ Выбрать из'справочника i| | ФизЛица
61 Криогенова Фекла Маринадовна 115.03.19651 Женский I Россия, r.N. уд. У. д. 005
Рис. 4.13. Результат фильтрации по реквизиту СемейноеПоложение
ПРИМЕЧАНИЕ
В данном примере мы рассмотрели способ считывания непериодических реквизитов справочника.
Вот так выглядит обработчик события "нажатие кнопки на встроенном языке 1С в контексте модуля Обработка (листинг 4.3).
। в браке (язык программирования 1 С)
Процедура Выполнить()
СпрФизЛица = СоздатьОбъект("Справочник.ФизЛица");
СпрФизЛица.ВыбратьЭлементы();
Пока СпрФизЛица.ПолучитьЭлемент()>0 Цикл
ЗначРеквизСправочн = СпрФиэЛица.СемейноеПоложение;
ЗначПеречисления = Перечисление . СемейноеПоложение.НикогдаНеСостоялВБраке;
Если ЗначРеквизСправочн = ЗначПеречисления Тогда
Сообщить(СпрФизЛица.Код + " | "
+ СпрФизЛица.Наименование * * | "
+ СпрФизЛица.ДатаРождения + ’ | ”
+ СпрФизЛица.Пол + " | "
* СпрФизЛица.ДомашнийАдрес);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
А это результат выполнения:
6 I Криогенова Секла Маринадовна | 15.03.65 | Женский | Россия, гЛ, ул., У, д. 005
Реквизит справочника
типа Строка неограниченной длины
Для того чтобы рассмотреть способ доступа к реквизитам типа Строка неор раниченной длины (аналог поля мемо), доработаем нашу конфигурацию.
Опираясь на информацию, полученную в главе 2, запустим Конфигуратор 1 и откроем нашу конфигурацию (lC_example.DB).
Откроем окно настройки справочника (см. рис. 4.5 и 4.6) и внесем в справот ник новый реквизит, как на рис. 4.14.
Обшив J Дополнительные)
f | чя|
Идентификатор: | олнит ельнаяИ мформация Синоним:||Дополнительная информ
Комментарий |
ок
Т кт значения: («Строка»jJ
. Длин*(о ^ р Неогр. Точность: Ю ;
Отмена
Обновить
Рис. 4.14. Реквизит типа Строка неограниченной длины
После этой операции список реквизитов справочника ФизЛица будет таким как показано на рис. 4.15.
- Реквизиты
ДатаРождения Домашниййдрес Пол
СемейноеПсложение
Рис. 4.15. Список реквизитов справочника ФизЛица
Поскольку значения реквизита данного типа (строка неограниченной длины) могут содержать специальные символы форматирования текста (перевод строки и возврат каретки), эту информацию невозможно будет корректно вносить в контексте списка (см. рис. 4.10). Чтобы решить эту проблему, нужно создать форму редактирования элементов справочника ФизЛица. Для этого в диалоговом окне создания и настройки справочника (см. рис. 2.13) нужно нажать кнопку Форма элемента. На экране появится диалоговое окно создания формы редактирования элемента справочника (рис. 4.16).
ДКодДКодРе« в*<з,<тыРе« в*<з,<ты' g) Диалог /(ПМ«уъ FtiL' g) Диалог /(ПМ«уъ FtiL| Вставить ] Отмена j Помощь || Вставить ] Отмена j Помощь |
ДКод
ДКод
Ре« в*<з,<ты
Ре« в*<з,<ты
' g) Диалог /(ПМ«уъ FtiL
' g) Диалог /(ПМ«уъ FtiL
| Вставить ] Отмена j Помощь |
| Вставить ] Отмена j Помощь |
форм.! злснентаЧДтравоч^.внчЛмра (Пример)
Размещение реке* wroe Гправое»*
^Наименование
ЙДатэРо-едение
Sf До-чаии*'«Адрес
-•'Лол
^;Семе>>«сеПоло»ение
^Яопо1»«тельнз«Инккхация
Р Вставлять имя И-л. .сталь |Пзгл весив
р Разместить а диалоге аетомапмесхя
Рис. 4.16. Разработка формы для редактирования элементов справочника ФизЛицаРис. 4.16. Разработка формы для редактирования элементов справочника ФизЛицаР Вызьеатьдлянсеькфсем
Рис. 4.16. Разработка формы для редактирования элементов справочника ФизЛица
Рис. 4.16. Разработка формы для редактирования элементов справочника ФизЛица
Изучение методов разработки форм в системе 1 С:Предприятие не входи в задачу этой книги, поэтому просто нажмем кнопку Вставить в этом окне После того как соответствующие элементы управления автоматически раз местятся в форме, можно расположить их по своему усмотрению (с помошьк мыши и клавиатуры). Например так, как показано на рис. 4.17.
Затем нужно щелчком левой кнопки мыши выделить элемент управлени: ДополнительнаяИнформация, щелчком правой кнопки мыши вызвав всплывающее меню, выбрать в нем пункт Свойства, в открывшемся диало говом окне настройки свойств элемента управления перейти на вкладку Ти1 (рис. 4.18) и установить флажок Многострочный.
Форма элемеита-Справочник.ФиэПица (Пример)Форма элемеита-Справочник.ФиэПица (Пример)Код:Код:|тод|тодСвойстваСвойстваОбщиеОбщиеДлинаДлина□К□КОтменаОтменаОбновитьОбновить/ А) Таблица/ А) ТаблицаПоля Ввода (ДополнительнаяИнформация)Поля Ввода (ДополнительнаяИнформация)Т ил | Дополнительно | Описание |Т ил | Дополнительно | Описание |। ОЧНОСП/। ОЧНОСП/|«Е трока:,'Неограниченная длина Ь Р Многострочный|«Е трока:,'Неограниченная длина Ь Р МногострочныйДополнительнаяИнформацияДополнительнаяИнформацияЗакрытьЗакрыть/ -^ Модель/ -^ Модель
Форма элемеита-Справочник.ФиэПица (Пример)
Форма элемеита-Справочник.ФиэПица (Пример)
Код:
Код:
|тод
|тод
Свойства
Свойства
Общие
Общие
Длина
Длина
□К
□К
Отмена
Отмена
Обновить
Обновить
/ А) Таблица
/ А) Таблица
Поля Ввода (ДополнительнаяИнформация)
Поля Ввода (ДополнительнаяИнформация)
Т ил | Дополнительно | Описание |
Т ил | Дополнительно | Описание |
। ОЧНОСП/
। ОЧНОСП/
|«Е трока:,'
Неограниченная длина Ь Р Многострочный
|«Е трока:,'
Неограниченная длина Ь Р Многострочный
ДополнительнаяИнформация
ДополнительнаяИнформация
Закрыть
Закрыть
/ -^ Модель
/ -^ Модель
Рис. 4.18. Окно редактирования
свойств элемента управления ДополнительнаяИнформация
Затем нужно закрыть форму редактирования элемента справочника и вы брать способ редактирования элементов справочника В диалоге (рис. 4.19). Теперь нужно сохранить сделанные в конфигурации изменения (см. рис. 2.17).
Рис. 4.19. Выбор способа редактирования элемента справочника
Рис. 4.20. Редактирование элемента справочника в диалоге
разделитель). Метод возвращает 1, если действие выполнено, и 0, если дейст«1 вне не выполнено (элемент не найден).
Перепишем обработчик (листинг 4.4) с учетом использования метода спра-1 Вочника НайтиПоКоду (листинг 4.5).
E
»@B№tK»S*t3!’R«MB!!*s№WWi^KRS^
procedure TForml.Button2Click(Sender: TObject);|
Var|
OleFizLica : OleVariant;I
begin|
ListBoxl.Items.Clear; ListBox2.Items.Clear;I
Memol.Lines.Clear;]
if not VarlsEmpty(OlelC) then begini
OleFizLica:=OlelC.CreateObject('Справочник.'+Edit3.Text); if not VarlsEmpty(OleFizLica) then begin|
// Вызываем метод справочникаI
if OleFizLica.НайтиПоКоду(l,0)>0 then beginI
ListBoxl.Items.Add(
Trim(OleFizLica.Код)+'|1|
+ Trim(OleFizLica.Наименование)+' | 'i
+ Trim(01eFizLica.ДополнительнаяИнформация) i ); Memol.Text:=Trim(OleFizLica.ДополнительнаяИнформация);
ListBox2.Items.Text:=Trim(01eFizLica.ДополнительнаяИнформация); end;
end;
end; end;
После компиляции и выполнения примера результат будет таким же. как и на рис. 4.25.
Примечание
Исходные тексты этого примера есть на сопроводительном компакт-диске в файле \Part_1\Chapter_04\Topic_4_1\ltem_4_1_2\sp_LoadUnlimitSlringFromRef_01 .PAS-
—
Реквизит справочника типа Справочник
Вновь доработаем нашу конфигурацию. Внесем еще два новых справочника без реквизитов (значения всех свойств — по умолчанию, длина наименования — 64 символа):
"Страны мира" (идентификатор — странымира);
"Города стран мира" (идентификатор — ГородаСтранМира).
Справочник ГородаСтранМира будет подчинен справочнику СтраныМира, а справочник Странымира будет владельцем справочника ГородаСтранМира. Эти отношения между справочниками устанавливаются в диалоговом окне настройки подчиненного справочника (рис. 4.26).
I^1' Справочник ГородаСтранМира
■■^И^НМ^М^^Н Па 1 х
Идентификатор (ГородаСтранМира
Комментарий: |
Подчинен(СтраныМира
Синоним:(Города стран мира
Рис. 4.26. Справочник ГородаСтранМира является подчиненнымсправочнику СтраныМира
В терминах Delphi справочник Странымира называется главной таблицей (master table), а справочник ГородаСтранМира — подчиненной таблицей (detail table).
На рис. 4.27 представлено дерево конфигурации после внесенных изменений.
ы8
Справочник!
S ФиэЛица|
■ ДатаРождения
■ ДомашмийАдрес
■ Пол
■ СемейноеП сложение
■ Доло/нительнаяИнФормация СтраныМира
5 ГородаСтранМира|
рис. 4.27. Ветвь справочников конфигурации после создания двух новых справочников
Сохраним изменения в конфигурации, запустим программу !С:Предприятие и откроем справочник-владелец "Страны мира" (рис. 4.28).
После заполнения справочника Странымира нужно выбрать строку спрдроч- а-владельца и, вызвав всплывающее меню, выбрать пункт Подчиненный справочник (рис. 4.29).
5252
52
52
Часть L 1С и механизм OLE Automatic
Рис. 4.28. Выбираем справочник-владелец
и Справочник: Страны мира
ВВЕЗ
s я ^ ц ^ ф ^!« @i a ty
I (Код J Наименование
3 Белорусия
| Росс
укр< S Новый
I
!У| Нс-ЭЯ Гр^ЛПд
S Изменить
^Просмотр
копировать
^ Пометить на уда поме
Del
&
Подчиненньм справочник
I
■*Ц
Рис. 4.29. Чтобы работать с подчиненным справочником,нужно открыть его из всплывающего меню владельца
Рис. 4.30. Открыт подчиненный справочникРис. 4.30. Открыт подчиненный справочник
Рис. 4.30. Открыт подчиненный справочник
Рис. 4.30. Открыт подчиненный справочник
Откроется список подчиненного справочника.i
Поочередно выбирая разные страны мира, заполним списки городов (рис. 4
Глава 4. Доступ к информации 1С из внешних приложений 53
На рис. 4.31 и 4.32 представлена структура обеих таблиц так. как она отражена в файле !Cv7.DD.
•■«■••ежееежежжжжееажжжжжжжжжжжжжжжежжжжжжжжжжжж•■■•■•
•••■■■■■■■■•■■■ ■ ■ ■
t,.TABLE по 9: Справочник СтраюсМира
, Кахе IDescrIType[A/S/U] IDBTableNaxeI Reusable
T-SC33 (Справочник СграммЯмра(AISC3311
,Fields
, КахеIDescriTypel Lengchl Precision
г„ц>116 objectIC1910
r,CQDE1 object codeIC1510
r.DESCR1 object descriptionIC16410
f,ISHARKIFlag Object isMarks IC1110
r-VERSTAMP1 Version steepIC1610
1-—Indexes
1 NueIDescr1Uhlque1 Indexed fields
1>П№lot ID10|ID
I-CODElot CODE|0I CODE (UPPER)
1 DBMaxe HDD (CODE
I-DESCR i
lot DESCR10IDESCR(UPPER)
1DESCR
Рис. 4.31. Содержание файла 1Cv7.DD. Структура справочника-владельца СтраныМира
• -TABLE
no 10: Справочник ГородаСтранМира
• Kaxe T-5C3S
IDescrlType[A/S/U]IDBTableSaee|ReUsable
1 Справочник ГоролаСтраиЯхраIAISC3511
l ВахеIDescr1 Type I Length1 Precision
F-ID|П> objectIC19|0
F-CODEI object code|C15|0
Г-DESCR|object description |C16410
Г-РАРЕЗГГЕХГI Parent in other tabi IC19|0
F-I5HARKIFlag Object Is MarkelC1110
F-VERSTAMP|Version staap|C16|0
Indexes
NaxeIDescrIUnique 1 Indexed fields
I-IDDlotID|0|ID
I-PCODE|otPARENT and 101 PARENTEXT, CODE (UPPER)
I-PDESCR lot PАРЕСТ and 101PARENTEXT,DESCR(UPPER)
^CODE|ofCODE10I CODE (UPPER)
bpESCP.|QfDESCR10IDESCR(UPPER)
IDBNa&e HDD 1PCODE 1PDESCR ICODE IDESCR
Рис. 4.32. Содержание файла 1Cv7.DD.
Структура справочника-владельца ГородаСтранМира
Как видите, в подчиненном справочнике ГородаСтранМира (файл SC35.DBF) Для связи со справочником-владельцем СтраныМира выделено отдельное поле P^ENTEXT.
Если открыть файл SC35.DBF (ГородаСтранМира), ТО (руКОВОДСТВуЯСЬ ИЗВССТ- н°и нам информацией о конфигурации) мы увидим, что поле parentext со- ДеРЖИТ КОДЫ соответствующих строк ИЗ таблицы SC33.DBF (СтраныМира). ^°пробуем прочитать информацию из этих двух справочников, используя знизм OLE Automation. Для этого создадим новый проект (рис. 4.34).
333 41 233 41 23123412345S789 АВ С5S789 АВ С11112222333322223333Рис. 4.34. Форма примера обработки справочника-владельца и подчиненного справочникаРис. 4.34. Форма примера обработки справочника-владельца и подчиненного справочника
3
3
3 4
1 2
3
3 4
1 2
3
1
2
3
4
1
2
3
4
5
S
7
8
9 А
В С
5
S
7
8
9 А
В С
1
1
1
1
2
2
2
2
3
3
3
3
2
2
2
2
3
3
3
3
Рис. 4.34. Форма примера обработки справочника-владельца и подчиненного справочника
Рис. 4.34. Форма примера обработки справочника-владельца и подчиненного справочника
"Содержание таблицы:
[|| N |Открыть таблицу
" cooeI'descr Iparentext]
Санкт-Петербург
Москва
Усинск Волгоград Одесса
Киев
Ильичевск
Донецк
Минск
Гомель
Брест Барановичи
Рис. 4.33. Содержание файла SC35.DBF,соответствующего справочнику ГородаСтранМира
Рассмотрим обработчик события "нажатие кнопки Выполнить" (листинг 4.6).
тинг 4.6. Считывание информации из справочников "владелец"
ВВ^А
procedure TForml.Button2Cliak(Sender: ТОЬject);
Var
iStr.iGor : integer;
idOwner : string;// Код владельца для элемента "справ.ГородаСтранМира'
OleStr,II Ссылка на справочник 'СтраныМира"
OleGor : OleVariant;// Ссылка на справочник "ГородаСтранМира*
Гпава 4. Доступ к информации 1С из внешних приложений 55 begin
RichEditl.Lines.Clear;
if not VarlsEmpty(OlelC) then begin
OleStr:=OlelC.CreateObject('Справочник.СтраныМира1);
if not VarlsEmpty(OleStr) then begin
OleGor:HoleIC.CreateObject('Справочник.ГородаСтранМира');
if not VarlsEnpty(OleGor) then begin
/ / Устанавливаем порядок сортировки справочника СтраньМира по кодам OleStr.ПорядокКодов;
if OleStr.ВыбратьЭлементы>0 then begin
while OleStr .Получить Элемент:» 0 do begin
//Выводим код и наименование страны
RichEditl. Lines. Add (
Trim(OleStr.Kon)+'.'
+ Trim(OleStr.Наименование)
);
// Устанавливаем порядок сортировки справочника “ГородаСтранМира" //по наименованиям
OleGor. ПорядокНаиманований,-
if OleGor.ВыбратьЭлементы(О)>0 then beginwhile OleGor.ПолучитьЭлемент>0 do
begin
// С помощью свойства "Владелец" подчиненного справочника
// получаем код строки-владельца для данного элемента справочника
//ГородаСтранМира
id0wnar:=Trim(01eGor.Владелец.Код);
// Сравниваем полученный код с кодом текущего элемента
// справочника "СтраныМира"
if idOwner=Trim(OleStr.Код) then begin
//Выводим код и наименование города соотв.страны
RichEditl.Lines.Add(11
+ Trim (OleGor.Код)+ '.'
* Tr im (OleGor.Наименование)
);
end;
Applicat ion.ProcessMessages;
end;
end;
Application.ProcessMessages;
end;
end;
end;
end;
end;
end;
Здесь мы организовали тривиальное считывание информации по циклу из справочника-владельца Странымира, а внутри этого цикла — внутренний цикл, где считывается и фильтруется информация из подчиненного справоч
НИКа ГородаСтранМира.
Единственное, что заслуживает внимания — это использование таких мето* ДОВ объекта агрегатного типа Справочник, как ПорядокКодов И ПорядокНаиме- нований, и свойства владелец. Оба метода предназначены для того, чтобы изменить порядок сортировки элементов справочника при выборке. По умолчанию выборка элементов справочника производится в порядке основного представления справочника, задаваемого в Конфигураторе.
Если посмотреть на структуру таблиц, отраженную в файле 1Cv7.DD, то видно, что при создании любого справочника сразу же создаются два индекса:
I=CODE |of CODE |0 |CODE(UPPER) |CODE
I=DESCR |Of DESCR |0 |DESCR(UPPER) |DESCR
To есть, вероятно, именно на использовании этих индексов и базируются ме ТОДЫ ПорядокКодовИПорядокНаименований.
Для подчиненного справочника ГородаСтранМира созданы еще два индекса: .
I=PCODE | of PARENT and [0 |PARENTEXT,CODE(UPPER) |PCODE
I=PDESCR |of PARENT and |0 |PARENTEXT,DESCR(UPPER) |PDESCR
Очевидно, что эти индексы ориентированы на поддержку свойства Владела! подчиненного справочника.
Примечание
Исходный текст этого примера приведен на сопроводительном компакт-диске книг* в файле \Part_1\Chapter_04\T<4)lc_4_1\ltem_4_1_3\sp_LoadOwnerChildsRef.PAS.
Краткое описание перечисленных методов и свойств справочников системы 1С:Предприятие:
порядокКодов (или orderByCode) — устанавливает режим выборки элементов справочника в порядке возрастания кодов элементов. Синтаксис: ПорядокКодов()
ПорядокНаименований (ИЛИ OrderByDescr) — устанавливает режим выборки элементов справочника в алфавитном порядке наименований элементов. Синтаксис:
ПорядокНаименований()
Владелец (или Owner) — предоставляет доступ к значению элемента сопряженного справочника (владельца), которому подчинен выбранный элемент текущего справочника. Синтаксис:
Владелец
На рис. 4.35 представлен результат выполнения программы.
Рис. 4.35. Результат работы программы.
Пример изменения порядка сортировки справочников
Кроме выполнения сортировки справочника по свойствам Код И Наименование, Можно воспользоваться методом ПорядокРеквизита (или OrderByAttribute). позволяющим сортировать выборку элементов справочника по реквизиту.
Этот метод устанавливает режим выборки элементов справочника в порядке возрастания значения указанного реквизита. Его синтаксис:
ПорядокРеквизита(сИденгификаторРеквиэита>)
Параметр <идентификаторРеквизита> — строковое выражение с идентификатором реквизита справочника, задающего порядок обхода элементов спра вочника.
Данный метод обычно используется до вызова метода выбрать Элементы, ко торый фактически открывает выборку. Дальнейшая выборка при помощ) метода получитьЭлемент будет осуществляться среди элементов текущей справочника в порядке возрастания значения реквизита.
Метод ПорядокРеквизита можно использовать только в том случае, есл| в Конфигураторе при описании данного реквизита установлен призна Сортировка (диалоговое окно Свойства Реквизита > вкладка Дополна тельные > флажок Сортировка).
Чтобы посмотреть, как это работает, откроем Конфигуратор 1С:Предприяти< внесем в справочник ФиэЛииа новый реквизит городПроживания тип Справочник.городаСтранМира (рис. 4.36) и установим для него призна Сортировка (рис. 4.37).
Рис. 4.36. Новый реквизит справочника ФизЛица
Рис. 4.37. Чтобы можно было сортировать справочник по реквизиту, нужно установить для реквизита признак Сортировка
С помощью встроенного дизайнера форм программы Конфигуратор 1С:Предприятие нужно внести изменения в форму редактирования элемента справочника ФизЛица, как это было сделано ранее (см. рис. 4.17). Это тривиальная процедура, и здесь мы не будем углубляться в детали.
На рис. 4.38 представлен список реквизитов справочника ФизЛица после создания нового реквизита ГородПроживания.
9 Я Справочники
Е
:- ■ ДатаРождения
j:- ■ ГородПроживания
i.- ■ Домашяийбдрес
?-■ Пол
;■ СемейноеПоложеяме
- Ж ДополнительмаяИнФормация
Рис. 4.38. Список реквизитов справочника ФизЛица
Сохраним сделанные в конфигурации изменения (см. рис. 2.17).
На рис. 4.39 представлена структура справочника ФизЛица так, как она отражена в файле 1Cv7.DD. Здесь видно, что в файле SC12.DBF появилось новое поле SP37 (ГородПроживания) и для него создан индекс с именем vi37 (очевидное следствие установки признака Сортировка для этого реквизита).
Чтобы внести информацию о городе проживания для физических лиц, запустим программу 1 С:Предприятие, откроем справочник ФизЛица и внесем значения реквизита ГородПроживания для каждого физического лица (рис. 4.40).
Рис. 4.39. Содержание файла 1Cv7.DD. Структура справочника ФизЛица
f ПКпп
НдммянпкйниаI Пята
1
Аксакалов Аксакал Аксакалович
01 01.70
Киев
Иванов Иван Иванович
01 01 71
Москва
6
Криогенова Фекла Маринадовна
15 03 65
Гомель
2
Петров Петр Петрович
01.01 72
Минск
3
Сидоров Сидор Сидорович
01 01 73
Волгоград
4
Федоров Федор Федорович
01 01 74
Киев
Рис. 4.40. Значения реквизита ГородПроживания в справочнике ФизЛица
Й-|аМЙ-|аМТеперь создадим в среде Delphi новый проект. За основу можно взять один f предыдущих примеров (например, см. рис. 4.12). Форма примера продета! лена на рис. 4.41.
Й-|аМ
Й-|аМ
1*1 Пример считывания реквизитов справочника. С.:
■ *-оейинить с |
[ Имя 1С-серв6ра(OLEAutomation)» jv77Application Строка инициализации - |/DE \1C_exarnple DB
l Сотрировка no реквизита "ГородПроживания"l Сотрировка no реквизита "ГородПроживания"I Выбрать из справочника ;I Выбрать из справочника ;(ФизЛица(ФизЛицаРис. 4.41. Форма примера, иллюстрирующего метод ПорядокРеквиэита справочникаРис. 4.41. Форма примера, иллюстрирующего метод ПорядокРеквиэита справочника
l Сотрировка no реквизита "ГородПроживания"
l Сотрировка no реквизита "ГородПроживания"
I Выбрать из справочника ;
I Выбрать из справочника ;
(ФизЛица
(ФизЛица
Рис. 4.41. Форма примера, иллюстрирующего метод ПорядокРеквиэита справочника
Рис. 4.41. Форма примера, иллюстрирующего метод ПорядокРеквиэита справочника
Изменим обработчик события "нажатие кнопки Выбрать из справочник! следующим образом (листинг 4.7).
дтгедрта,®гает^^™та1!№8ет№-7^Т™Т’ЯЯ (Листинг 4.7. Иллюстрация применения метода справочника ПорядокРеквизи«
procedure TForml.Button2Click(Sender: TObject);
VarI
OleFizLica: OleVariant;J
beginT
ListBoxl.Items.Clear;J
if not VarlsEmpty(OlelC) then begin
OleFizLica:=OlelC.CreateObject('Справочник.1+Edi t3.Text);
if not VarlsBnpty(OleFizLica) then begin
OleFizLica.ПорядокРеквиэита(1ГородПроживания1);
if OleFizLica.ВыОратьЭлементы>0 then begin while OleFizLica.ПолучитьЭлемент>0 do begin
ListBoxl.Items.Add( Trim(OleFizLica.Kon)+‘ | ‘
+ Trim(01eFizLica.Наименование)+■ |'
+ Trim (OleFizLica.ГородПроживания.Владелец.Код) +'.'
♦ Trim(OleFizLica.ГородПроживания.Владелец.Наименование)+' | '
♦ Trim (OleFizLica.ГородПроживания.Код) + '.'
* Trim(OleFizLica.ГородПроживания.Наименование) );
Application.ProcessMessages ;
end;
end;
end;
end;
end;
Здесь все прозрачно и пояснения не требуются.
Примечание
Исходные тексты этого примера находятся на сопроводительном компакт-диске книги в файле \Part_1\Chapter_04\Topic_4_1\ltem_4_1_3\sp_LoadRefFromRef.PAS.
Результат выполнения программы представлен на рис. 4.42.
«Г Пример считывания реквизитов справочника. Сор— НИ □
Соединить с 1С |
Имя 1 С-сереера (OLE Automation) - |V77 Application * Строка инициализации = |/DE А1 C_example.DB I Выбрать тех. кто никогда не сост. в браке:
[ Выбрать из справочника |физЛица
1 I Иванов Иван Иванович I 1 Россия 12Москва
31 Сидоров Сидор Сидорович I 1 Россия 14 Волгоград
41 Федоров Федор Федорович! 2. У крайне 12 Киев
51 Аксакалов Аксакал Аксакалович | 2Украина 12 Киев
21 Петров Петр Петрович | ЭБелорусия 11 .Минск
61 Криогенова Фекла Маринадоена I ЗБелордсия |2Гомель
Рис. 4.42. Результат выборки из справочника ФизЛицас использованием метода ПорядокРеквизита
^к 1064
;Т-Выборкаэлементов справочника:*;Т-Выборкаэлементов справочника:*Есть соединение с 1СЕсть соединение с 1СРис. 4.43. Форма просмотрщика для 1С:Предприятие (OLE Automation)Рис. 4.43. Форма просмотрщика для 1С:Предприятие (OLE Automation)11^Л1Ьм4^=.^^Л1Ьм4^=.^
;Т-Выборкаэлементов справочника:*
;Т-Выборкаэлементов справочника:*
Есть соединение с 1С
Есть соединение с 1С
Рис. 4.43. Форма просмотрщика для 1С:Предприятие (OLE Automation)
Рис. 4.43. Форма просмотрщика для 1С:Предприятие (OLE Automation)
1
1
^Л1Ьм4^=.^
^Л1Ьм4^=.^
6262Часть I. 1С и механизм OLE Automatic
62
62
Обобщение пройденного материала
Мы достаточно потренировались в программировании на простых и разр ненных примерах. Теперь попробуем все это обобщить и объединить в ед ное средство, возможности которого будем наращивать по ходу изложени Назовем его "Простой просмотрщик для 1 С:Предприятие (OLE Automation) Создадим в среде Delphi новый проект с именем sp_lCv7_Viewer_vi OLE.DPR.
Примечание
Исходный текст этого проекта находится на сопроводительном компакт-ди книги в палке \Part_1\Chapter_04\sp_1Cv7_Viewer_via_OLE.PAS\01.
Форма примера представлена на рис. 4.43.
^ Простой просмотрщик для 1С:Предприятие(01Е Automation) НН Bl
1С |" 4^ Строкаимиц ^ ации1С:Предприятие: pD E:\1C_exampleO В
Справочники |
г Что смотреть :
Идентификатор справочника:
; [ФизЛица
i|E сть соединение с СОМ-объектом
jr - Список реквизитов для чтения; ■
М efno_UstAtti_R d
В предыдущих примерах мы обращались к методам, свойствам и реквиз справочников по их идентификаторам, точно зная, что они актуальны (т. присутствуют в конфигурации). В общем случае это недопустимо.
Система 1С:Предприятие (как сервер OLE Automation) предоставляет можности доступа к метаданным конфигурации, что позволяет проводи анализ информационной структуры из внешних приложений.
Работа с метаданными выполняется через глобальный атрибут метадан (или Metadata), который имеет тип метаданные и всегда присутствует в си
6363Глава 4. Доступ к информации 1С из внешних приложений
63
63
№№Глобальный атрибут Метаданные является вспомогательным объектом системы и предназначен для доступа к свойствам структуры метаданных конфигурации. Например, можно проверить, существует ли справочник с заданным идентификатором, используя способ, приведенный в листинге 4.8.
№
№
^Листинг 4.8, Проюрка руществорания справочника в зада^й^орАигураций ^ш
KesulC:=false;
if ole 1С. Метаданные. Справочник ( ' '+idReference) .Выбран>0 then begin Result:=true;
end;
В данном примере переменная idReference (типа string) содержит тестируемый идентификатор справочника. Пустая строка ' *, присутствующая перед переменной idReference, — это не причуды программиста. Система 1С:Предприятие не всегда корректно выполняет вызовы методов, процедур и функций, если не использовать такую "конструкцию".
Примечание
Полный текст функции, решающей эту задачу, приведен в файле \sp_Lib\sp_ Lib_Delphi.PAS на сопроводительном компакт-диске книги.
Проверить, существует ли реквизит справочника с заданным идентификатором, можно способом, приведенным в листинге 4.9.
[Листинг 4.9. Проверка существования реквизита срчн
Result:=false;
if
0ielc.Метаданные.Справочник(' '+idReference) .Реквизит(' ’+idAttr) .Выбран>0 then begin
Result:=true;
end;
^ Данном примере переменная idAttr (типа string) содержит идентифика- ГоР тестируемого реквизита в справочнике с идентификатором idReference.
Примечание
Полный текст функции, решающей эту задачу, приведен в файле ^P-LibXsp.Lib.Delphi.PAS на сопроводительном компакт-диске книги.
У объекта метаданные есть метод выбран (или selected), который проверяв] спозиционирован объект типа метаданные на конкретном объекте метадад ных или нет. Синтаксис:
Выбран()
Метод возвращает число 1 (если объект соответствует объекту метаданные т. е. спозиционирован) или 0 (если не соответствует). Например, при обрацц нии к массиву подчиненных метаданных по идентификатору, если объект! метаданных с таким идентификатором не существует, возвращается неспоз»] ционированный объект типа Метаданные.
Изменим обработчик события "нажатие кнопки Открыть справочник (кнопка с пиктограммой открытой книги, см. рис. 4.43) следующим образо) (листинг 4.10).
«й^^-пг™--?^ ,.—г ^"-w^™^ .— Л
procedure TForml.SBRef„connectCliok(Sender: TObject);
// Создать объект типа "Справочник*
begin
SB_Ref_disconnect.Click;
if not VarlsEmpty(ole_lC) then begin
H Проверка существования справочника в данной конфигурации
if YeeReferencelnThielC(ole_lC,Trim(Edit_RefName.Text)} then begin1
// Справочник с именем, заданным в Edit_RefName.Text, существует.
// Создаем этот справочник и получаем на него ссылку
ole_lC_ref:=ole_lC.CreateObject('Справочник.1+Trim(Edit_RefName.Text)); j if not VarIsErrpty(ole_lC_ref) then begin
//Справочник создан и ссылка на него существует
Label_YesConnect_to_Obj.Visible:=TRUE;
SB_Ref„connect.Enabled:=FALSE;
SB_Ref_disconnect.Enabled:=TRUE;
SB_Ref„Load.Enabled:=TRUE;
Edit_RefName.Enabled:= FALSE;
Edit_RefNaine. Color: =clSilver ;
end;
end
else begin
ShowMessage('Справочник.’
+ Trim (Edi t_RefName. Text)
+ • не существует в этой конфигурации');
end;
end;
end;
Поясним текст обработчика.
В данном случае подход тот же, что и ранее (например, в листинге 4.7), единственное отличие — это проверка существования справочника в текущей конфигурации.
Примечание
Проверку производит функция YesReferencelnThislC, полный текст которой приведен на сопроводительном компакт-диске книги в файле \sp_Ub\sp_Lib_ DelphLPAS.
Если после компиляции и запуска программы ввести идентификатор несуществующего справочника (например, *иалица_ххх), обработчик (листинг 4.10) выведет на экран соответствующее сообщение (рис. 4.44).
Спавочмик. ФизЛица _ХХХ
w существует в этой конфигурации
Рис. 4.44. Сообщение
Теперь изменим обработчик события "нажатие кнопки Выполнить действие" (кнопка с пиктограммой бегущих человечков, см. рис. 4.43) следующим образом (листинг 4.11).
^~""'"-----V-w4r---5PT--=^~.-w^^"^™'rr-^:Ivv^^^^
Листинг 4.11. Обработчик события “нажатие кнопки Выполнить действие"
Procedure TForml. SB_Raf_LoadClick(Sender: TObject);
^Сделать выборку элементов справочника
Var
idAttr: string; II Идентификатор реквизита справочника iCol : integer; II Номер столбца для SG_Info
begin
SG_In fo_Clear;
if not VarlsEmpty(ole_lC_ref) then begin
'' По умолчанию, если свойство Memo_ListAttr_Ref.Lines
Об Часть I. 1Си механизм OLE Automatic
//не содержит строк, в выборку попадут толькоЯ
// "Код" и "Наименование" элемента справочника■
if Memo_ListAttr_Ref.Lines.Count>0 then beginЯ
// Если в списке были указаны идентификаторы реквизитов справочника, Я // для каждого из них должен быть зарезервированЯ
// отдельный столбец в SG_Info(™na TStringGrid)
SG_Infо.ColCount:=SG_Infо.ColCount+Memo_ListAttr_Ref.Lines.Count! for iCol:=2 to (SG_Info.ColCount-l) do begin
idAttr:=Trim(Memo_ListAttr_Ref.Lines[iCol-2]);Я
// Идентификаторы реквизитов размещаем взаголовке■
// соответствующего столбца таблицы®
SG_Info.Cells[iCol,0]:=idAttr; end;M
//=======================^===========^■
// Здесь будем в дальнейшем расширять возможности
// программы для реализации различных спсобов выборки
// элементов справочника1
if (CcsnboBox_Action. Itemindex in [0]) then begin|
// Метод выбора элементов справочника:
// "ВыбратьЭлементы без учета иерархии"|
//Эта функция реализует непосредственно выборку func_Ref_SelectItems_O; end;।
J/===========================================
end;
end;I
Поясним текст обработчика (листинг 4.11). Здесь все тривиально. Проверяется. I существует ли ссылка на справочник (переменная oie_ic_ref). Затем анализируется список реквизитов для чтения (см. рис. 4.43). Далее, в зависимости от того, какое действие было выбрано (значение comboBox_Action. itemindex. | рис. 4.45), вызывается соответствующая функция (в данном случае —Я func_Ref_SelectItems_O).—I
ВвйратьЭпемвнгы с учетом иерархии
Рис. 4.45. Выбор действия при обработке справочника
Текст функцииТекст функцииfunc_Ref_Select!tems_O приведен в листинге 4.12.func_Ref_Select!tems_O приведен в листинге 4.12.TForml.funcRef_SelectItenw_O: integer;TForml.funcRef_SelectItenw_O: integer;functionfunctionметод выбора элементов "ВыбратьЭлементы" справочникаметод выбора элементов "ВыбратьЭлементы" справочникаГп^.
Текст функции
Текст функции
func_Ref_Select!tems_O приведен в листинге 4.12.
func_Ref_Select!tems_O приведен в листинге 4.12.
TForml.funcRef_SelectItenw_O: integer;
TForml.funcRef_SelectItenw_O: integer;
function
function
метод выбора элементов "ВыбратьЭлементы" справочника
метод выбора элементов "ВыбратьЭлементы" справочника
idRef.
idAttr: string;
sValAttr: string;
// Идентификатор справочника,
// идентификатор реквизита,
// значение реквизита,которое нужно // разместить в таблице,
ЫГТуре,
// тип реквизита
И заесъ реализован
var
iCol.iRow: integer;
begin
Result:=0;
GroupBox_Method_l.Caption:=,Метод: ВыбратьЭлементы без учета иерархии'; if not VarlsEnpty(ole_lC_ref) then begin // Считываем идентификатор справочника.
// Он нужен нам для того, чтобы проверить
// существование реквизита этого справочника idRef: =Tr ini (Edi t_RefName. Text) ;
/ / Выбираем все элементы справочника
if ole_lC_ref.ВыбратьЭлементы(0)>0 then begin
// Поочередно извлекаем из выборки // все элементы справочника в цикле iRoW:=0;
while ole_lC_ref.ПолучитьЭлемент>О do begin
Result:=Result+l;
iRow:=iRow+l;
if iRow>=SG_Info.Rowcount then SG_Info.RowCount:=SG_Info.RowCount+l; SG_lnfо.Rows[iRow).Clear;
// Размещаем в таблице код элемента справочника SG_Infо.Cells[0,iRow]:=Trim(ole_lC_ref.Код);
// Размещаем в таблице наименование элемента справочника SG_info.Cells[l,iRow]:=Trim(ole_lC_ref.Наименование);
if SG_lnfo.ColCount>2 then begin
// Если заданы реквизиты для считывания, // сканируем соответствующие столбцы и выбираем
// из их заголовков идентификаторы реквизитов
tor iCol:=2 to (SG_Info.ColCount-l) do begin
// Считываем идентификатор реквизита
idAttr:=Trim(SG_Info.Cells[iCol,0]);
// Определяем тип реквизита
NrType:=GetTypeAttrReference_lC(ole_lC,idRef,idAttr);
sValAttr:= *<???>';
//===—^^^=======^==ss=:===:=:=Ksas:a=:z^ss=e=====a======:=s j // Считываем реквизит с учетом его типа
if (NrType in [1..3]) then begin И Базовый тип
//Строка, Число или Дата
sValAttr:=Trim(ole_lC_ref.ПолучитьАтрибут{1'+idAttr));' end;
if NrType=10 then begin // Перечисление
sValAttr:= Trim (ole_lC_ref-ПолучитьАтрибут(1'+idAttr).Идентификатор); end;
if NrType=ll then begin // Справочник sValAttr:= Trim(ole_lC_ref.ПолучитьАтрибут(1*+idAttr).Наименование);I end;
//========================================================
/l Записываем считанное значение реквизита
// в соответствующий столбец
SG_Infо.Cells(iCol,iRow]:=sValAttr;
end;
end;
Application.ProcessMessages;
end;
end;
end;
end;
Поясним текст обработчика (листинг 4.12).
Как и раньше (например, см. листинг 4.7), выборка из справочника произ! дится с использованием метода Выбрать элементы, а позиционирование на ка дом элементе справочника — с использованием метода получить Элемент.
Затем в обязательном порядке считываются код и Наименование элеме> справочника.
. ее, если указаны реквизиты, то в цикле считываются их идентификаторы, ПреДСЛЯетСЯ ТИП реквизита (функция GetTypeAttrReference_10) и, в зависимости от типа реквизита, считывается его свойство (как значение для разрешения в таблице).
ПРИМЕЧАНИЕ
Полный текст функции GeCTypeAttrReference_lC приведен в файле \sp_Lib\sp_Lib_Delphi.PAS на сопроводительном компакт-диске книги.
Чтобы проверить, как все это заработает, скомпилируем проект и запустим его на выполнение. Укажем справочник Физлица и внесем в список реквизитов для чтения идентификаторы соответствующих реквизитов (рис. 4.46).
Что смотреть: [Идентификатор справочнике:
| [ФизЛица
- Список реквизитов для чтения:
ДатаРождения3
ГородПроживания ДомашнийАдрес Пол
СемейноеПоложение
Рис. 4.46. Список реквизитов справочника,значения которых нужно выбрать
Теперь запустим 1С:Предприятие (как сервер OLE Automation), нажав кнопку 1С (см. рис. 4.43). Затем откроем справочник (кнопка с пиктограммой открытой книги) и запустим выборку элементов справочника (кнопка с пиктограммой бегущих человечков). Результат представлен на рис. 4.47.
Buioi i1»
I
*аэлементов справочника—~ ".
Наидатаани,| ДатаРожд^ ГорооПрок,] ДсяаастяйАдрес|Поп|См«<1ноеЛало.™**[
01 011970 МееРсссия.гБ.уяБ.дООМухстой Раземеи
ИыиоеИынИыноаж01011971МостыРоссия, г Нацист,».-., ул А. а.01МужскойСостонгВЗарегистрироыккомБрам»
'««еноеаФстыМаошеао 15031965ГонегъРоссия. г N. ул. У.а 005ЖенатаНилогдаНеСостояЛБрака
Пегие Петр Петрова01 01 1972М.истРоссия, г Неиамстиьй. улА.дО2МужскойГраждлюяйБр®.
Сидоров Geop Сидорович01 01.19738олгоградРоссия, г Неиэвеет»». улА. д 03МужстсйВесели
феасоое Федор Фщиееич 01011974 КимРоссия, г Известие* улБ .я001 Мужской Разошелся
Рис. 4.47. Результат выборки элементов справочника
Теперь попробуем прочитать элементы справочника с учетом иерархии. Для "ачала — с учетом владельца. Текст функции, решающей эту задачу, приве- 4ен в листинге 4.13.
Листинг# 13. Выборка элементов справочника Фиэлица с учетом владельца!
function TForml.func_Ref_8electltema_l: integer;
// Здесь реализован метод выбора элементов
// справочника "ВыбратьЭлементы" с учетом владельца Var
ole_lCRef_Owner, // Ссылка на справочник-владелец ole_lCRef_OwnerTekEl: OleVariant; // Ссылка на текущий элемент // справочника-владельца idRefOwner, idRef,//Идентификаторсправочника,
idAttr:string;//идентификаторреквизита,
sValAttr:string;//значение реквизита,которое нужно
// разместить в таблице, NrType,//тип реквизита
iCol.iRow: integer; begin
Result:=0;
ole_lCRef_Owner:=UnAssigned;
ole_lCRef_OwnerTekEl:=UnAssigned;
GroupBox_Method_l.Caption:='Метод: ВыбратьЭлементы с учетом владельца; if not VarlsEmpty(ole_lC_ref) then begin IJ Считываем идентификатор справочника.
//Он нам нужен для того, чтобы проверить существование // реквизита этого справочника idRef:=Trim(Edit_RefName.Text);
// Проверяем, есть ли владелец у этого справочника
if о!е_1С.Метаданные.Справочник!''+idRef).Владелец.Выбрам>О then begin // Справочник-владелец существует
// Считываем идентификатор справочника-владельца
idRefOwner:=Trim(о!е_1С.Метаданные.Справочник!'' +idRef).Владелец. Идентификатор);
//Создаем объект: справочник-владелец ole_lCRef_Owner:=ole_lC.CreateObject('Справочник.'+idRefOwner); if not VarIsBnpty(ole_lCRef_Owner) then begin
// Выбираем владельца
if ole_lCRef_Owner.Выбрать!'Выберите владельца','')>0 then begin H Читаем ссылку на текущий элемент справочника
ole_lCRef_OwnerTekEl:=ole_lCRef_Owner.ТвкушийЭлемеит;
^авэ_4. Доступ к информации 1С из внешних приложений end;
end;
end;
if not VarlsBnpty(ole_lCRef_OwnerTekEl) then begin ц Если владелец был выбран, вызываем соответствующий. ц метод для фильтрации
ole_lC_ref.ИспальзоаатьВладвльца(о1е_1СКе£_0«пегТекЕ1,0);
//В некоторых случаях вызов метода, как в предыдущей строке, // может не сработать. Тогда возможен следующий вариант:
//ole_lC_ref.ИспольэоватьВладельца(ole_lCRef_Owner.ТекущийЭлемент,0);
end;
// Выбираем все элементы справочника с учетом иерархии
if ole_lC_ref.ВыбратьЭлементы(1}>0 then begin
// Поочередно извлекаем из выборки
И все элементы справочника в цикле
iRow:=0;
while ole_lC_ref.ПолучитьЭлемент>0 do begin
Result:=Result+1;
iRow:=iRow+l;
if iRow>=SG_Info.RowCount then SG_Info.RowCount:=SG_Info.RowCount+l;
SG_Info.Rows[iRow].Clear;
// Размещаем в таблице код элемента справочника
SG_Info.Cells[0,iRow]:=Trim(ole_lC_ref.Код);
// Размещаем в таблице наименование элемента справочника
SG_Info.Cells[l,iRow):=Trim(ole_lC_ref.Наименование);
if SG_Info.ColCount>2 then begin
// Если заданы реквизиты для считывания, сканируем соответствующие
// столбцы и выбираем из их заголовков идентификаторы реквизитов
for iCol:=2 to (SG_Info.ColCount-l) do begin
// Считываем идентификатор реквизита
idAttr:=Trim(SG_Info.Cells[iCol,0));
11 Определяем тип реквизита
NrType:=GetTypeAttrReference_lC(ole_lC,idRef,idAttr); sValAttr:= '<???>';
^”====== ============SSS=SS===========S====SX==X=S=
// Считываем реквизит с учетом его типа
if (NrType in [1..3]) then begin // Базовый тип
//Строка, Число или ДатаЛ
sValAttr:=Tr im(ole_lC_ref.ПолучитьАтрибут{''+idAttr));Я
end;|
if NrType=10 then begin И Перечислениея
sValAttr: = Trim(ole_lC_ref.ПолучитьАтрибут(''+idAttr).Идентификатор)
end;Я
if NrType=ll then begin // Справочник0
sValAttr:= Trim (ole_lC_ref.ПолучитьАтрибут!1'+idAttr).Наименование);Я
end;a
//=======================================================1
// Записываем считанное значение реквизита в соответствующийстолбецЯ
SG_Info.Cells[iCol,iRowJ:=sValAttr;9
end;я
end;1
Application.ProcessMeasages;|
end;I
end;■
end;Я
end;Я
Поясним текст обработчика (листинг 4.13).1
Здесь в строке:
if о1е_1С.Метаданные.Справочник!'1tidRef)-Владелец.Выбран>0 then begin 1 определяется, есть ли у данного справочника (idRef) справочник-владелец! Если нет, все происходит так же. как и в функции func_Ref_selectitems_fl (листинг 4.12). Если справочник-владелец существует, то создаем ссылку № этот справочник:j
ole_lCRef_Owner:=ole_lC.CreateObject('Справочник. Ч-idRefOwner);|
Затем вызываем метод справочника-владельца для выбора элемента в окнЯ диалога:|
if ole_lCRef_Owner.Выбрать!'Выберитевладельца',1')>0thenbegin|
При вызове этого метода на экране появится диалоговое окно 1С:Предприятие (рис. 4.49), где можно выбрать двойным щелчком элемен11 справочника. Если элемент справочника был выбран, считываем ссылку H# него с помощью свойства ТекущийЭлемент справочника-владельца:■
ole_lCRef_OwnerTekEl:=ole_lCRef_Owner.ТекущийЭлемент;|
Если ссылка на ТекущийЭлемент корректна, вызываем метод ИспользоватьВда-*! дельца подчиненного справочника:|
ole_lC_ref.ИспольаоватьВладальца(ole_lCRef_OwnerTekEl,0);J
Ц1И
oie ic_ref.ИспольэомтьВлалелъца(о1е_1СКе£_Омпег.ТекущийЭлемент,0);
уеМ самым обеспечивается фильтрация выборки элементов справочника при
вызове метода Выбрать Элементы.
Установить выборку подчиненного справочника позволяет метод использо- ватьВладельца (ИЛИ UseOwner). Синтаксис:
ИспользоватьВладельца(Владелец, ФлагИзменения)
Параметры: <владелец> (необязательный) — выражение со значением элемента справочника-владельца; <ФлагИэменения> (необязательный) — регулирует возможность интерактивного изменения владельца (1 — пользователь может изменить владельца интерактивно. О — пользователь не может интерактивно изменить владельца). Метод возвращает значение элемента справочника-владельца для текущего подчиненного справочника (на момент до исполнения метода).
Добавим в свойство Lines компонента comboBox_Action (Delphi) строку:
"ВыбратьЭлементы с учетом владельца"
Изменим обработчик события "нажатие кнопки Выполнить действие (SB_Ref_Load)" следующим образом (листинг 4.14).
,/======================
in [0]) then beginin [0]) then beginif (ComboBoxAction.Itemindex
in [0]) then begin
in [0]) then begin
end;
if (ComboBoxAction.Itemindex in [ID then begin
// Метод выбора элементов справочника:
// "ВыбратьЭлементы с учетом иерархии"
// Эта функция реализует непосредственно выборку func_Ref_SelectIteme_l;
end;
//===========================================
И запустим наш проект на выполнение.
Создадим соединение с 1С:Предприятие.
Укажем идентификатор справочника, имеющего владельца, способ выборки fc помощью раскрывающегося списка) и запустим выборку элементов справочника (рис. 4.48).
Рис. 4.48. Режим выборки элементов справочникаРис. 4.48. Режим выборки элементов справочника
Рис. 4.48. Режим выборки элементов справочника
Рис. 4.48. Режим выборки элементов справочника
В ответ на запрос (вызов метода выбрать справочника) програ, 1С:Предприятие выведет на экран диалоговое окно выбора элементов щ вочника (рис. 4.49).
^ 0^ 0НаименованиеЗЦБелорусия Россия-3| УкраинаНаименованиеЗЦБелорусия Россия-3| Украина.Выберите владельца (Выбор)
^ 0
^ 0
Наименование
ЗЦБелорусия Россия
-3| Украина
Наименование
ЗЦБелорусия Россия
-3| Украина
J
Рис. 4.49. Диалоговое окно (1С:Предприятие)для интерактивного выбора элемента справочника
Выбор элемента производится двойным щелчком мыши на соответствуют строке.
Примечание
Окно программы 1С:Предприятие (как сервера OLE Automation) по умолчаг остается невидимым. Поэтому диалоговое окно, показанное на рис. 4.49, мо; быть скрыто другими окнами различных приложений, запущенных в дань момент на компьютере. В таком случае можно "найти" диалоговое окно с мощью сочетания клавиш <Alt>+<Tab>. На рис. 4.50 показана пиктограм! которую нужно выбрать для того, чтобы диалоговое окно появилось лов! остальных окон.
Рис. 4.50. Пиктограмма,соответствующая приложению 1 С: ПредприятиеРис. 4.50. Пиктограмма,соответствующая приложению 1 С: ПредприятиеНа рис. 4.51 представлен результат выборки элементов СтранМира для элемента справочника-владельца Россия.На рис. 4.51 представлен результат выборки элементов СтранМира для элемента справочника-владельца Россия.справочника Города1справочника Города1
Рис. 4.50. Пиктограмма,соответствующая приложению 1 С: Предприятие
Рис. 4.50. Пиктограмма,соответствующая приложению 1 С: Предприятие
На рис. 4.51 представлен результат выборки элементов СтранМира для элемента справочника-владельца Россия.
На рис. 4.51 представлен результат выборки элементов СтранМира для элемента справочника-владельца Россия.
справочника Города1
справочника Города1
Глава.Глава.-Что смотреть: —-Что смотреть: —лементы с учетом владельца1 г Метоп: В ыбрятьЗ лементы—лементы с учетом владельца1 г Метоп: В ыбрятьЗ лементы—ЕиФикатор crpaeowKa:«аС^онМирй е*й*мие собъектом г Список реквизитов для чтения: —;|ЕиФикатор crpaeowKa:«аС^онМирй е*й*мие собъектом г Список реквизитов для чтения: —;|Код (НаименованиеКод (Наименование44ВолгоградВолгоград2,32,3МоскваСанкт-ПетербургУсинскМоскваСанкт-ПетербургУсинск
Глава.
Глава.
-Что смотреть: —
-Что смотреть: —
лементы с учетом владельца
1 г Метоп: В ыбрятьЗ лементы—
лементы с учетом владельца
1 г Метоп: В ыбрятьЗ лементы—
ЕиФикатор crpaeowKa:
«аС^онМирй е*й*мие собъектом г Список реквизитов для чтения: —;|
ЕиФикатор crpaeowKa:
«аС^онМирй е*й*мие собъектом г Список реквизитов для чтения: —;|
Код (Наименование
Код (Наименование
4
4
Волгоград
Волгоград
2,
3
2,
3
Москва
Санкт-Петербург
Усинск
Москва
Санкт-Петербург
Усинск
Рис. 4.51. Результат выборки из справочника.
Фильтрация с применением метода ИспольэоватьВладельца
Объекты типа справочник в системе 1 С:Предприятие могут иметь иерархическую структуру. Это значит, что элементы справочников могут быть сгруппированы определенным образом. Чтобы посмотреть, как механизм OLE
Automation позволяет делать это, вновь изменим структуру справочника Физлица. Для этого запустим Конфигуратор 1С:Предприятие и откроем справочник ФизЛица (СМ. рис. 2.13).
Внесем изменения, показанные на рис. 4.52.
Кол-во. уровней [й 3Еаэмещагь группы сверху Р
Рис. 4.52. Установка глубины вложенностииерархической структуры справочника ФизЛица
Сохраним конфигурацию (см. рис. 2.17). Созданные нами изменения отразятся в словаре данных (файл 1Cv7.DD, рис. 4.53).
Как видите, в файле SC12.DBF появились два дополнительных поля parentid и ISFOLDER, а также индекс VIP37.
Теперь запустим программу 1С:Предприятие (см. рис. 2.23) и откроем справочник ФизЛица. В списке справочника откроем всплывающее меню (рис. 4.54) и выберем пункт Иерархический список.
Затем опять откроем всплывающее меню и выберем пункт Новая группа (рис. 4.55).
На экране появится диалоговое окно редактирования группы справочника, где нужно внести наименование группы и нажать кнопку ОК (рис. 4.56).
Далее последует запрос подтверждения изменений (рис. 4.57).
Результат представлен на рис. 4.58.
[-пава 4. Доступ к информации 1С из внешних приложений
77
76
Часть I. 10 и механизм OLE Automati
Рис. 4.53. Содержание файла 1Cv7.DD. Структура справочника ФизЛица
Код: |7 Наименование: [Группа-1
ОК | Закрыть
Рис. 4.56. Диалоговое окно редактирования группы справочника
Рис. 4.57. Запрос на сохранение изменений в справочнике
Рис. 4.54. Включение/отключение режима визуализации справочника ФизЛица с учетом иерархической структуры
113 £3 Список Фиэи^ ' 1 Группа-1
□
ma
Наименование
Дата рож.
Ml
Г руппа-1
М
5
Аксакалов Аксакал Аксакалович
01.01.70
Ml
1
Иванов Иван Иванович
01.01.71
Ml
6
Криогенова Фекла Маринадовна
1503 65
м
2
Петров Петр Петрович
01.01.72
Ml
3
Сидоров Сидор Сидорович
01.01.73
Ml
4
Федоров Федор Федорович
01 01.74
Рис. 4.58. Список справочника в режиме отображения иерархии
Э ^ Список физических лиц
Группа-1
Рис. 4.59. Выбор группы в иерархическом списке справочника
Рис. 4.55. Новая группа в справочнике
Рис. 4.60. Перенос элемента справочника в другую группу
Как видите, группа создана, но в эту группу не входит ни один из элементо справочника. Чтобы перенести элемент справочника в группу, отметим cooi ветствующую группу (рис. 4.59).
Затем отметим тот элемент справочника, который нужно перенести в групп] и откроем всплывающее меню, где выберем пункт Перенести в другу) группу (рис. 4.60).
Последует запрос подтверждения переноса (рис. 4.61).
Перенести Иванов Иван Иванович в Гругпа-1 ?Перенести Иванов Иван Иванович в Гругпа-1 ?
Перенести Иванов Иван Иванович в Гругпа-1 ?
Перенести Иванов Иван Иванович в Гругпа-1 ?
ДаДаНет
Да
Да
Рис. 4.61. Запрос подтверждения переноса элемента справочника в другую группу
На рис. 4.62 представлен результат, когда все физические лица (кроме элемя та с кодом 6) разнесены по группам.
На рис. 4.63 представлено содержание группы "Группа-1".
в-а , |Tj Группа-1 ill Группа-2 £] Грута-3в-а , |Tj Группа-1 ill Группа-2 £] Грута-3Список Фи31Список Фи31Рис. 4.62. Список справочника в режиме отображения иерархииРис. 4.62. Список справочника в режиме отображения иерархииРис. 4.63. Список справочника в режиме отображения иерархии. Труппа-1" справочникаРис. 4.63. Список справочника в режиме отображения иерархии. Труппа-1" справочника
в-а , |Tj Группа-1 ill Группа-2 £] Грута-3
в-а , |Tj Группа-1 ill Группа-2 £] Грута-3
Список Фи31
Список Фи31
Рис. 4.62. Список справочника в режиме отображения иерархии
Рис. 4.62. Список справочника в режиме отображения иерархии
Рис. 4.63. Список справочника в режиме отображения иерархии. Труппа-1" справочника
Рис. 4.63. Список справочника в режиме отображения иерархии. Труппа-1" справочника
На рис. 4.64 представлен список справочника, когда отключен режим иера хического отображения.
: CJ Группа-1О Групла-2 '- CJ Г руппа-3: CJ Группа-1О Групла-2 '- CJ Г руппа-3[Ко^НаименованиеАксакалов Аксакал Аксакалоеич7Г руппа-18Грута-29Г рута-31Иванов Иван ИвановичБКриогенова Фекла Маринад овна2Петров Петр Петрович3Сидоров Сидор Сидорович4Федоров Федор Федорович[Ко^НаименованиеАксакалов Аксакал Аксакалоеич7Г руппа-18Грута-29Г рута-31Иванов Иван ИвановичБКриогенова Фекла Маринад овна2Петров Петр Петрович3Сидоров Сидор Сидорович4Федоров Федор Федорович
: CJ Группа-1
О Групла-2 '- CJ Г руппа-3
: CJ Группа-1
О Групла-2 '- CJ Г руппа-3
[Ко^
Наименование
Аксакалов Аксакал Аксакалоеич
7
Г руппа-1
8
Грута-2
9
Г рута-3
1
Иванов Иван Иванович
Б
Криогенова Фекла Маринад овна
2
Петров Петр Петрович
3
Сидоров Сидор Сидорович
4
Федоров Федор Федорович
[Ко^
Наименование
Аксакалов Аксакал Аксакалоеич
7
Г руппа-1
8
Грута-2
9
Г рута-3
1
Иванов Иван Иванович
Б
Криогенова Фекла Маринад овна
2
Петров Петр Петрович
3
Сидоров Сидор Сидорович
4
Федоров Федор Федорович
Рис. 4.64. Список справочника при выключенном режиме отображения иерархии
Содержание таблицы:
sew
ZE
Т-1
Открьлъ таблицу |
ID
| PARENTID | COD
eTdESCRllSFOLDER II
►
1
| 7
1
Иванов Иван Иванович
2
2
8
2
Петров Петр Петрович
2
3
8
, 3
Сидоров Сидор Сидорович
2
4
У 9
4
Федоров Федор Федоров к
2
5
: 7
5
.Аксакалов Аксакал Аксакг
2
6
0
6
Криогенова Фекла Марша
2
7
0
7
Группа-1
Г
В
0
8
Группа-2
1-
9
0
9
Группа-3
1
Рис. 4.65. Содержание файла SC12.DBF
Откроем файл SC12.DBF в любом просмотрщике DBF-файлов (рис. 4.65).
Здесь видно, что поле parentid содержит ссылку на соответствующую группу справочника.
Теперь вернемся к нашему проекту (Delphi). Создадим новую форму диалога с Именем Dlg_Sel_Grp_In_Ref (рис. 4.66).
Рис. 4.66. Форма диалога для выбора группы справочникаРис. 4.66. Форма диалога для выбора группы справочника
Рис. 4.66. Форма диалога для выбора группы справочника
Рис. 4.66. Форма диалога для выбора группы справочника
80
Создадим метод Execute, который должен обеспечить выбор группы спр вочника (листинг 4.15).
function TDlg_Sel_Grp_In_Ref.Execute(ole_lC_ref: OleVariant): string;
// Метод возвращает код выбранной группы.
И ole_lC_ref - корректная ссылка на справочник.
Var
Sx: string;
begin
Result:='';
ListBoxl.Items.Clear;
if not VarIsEmpty(ole_lC_ref) then begin
if ole_lC_ref.ВыбратьЗлементы(О)>0 then begin
while ole_lC_ref.Получить3лемент>0 do
begin
if ole_lC_ref.ЭгоГруппа>0 then begin
// Выбираем только группы в справочнике
Sx:=Trim(ole_lC_ref.Код);
Sx:=Sx+'.'+Trim(ole_lC_ref-Наименование);
ListBoxl.Items.ADD(Sx);
end;
end;
end;
if ShowModal = mrOk then begin
if ListBoxl.ItemIndex>=0 then begin
// Если группа выбрана, выделим из строки код группы Sx:=ListBoxl.Items[ListBoxl.Itemindex);
Result:=Trim(Bp_GetWordFronString('.',Sx,1));
end;
end;
end;
end;
Поясним текст обработчика (листинг 4.15).
Здесь в цикле отбираются только группы справочника (для проверки испо зуется метод справочника Этогруппа). Таким образом, заполняется спис
ListBoxl.
Если выбор в списке произведен и нажата кнопка ОК, из выбранной строки выделяется КОД группы (ЭТО делает функция sp_GetWordFromString).
Примечание
Полный исходный код этой функции приведен на сопроводительном компакт- диске книги в файле \sp_Llb\sp_Lib_Delphi.PAS.
Создадим функцию, реализующую вывод информации с учетом группировки (листинг 4.16).
(ЛистингМиоттов справочника ♦хелица с учетом родителя
function TForml.func_Ref_SelectItems_2: integer;
// Здесь реализован метод выбора элементов справочника:
// ВыбратьЭлементы с учетом родителя
Var
ole_lCRef_ParentTekEl: OleVariant; // Ссыпка на группу
И (текущий элемент)
idRefParent, // Идентификатор группы
idRef,//Идентификаторсправочника
idAttr: string; // Идентификатор реквизита
sValAttr: string; // Значение реквизита, которое // нужно разместить в таблице
НгТуре, // Тип реквизита
NrMode, Н Режим открытия выборки
OleBuf: oleVariant;
iCol,iRow: integer;
begin
Result:=0;
01e_lCRef_ParentTekEl:=UnAssigned;
idRefParent:='';
Gr°upBox_Method_l.Caption: = 'Метод: ВыбратьЭлементы (с учетом родителя)';
if not VarlsBnpty(ole_lC_ref) then begin
И Считываем идентификатор справочника.
* Он нам нужен для того, чтобы проверить
* существование реквизита этого справочника
idRef:=Trim(Edit_RefName.Text);
1 По умолчанию устанавливаем режим выборки
11 элементов справочника без учета иерархии
NrMode:=0;
11 Проверяем, иерархический ли это справочник
if о!е_1С.Метаданные.Справочник!1’+idRef)-Количаст»оУрожмей>1 then beg И Это иерархический справочник.
// Устанавливаем режим выборки элементов справочника
//с учетом иерархии
NTMode:=l;
// Выбираем родителя (группу)
idRefParent:=Dlg_Sel_Grp_In_Ref-Execute(ole_lc_ref);
if length(idRefParent)>0 then begin
// Если выбрали родителя — позиционируемся на нем
if (ole_lC_ref-НайтиПоКоду(1'+idRefParent,0))*l>0 then begin' // Установим фильтрацию по выбранному родителю (группе) ole_lCRef_ParentTekEl:=ole_lC_ref.ТекущийЭлемент;
ole_lC_ref.ИспользоватьРодителя(о1е_1СКе£_РагепСТекЕ1,0);■
// В некоторых случаях вызов метода,1
// как в предыдущей строке, может не сработать.
//Тогда возможен следующий вариант:
//ole_lC_ref.ИспользоватьРодителя(ole_lC_ref.ТекущийЭлемент^ end;
end;
end;
// Выбираем все элементы справочника с учетом иерархии
if ole_lC_ref .ВыбратьЭлементы(№№х1е*1)>0 then begin
// Далее, поочередно извлекаем из выборки
// все элементы справочника в цикле
iRow:=0;
while ole_lC_ref.ПолучитьЭлемент>0 do
begin
Result:=Result+l;
iRow:=iRow+l;
if iRow>=SG_Info.RowCount then SG_Infо.RowCount:=SG_Infо.RowCount+1/ SG_Info.Rows[iRow]-Clear;
// Размешаем в таблице Код элемента справочника
SG_Info.Cells[0,iRow):=Trim(ole_lC_ref-Код);
// Размещаем в таблице наименование элемента справочника SG_Info.Cells[l,iRow]:=Trim(ole_lC_ref-Наименование);
if SG_Info.ColCount>2 then begin
// Если заданы реквизиты для считывания, // сканируем соответствующие столбцы и выбираем
// из их заголовков идентификаторы реквизитов for iCol:=2 to (SG_Info.ColCount-l) do begin
// Считываем идентификатор реквизита ^dAttr:=Trim(SG_Info.Cells[iCol,0]); И ОПРЕДЕЛЯЕМ тип реквизита
NrType:=GetTypeAttrReference_lC(ole_lC,idRef,idAttr); SValAttr;= '<???>';
// Считываем реквизит с учетом его типа
if (NrType in [1..3]) then begin II Базовый тип
// Строка, Число или Дата
sValAttr:=Trim(ole_lC_ref.ПолучитьАтрибут(''+idAttr)); end;
if NrType=10 then begin И Перечисление
sValAttr:= Trim(ole_lC_ref.ПолучитьАтрибут(''+idAttr|.Идентификатор); end;
if NrType=ll then begin // Справочник
sValAttr:= Trim(ole_lC_ref.ПолучитьАтрибут(''+idAttr).Наименование); end;
if NrType=12 then begin // Документ
oleBuf:= ole_lC_ref.ПолучитьАтрибут(1"+idAttr);
sValAttr:= Trim(oleBuf.Вид)
+ ' N '
+ Trim(oleBuf.НомерДок)
+ ' I’
+ Trim (oleBuf.ДатаДок)
end;
======================================================= писываем считанное значение реквизита в соответствующий столбец
SG_Infо.Cells[iCol,iRow]:=sValAttr;
end;
end;
Applica tion.ProcessMessages;
end;
end;
end,, end,-
Функция func_Ref_Selectitems_2 позволяет проверить, является ли даннь справочник иерархическим. Для этого используется объект Метаданные. Ecj справочник имеет иерархическую структуру, то атрибут количествоУровж принимает значение больше 1. Если справочник иерархический, то вызыа ется метод Dlg_Sel_Grp_In_Ref .Execute (листинг 4.15), который возвраща код выбранной группы. Далее используется метод справочника НайтиПоКа для того, чтобы получить значение свойства выбранной группы ТекушийЭле.ме| Затем вызывается метод справочника Использовать Родителя, который определяет фильтрацию элементов справочника при выборке.
Примечание
Обратите внимание: умножение на 1 — это не каприз программиста, а нюан работы системы 1С:Предприятие посредством механизма OLE Automation.
Далее производится выборка элементов справочника и визуализация инфе мации. В частности, реквизитов типа Документ.
Метод использовать Родителя (или useParent) справочника позволяет ус| новить выборку по группе справочника. Синтаксис:
ИспользоватьРодителя(<Группа>)
Необязательный параметр <группа> — выражение со значением трупа справочника. Метод возвращает значение текущей группы для справочки) (на момент до исполнения метода).
Данный метод используется до вызова метода выбрать элементы, котом фактически открывает выборку. Дальнейшая выборка при помощи мето! получитьэлемент будет выполняться только среди элементов текущего спр вочника. принадлежащих указанной группе.
Добавим в свойство Lines компонента comboBox_Action (Delphi) строку:
"ВыбратьЭлементы с учетом родителя"
Изменим обработчик события "нажатие кнопки Выполнить действ (SB_Ref_Load)" следующим образом (листинг 4.10).
’•■• ■ —V"—••■ -"’ - <
1Г4.17. Обработчик события "нажатие кнопки Выполнить действие
//========================================== if (ComboBox_Action.Itemindex in [0]) then begin
end;
if (ComboBox_Jkction.Itemindex in [1]) then begin
er.d;
;f (ComboBox_^Action. Itemlndex in [2]) then begin
// Метод выбора элементов справочника:
// "ВыбратьЭлементы с учетом Родителя"
II Эта функция реализует непосредственно выборку func_Ref_8electlteme_2;
end;
I /-================= = = = = ====== ================
И запустим наш проект на выполнение.
Создадим соединение с 1С: Предприятие.
Укажем идентификатор справочника с иерархической структурой, способ выборки (с помощью раскрывающегося списка) и запустим выборку элементов справочника (рис. 4.67).
Рис. 4.67. Выбор элементов справочника с учетом родителя
Если справочник иерархический, на экран будет выведено диалоговое окно Для выбора группы (рис. 4.68).
Рис. 4.68. Выбор группы справочника
На рис. 4.69 показан результат выборки для справочника Физлица по группе с кодом 8 ("Группа-2").
На рис. 4.70 показан результат выборки злемеито. справочника Физлица для ^Учая. когда группа не указана (см. рис. 4.68).
86
Рис. 4.69. Результат выборки элементов справочника о заданной группе
х
9 Групгм-3
Cancel
OK
• Выбрать группу
Рис. 4.70. Результат выборки из справочника с иерархической структурой
Список групп справочника.
7 Г пиппа-
В этом случае метод ИспользоватьРодителя не вызывается (листинг 4.16), методу выбратьэлементы в качестве параметра передается 1. что озна "выбирать элементы с учетом иерархии".
Как видите, при выводе результатов выборки порядок иерархии соблюл
4.1.5. Периодические реквизиты справочников
Периодические реквизиты — это реквизиты, значения которых свя с датой. При изменении значения периодического реквизита старое знач сохраняется, при этом новое значение действует с указанной даты, а ста до указанной даты. Работа с периодическими реквизитами осущсствля при помощи методов Получить и ИспользоватьДату, а также при поМ специального агрегатного типа данных Периодический (или Periodic). Вновь доработаем нашу конфигурацию. Внесем изменения в структуру вочника Физлица. Для этого запустим Конфигуратор 1С и создадим новое речисление СостояниеФизлица (рис. 4.71).
Далее, откроем окно редактирования свойств справочника Физлица рис. 2.13) И внесем новый реквизит СостояниеФизлица (рис. 4.72).
№ ер-.-чис лени-
щ й Пол
» й СемейноеП сложение
Э й СостояниеФизлица
■ Сотр^дмиг.Осиоеной
а СотруаникНеосноеной
Я» ВременноНеРабатает
Рис. 4.71. Содержание перечисления СостояниеФизлица
Сьоне та Реквизита
Общие | Дополнительные |
Идентификатор: [СостояниеФизлица
Синоним:
Комментарий Тип значения
Длина:
|Состояние Физлица
(Перечне пение. СостояниеФиэтца
Рис. 4.72. Свойства реквизита справочника СостояниеФизлица
Свойства Реквизита
Общие Дополнительные |
Разделять гр1<5аы Негл риивт^гмм# Периодический Сортирпдь.з
Г р
Отбор по реквизиту Г
Использовать:
| Для элемента
Р Изменяется Документами Ручное изменение
Рис. 4.73. Признак ■периодичности- реквизита справочника
^ическим8^^ Д°)полнительные' Укажем, что этот реквизит будет пе-
за^1УЛЬтате СГ|исок НЬ|и на рис. 4.74.
Примечание
^Лредпр^° сеойствах периодических реквизитов системы
Р е можно наити в специальной литературе.
реквизитов справочника Физлица будет иметь вид. пока-
г-Реквизиты
атаРождения
ГородПроживания Домашний4дрес Пол
СемейноеПсложение
ДополнигельнаяИ нформация
Рис. 4.74. Список реквизитов в справочнике ФизЛица
Рис. 4.75. Форма редактирования элементов справочника ФизЛица
Внесем соответствующие изменения в форму редактирования элемента ел? вочника ФизЛица (рис. 4.75).
После этого сохраним изменения в конфигурации (см. рис. 2.17).
Примечание
Если открыть словарь данных (файл 1Cv7.DD), то можно увидеть, что содер ние файла не изменилось. То есть несмотря на то, что в справочн был внесен новый реквизит, это не было отражено в словаре данных.
Запустим программу 1С:Предприятие. откроем справочник ФизЛица и сд< ем двойной щелчок на строке с кодом 4. На экране появится форма рея рования элемента справочника (рис. 4.76).
»л Список физических лиц:Группа-З.Федор... ВИ 13
а С?
44Код:
4
4
Наименование: Федоров Федор Федорович
Дота рождения:Дота рождения:Домашний адрес:Домашний адрес:01.01.74 QРоссия, г.Иэвестный. ул Б., д.00101.01.74 QРоссия, г.Иэвестный. ул Б., д.001ПодСемейное положение:ПодСемейное положение:Город проживания.Город проживания.МужскойРазошелся (разошлась](КиевМужскойРазошелся (разошлась](КиевQQQQ
Дота рождения:
Дота рождения:
Домашний адрес:
Домашний адрес:
01.01.74 Q
Россия, г.Иэвестный. ул Б., д.001
01.01.74 Q
Россия, г.Иэвестный. ул Б., д.001
Под
Семейное положение:
Под
Семейное положение:
Город проживания.
Город проживания.
Мужской
Разошелся (разошлась]
(Киев
Мужской
Разошелся (разошлась]
(Киев
Q
Q
Q
Q
основному месту работы неосновному месту работь!основному месту работы неосновному месту работь!Состояние физлица |Временно не работает
основному месту работы неосновному месту работь!
основному месту работы неосновному месту работь!
Дополнительная инФор[Сотрудник по
IСотрчдник по
Рис. 4.76. Редактирование элемента справочника в диалоге
Выберем значение реквизита "Состояние физлица" в раскрывающемся списке Состояние физлица (см. рис. 4.76).
После закрытия формы редактирования (нажатием кнопки ОК) и подтверждения в ответ на запрос о сохранении на экране появится диалоговое окно, предлагающее подтвердить сохранение изменений периодических реквизитов элемента справочника (рис. 4.77).
Примечание
Значения периодических реквизитов устанавливаются на определенную (рабочую) дату. Рабочую дату можно установить в диалоговом окне настройки системы (рис. 4.80).
Рис. 4.77. Запрос на подтверждение сохранения значений периодических реквизитов элемента справочникаРис. 4.77. Запрос на подтверждение сохранения значений периодических реквизитов элемента справочника
Рис. 4.77. Запрос на подтверждение сохранения значений периодических реквизитов элемента справочника
Рис. 4.77. Запрос на подтверждение сохранения значений периодических реквизитов элемента справочника
Далее, точно так же заполним значения реквизита "Состояние физлица" остальных элементов справочника. Результат приведен на рис. 4.78.
Коя
Н аименование|| Дата ...
Состояние Физлица
№
■
7
Аксакалов Аксакал Аксак
01.01.70
Сотрудник по неосновному месту работы
МГ
Группа-1
И
8II Группа-2
Pill
91 Грута-3
И:
1
Иванов Иван Иванович
01 01.71
Сотрудник по основному месту работы
№
8II Криогенова Фекла Марин-
15.03.65
Сотрудник по основному месту работы
@1
2
Петров Петр Петрович
01.01.72
Временно не работает
И
3|| Сидоров Сидор Сидорович
01 01 73
Сотрудник по неосновному месту работы
1®1
41| Федоров Федор Федоров
01.01.74
В ременно не работает
Рис. 4.78. Список элементов справочника ФизЛица
Для того чтобы можно было экспериментировать с периодическими рек» тами, нужно для каждого элемента справочника внести еще значения р» зита "Состояние физлица", но на другую дату. I Выберем в меню Сервис программы 1С:Предприятие пункт Парам» (рис. 4.79). 6
Рис. 4.79. Выбор пункта меню Сервис для настройки системы 1 С: Предприятие
На экране появится диалоговое окно настройки системы 1С:ПредпрИ (рис. 4.80).
На вкладке Общие этого окна установим новую рабочую дату. Зачем вне значения периодического реквизита "Состояние физлица" на новую дату зультат представлен на рис. 4.81.
В табл. 4.4 приведены значения периодического реквизита СостояниеФиб на даты "07.06.2006" и "24.06.2006".
[Наг, тройка параметров системы
Р^ядота [оТоЁЗЙГ^Р^ядота [оТоЁЗЙГ^изменять в полночьизменять в полночьГод начале ра.Год начале ра.Число цифр ГСЧисло цифр ГС Июнь 2006 Пн Вт Ср Чт Л, Июнь 2006 Пн Вт Ср Чт Л,28 30 31 128 30 31 1Использовать 5 6 LZj 8Использовать 5 6 LZj 8Отключить ра.- Период опрос.Отключить ра.- Период опрос.121S26121S2613 14 1520 21 2227 28 2913 14 1520 21 2227 28 29□3 4 5 6Время ожидаиря-Я1ва1а i аил.□3 4 5 6Время ожидаиря-Я1ва1а i аил.2916233029162330Сб3101724Сб3101724ВсВс1116251116258833к);к);тазы даллых (сек.):тазы даллых (сек.):Режим открытия объектов[РедактцюзаниеРежим-деления объектов:(Ломоткз на удалениеРежим открытия объектов[РедактцюзаниеРежим-деления объектов:(Ломоткз на удаление0К | Отмена [ Применить0К | Отмена [ Применить1946^1946^юю1515ПомощьПомощьРис. 4.80. Диалоговое окно настройки системы 1 С: ПредприятиеРис. 4.80. Диалоговое окно настройки системы 1 С: Предприятие||Код[[Наименование| ДатаСостояние ФизлицаД 85L_9Аксакалов Аксакал Аксакало- Группа-1Группа-2Г рута-3[01.01.70Временно не работает □16234Иванов Иван Иванович Криогенова Фекла М аримад ое Петров Петр Петрович01.01.7115.03.6501.01.72Сотрудник по неосновному месту работы Временно не работает СотрШНИК ПО OCHORMTiMU мяс-тиСидоров Сидор Сидорович Федоров Федор Федорович,01.01 73 01.01.74Сотрудник по основному месту работы Сотрудник по основному месту работы||Код[[Наименование| ДатаСостояние ФизлицаД 85L_9Аксакалов Аксакал Аксакало- Группа-1Группа-2Г рута-3[01.01.70Временно не работает □16234Иванов Иван Иванович Криогенова Фекла М аримад ое Петров Петр Петрович01.01.7115.03.6501.01.72Сотрудник по неосновному месту работы Временно не работает СотрШНИК ПО OCHORMTiMU мяс-тиСидоров Сидор Сидорович Федоров Федор Федорович,01.01 73 01.01.74Сотрудник по основному месту работы Сотрудник по основному месту работыРис. 4.81. Список элементов справочника ФизЛицаРис. 4.81. Список элементов справочника ФизЛицаКодКодТаблица 4.4. Значения периодического реквизита СостояниеФнзлицаТаблица 4.4. Значения периодического реквизита СостояниеФнзлицаНаименованиеНаименование11Состояние на 07.06.2006Состояние на 07.06.2006ИвановИван ИвановичПетровПетр ПетровичИвановИван ИвановичПетровПетр ПетровичСостояние на 24.06.2006Состояние на 24.06.2006-иДор Сидорович-иДор СидоровичСотрудник по неосновному месту работыСотрудник по основному месту работыСотрудник по основному месту работыСотрудник по неосновному месту работыСотрудник по основному месту работыСотрудник по основному месту работыСотрудник по основному месту работыВременно не работаетСотрудник по основному месту работыВременно не работаетСотрудник ло неосновному месту работыСотрудник ло неосновному месту работыРасчет | Бухгалтерия ] Операция | Бухгалтерские итоги | МониторОбщие | Текст | Интерфейс | Журналы | Оперативный учет
Р^ядота [оТоЁЗЙГ^
Р^ядота [оТоЁЗЙГ^
изменять в полночь
изменять в полночь
Год начале ра.
Год начале ра.
Число цифр ГС
Число цифр ГС
Июнь 2006 Пн Вт Ср Чт Л,
Июнь 2006 Пн Вт Ср Чт Л,
28 30 31 1
28 30 31 1
Использовать 5 6 LZj 8
Использовать 5 6 LZj 8
Отключить ра.- Период опрос.
Отключить ра.- Период опрос.
12
1S
26
12
1S
26
13 14 15
20 21 22
27 28 29
13 14 15
20 21 22
27 28 29
□3 4 5 6
Время ожидаиря-Я1ва1а i аил.
□3 4 5 6
Время ожидаиря-Я1ва1а i аил.
2
9
16
23
30
2
9
16
23
30
Сб
3
10
17
24
Сб
3
10
17
24
Вс
Вс
11
16
25
11
16
25
8
8
3
3
к);
к);
тазы даллых (сек.):
тазы даллых (сек.):
Режим открытия объектов[Редактцюзание
Режим-деления объектов:(Ломоткз на удаление
Режим открытия объектов[Редактцюзание
Режим-деления объектов:(Ломоткз на удаление
0К | Отмена [ Применить
0К | Отмена [ Применить
1946^
1946^
ю
ю
15
15
Помощь
Помощь
Рис. 4.80. Диалоговое окно настройки системы 1 С: Предприятие
Рис. 4.80. Диалоговое окно настройки системы 1 С: Предприятие
||Код
[[Наименование| Дата
Состояние Физлица
Д 8
5L_9
Аксакалов Аксакал Аксакало- Группа-1
Группа-2
Г рута-3
[01.01.70
Временно не работает
□
1
6
2
3
4
Иванов Иван Иванович Криогенова Фекла М аримад ое Петров Петр Петрович
01.01.71
15.03.65
01.01.72
Сотрудник по неосновному месту работы Временно не работает СотрШНИК ПО OCHORMTiMU мяс-ти
Сидоров Сидор Сидорович Федоров Федор Федорович
,01.01 73 01.01.74
Сотрудник по основному месту работы Сотрудник по основному месту работы
||Код
[[Наименование| Дата
Состояние Физлица
Д 8
5L_9
Аксакалов Аксакал Аксакало- Группа-1
Группа-2
Г рута-3
[01.01.70
Временно не работает
□
1
6
2
3
4
Иванов Иван Иванович Криогенова Фекла М аримад ое Петров Петр Петрович
01.01.71
15.03.65
01.01.72
Сотрудник по неосновному месту работы Временно не работает СотрШНИК ПО OCHORMTiMU мяс-ти
Сидоров Сидор Сидорович Федоров Федор Федорович
,01.01 73 01.01.74
Сотрудник по основному месту работы Сотрудник по основному месту работы
Рис. 4.81. Список элементов справочника ФизЛица
Рис. 4.81. Список элементов справочника ФизЛица
Код
Код
Таблица 4.4. Значения периодического реквизита СостояниеФнзлица
Таблица 4.4. Значения периодического реквизита СостояниеФнзлица
Наименование
Наименование
1
1
Состояние на 07.06.2006
Состояние на 07.06.2006
Иванов
Иван Иванович
Петров
Петр Петрович
Иванов
Иван Иванович
Петров
Петр Петрович
Состояние на 24.06.2006
Состояние на 24.06.2006
-иДор Сидорович
-иДор Сидорович
Сотрудник по неосновному месту работы
Сотрудник по основному месту работы
Сотрудник по основному месту работы
Сотрудник по неосновному месту работы
Сотрудник по основному месту работы
Сотрудник по основному месту работы
Сотрудник по основному месту работы
Временно не работает
Сотрудник по основному месту работы
Временно не работает
Сотрудник ло неосновному месту работы
Сотрудник ло неосновному месту работы
Таблица 4.4 (окончат
Код
Наименование
Состояние на 07.06.2006
Состояние на 24.06.2006
4
Федоров
Федор Федорович
Сотрудник по основному месту работы
Временно не работает
5
Аксакалов
Аксакал Аксакалович
Временно не работает
Сотрудник по неосновному месту работы
6
Криогенова
Фекла Маринадовна
Временно не работает
Сотрудник по основ ному месту работы
Для того чтобы понять, как именно система 1С:Предприятие размещает эд чения периодических реквизитов, с помощью любого просмотрщика D] файлов откроем файл SC12.DBF и убедимся, что его содержание не измен лось. Затем откроем файл 1SCONST.DBF (рис. 4.82).
-Содержание таблицы: ШГПМЧТ ПЯГ.-Л?Е$*Е . . •• - -ЕЕГ-ЕЕОткрыть таблицу ||оВЛО|Ю (DATEPARTNojvALUE1624.06.20060 1411624.06.20060 13J 41624.06.20060 1561624.06 20060 1321624.06.20060 1531624.06 20060 1451607.06.20060 1511607.06 20060 1421607.06 20060 1331607.06 20060 1341607.06 20060 13J 61607.06 20060 15-Содержание таблицы: ШГПМЧТ ПЯГ.-Л?Е$*Е . . •• - -ЕЕГ-ЕЕОткрыть таблицу ||оВЛО|Ю (DATEPARTNojvALUE1624.06.20060 1411624.06.20060 13J 41624.06.20060 1561624.06 20060 1321624.06.20060 1531624.06 20060 1451607.06.20060 1511607.06 20060 1421607.06 20060 1331607.06 20060 1341607.06 20060 13J 61607.06 20060 15Рис. 4.82. Содержание файла 1 SCONST.DBFРис. 4.82. Содержание файла 1 SCONST.DBF
-Содержание таблицы: ШГПМЧТ ПЯГ.-Л
?Е$*Е . . •• - -
ЕЕ
Г-
ЕЕ
Открыть таблицу |
|оВЛО|Ю (DATE
PARTNojvALUE
16
24.06.2006
0 14
1
16
24.06.2006
0 13
J 4
16
24.06.2006
0 15
6
16
24.06 2006
0 13
2
16
24.06.2006
0 15
3
16
24.06 2006
0 14
5
16
07.06.2006
0 15
1
16
07.06 2006
0 14
2
16
07.06 2006
0 13
3
16
07.06 2006
0 13
4
16
07.06 2006
0 13
J 6
16
07.06 2006
0 15
-Содержание таблицы: ШГПМЧТ ПЯГ.-Л
?Е$*Е . . •• - -
ЕЕ
Г-
ЕЕ
Открыть таблицу |
|оВЛО|Ю (DATE
PARTNojvALUE
16
24.06.2006
0 14
1
16
24.06.2006
0 13
J 4
16
24.06.2006
0 15
6
16
24.06 2006
0 13
2
16
24.06.2006
0 15
3
16
24.06 2006
0 14
5
16
07.06.2006
0 15
1
16
07.06 2006
0 14
2
16
07.06 2006
0 13
3
16
07.06 2006
0 13
4
16
07.06 2006
0 13
J 6
16
07.06 2006
0 15
Рис. 4.82. Содержание файла 1 SCONST.DBF
Рис. 4.82. Содержание файла 1 SCONST.DBF
Примечание
До этого момента файл 1 SCONST.DBF был пустым. То есть очевидно, что чения периодических реквизитов справочников система 1 С:Предприяти мещает в файле 1 SCONST.DBF.
пернемся к нашему проекту (Delphi) и сделаем изменения, которые обеспе- цивали бы возможность считывания значений периодических реквизитов справочников.
добавим в свойство Lines компонента ComboBox_Action (Delphi) строку: .дабратьЭлементы с учетом родителя и периодических реквизитов"
Создадим функцию, реализующую вывод значений периодических реквизи- тоВ на заданную дату (поскольку текст этой функции имеет значительную длину, здесь он не приводится).
Примечание
Полный текст этой функции находится на сопроводительном компакт-диске книги в папке \Part_1\Chapter_04\sp_1Cv7_Viewer_via_OLE.PAS\01. Здесь приведено лишь то, что является существенным с точки зрения считывания значений периодических реквизитов.
Следует отметить, что в данном случае речь идет о считывании значений на заданную дату. В листинге 4.18 приведена часть текста функции func_Ref_ Select Items_3.
1СТИНГ 4.18. Считывание значении периодических реквизитов “™"И»7
function TForml. f unc_Ref_SelectIt«ne_3: integer; // В этой функции учтена возможность считывания И значений периодических реквизитов Var
U Дата, на которую считываются периодические реквизиты: sDate_for_AttrPeriod: string;
begin
SQate_for_Attr₽eriod: = '24.06.2006' ;
■f InputQueryl 'Дата для пер.рекв.','Введите дату:' , sDate_for^ttrPeriod) Ehen begin
sDate_for_At trPeriod: =Trim (sDate_for_AttrPeriod) ;
if length(sDate_for_AttrPeriod)>0 then begin
ole_ic_ref.ИспользоватьДату(''+sDate_for_AttrPeriod,1);
Поясним текст функции (здесь все достаточно просто).
После ввода корректной даты (inputQuery) вызывается метод Использов» дату справочника, где в качестве параметров передаются введенная д (строка) и единица. В остальном считывание значений периодических рек зитов (на заданную дату) ничем не отличается от того, как это делалось ране Установить дату выборки периодических реквизитов справочника позвол Метод ИспользоватьДату (или UseDate) объекта Периодический. Синтаксис
ИслользоватьДату(<Дата>, <УстСразу>)
Параметры: <дата> — выражение со значением типа Дата; <устСразу> ( обязательный) — число (1 — дата, переданная в качестве параметра, бу установлена уже в текущей выборке; 0 — дата, переданная в качестве па метра, будет установлена при следующем открытии выборки; значение умолчанию — 0).
Изменим обработчик SB_Ref_Load события "нажатие кнопки Выиолш действие" следующим образом (листинг 4.19).
• Листинг 4.19. Обработчик события "нажатие кнопки Выполнить действий
//=======================================
if (ComboBox_Action.Itemindex in [0]) then begin
end;
if (ComboBox-Action.Itemindex in [1]) then begin
end;
if (ComboBox-^Action. Itemindex in [2]) then begin
end;
if (ComboBox_Action.Itemindex in [3]) then begin //Считывание периодических реквизитов
funcRef_SelectItems3;
Скомпилируем и запустим наш проект на выполнение. Создадим соедине: с 1С:Предприятие. Укажем идентификатор справочника, в структуру кото го входят периодические реквизиты, способ выборки (в раскрывают^: списке) и запустим выборку элементов справочника (рис. 4.83).
; Что смотреть:; Что смотреть:Идентификатор справочника (физПицаИдентификатор справочника (физПица!■ Список реквизитов для чтения: -!■ Список реквизитов для чтения: -Рис. 4.83. Выборка элементов справочника и чтение значений реквизита, включая периодическиеРис. 4.83. Выборка элементов справочника и чтение значений реквизита, включая периодические? ДатаРождения
; Что смотреть:
; Что смотреть:
Идентификатор справочника (физПица
Идентификатор справочника (физПица
!■ Список реквизитов для чтения: -
!■ Список реквизитов для чтения: -
Рис. 4.83. Выборка элементов справочника и чтение значений реквизита, включая периодические
Рис. 4.83. Выборка элементов справочника и чтение значений реквизита, включая периодические
S СостояниеФизлица
I; ГородПроживания
h ДомашнийАдрес
Пол
СемейноеПоложенив
На экране появится диалоговое окно ввода даты, на которую нужно прочитать значения периодических реквизитов (рис. 4.84).
'Дата для периодич.рекв.'Дата для периодич.рекв.Результат считывания представлен на рис. 4.85.
'Дата для периодич.рекв.
'Дата для периодич.рекв.
Введите дату: (07.06.2005
Cancel |Cancel |
Cancel |
Cancel |
Рис. 4.84. Ввод даты, на которую нужно прочитать значенияпериодических реквизитов
15Аксакалов Аксакал Аксакалович 01.01 1970Иванов Иван Иванович0101.1971Группа-22Петров Петр Петрович01.01.19723Сидоров Сидор Сидорович01.01.19733Г рупла-34Федоров Федор Федорович 01.01.1974Криогенова Фекла Маринадовна 15.03.196515Аксакалов Аксакал Аксакалович 01.01 1970Иванов Иван Иванович0101.1971Группа-22Петров Петр Петрович01.01.19723Сидоров Сидор Сидорович01.01.19733Г рупла-34Федоров Федор Федорович 01.01.1974Криогенова Фекла Маринадовна 15.03.1965В ременноН еРаботаетКиевРоссия, г Б. улСотрудники кос поеной МоскваРоссия. г.НеиэСотрудникО сновнойМинскРоссия. г.НеизСотрудникО сновнойВолгоградРоссия, г.НеиэСотрудникОсновнойКиевРоссия. г.ИзвеВ ременноН еРаботаетГомельРоссия, г.Н.улВ ременноН еРаботаетКиевРоссия, г Б. улСотрудники кос поеной МоскваРоссия. г.НеиэСотрудникО сновнойМинскРоссия. г.НеизСотрудникО сновнойВолгоградРоссия, г.НеиэСотрудникОсновнойКиевРоссия. г.ИзвеВ ременноН еРаботаетГомельРоссия, г.Н.ул
15
Аксакалов Аксакал Аксакалович 01.01 1970
Иванов Иван Иванович0101.1971
Группа-2
2
Петров Петр Петрович01.01.1972
3
Сидоров Сидор Сидорович01.01.1973
3
Г рупла-3
4
Федоров Федор Федорович 01.01.1974
Криогенова Фекла Маринадовна 15.03.1965
15
Аксакалов Аксакал Аксакалович 01.01 1970
Иванов Иван Иванович0101.1971
Группа-2
2
Петров Петр Петрович01.01.1972
3
Сидоров Сидор Сидорович01.01.1973
3
Г рупла-3
4
Федоров Федор Федорович 01.01.1974
Криогенова Фекла Маринадовна 15.03.1965
В ременноН еРаботает
Киев
Россия, г Б. ул
Сотрудники кос поеной Москва
Россия. г.Неиэ
СотрудникО сновной
Минск
Россия. г.Неиз
СотрудникО сновной
Волгоград
Россия, г.Неиэ
СотрудникОсновной
Киев
Россия. г.Изве
В ременноН еРаботает
Гомель
Россия, г.Н.ул
В ременноН еРаботает
Киев
Россия, г Б. ул
Сотрудники кос поеной Москва
Россия. г.Неиэ
СотрудникО сновной
Минск
Россия. г.Неиз
СотрудникО сновной
Волгоград
Россия, г.Неиэ
СотрудникОсновной
Киев
Россия. г.Изве
В ременноН еРаботает
Гомель
Россия, г.Н.ул
СМетоо: ВыбратьЗлементы (с учетом родителя и периодич рекв.] "■
|| К 0д
Наименование
ДатаРожде] СостояниеФизлица |ГородПро^ ДомашнийАдр,
Группа 1
рис. 4.85. Результат считывания значений периодических реквизитов на 07.06.2006
।иыирагьзлемемты [с учетом родителя и пермодичреКс.]Код7; 5182Наименование| ДатаРожде| СостояниеФ излица ГородП po>t| ДомашнийАдрАксакалсвАксакалАксакалови'01.01.1970 СотрудникНеосновной КиевРоссия, г Е. уИванов Иван Иванович01.01.1971 Сотрудникесковной Москва Россия. гНеиГ руппа-2Петров Петр Петрович01.01.1972 ВременноНеРаботает МинскРоссия, г Неи;3946Сидоров Сидор Сидорович01.01.1973 Сотрудники еосновной Волгоград Россия, г Неи:Г рулпа-3Федоров Федор Федорович 01.01.1974 ВременноНеРаботает КиевРоссия. г.ИзвКриогенова Фекла Маринадовнг 15.03.1965 СотрудникОсновнойГомельРоссия, г N. у।иыирагьзлемемты [с учетом родителя и пермодичреКс.]Код7; 5182Наименование| ДатаРожде| СостояниеФ излица ГородП po>t| ДомашнийАдрАксакалсвАксакалАксакалови'01.01.1970 СотрудникНеосновной КиевРоссия, г Е. уИванов Иван Иванович01.01.1971 Сотрудникесковной Москва Россия. гНеиГ руппа-2Петров Петр Петрович01.01.1972 ВременноНеРаботает МинскРоссия, г Неи;3946Сидоров Сидор Сидорович01.01.1973 Сотрудники еосновной Волгоград Россия, г Неи:Г рулпа-3Федоров Федор Федорович 01.01.1974 ВременноНеРаботает КиевРоссия. г.ИзвКриогенова Фекла Маринадовнг 15.03.1965 СотрудникОсновнойГомельРоссия, г N. уФикатор спр,Фикатор спр,[-•Список реквизит си ДатаРождения КолвоДетей тСостояниеФиз. {[-•Список реквизит си ДатаРождения КолвоДетей тСостояниеФиз. {75Аксакалов Аксакал Аксакалоаич 01.01.1970 3ВременноНеРаботаетИванов Иван Иванович01.01.19712Сотрудники ессновнойГрупла-2Петров Петр Петрович01.01.19721СотрданикОсноснойСидоров Сидор Сидорович01.01.19731СотрдатмкОсновнойГруппа-3Федоров Федор Федорович01 01.19742СотрудникОсновнойКриогеиова Фекла Маринадовна 15.03.19650ВременноНеРаботает182394675Аксакалов Аксакал Аксакалоаич 01.01.1970 3ВременноНеРаботаетИванов Иван Иванович01.01.19712Сотрудники ессновнойГрупла-2Петров Петр Петрович01.01.19721СотрданикОсноснойСидоров Сидор Сидорович01.01.19731СотрдатмкОсновнойГруппа-3Федоров Федор Федорович01 01.19742СотрудникОсновнойКриогеиова Фекла Маринадовна 15.03.19650ВременноНеРаботает1823946■0ЛВ0.■0ЛВ0.Код IНаименованиеКод IНаименование
।иыирагьзлемемты [с учетом родителя и пермодичреКс.]
Код
7
; 5
1
8
2
Наименование| ДатаРожде| СостояниеФ излица ГородП po>t| ДомашнийАдр
АксакалсвАксакалАксакалови'01.01.1970 СотрудникНеосновной КиевРоссия, г Е. у
Иванов Иван Иванович01.01.1971 Сотрудникесковной Москва Россия. гНеи
Г руппа-2
Петров Петр Петрович01.01.1972 ВременноНеРаботает МинскРоссия, г Неи;
3
9
4
6
Сидоров Сидор Сидорович01.01.1973 Сотрудники еосновной Волгоград Россия, г Неи:
Г рулпа-3
Федоров Федор Федорович 01.01.1974 ВременноНеРаботает КиевРоссия. г.Изв
Криогенова Фекла Маринадовнг 15.03.1965 СотрудникОсновнойГомельРоссия, г N. у
।иыирагьзлемемты [с учетом родителя и пермодичреКс.]
Код
7
; 5
1
8
2
Наименование| ДатаРожде| СостояниеФ излица ГородП po>t| ДомашнийАдр
АксакалсвАксакалАксакалови'01.01.1970 СотрудникНеосновной КиевРоссия, г Е. у
Иванов Иван Иванович01.01.1971 Сотрудникесковной Москва Россия. гНеи
Г руппа-2
Петров Петр Петрович01.01.1972 ВременноНеРаботает МинскРоссия, г Неи;
3
9
4
6
Сидоров Сидор Сидорович01.01.1973 Сотрудники еосновной Волгоград Россия, г Неи:
Г рулпа-3
Федоров Федор Федорович 01.01.1974 ВременноНеРаботает КиевРоссия. г.Изв
Криогенова Фекла Маринадовнг 15.03.1965 СотрудникОсновнойГомельРоссия, г N. у
Фикатор спр,
Фикатор спр,
[-•Список реквизит си ДатаРождения КолвоДетей т
СостояниеФиз. {
[-•Список реквизит си ДатаРождения КолвоДетей т
СостояниеФиз. {
7
5
Аксакалов Аксакал Аксакалоаич 01.01.1970 3ВременноНеРаботает
Иванов Иван Иванович01.01.19712Сотрудники ессновной
Групла-2
Петров Петр Петрович01.01.19721СотрданикОсносной
Сидоров Сидор Сидорович01.01.19731СотрдатмкОсновной
Группа-3
Федоров Федор Федорович01 01.19742СотрудникОсновной
Криогеиова Фекла Маринадовна 15.03.19650ВременноНеРаботает
1
8
2
3
9
4
6
7
5
Аксакалов Аксакал Аксакалоаич 01.01.1970 3ВременноНеРаботает
Иванов Иван Иванович01.01.19712Сотрудники ессновной
Групла-2
Петров Петр Петрович01.01.19721СотрданикОсносной
Сидоров Сидор Сидорович01.01.19731СотрдатмкОсновной
Группа-3
Федоров Федор Федорович01 01.19742СотрудникОсновной
Криогеиова Фекла Маринадовна 15.03.19650ВременноНеРаботает
1
8
2
3
9
4
6
■0ЛВ0.
■0ЛВ0.
Код IНаименование
Код IНаименование
96
Вновь запустим выборку элементов справочника, но укажем "24.06.2006". Результат считывания представлен на рис. 4.86.
излицаизлицаРис. 4.86. Результат считывания значений периодических реквизитов на 24.06.2006
излица
излица
Результат считывания можно сопоставить с той информацией, что мы вво ли в программе 1С:Предприятие (табл. 4.4).
Точно так же считываются значения периодических реквизитов, имею базовый тип (например, тип число). Чтобы проверить это, внесем в спра ник Физлица периодический реквизит колводетей (тип число) и заполни элементы справочника соответствующими значениями. На рис. 4.87 и 4. представлены результаты выборки из справочника.
Часто требуется прочитать историю изменений значения периодического квизита справочника. Для того чтобы проиллюстрировать это. доработа наш проект. Создадим новую форму (рис. 4.89).
Что смотреть • м Метод ВыбратьЗламенты (с учетом родителя и периоаич реке)^
Рис. 4.87. Результат считывания значений периодических реквизитов на 01.05.2006
5*1 SI | В ыбратьЭ лементы с учетом родителя и периодиче •* |i
нт смотреть: т f Метод: ВыбратьЭ лементы (с учетом родителя и периодичрекв.)”
([^ктификатор спр!
Код
Наименование| ДатаРожд^ КолвоДетей | СостояниеФизлица
£СТЬ соединение^; . Слисок реквизитое, (датаРо-кдения .^ji' КолвоДетей СостояниеФиз. >i j
1
7
Группа 1
5
1
8
2
3
9
4
6
Аксакалов Аксакал Аксакало; 01.01.19703СотрудникНеосноеной
Иванов Иван Иванович01.01.19712СотрудникОсновной
Группа-2
Петров Петр Петрович01.01.1972'1ВремемноНеРабстает
Сидоров Сидор Сидорович01.01.19732СотрудникНеосновной
Г руппа-3
Федоров Федор Федорович 01.01.1974 2ВреметеюНеРаботает
Криогенова Фекла Маринадot 15.03.1965 1Сотрудт«кОсновной
Рис. 4.88. Результат считывания значений периодических реквизитов на 24.06.2006
Рис. 4.89. Форма (Delphi) длд визуализации истории изменения значений периодического реквизитаРис. 4.89. Форма (Delphi) длд визуализации истории изменения значений периодического реквизита
Рис. 4.89. Форма (Delphi) длд визуализации истории изменения значений периодического реквизита
Рис. 4.89. Форма (Delphi) длд визуализации истории изменения значений периодического реквизита
Внесем изменения в текст, сгенерированной Delphi для этой формы по умол
чанию (листинг 4.20).
typetype
type
type
Panel!:Label2:Panel!:Label2:TPanel;TLabel;TPanel;TLabel;11 ,ien**e*--^ «i11 ,ien**e*--^ «i
Panel!:
Label2:
Panel!:
Label2:
TPanel;
TLabel;
TPanel;
TLabel;
11 ,ien**e*--^ «i
11 ,ien**e*--^ «i
^Ig-ActrPeriod-History = class(TForm)
Panell: TPanel;
OKBtn: TButton;
CancelBtn: TButton;
Label_id_Attr_Period: TLabel;
GroupBoxl: TGroupBox;
ListBoxl: TListBox;
Label_id_Ref: TLabel; private ( Private declarations } ole_Ref: 01 eVariant;// Ссылка на объект типа "Справочник"
ole_TekEl: OleVariant; // Ссылка на текущий элемент справочника public
{ Public declarations }
function Execute(idRef,IdAttrPeriod,eCode: string): boolean; end;
Как видите, у формы появились 2 новых свойства: □ oie_Ref —ссылка на объект типа справочник;
ole_TekEi — ссылка на текущий элемент справочника.
Примечание
Термин "элемент справочника’ в системе 1С:Предприятие адекватен пеня" "строка таблицы базы данных". Значения всех периодических реквизитов в справочников содержатся в отдельной таблице (файл 1SCONST.DBF, рис. 4.12) и, следовательно, "привязаны" к элементам справочников (по пр ципу Master-Detail). Более подробно об этом рассказано в части II.
Для того чтобы прочитать историю изменения значений реквизита справочн с использованием ме.ханизма OLE Automation, нужно спозиционировать сг вочник на нужном элементе и получить на него ссыпку ("текущий элемент").
Получить значение элемента справочника позволяет метод ТекущийЗлем< (или currentltem) справочника. Синтаксис:
ТекущийЭлемент()
Метод ТекущийЭлемент возвращает значение элемента справочника в цел как объект. Данный метод применяется, например, если нужно передать : мент справочника как параметр в вызове какого-либо метода или присво какому-либо реквизиту.
В листинге 4.21 представлен текст метода Execute формы (рис. 4.89).
IЛистинг 4.21. Метод Execute формы (просмотр истории периодического
function TDlg_AttrPeriod_
History.Execute(idRef,idAttrPeriod,sCode:string):boolean;
// Входные параметры:
,/ idRef - идентификатор справочника,
у/ idAttrPeriod — идентификатор периодического реквизита, ц вСойе — код строки справочника.
уаг
ole_peri°d: OleVariant; // Ссылка на объект типа "Периодический" sValAttr: string;
NrType: integer;
begin
Resul t: =FALSE;
ole_period:=UnAssigned;
ole_Ref:=UnAssigned;
ole_TekEl:=UnAssigned;
ListBoxl. Items .Clear,-
idAttrPeriod:=Trim(idAttrPeriod);
idRef: =Trim(idRef) ;
sCode: =Tr im (sCode) ;
Label_id_J\ttr_Period.Caption: = ' ' ;
Label_id_Ref.Caption: =' 1;
if (length(idAttrPeriod)>0) and (length(sCode)>0) then begin Label_id_Attr_Period.Caption:=idAttrPeriod;
ole_Ref:=Fonnl.ole_ic.CreateObject {'Справочник.'+ldRef);
if not VarlsEmpty(ole_Ref) then begin
if (ole_Ref.НайтиПоКоду(''+«Code, 0)) *l>0 then begin ole_TekEl:=ole_Ref.ТекущийЭлемект;
// Проверяем, есть ли ссылка на "ТекущийЭлемент" справочника
if not VarlsBnpty(ole_TekEl) then begin
II Метод "Вид" текущего элемента справочника возвращает // идентификатор справочника
Label_id_Ref.Caption:= Trim(ole_TekEl.Вид);
И Считываем тип реквизита sValAttr:= Label_id_Ref.Caption; II Чтобы укоротить строку //в книге
NrType:=GetTypeAttrReference_lC(Forml.ole_lC,sValAttr,idAttrPeriod);
II Создаем объект "Периодический" для того, // чтобы прочитать историю значений периодического II реквизита справочника
ole_period:=Forml.ole_lC.CreateObject('Периодический');
if not VarlsElripty (ole_period) then begin
1f ole_period.Исполъ эоватьОбгьект(''чIdAttrPeriod, ole_TekKl) * 1 > 0 then begin
о1e_period.ВыбратьЗначения;
while ole_period.Получитъ3начение>0 do
begin
sValAttr:= '<???>';
//========================================================
// Считываем реквизит с учетом его типа
if (NrType in [1..3]) then begin II Базовый тип
// Строка, Число или Дата
sValAttr:= Trim(ole_period.Значение); end;
if NrType=10 then begin // Перечисление
sValAttr:= Tr im (ole_period.Значение.Идентификатор); end;
if NrType=ll then begin // Справочник sValAttr:= Trim(ole_period.Наименование); end;
/ / =========================================================
// Результат считывания записываем в LiatBoxl
ListBoxl.Items.ADD(Trim(ole_period.flaTa3Ha4)+' | '+sValAttr); end;
end
else begin
ShowMessage('Неудачный вызов метода ИспользоватьОбъектО')? end;
end
else begin
ShowMessage('Неудачное создание объекта типа "Периодический"1); end;
if ShowModal=mrCk then begin Result:=TRUE;
end;
end;
end;
end;
end;
ole_period:=UnAssigned;
(дэва 4. Доступ к информации 01е_ТекЕ1:=UnAssigned; ole_Ref:=UnAssigned; ^istBoxl. Items.Clear;
Поясним листинг 4.21. Как видите, в качестве входных параметров методу
Execute передаются:
g idRef — идентификатор справочника;
idAttrPeriod — идентификатор периодического реквизита (историю изменения значений которого нужно прочитать);
scode — код строки справочника (для позиционирования на соответствующем элементе справочника).
Далее выполняются следующие действия:
Создание объекта типа Справочник с идентификатором idRef в контексте уже открытого сервера OLE Automation 1С:Предприятие (Formi.ole_ic) и получение ссылки на него:
ole_Ref:=Forml,ole_lC.CreateObject('Справочник.'+idRef);
Позиционирование справочника на элементе с кодом scode:
if (ole_Ref.НайтиПоКоду(''+eCode,0))*1>0 then begin
Получение ссылки на текущий элемент справочника (соответствует строке таблицы SC12.DBF с кодом scode):
ole_TekEl:=ole_Ref.ТекущийЭлемент;
Создание объекта типа периодический в контексте уже открытого сервера OLE Automation 1С:Предприятие (Formi .ole_ic) и получение ссылки на
него:
ole_period:=Forml.ole_lC.CreateObject('Периодический');
Вызов метода использоватьОбъект для созданного объекта типа периодический. В качестве параметров передаются идентификатор периодического реквизита и ссылка на текущий элемент справочника:
if ole_period.ИспольэоватьОбъект(1'+idAttrPeriod, ole_TakEl)*1>0
then
Очевидно, что это определение фильтра по таблице , (файлу) 1SCONST.DBF.
^ Выбор значений периодического реквизита (фильтруем строки таблицы 1SCONST.DBF):
О1е_регiod.ВыбратьЗначения;
Поочередный (в цикле) выбор строк из полученной выборки:U
while о1е_рег1од.ПолучитьЗначение>0 do
Далее, в зависимости от типа реквизита, считывание соответствую® строковых значений реквизита (более подробно это рассмотрено ранее®
Задать объект применения позволяет метод ИспользоватьОбъект Useobject) объекта Периодический. Синтаксис:|
Использовать Объект (<ИмяРеквизита», <ОСгьект»)
Параметры: <ИмяРеквизита» — строковое выражение, задающее илснтиД катор периодического реквизита справочника, как указано в конфигуратх® <0бъект> — значение элемента справочника, для которого задается прим^Д ние объекта Периодический. Возвращаемое значение (число): 1 — если выЖ метода закончился успешно, 0 — если нет.
Метод использоватьОбъект задает соответствие созданного ранее объеД Периодический тому периодическому реквизиту справочника, для котор® он будет применяться. Если параметр < Имя Реквизита» не задан (пустая ст» ка), а параметр <объект> задает элемент справочника, то выборка будет о<& ществляться по всем периодическим реквизитам справочника.
Открыть выборку периодических значений в интервале дат позволяет мете ВыбратьЗначения (ИЛИ Selectitems) объекта Периодический. Синтаксис:
ВыбратьЗначения(<ДатаНачала», <ДатаКонца»)
Параметры: <датаначала> (необязательный) — выражение типа Дата (да! начала периода выборки периодических значений; если параметр не задан,« выборка начинается с самой ранней имеющейся даты); <датаКонца> (неоЯ зательный) — выражение типа Дата (дата конца периода выборки период! ческих значений; если параметр не задан, то выборка заканчивается само! последней имеющейся датой). Возвращаемое значение (число): 1 — если в1 зов метода закончился успешно, 0 — если нет.
Метод ВыбратьЗначения предоставляет возможность (открывает выбор» выбирать периодические значения при помощи метода ПолучитьЗначени< Дальнейшая выборка при помощи метода ПолучитьЗначение будет промер дить среди периодических значений текущего объекта применения, заданно* го методом ИспользоватьОбъект.
Получить из выборки следующее периодическое значение позволяет мето, ПолучитьЗначение (или Getvalue) объекта периодический. Синтаксис:
ПолучитьЗначение()
Возвращаемое значение (число): 1 — если элемент выбран успешно, 0 — есл» элемент не выбран (отсутствует).
4. Доступ к информации 1С из внешних приложенийдсхоД ПолучитьЗначение выбирает периодическое значение в последова- ^ьности выборки, открытой перед этим при помощи метода ВыбратьЗначения ^н ЕыОратьПоДокументу. Само полученное значение следует считывать из атрибута значение. Дату этого значения можно считать из атрибута ДатаЗнач. дои значение периодического реквизита установлено документом, то этот документ можно, получить при помощи метода Текушийдокумент. Метод ,еКущийОбъект позволит определить значение текущего элемента справочника. а метод текущийРеквизит — определить наименование текущего рек-' вИзита справочника.I Теперь разместим в главной форме приложения компонент PopupMenui. присвоим свойству PopupMenu компонента sc_info значение PopupMenui и созда- I дим пункт меню "История периодического реквизита" (рис. 4.90).4. Доступ к информации 1С из внешних приложенийдсхоД ПолучитьЗначение выбирает периодическое значение в последова- ^ьности выборки, открытой перед этим при помощи метода ВыбратьЗначения ^н ЕыОратьПоДокументу. Само полученное значение следует считывать из атрибута значение. Дату этого значения можно считать из атрибута ДатаЗнач. дои значение периодического реквизита установлено документом, то этот документ можно, получить при помощи метода Текушийдокумент. Метод ,еКущийОбъект позволит определить значение текущего элемента справочника. а метод текущийРеквизит — определить наименование текущего рек-' вИзита справочника.I Теперь разместим в главной форме приложения компонент PopupMenui. присвоим свойству PopupMenu компонента sc_info значение PopupMenui и созда- I дим пункт меню "История периодического реквизита" (рис. 4.90).1йОбъект1йОбъект103103ЖЕЖЕ!. Пр^^*Ш1ЙАМИЕ!. Пр^^*Ш1ЙАМИЕдля вызова формы истордля вызова формы истор-Что смотреть.-Что смотреть.moaeowKamoaeowKaФиэЛтеФиэЛтеJ/OE.MC.exampteDBJ/OE.MC.exampteDBСправочникиСправочникиTMemo.LktABi.RelTMemo.LktABi.RelЗыборка з леменговспраео^Зыборка з леменговспраео^История период.реквизитаИстория период.реквизитаЕсть соединена с )СЕсть соединена с )С
4. Доступ к информации 1С из внешних приложений
дсхоД ПолучитьЗначение выбирает периодическое значение в последова- ^ьности выборки, открытой перед этим при помощи метода ВыбратьЗначения ^н ЕыОратьПоДокументу. Само полученное значение следует считывать из атрибута значение. Дату этого значения можно считать из атрибута ДатаЗнач. дои значение периодического реквизита установлено документом, то этот документ можно, получить при помощи метода Текушийдокумент. Метод ,еКущийОбъект позволит определить значение текущего элемента справочника. а метод текущийРеквизит — определить наименование текущего рек-
' вИзита справочника.
I Теперь разместим в главной форме приложения компонент PopupMenui. присвоим свойству PopupMenu компонента sc_info значение PopupMenui и созда- I дим пункт меню "История периодического реквизита" (рис. 4.90).
4. Доступ к информации 1С из внешних приложений
дсхоД ПолучитьЗначение выбирает периодическое значение в последова- ^ьности выборки, открытой перед этим при помощи метода ВыбратьЗначения ^н ЕыОратьПоДокументу. Само полученное значение следует считывать из атрибута значение. Дату этого значения можно считать из атрибута ДатаЗнач. дои значение периодического реквизита установлено документом, то этот документ можно, получить при помощи метода Текушийдокумент. Метод ,еКущийОбъект позволит определить значение текущего элемента справочника. а метод текущийРеквизит — определить наименование текущего рек-
' вИзита справочника.
I Теперь разместим в главной форме приложения компонент PopupMenui. присвоим свойству PopupMenu компонента sc_info значение PopupMenui и созда- I дим пункт меню "История периодического реквизита" (рис. 4.90).
1йОбъект
1йОбъект
103
103
ЖЕ
ЖЕ
!. Пр^^*Ш1ЙАМИЕ
!. Пр^^*Ш1ЙАМИЕ
для вызова формы истор
для вызова формы истор
-Что смотреть.
-Что смотреть.
moaeowKa
moaeowKa
ФиэЛте
ФиэЛте
J/OE.MC.exampteDB
J/OE.MC.exampteDB
Справочники
Справочники
TMemo.LktABi.Rel
TMemo.LktABi.Rel
Зыборка з леменговспраео^
Зыборка з леменговспраео^
История период.реквизита
История период.реквизита
Есть соединена с )С
Есть соединена с )С
Создадим обработчик события OnClick для пункта меню "История периодического реквизита" (листинг 4.22).
- M^W^W1_TW.MW,„. ,^-r~.~-~r’1^?vi'?i*,-e'ir^r?*^W
Листинг 452. Обработчик события OnClick пункта меню "История «№^832^^._ : ' -.■ - -
Procedure TFonnl.NlClicktSender: TObject);
Var
idRef, // Идентификатор справочника
idAttr,// Идентификатор периодического реквизита
sCode: string; H Код строки справочника
oleBuf: OleVariant; II Вспомогательная переменная begin
if not VarIsEmpty(ole_lC_ref) then begin
if (SG_Info.Row>0) and (SG_Info.Col>=2) then begin
■Code:=Trim(SG_Info.Cells[0,SG_Info.Row));
if length(sCode)>0 then begin
IdRef: =Trim (Edi t_RefName. Text) ;
II Идентификатор реквизита, который указал Пользователь
IdAttr:=Trim(SG_Infо.Cells[SG_Info.Col,0));
II Проверяем, существует ли реквизит idAttr
// в справочнике idRef
if YeeAttrInReference_lC(ole_lC,idRef,idAttr) then begin
II Проверяем, является ли реквизит idAttr
И в справочнике idRef периодическим
oleBuf:=о1е_1С.Метаданные.Справочник(''+idRef);
if (oleBuf.Реквизит)''+idAttr).Периодический)*1>0 then begin
// Вызываем диалоговое окно просмотра истории пер. рекв.
Dlg_AttrPerlod_Hietory.Execute(idRef,idAttr,sCode);
end
else begin
ShowMessage!'Этот реквизит:'+idAttr+' не периодический'); end;
end
else begin .
ShowMessage('Реквизит:'+idAttr+' не существует'); end;
end
else begin
ShowMessage('He выбран элемент справочника');
end;
end
else begin
ShowMessage(1 He выбран элемент или реквизит справочника');
end;
end
else begin
ShowMessage('Ссылка на справочник - не корректна1); end;
end;
Поясним текст* обработчика. Здесь все прозрачно, пояснений требуют лишь две строки:
Проверка, является ли реквизит справочника периодическим if (oleBuf.Реквизит!1*+idAttr).Периодический)*1>0 Chen begin
Вызов созданной нами формы для просмотра истории значений периодического реквизита (рис. 4.89).
Dlg_AttrPeriod_History.Execute(idRef,idAttr,sCode);
Скомпилируем проект и запустим на выполнение. Сделаем выборку элементов справочника и поэкспериментируем с программой в рамках уже сделанных нами разработок. Для начала выделим ячейку в строке с кодом 5 и столбце ДатаРождения (рис. 4.91).
На экране появится сообщение (рис. 4.92).
Код
7
1ё
Наименование | ДатаРо>аде||СостояниеФизг|КолвоДет
Группа-1
I Аксакалов АксакаЩВЖЙ^^
1_ 8_
2.
3
i
Иванов Иван Ивам 01 I
История период.реквизита
Группа-2
Петров Петр Петре 01.01 1972 ВременноНеРаС 1
Сидоров Сиаор Сие 01.01.1973 СотрудмикНеоск 2
Г руппа-3
Федоров Федор Ф 01.01.1974 ВременноНеРаС 2
Коиогеноеа Фекла 15 031965 СотруанжОсное 1
Рис. 4.91. Вызов меню для просмотра историизначений периодического реквизита справочника
Iisp_lcv7 „viewer _via_ole
Этот реквизит : ДатаРождения не периодический
Рис. 4.92. Сообщение о некорректности обращения к реквизиту как к периодическому
В данном случае сработала проверка на корректность (листинг 4.22) в строЛ if (oleBuf.Реквизит!1'+idAttr>.Периодический)*1>0 then begin я То есть реквизит датаРождения действительно не периодический. | Теперь то же самое повторим для ячейки в строке с кодом 6 и столбе КолвоДетей (рис. 4.93). J
^±1 ^(Что смотреть: , гМетод: ВыбратьЭлементы (с учетом родителя и периодич.реквГ^±1 ^(Что смотреть: , гМетод: ВыбратьЭлементы (с учетом родителя и периодич.реквГИдентификатор спр.'|У.ИэЯИы ‘ ]EofcoaeMWHWc’e-Список реквизитовИдентификатор спр.'|У.ИэЯИы ‘ ]EofcoaeMWHWc’e-Список реквизитовКойКой55НаименованиеНаименованиеГруппа-1Аксакалов Аксакал Аксакалович 01.01.1970 3Группа-1Аксакалов Аксакал Аксакалович 01.01.1970 3| ДатаРожд^КолваДетв^СосгоямвФизлица || ДатаРожд^КолваДетв^СосгоямвФизлица |ДатаРождектя -| КолвоДетей СостоягмеФиэтДатаРождектя -| КолвоДетей СостоягмеФиэт£777£777Иванов Иваи ИвановичГруппа-2Петров Петр Петрович Сидоров Сидор СидоровичГруша 3Федоров Федор ФедоровичИванов Иваи ИвановичГруппа-2Петров Петр Петрович Сидоров Сидор СидоровичГруша 3Федоров Федор Федорович,01 01.1971 2,01 01.1971 201.01.1972 101.01.1973 201.01.1972 101.01.1973 201.01.1974 201.01.1974 2ееСот руаиикНеоспоенойСотруоникОсновнойСот руаиикНеоспоенойСотруоникОсновнойВременноНеРаботаетСотрудники еосновнойВременноНеРаботаетСотрудники еосновнойКриогенова Фекла Маринааоена 15.03.1965 МимиКриогенова Фекла Маринааоена 15.03.1965 МимиВременноНеРвботавтВременноНеРвботавтИстория период,реквизитаИстория период,реквизита
^±1 ^(
Что смотреть: , гМетод: ВыбратьЭлементы (с учетом родителя и периодич.реквГ
^±1 ^(
Что смотреть: , гМетод: ВыбратьЭлементы (с учетом родителя и периодич.реквГ
Идентификатор спр.'
|У.ИэЯИы ‘ ]
EofcoaeMWHWc’e
-Список реквизитов
Идентификатор спр.'
|У.ИэЯИы ‘ ]
EofcoaeMWHWc’e
-Список реквизитов
Кой
Кой
5
5
Наименование
Наименование
Группа-1
Аксакалов Аксакал Аксакалович 01.01.1970 3
Группа-1
Аксакалов Аксакал Аксакалович 01.01.1970 3
| ДатаРожд^КолваДетв^СосгоямвФизлица |
| ДатаРожд^КолваДетв^СосгоямвФизлица |
ДатаРождектя -| КолвоДетей СостоягмеФиэт
ДатаРождектя -| КолвоДетей СостоягмеФиэт
£
7
7
7
£
7
7
7
Иванов Иваи Иванович
Группа-2
Петров Петр Петрович Сидоров Сидор Сидорович
Груша 3
Федоров Федор Федорович
Иванов Иваи Иванович
Группа-2
Петров Петр Петрович Сидоров Сидор Сидорович
Груша 3
Федоров Федор Федорович
,01 01.1971 2
,01 01.1971 2
01.01.1972 1
01.01.1973 2
01.01.1972 1
01.01.1973 2
01.01.1974 2
01.01.1974 2
е
е
Сот руаиикНеоспоеной
СотруоникОсновной
Сот руаиикНеоспоеной
СотруоникОсновной
ВременноНеРаботает
Сотрудники еосновной
ВременноНеРаботает
Сотрудники еосновной
Криогенова Фекла Маринааоена 15.03.1965 Мими
Криогенова Фекла Маринааоена 15.03.1965 Мими
ВременноНеРвботавт
ВременноНеРвботавт
История период,реквизита
История период,реквизита
Рис. 4.93. Вызов меню для просмотра истории значенийпериодического реквизита справочника
На экране появится разработанная выше форма просмотра истории значен периодического реквизита справочника (рис. 4.94). Тип значения: Базовый) Число.
Рис. 4.94. История значений периодического реквизита КолвоДетейРис. 4.94. История значений периодического реквизита КолвоДетей
Рис. 4.94. История значений периодического реквизита КолвоДетей
Рис. 4.94. История значений периодического реквизита КолвоДетей
Затем отметим ячейку в столбце состояниеФизлица и вновь вызовем меШ "История периодического реквизита" (рис. 4.95).
На экране появится форма, где отражена история значений периодической реквизита типа Агрегатный — Перечисление (рис. 4.96).
Кое НаименованиеКое Наименование| ДатаРохд^ КолвоДетеС СостояниеФизлица |
Кое Наименование
Кое Наименование
История период.реквизитаИстория период.реквизита7Г руппа-1
История период.реквизита
История период.реквизита
5Аксакалов Аксакал Ахыкалоеич 01.01.19703
1Иванов Иван Иванович010119712
Рис. 4.95. Вызов меню для просмотра истории значенийпериодического реквизита справочника
* История периодического реквизит.
ИдвниФикатор реквизита; СостояниеФизлица I
г История реквизита;" '
07 06.20061 ВременноНеРабстает
24.06.20061 СотрданикНеосновной
|ФизЛица
Рис. 4.96. История значенийпериодического реквизита СостояниеФизлица
В данном случае мы рассмотрели вариант, когда значение периодического реквизита изменяется вручную. Но часто для изменения значений периодических реквизитов справочников используют механизм проведения документов (более подробно о проведении документов можно прочитать в специальной литературе по системе 1С:Предприятие).
Чтобы продемонстрировать способ считывания истории значений периодических реквизитов справочников с учетом документов, вновь доработаем нашу конфигурацию. Для этого запустим Конфигуратор 1 С:Предприятие и откроем нашу конфигурацию (см. рис. 2.8).
Создадим новый тип документов, которые при проведении будут выполнять следующие простые действия: для указанных физических лиц (элементов справочника Физлица) будут изменены значения периодического реквизита "остояниеФизлица на новые, указанные в документе.
В дереве конфигурации выберем ветку "Журналы документов" и создадим Новый журнал документов журналДокументовФиэЛиц (рис. 4.97).
ЖурмалДокументовФ и з Л ииЖурмалДокументовФ и з Л ииеМЖурналы документов= ГраФы отбора
ЖурмалДокументовФ и з Л ии
ЖурмалДокументовФ и з Л ии
Рис. 4.97. Новый журнал документовв конфигурации 1С:Предприятие
Далее, в дереве конфигурации выберем ветку "Документы" и внесем но реквизит в раздел "Общие реквизиты" (рис. 4.98).
На рис. 4.99 представлены свойства нового реквизита.
На рис. 4.100 показано дерево конфигурации после внесенных изменений.
Теперь создадим (рис. 4.101 и 4.102),
новый тип документов ИзменениеСостояничФи
£3 Документы
ибшие рек ел Ck
ГО
5у Нумераторы у
Новый Реквизит
Рис. 4.98. Новый общий реквизит документов в конфигурации системы
Свойства Реквизита
Общие | Дополтеттельные |
Идентификатор:
Синоним
Комментарий
Т кт значения:
^оммент.
(Комментарий
Длина:
Точность: In
Рис. 4.99. Свойства общего реквизита документов Комментарий
S сЗ Документы
। 8 -ж* Общие реквизиты
ког^ментарий!
Рис. 4.100. Список общих реквизитов документов
Общи, У
| ювый Документ
Рис. 4.101. Создание нового типа документов
Конструктор Документа
х
Идентификатор: (ИзменениеСостоянияФизЛиц
£woihm
(Изменение состояния Физиче
Комментарий Р
Рис. 4.102. Идентификатор нового типа документов
укажем. что С03Даваемь™ нами тип документов должен поддерживать механизм проведения и при сохранении документа должен перепроводиться (рис- 4.103).
ПРИМЕЧАНИЕ
настройки свойств документовнастройки свойств документовБолее подробную информацию о механизме проведения документов можно найти в специальной литературе по системе 1С:Предприятие.
настройки свойств документов
настройки свойств документов
На рис- 4.104 представлено диалоговое окно типа изменениеСостоянияФивлиц.
Конструктор Документа
Р @ВЫИ£^8й2КЖ^
Этот признак нужно выбрать, если данный документ будет отражаться в учете Если документ создается только для печати, то его проводить не обязательно.
Р При записи документ должен перепроводиться
Выбор этого признаке установит режки. при котором изменетя проведенного документа будут сохраняться только в случае удачного перепроведения документа (рекомендуется)
Рис. 4.103. Способность документов данного типа поддерживать механизм проведения
Рис. 4.104. Окно настройки свойств документов
Примечание
При создании у нового документа есть только два обязательных свойсте торые создаются системой 1С:Предприятие автоматически для любого документов, — дата и номер документа.
Документы состоят из двух частей: шапка документа и многостро табличная часть, поэтому реквизиты документа также делятся на Рекв шапки И Реквизиты табличной части.
Внесем реквизиты табличной части документов этого типа (рис. 4.105 и 4.1
Отмена
[Свойства Реквизита
Рис. 4.105. Реквизит ФизЛицо табличной части документов типаИзменениеСостоянияФизЛиц
OK
Обновить
[Свойства Реквизита
Общие | Дополнительные |
П
Идентификатор:
Сиюнам-
Комментарий
Тип значения
Дш-на:
(НоеоеСостояниеФизЛиц (Ноесе состояние Физ лиц
(Перечисление.СостояниеФизлица "^1[3 5 Г" Неогр. вечность |и -й
ОК
Отмена
Обновить
Рис. 4.106. Реквизит НовоеСостояниеФизЛиц табличной частидокументов типа ИзменениеСостоянияФизЛиц
П
Примечание
Реквизит документа ФизЛицо — это ссылка на элемент справочника ФизЛи- а реквизит документа НовоеСостояниеФизЛиц — это новое значение пери дического реквизита СостояниеФизлица элемента справочника, на котор ссылается реквизит документа ФизЛицо.
Рис. 4.107. Окно настройки свойств документов типа ИзменениеСостоянияФизлиц
Далее в раскрывающемся списке Журнал выберем созданный нами журнал ЖурналДокументовФнзЛнц (рис. 4.107).
Теперь нужно написать текст процедуры, где будет реализован алгоритм проведения документов данного типа. Для этого нужно нажать кнопку Модуль Документа (см. рис. 4.107) и с помощью языка программирования системы 1С:Прсдприятие реализовать алгоритм проведения документов данного типа. В листинге 4.23 представлен текст процедуры, реализующей простей
ший алгоритм проведения документа.
'"Роцедура ОбработкаПроведения() ВыбратьСтроки();
Пока ПолучитьСтроку() = 1 Цикл
112
•Часть!. 1С и механизм OLF Automan#
ПривязыватьСтроку(НомерСтроки);
УстановитьРеквизитСправочника(
ФизЛицо,
"СостояниеФизлица",'
НовоеСостояниеФизЛица, ДатаДок
КонецЦикла;1
КонецПроцедуры
В табл. 4.5 приведено краткое пояснение к каждой строке процедуры.
Таблица 4.5. Назначение строк процедуры обработки проведения докуменпх
типа ИзменениеСостоянияФизт
Строка процедуры
Процедура ОбработкаПроведения()
Назначение
Предопределенная процедура модуля документа
ВыбратьСтроки;
Пока ПолучитьСтроку{) = 1 Цикл
Открывает выборку строк табличной час- ти данного документа
Позиционирование на каждой строке документа (из выбранных) в цикле
ПривязыватьСтроку(НомерСтроки);
Означает, что при выполнении движений, создаваемых документом (например, по регистрам или при записи значений периодических реквизитов), движения будут .записываться с привязкой не только к документу, но и к номеру строки табличной части документа. Это бывает крайне полезно, когда в документе много строк
УстановитьРеквизитСправочника
Записывается значение периодического реквизита справочника с привязкой к документу (и строке документа в данном случае)
Примечание
па^оеТе™^^ ” свойства Документов описаны в специальной лите-'' ратуре по системе 1С ."Предприятие.
Геперь создадим форму документов типа изменениеСостоянияФиэлии. Дл*
этого нужно нажать кнопку Форма (см. рис. 4.107).
В диалоговом окне настройки размещения реквизитов документа в форме (рис. 4.108) нужно отметить все реквизиты документа и нажать кнопку Вставить.
[размещение реквизитов Документа
Реквизиты
Q Номер Док
уДагаДок
у Комментарий
|7 Вставлять имя Ьстазлять |Пэоееьма
:Реквизиты г «5 листай части
уНомерСтроки УФизЛицо
у НовоеСостояниеФ изЛица
I* Разместить в диалоге автоматически
Р Вызывать для новых форм
Вставить ] Отмена [ Помощь |
Рис. 4.108. Окно настройки размещения реквизитов документа в форме документа
После автоматического размещения соответствующих элементов управления в форме документа нужно самостоятельно их переместить на новую позицию или выровнять, если требуется (рис. 4.109).
Сохраним изменения в конфигурации (см. рис. 2.17) и запустим программу *С:Предприятис (см. рис. 2.23). В меню программы 1С:Предприятие выберем пункт Операции > Журналы документов (рис. 4.110).
В открывшемся списке журналов выберем тот, к которому привязаны документы типа ИзменениеСостоянияФиэЛии (рис. 4.111).
Для того чтобы внести новый документ, вызовем всплывающее меню в спи- ске документов журнала и выберем пункт Новый (рис. 4.112).
В открывшейся форме документа введем информацию, как указано на рис. 4.113, и нажмем кнопку ОК.
Рис. 4.109. Форма документов вида ИзменениеСостоянияФизЛицРис. 4.109. Форма документов вида ИзменениеСостоянияФизЛиц1С:Предприятие - Задача1С:Предприятие - ЗадачаФайл ! Операции Сервис Окна I
Рис. 4.109. Форма документов вида ИзменениеСостоянияФизЛиц
Рис. 4.109. Форма документов вида ИзменениеСостоянияФизЛиц
1С:Предприятие - Задача
1С:Предприятие - Задача
Журналы документов...Журналы документов...1п м
Журналы документов...
Журналы документов...
Рис. 4.111. Для того чтобы работать с документами, выберем соответствующий журналРис. 4.111. Для того чтобы работать с документами, выберем соответствующий журналРис. 4.112. Для того чтобы ввести новый документ, выберем в соответствующем журнал! пункт Новый всплывающего менюРис. 4.112. Для того чтобы ввести новый документ, выберем в соответствующем журнал! пункт Новый всплывающего менюРис. 4.113. Документ типа ИэменениеСостоянияФизлиц в режиме редактирования информацииРис. 4.113. Документ типа ИэменениеСостоянияФизлиц в режиме редактирования информацииРис. 4.110. Меню для выбора списка журналов документов
Рис. 4.111. Для того чтобы работать с документами, выберем соответствующий журнал
Рис. 4.111. Для того чтобы работать с документами, выберем соответствующий журнал
Рис. 4.112. Для того чтобы ввести новый документ, выберем в соответствующем журнал! пункт Новый всплывающего меню
Рис. 4.112. Для того чтобы ввести новый документ, выберем в соответствующем журнал! пункт Новый всплывающего меню
Рис. 4.113. Документ типа ИэменениеСостоянияФизлиц в режиме редактирования информации
Рис. 4.113. Документ типа ИэменениеСостоянияФизлиц в режиме редактирования информации
1С:Предприятие1С:ПредприятиеXXСохранить Документ?Сохранить Документ?
1С:Предприятие
1С:Предприятие
X
X
Сохранить Документ?
Сохранить Документ?
Да | Нет Отмена
Рис. 4.114. Запрос на сохранение изменений в документе
Рис. 4.115. Запрос на проведение документаРис. 4.115. Запрос на проведение документа
Рис. 4.115. Запрос на проведение документа
Рис. 4.115. Запрос на проведение документа
Подтвердим запрос на сохранение (рис. 4.114) и проведение (рис. 4.115) до- кумента.
Новый документ появится в журнале документов. Чтобы посмотреть движения, созданные этим документом при проведении, нужно вызвать всплывающее меню и выбрать пункт Движения документа (рис. 4.116).
Рис. 4.116. Пункт меню для вызова диалогового окна просмотра движений, созданных данным документомРис. 4.116. Пункт меню для вызова диалогового окна просмотра движений, созданных данным документом
Рис. 4.116. Пункт меню для вызова диалогового окна просмотра движений, созданных данным документом
Рис. 4.116. Пункт меню для вызова диалогового окна просмотра движений, созданных данным документом
На экране появится диалоговое окно для выбора вида движений, созданных Данным документом (рис. 4.117).
Рис. 4.117. Список видов движений, созданных данным документомРис. 4.117. Список видов движений, созданных данным документом
Рис. 4.117. Список видов движений, созданных данным документом
Рис. 4.117. Список видов движений, созданных данным документом
iCMhi
В данном случае, согласно принятому нами алгоритму проведения доку^д тов типа изменениеСостоянияФизЛиц (см. листинг 4.23), были созданы двЛ ния, связанные только с записью новых значений периодического реквиЛ СостояниеФизлица справочника ФизЛица. После выбора вида движения най ране появится таблица (рис. 4.118). где перечислены новые значения пере дического реквизита СостояниеФизлица, установленные при проведении дай кого документа. ■
!=Q!=Qmilmil1||Справочник ||Реквизит j Элемент|Дата Значение|| Список Физических ли | Состояние Физ/ЙАксакалое Аксакал АД 28,06 06 Сотру»Состояние физг Федоров Федор Фел 28.06.06 Сотрудник по неосное»Список физических лиДСостояние Физ/j Криогенова Фекла М Ц 28 06.06 Ц Временно не работает1||Справочник ||Реквизит j Элемент|Дата Значение|| Список Физических ли | Состояние Физ/ЙАксакалое Аксакал АД 28,06 06 Сотру»Состояние физг Федоров Федор Фел 28.06.06 Сотрудник по неосное»Список физических лиДСостояние Физ/j Криогенова Фекла М Ц 28 06.06 Ц Временно не работаетИК ПО OCIИК ПО OCIiHiir. по неос!iHiir. по неос!Рис. 4.118. Значения периодического реквизита, установленныеПосмотрим, каким образом изменилась история значений реквизита в справочнике после проведения документа. Дл справочник ФизЛица, выберем строку с кодом 5 (рис. 4.119).Рис. 4.118. Значения периодического реквизита, установленныеПосмотрим, каким образом изменилась история значений реквизита в справочнике после проведения документа. Дл справочник ФизЛица, выберем строку с кодом 5 (рис. 4.119).документомдокументомпериодичес,я этого откгпериодичес,я этого откгРис. 4.119. Чтобы посмотреть, как изменилась история значений оеквититя поел. пр„е„,„„„ документа. .ы6ере„ ^ с К0Д0„Р5 , “^“ХаРис. 4.119. Чтобы посмотреть, как изменилась история значений оеквититя поел. пр„е„,„„„ документа. .ы6ере„ ^ с К0Д0„Р5 , “^“Ха
!=Q
!=Q
mil
mil
1||Справочник ||Реквизит j Элемент|Дата Значение
|| Список Физических ли | Состояние Физ/ЙАксакалое Аксакал АД 28,06 06 Сотру»
Состояние физг Федоров Федор Фел 28.06.06 Сотрудник по неосное»
Список физических лиДСостояние Физ/j Криогенова Фекла М Ц 28 06.06 Ц Временно не работает
1||Справочник ||Реквизит j Элемент|Дата Значение
|| Список Физических ли | Состояние Физ/ЙАксакалое Аксакал АД 28,06 06 Сотру»
Состояние физг Федоров Федор Фел 28.06.06 Сотрудник по неосное»
Список физических лиДСостояние Физ/j Криогенова Фекла М Ц 28 06.06 Ц Временно не работает
ИК ПО OCI
ИК ПО OCI
iHiir. по неос!
iHiir. по неос!
Рис. 4.118. Значения периодического реквизита, установленные
Посмотрим, каким образом изменилась история значений реквизита в справочнике после проведения документа. Дл справочник ФизЛица, выберем строку с кодом 5 (рис. 4.119).
Рис. 4.118. Значения периодического реквизита, установленные
Посмотрим, каким образом изменилась история значений реквизита в справочнике после проведения документа. Дл справочник ФизЛица, выберем строку с кодом 5 (рис. 4.119).
документом
документом
периодичес,
я этого откг
периодичес,
я этого откг
Рис. 4.119. Чтобы посмотреть, как изменилась история значений оеквититя поел. пр„е„,„„„ документа. .ы6ере„ ^ с К0Д0„Р5 , “^“Ха
Рис. 4.119. Чтобы посмотреть, как изменилась история значений оеквититя поел. пр„е„,„„„ документа. .ы6ере„ ^ с К0Д0„Р5 , “^“Ха
Элемент справочника ФизЛица с кодом 5 присутствует в табличной ча проведенного документа (см. рис. 4.113). Следовательно, история значе! периодического реквизита СостояниеФизлица (рис. 4.120) этого элеме! справочника была изменена проведенным документом.
5588НаименованиеАксакалов Аксакал АГруппа-1Г руппа-2НаименованиеАксакалов Аксакал АГруппа-1Г руппа-2Дата... ||Состояние Физлица UI UIдо IrfMSWMWgBWMWДата... ||Состояние Физлица UI UIдо IrfMSWMWgBWMWботыботыГпмппа-1Гпмппа-111Чй)Чй)я значенияя значения
5
5
8
8
Наименование
Аксакалов Аксакал А
Группа-1
Г руппа-2
Наименование
Аксакалов Аксакал А
Группа-1
Г руппа-2
Дата... ||Состояние Физлица UI UIдо IrfMSWMWgBWMW
Дата... ||Состояние Физлица UI UIдо IrfMSWMWgBWMW
боты
боты
Гпмппа-1
Гпмппа-1
1
1
Чй)
Чй)
я значения
я значения
Рис. 4.120. Выбор пункта меню для просмотра истории значенийпериодического реквизита справочника
^ диалоговом^ диалоговомокне (рис. 4.121) выберем периодический реквизит Состояние-окне (рис. 4.121) выберем периодический реквизит Состояние-№элииа.№элииа.
^ диалоговом
^ диалоговом
окне (рис. 4.121) выберем периодический реквизит Состояние-
окне (рис. 4.121) выберем периодический реквизит Состояние-
№элииа.
№элииа.
Реквизит
Состояние Физлица
Количество детей
Рис. 4.121. Выбор периодического реквизитадля просмотра истории значений
На экране появится окно истории изменения значений выбранного периодического реквизита (рис. 4.122).
Дата IIВ ремя || Документ
Номер
| Значение
® Ц07.06061|
Временно не работает
S 24 06 06
Сотрудник по неосновному месту работы
^уУ^|£||д|2338&|из^^
1
Сотрудник по основному месту работы
Рис. 4.122. История значений периодического реквизита СостояниеФизлицав справочнике ФизЛица для элемента с кодом 5
Как видите, в истории периодического реквизита есть значения, которые были изменены вручную, но последнее значение (см. рис. 4.122) было изменено документом, который был создан и проведен (см. рис. 4.112—4.115).
Примечание
Возможность изменения значений реквизита вручную и/или при проведении документов указывается при формировании конфигурации 1С:Предприятие. В данном случае при создании периодического реквизита СостояниеФизлица в справочнике ФизЛица были разрешены оба способа (см. рис. 4.109).
Вернемся к нашему проекту (Delphi). Посмотрим, как с помощью механизма OLE Automation можно прочитать информацию о том. каким именно спосо- ^°м изменялись значения периодических реквизитов. Для этого изменим ме- Т°Д Execute формы (см. рис. 4.89) следующим образом (листинг 4.24). Доба- вим две переменные:
°ie_doc — ссылка на объект типа Документ, при проведении которого было создано значение реквизита справочника ФизЛица;
*1 sNameDoc — строка, где будем формировать наименование этого документа.
-t. Формы-История пвриадиче(
•кеизита"НИя в мег0Д6 ^«и
Ч-==^^!№мО^ЕЛШо,
“ K""1^
Var
ole_doc , OleVariant
■N«”*Doc: String;
“’^'^ -^.^„^^
1 И Ссылка на -
// Наименов,
ТекущийДокумент *
'ание документа
Дополним текст метпп» „
ТИНГ4.25). MCTO™ — ^=ти„г 4.2,) слсдующими сгрокаад J
Sa- —^~
if NrType=ll then begin // Справочник sValAttr:= Trim(ole_period.Наименование); end;
//============================ =============;
sNameDoc:=1';
ole_doc:=ole_perlod.ТекущийДокумент;
if length(Trim(ole_doc.Вид))>0 then begin sNameDoc:=Trim(ole_doc.Вид)
+ ' N *
+ Trim(ole_doc.Hc«epfloK)
end;
+ Trim(ole_doc.ДатаДок)
+ Trim(ole_doc.Комментарий);
if length(eNroeDoc)>0 then
ListBoxl.items.
'-1-sNameDoc) ; end
else begin
begin
—^o^,^^.,
ListBoxl - Items .ADD (Trim
end;е^1оа.ДаТазнаЧ) + 1 , '♦sValAttr);
,Н1|М текст метода Execute (листинг 4.25).
дидите, ссылку на документ, сформировавший значение периодического визита при проведении, можно получить, обратившись к свойству теку- ^...-укумент объекта Периодический (см. выше в ЭТОМ разделе).
уо выполняется в строке:
Ve а0с:=°1е--Рег^-тв’'У’«ийДоку^
Если ссылка на Текущийдокумент актуальна, то метод Вид текущего докумен- гз возвращает непустую строку. В этом случае для формирования наименования документа можно обратиться к соответствующим свойствам текущего документа:
sNameDoc:=Tr im (ole_doc. Вид)
+ 1 N 1
* Trim(ole_doc.НомерДок|
* ' С
+ Trim(ole_doc.ДатаДок)
♦ Trim(о1e_doc.Комментарий);
Сохраним наши изменения, скомпилируем и запустим проект на выполнение, после чего произведем выборку элементов справочника ФизЛица (рис. 4.123).
77Группа 1Группа 1Код |НаименованиеДатаРожд^СостояниеФизлица
7
7
Группа 1
Группа 1
51_2 72951_2 72966Аксакалов Аксакал Ак 01.01.1970 Сотрудник.0 сновмой
5
1_
2 7
2
9
5
1_
2 7
2
9
6
6
Иванов Иван Иванова 01.01.1971 СструдникОсноеной
Группа-2
Петров Петр Петрович 01.01.1972 ВременноНеРаботает
Сидоров Сидор Сидоро 01.01.1973 СотруаникНвосмовной
Группа-3
Федоров Федор Федо 01.01.1974 СотрудникНеосновной
Криогенова Фекла Ма| 15.03.1965 ВременноНеРаботает
Рис. 4.123. Выборка элементов справочника ФизЛица
Дм» отметим ячейку . строке с кодом 5 и столбце СостокнвеФизлнца <Рис.4.124).
На экране появится разработанная нами Delphi-форма, гдепоове-
изменения значений периодического реквизита справочника с у
Денных документов (рис. 4.125).
КодКодЧасть I. 1С и механизм OLE 4uto^j Наименование [ДатаРожд^ СостояниеФиэлица||
Код
Код
Г р/тла-1
ТТ| Аксакалов Аксакал Ах 01 01.1970 pRT№ Иванов Ивам Иванов»! 01 01 1971 i| Аксакалов Аксакал Ах 01 01.1970 pRT№ Иванов Ивам Иванов»! 01 01 1971 il никОсновнойl никОсновнойИстория период.реквизитаИстория период.реквизита
Т
Т
| Аксакалов Аксакал Ах 01 01.1970 pRT№ Иванов Ивам Иванов»! 01 01 1971 i
| Аксакалов Аксакал Ах 01 01.1970 pRT№ Иванов Ивам Иванов»! 01 01 1971 i
l никОсновной
l никОсновной
История период.реквизита
История период.реквизита
^2^я периодического реквизита^2^я периодического реквизитаФФN 1 [28.06.20061 Здесь - комментN 1 [28.06.20061 Здесь - комментРис 4.125. История измененийРис 4.125. История изменений'TDDOC™ У*к«'“ »«=—»= •— In, 1<»К4**™,.^*'TDDOC™ У*к«'“ »«=—»= •— In, 1<»К4**™,.^*I Тур.I Length! Pr.cl.ionI Тур.I Length! Pr.cl.ion1010ГО I Defer lol ItoOCГО I Defer lol ItoOCI Unique | IndexedI0|ZDDOCI Unique | IndexedI0|ZDDOC<1.14.<1.14.ЮВМежаI IDЮВМежаI ID■•7ABLI Меже 0146■•7ABLI Меже 0146ID.acrID.acr: Дсжум.а. (&>.«.> Хпие,«неСостожмкп^иЛэ<и: Дсжум.а. (&>.«.> Хпие,«неСостожмкп^иЛэ<и1До«п««. №...1До«п««. №...•IDDOC-LIMIHO «КО•IDDOC-LIMIHO «КОIDeecrIDeecr, ,, |1»«1*/в/о1|ввты>1л„.|й.о.й,1.) KWM.«H.C.c,|A,рТ«6„I Тура I length IKr.cieien, ,, |1»«1*/в/о1|ввты>1л„.|й.о.й,1.) KWM.«H.C.c,|A,рТ«6„I Тура I length IKr.cieienI LmeloI (>)**жЛкцоI LmeloI (>)**жЛкцоICICkJ'"-'ГО11НСkJ'"-'ГО11НСI О) Но>о«Сос*о*»м*м* | СI О) Но>о«Сос*о*»м*м* | СlOexcrlOexcrI Unique 1IndexedI Unique 1Indexed101010101010field*field*1.Г IDPOC.llneSIOI ЮР ОС. LIHIX01.Г IDPOC.llneSIOI ЮР ОС. LIHIX011-ВМе^I n»ii NL11-ВМе^I n»ii NL
^2^я периодического реквизита
^2^я периодического реквизита
Ф
Ф
N 1 [28.06.20061 Здесь - коммент
N 1 [28.06.20061 Здесь - коммент
Рис 4.125. История изменений
Рис 4.125. История изменений
'TDDOC™ У
*к«'“ »«=—»= •
— In, 1<»К4**™,.^*
'TDDOC™ У
*к«'“ »«=—»= •
— In, 1<»К4**™,.^*
I Тур.I Length! Pr.cl.ion
I Тур.I Length! Pr.cl.ion
10
10
ГО I Defer lol ItoOC
ГО I Defer lol ItoOC
I Unique | Indexed
I0|ZDDOC
I Unique | Indexed
I0|ZDDOC
<1.14.
<1.14.
ЮВМежа
I ID
ЮВМежа
I ID
■•7ABLI Меже 0146
■•7ABLI Меже 0146
ID.acr
ID.acr
: Дсжум.а. (&>.«.> Хпие,«неСостожмкп^иЛэ<и
: Дсжум.а. (&>.«.> Хпие,«неСостожмкп^иЛэ<и
1До«п««. №...
1До«п««. №...
•IDDOC
-LIMIHO «КО
•IDDOC
-LIMIHO «КО
IDeecr
IDeecr
, ,, |1»«1*/в/о1|ввты>1л„.|й.о.й,1.
) KWM.«H.C.c,|A,рТ«6„
I Тура I length IKr.cieien
, ,, |1»«1*/в/о1|ввты>1л„.|й.о.й,1.
) KWM.«H.C.c,|A,рТ«6„
I Тура I length IKr.cieien
I Lmelo
I (>)**жЛкцо
I Lmelo
I (>)**жЛкцо
IC
IC
kJ'"-'
ГО11НС
kJ'"-'
ГО11НС
I О) Но>о«Сос*о*»м*м* | С
I О) Но>о«Сос*о*»м*м* | С
lOexcr
lOexcr
I Unique 1Indexed
I Unique 1Indexed
10
10
10
10
10
10
field*
field*
1.Г IDPOC.llneSIOI ЮР ОС. LIHIX0
1.Г IDPOC.llneSIOI ЮР ОС. LIHIX0
11-ВМе^
I n»ii NL
11-ВМе^
I n»ii NL
" — Ж,=™=—-
Иде^.каГор реквизита: СостояниеФ излица гHcropigреквизита: " ~
jl9?$^O61 ВременноНеРаботает
■ г ^1 СотрааникНеосновной
। 2° №2061 СотрудникОсновной <• ИэменениеСостоянияФиэПиц
периодического реквизита СостояниеФиэлица
Результат, представленный на рис. 4.125. можно сравнить с тем. что пок на рис. 4.122. Как видите, информация, считанная с использованием м низма OLE Automation, совпадает с той. что представлена путем визуал ции истории изменения значений периодического реквизита стандартн средствами системы 1С:Предприятие.
Созданные нами изменения в конфигурации отражены в словаре дан (файл !Cv7.DD) следующим образом (рис. 4.126).
С ,-Т ^^^: *•■■"“" в»—»•Соет«те,».^ь<ц’
*-'---^.;i”^^“—c"™‘«!^‘,VI/v\'^^“-^
Рис. 4.126. Содержание файла 1Cv7.DD.
Структура документа ИзменениеСостоянияФизЛиц
^зк видите, для каждого нового типа документов создаются две таблицы. Одна таблица (с префиксом он) соответствует "шапке" документа, другая (( префиксом от) — "табличной части" документа. Более подробно об этом — г части IL
15J0URH15J0URHО помощью любого просмотрщика DBF-файлов откроем журнал документов (файл 1SJOURN.DBF, рис. 4.127).
15J0URH
15J0URH
| mJ Открыть ra6>Mi/J
touRNAL|lDDOC|lDDOCDEF|APPCODE|bATE |Т1МЕ |DNPREFIX|DOCNO|cLOSED |ISMABk|aCTCNT|VERSTAM^ 2 1A8 28.06.2006 E2SLK0 461I13I2
Рис. 4.127. Журнал документов (файл 1SJOURN.DBF)
В журнале всего одна строка, соответствующая созданному документу. Здесь следует отметить, что поле iddoc содержит значение 2. Это связано с тем. что в процессе работы над книгой был создан еще один документ, но затем удален. Откроем файл 1SCONST.DBF (где система 1С:Предприятие размещает значения периодических реквизитов). Как видите, строки, созданные при проведении документов, имеют соответствующие ссылки на ТекущийДокумент в поле оосго(рис. 4.128).
; Содержание таблицы:*
IbLUNSI
'I-
J21I
Открыть таблицу j
[08JID |lD
DATE
PARING (VALUE IDODD
| TIME
ACTNOjUNENO |TVALUE
►
■EH 16
24 06.2006
0
14
0
0
0
0
116
24 06.2006
0
13
0
0
0
0
416
24 06.2006
0
15
0
0
0
0
616
24 06.2006
0:
13
0
0
0
0
216
24.06.2006
0
15
0
0
0
0
617
24.06.2006
0
1 1
0
0
0
0
317
24.06.2006
0
2!
0
0
0
0
516
28.06.200$
0
13
2
E2SLK0
1
0
416
28.06.2006
0
14
2
E2SLK0
2
0;
616
28.06.2006
0
15
2
E2SLK0
3
0
Рис. 4.128. Значения периодических реквизитов справочниковразмещаются в файле 1 SCONST.DBF
г*м* .
Откроем файл DH46.DBF ("шапка" документа изменениеСостоянияФи: На рис. 4.129 представлено содержание "шапки" документа.
Рис. 4.129. “Шапка" документа типа ИзменениеСостоянияФизЛиц (файл DH46.D
Как видите, в этой таблице хранятся только системный идентификатор < ки (поле IDDOC), соответствующей конкретному документу, и рекви "шапки" документов. Свойства дата и время этого документа xpai в журнале документа (см. рис. 4.127).
Теперь откроем табличную часть документов этого типа (файл DT46.E Как видите (рис. 4.130), в этой таблице хранятся системный идентифик строки (поле ПЛЮС), соответствующей конкретному документу, hi строки документа (поле LINENO) и реквизиты "табличной части" докумен
г Содержание таблицы: —
' I I * I w I Открыть таблицу |РUNENO |sP50 |SP51 |
1513
2414
3615
Рис. 4.130. “Табличная часть" документа, типа ИзменениеСостоянияФизЛиц(файл DT46.DBF)
Эта информация пригодится нам в части П, когда мы будем рассматривай'! возможность доступа к базе данных системы I С: Предприятие с использов® нием SQL-запросов. В этом разделе не были затронуты вопросы визуали#! ции реквизитов неопределенного типа. Их мы коснемся в раза. 4.7.1.
Примечание
Напомню, что представленные примеры исходных текстов — это упрощенная иллюстрация к рассматриваемым вопросам. Назначение этих примеров — представление о возможном подходе при решении задач информационного обмена с системой 1С:Предприятие. При работе с реальными базами Ю може потребоваться их дальнейшая доработка.
д2. Считывание информации
и3 документов
I документ — важное понятие системы 1 С:Предприятие (подробную инфор- 1 цаплю 0 документах можно найти в специальной литературе по системе 1 |С;ПрмпРиятие)- Нас в этом разделе будут интересовать только способы считывания информации о документах с использованием механизма OLE
■ Auiomation.
Откроем Конфигуратор 1С:Предприятие и внесем следующие изменения в нашу конфигурацию:
Создадим новое перечисление приоритетдокумента (рис. 4.131).
Внесем новый реквизит типа Перечисление. приоритетдокумента в шапку документа ИзменениеСостоянияФизЛиц (рис. 4.132).
Й ^ Прц»ютетДокумекта|
: в Высоки)
а Обычный
- - ■ Низки)
Рис. 4.131. Перечисление, определяющее приоритет документа
Сиойова Реквизита
Общие | Дополнительные |
Идентификатор:
Синоним
Комментарий:
[ПририотетДокумента |Пририотет документа
II
Тип значения:
Длину.
| Перечнеление.ПририотетДокумента^] |0 -т| Г Неогр Ттяносгь |0 ^
Рис. 4.132. Новый реквизит шапки документа типаПеречисление.Приоритетдокумента
На рис. 4.133 представлена структура документа ИзменениеСостоянияФизЛиц после внесенных изменений.
Сохраним изменения в конфигурации (см. рис. 2.17).
Попробуем прочитать информацию о структуре документа (см. рис. 4ЛЗА используя механизм OLE Automation. Для этого создадим ■Delphi).
У Й ИзменвниеСосгоянияФиэЛиц
Э ЕВ Шелка
■• —j ПририотетДокумента
8 И Таб/мчная часть
—j ФизЛщо
—। НоаоеСостояниеФизЛица
Рис. 4.133. Список реквизитов документа ИзменениеСостоянияФизЛии
Примечание
Пример есть в папке \Part_1\Chapter_04\Topic_4_2\sp_LoadAttrFromDoc.PAS сопроводительном компакт-диске книги.
На рис. 4.134 представлена форма проекта.
Рис. 4.134. Форма главного окна приложения sp_LoadAttrFromDocj
Этот проект создан по подобию проектов, рассмотренных ранее, поэтому П» яснения не требуются. Интерес представляет только обработчик событЯ "нажатие кнопки Прочитать". Но прежде чем написать текст обработчик* попробуем разобраться в вопросе, какие именно свойства и методы докумс® тов, необходимые для решения этой задачи, доступны через механизм Oil Automation. Мы уже знаем, что все свойства (реквизиты) документов мо»Я разделить на три категории:
общие реквизиты документов;
реквизиты "шапки" документов;■
реквизиты "табличной части" документов.
Напишем функции, которые позволят прочитать список идентификатору реквизитов документов каждой из этих трех категорий.
■
g листинге 4.26 представлен текст функции, считывающей список идентификаторов общих реквизитов всех документов.
ir4.
function Get_DocAttrCoranon_to_Liet(handlelC:01eVariant; List:TStrings): integer;
// Получить список значений общих реквизитов документов
// handlelC — ссылка на 1С:Предприятие
// List// Listсписок, в котором возвращаются общие реквизиты документов
// List
// List
Var
Yes: byte;//Вспомогательнаяпеременная
oleBuf: OleVariant; II Вспомогательная переменная
sValAttr,//Значение реквизита(строка)
KindAttr,//Вид реквизита
TypeAttr,//Тип реквизита
idAttr: string; // Идентификатор реквизита
iAttr,*
CountAttr: integer; // Количество общих реквизитов документов begin
Result:=0;
Yes: = 0;
if ListoNIL then begin
List.Clear;
if not VarlsQnpty(handlelC) then begin Yes:=l;
end;
end;
if Yes>0 then begin
11 Количество общих реквизитов документов
CountAttr:=1‘handlelC.Метаданные.ОбщийРеквизитДокумента;
if CountAttr>0 then begin
iAttr:=0;
while iAttr<CountAttr do
begin
iAttr:=iAttr+l;
// Читаем ссылку на реквизит табличной части
OleBuf:=handlelC.Метаданные.ОбщийРеквизитДокумента(1 *iAttr);
// Считываем идентификатор реквизита
idAttr:=Trim(oleBuf.Идентификатор);
’^ 10М
коЧасть I. IC и механизм OLE Autop®
// Считываем вид реквизита
KindAttr:=Trim(oleBuf.Вид);
// Считываем тип реквизита
TypeAttr:=Trim(oleBuf.Тип);■
List.Values[idAttr]:='Вид:'+KindAttr+'; Тип:'+TypeAttr;■
end;
Result:=List.Count;
end;
end;
end;$|
Поясним текст функции Get_DocAttrCommon_to_List. Как видите, и чД основную роль играет объект Метаданные.
В функцию Get_DocAttrCommon_to_List передаются два параметра. Я □ handleic — ссылка на 1С:Предприятие (сервер OLE Automation);
List— список, в котором возвращаются общие реквизиты документом J Текст функции достаточно прост, поэтому отметим лишь основные моментам I □ Если метод ОбщийРеквизитДокумента:
handleic.Метаданные.ОбщийРеквизитДокумента;
вызывается без параметров, то возвращается количество общих реквИ® тов документов.
Если метод ОбщийРеквизитДокумента:
oleBuf:=handlelC.Метаданные.0ба»«йРеквизитДокумента(l*iAttr);
вызывается с параметром (номер общего реквизита документов), то воз* вращается ссылка на общий реквизит документов, соответствующий yi®* занному номеру.
Получив ссылку на общий реквизит документов как объект, можно об|* щаться к его свойствам и методам.
В данном случае МЫ используем свойства реквизита: Идентификатор, ^«Ь Тип.
Теперь напишем функцию, которая позволит считывать список идентифик* торов реквизитов "шапки" документов (листинг 4.27).1
Листинг 4.27.Получение списка реквизитов "шапки" документа
function Get_DocAttrHead_to_*
List(handleic:01eVariant;idDoc:string;List:TStrings):integer;
// Получить список значений реквизитов "шапки" документа
nandleic " ссылка на 1С:Предприятие
- идентификатор тестируемого документа
'. _— список, в котором возвращаются реквизиты "шапки* документа
VarVar// Вспомогательная переменная// Вспомогательная переменная// Ь15С
Var
Var
// Вспомогательная переменная
// Вспомогательная переменная
yes: byte; „
leBuf: OleVariant; // Вспомогательная переменная gValAttr, // Значение реквизита (строка)
KindAttr, И Вид реквизита rypeAttr, И Тип реквизита idAttr: string; // Идентификатор реквизита
CountAttr: integer; // Количество реквизитов -шапки" документов
begin
Result :=0;
Yes:= 0;
if ListoNIL then begin
List.Clear;
if not VarlsEnipty(handlelC) then begin
idDoc:=Tr im (idDoc);
if length(idDoc)>0 then begin
// Проверяем существование документа с идентификаторе»» idDoc
if handlelC.Метаданные.Документ!1 ч-idDoc).Выбран>0 then begin
Yes:=l;
end;
end;
end;
end;
if Yes>0 then begin
// Количество реквизитов "шапки" документа
CountAttr:=1‘handlelC.Метаданные.Документ(1'+idDoc).РеквиэитШапки;
if CountAttr>0 then begin
iAttr:=0;
while iAttr<CountAttr do
begin
iAttr:=iAttr+l;
I/ Читаем ссыпку на реквизит табличной части leBuf:=handlelC.Метаданные.Документ(1'+ idDoc).РеквизитШапки(1*iAt tr);
// Считываем идентификатор реквизита
idAttr:=Trim(oleBuf.Идентификатор);
128128□ □ □□ □ □□□□□□□□□ВВtuafl-tuafl-^^^^I*I*// ^// ^2^2^_^^'С"^^_^^'С"^^„———— " ™"„———— " ™"handlelC - ссыпка на IC: Предприятие- идентификатор тестируемого документа LigC - список, в котором возвращаются реквизиты у/ табличной части тестируемого документаhandlelC - ссыпка на IC: Предприятие- идентификатор тестируемого документа LigC - список, в котором возвращаются реквизиты у/ табличной части тестируемого документас идентификатором idDocс идентификатором idDoc),выбраи>0 Chen begin),выбраи>0 Chen beginтабличной части документатабличной части документа(•-+idDoc).(•-+idDoc).
128
128
□ □ □
□ □ □
□
□
□
□
□
□
□
□
В
В
tuafl-
tuafl-
^^
^^
I*
I*
// ^
// ^
2^
2^
_^^'С"^^
_^^'С"^^
„———— " ™"
„———— " ™"
handlelC - ссыпка на IC: Предприятие
- идентификатор тестируемого документа LigC - список, в котором возвращаются реквизиты у/ табличной части тестируемого документа
handlelC - ссыпка на IC: Предприятие
- идентификатор тестируемого документа LigC - список, в котором возвращаются реквизиты у/ табличной части тестируемого документа
с идентификатором idDoc
с идентификатором idDoc
),выбраи>0 Chen begin
),выбраи>0 Chen begin
табличной части документа
табличной части документа
(•-+idDoc).
(•-+idDoc).
Часть I. 1С и механизм OLE Ань
// Считываем вид реквизита KindAttr:=Trim(oleBuf.Вид);
И Считываем тип реквизита
TypeAttr:=Trim(oleBuf.Тип);
List.Values[idAttr]:='Вид:'+KindAttr+1; Тип:'+TypeAttr; end;
Result:=List.Count;
end;
end;
end;
ПОЯСНИМ текст функции Get_DocAttrHead_to_List.
В функцию Get_DocAttrHead_to_List передаются три параметра:
handlelC — ссылка на 1С:Предприятие (сервер OLE Automation);
idDoc — идентификатор тестируемого документа;
List — список, в котором возвращаются реквизиты шапки тестируемо документа.
Текст функции достаточно прост, поэтому отметим лишь основные момент
Проверяется существование документа с идентификатором idDoc: if handlelC.Метаданные.Документ!''+idDoc).Выбран>0 then begin ЕСЛИ метод РеквизитШапки:
handlelC.Метаданные.Документ(''<idDoc).РеквизитШапки; вызывается без параметров, то возвращается количество реквизитов ки документа.
Если метод РеквизитШапки:
oleBuf:=handlelC.Метаданные.Документ(''+idDoc).РеквизитШапки(1 *iAttr) ■ вызывается с параметром (номер реквизита документа), то возвра ся ссылка на реквизит шапки документа, соответствующий указанному номеру.
Получив ссылку на реквизит документа как объект, можно обращаться к его свойствам и методам.
данном случае мы используем свойства реквизита: идентификатор.
Тип.
Теперь напишем функцию, которая позволит считывать список идентифи1* торов реквизитов табличной части документов (листинг 4.28).
Yes: byte; // Вспомогательная переменная oleBuf: OleVariant; // Вспомогательная переменная sValAttr, // Значение реквизита (строка)
KindAttr, // Вид реквизита
TypeAttr, // Тип реквизита
idAttr: string; И Идентификатор реквизита
iAttr,
CountAttr: integer; // Количество реквизитов табличной части документов begin
Result:=0;
Yes:= 0;
if ListoNIL then begin
List.Clear;
if not VarlsEmpty(handlelC) then begin
idDoc:=Trim(idDoc);
if length!idDoc)>0 then begin // Проверяем существование документа if handlelC.Метаданные.Документ!''+idDoc
Yes:=1;
end;
end;
end;
end;
if Yes>0 then begin
// Количество реквизитов
c=untAttr: =1 «handlelC. Метаданные. Документ if CountAttr>0 then begin
iAttr:=0;
частичастиТип:'+TypeAttr;Тип:'+TypeAttr;"""Я"""Я
части
части
Тип:'+TypeAttr;
Тип:'+TypeAttr;
"""Я
"""Я
*чг
while iAttrcCountAttr do
begin
iAttr:=iAttr+l;
// Читаем ссылку на реквизит табличной
’ '+idDoc)-РеквизитТабличнойЧа,’ '+idDoc)-РеквизитТабличнойЧа,oleBuf:-handlelC.Метаданные.Документ( (l*iAttr);
’ '+idDoc)-РеквизитТабличнойЧа,
’ '+idDoc)-РеквизитТабличнойЧа,
// Считываем идентификатор реквизита idAttr:=Trim(oleBuf.Идентификатор);
// Считываем вид реквизита
KindAttr:=Trim(oleBuf.Вид);
// Считываем тип реквизита
TypeAttr:=Trim(oleBuf.Тип);
List.Values[idAttr]:='Вид:'+KindAttr+'; end;
Result:=List.Count;
end;
Result:=List.Count;
end;
end;
1
Поясним текст функции Get_DocAttrTabie_to_List. Она отличается йВ функции Get_DocAttrHead_to_List лишь тем, что вместо метода Реквиз Шапки вызывается метод РеквизитТабличнойЧасти. В остальном тексты об функций идентичны.
Примечание
В методы РеквизитШапки, РеквизитТабличнойЧасти и ОбшийРеквиз Документа можно передавать не только переменные типа Integer, но и ременные типа string. Если передается переменная типа integer, то это терпретируется как порядковый номер реквизита. Если передается переменна типа string, то это интерпретируется как идентификатор реквизита. Далее mi будем использовать эти возможности.
Теперь, наконец, напишем текст обработчика события "нажатие кноп Прочитать" (листинг 4.29).
^Листинг 4^рб|»^тчикс^^
procedure TForml.Buсton2С1ick(Sender: TObject);
H Прочитать список реквизитов документа:
// Edit3.Text - идентификатор тестируемого документа.
„ j Доступ к информации 1С из внешних приложений
, iscBoxl.Items - результат считывания реквизитов,
^тируемого документа,
.: „г - вспомогательная переменная
чех
List: TStrings;
tegin
ListBoxl. I terns. Clear ,-
if not VarlsEmpty(OlelC) then begin List:=TStringList.Create;
TRY
// Читаем список общих реквизитов документов ListBoxl.Items.Add(1 Общие реквзиты:');
Get_DocXttrCceniQ«i_to_biet (OlelC, List) ;
ListBoxl.Items.AddStrings(List);
ListBoxl. Items. Add ('.-') ;
// Читаем список реквизитов "шапки" документа
ListBoxl.Items.Add(1 Реквизиты шапки:');
Get_DocAttrHead_to_Liet(01elC,Trim(Edit3.Text).List);
ListBoxl.Items.AddStrings(List);
ListBoxl.Items.Add('1) ;
// Читаем список реквизитов табличной части документа ListBoxl.Items.Add('Реквизиты табличной части:')г Get_DocXttzTable_to_Llst(OlelC,Trim(Edit3.Text).List);
ListBoxl.Items.AddStrings(List);
FINALLY
if ListoNIL then begin List .Clear ,- List.Free;
List:=NIL;
end;
END;
end;
end;
Поясним текст обработчика.
Здесь поочередно вызываются созданные ранее функции (Get_DocAttrcommon_ to_List, Get_DocAttrHead_to_List, Get_DocAttrTable_to_List) И результа считывания реквизитов документа записывается в ListBoxl. items.
Часть I. 1С и механизм OLE Auh
Скомпилируем наш проект и запустим на выполнение. После соедини с системой 1 С:Предприятие нажмем кнопку Прочитать. Результат предо лен на рис. 4.135, пояснения излишни.
^inix^inix• Г Чтение реквизитов документов
^inix
^inix
Соединить с 1С |
। Имя 1 С-сервера (OLE Automation) = |V77 Application
| Строка инициализации - |/DEA1C_example.DB
I Прочитатъреквизитыдокумеита:
L, Прочитать J^ (ИзменениеСостоянияФизЛиц
Общие рекезиты
Комментарий-Вид;; ТипСтрока
Рекезиты шапки:
.,.,—._.*4^Эл>ста=пид:1 |ририотетДокумента; Тип;Перечисление Рекезиты табличной части:
ФизЛицо=Вид;ФизЛица; Тип Справочник
НоеоеСостояниеФизЛица-биаСостоя^еФизлица. Тип; Перечисление . I
=^ I
Рис. 4.135. Список реквизитов документа вида ИзменениеСостоянияФизЛиц
При обработке документов часто требуется проверить наличие реквизита (по идентификатору) в документах заданного вида. В глобальном модуле системы 1С:Предприятие для этого есть соответствующие "штатные" функции (листинги 4.30 и 4.33). Мы разработаем собственные функции, которые позволят выполнять эти же действия, но с помощью механизма OLE Automation.
Вот как в глобальном модуле 1С:Предприятие реализована проверка существования реквизита среди общих реквизитов документов и в "шапке" документа (листинг 4.30).
< ппг ч.ои. I |роверка существования реквизита среди общих реквизитов :^.®*шап^'.5?^^„.., .„-...j^c—
Функция глЕстьРеквизитШапхи(ИмяРеквизита, ВидЦокумента) Экспорт Если ПустоеЗначение(ИмяРеквизита) = 1 Тогда
Возврат 0;
ИначеЕсли Метаданные.ОбдийРеквизитДокумеита(ИмяРеквизита).Выбран!) = 1 Тогда
Возврат 1;
ИначеЕсли ПустоеЗначение(ВидЦокумента) = 1 Тогда
. д№туп к информации 10 из внешних приложений.
^Гм^данные.ДокументСВидДокумента) .Реквизит^<— . Тогда
ВозвратиначеВозврат ^неиЕс™1'"ВозвратиначеВозврат ^неиЕс™1'"1;1;0;0;к=неиФУнкииик=неиФУнкиии// глЕстьРеквизитШапкиО// глЕстьРеквизитШапкиО
Возврат
иначе
Возврат ^неиЕс™1'"
Возврат
иначе
Возврат ^неиЕс™1'"
1;
1;
0;
0;
к=неиФУнкиии
к=неиФУнкиии
// глЕстьРеквизитШапкиО
// глЕстьРеквизитШапкиО
Здесь: ймяРеквиэита — идентификатор тестируемого реквизита; видДоку- мента — идентификатор тестируемого документа.
Текст функции прост и не требует пояснений. Единственное, что можно отметить, — в одной функции совмещены две проверки:
проверка на существование тестируемого реквизита среди общих реквизитов документов;
проверка на существование тестируемого реквизита среди реквизитов "шапки" документа.
При разработке своей (аналогичной) функции мы разделим эти проверки. В листинге 4.31 представлен текст функции, проверяющей существование тестируемого реквизита среди общих реквизитов документов.
Листинг 4.31. Проверка существования реквизита среди общих реквизитов=5-^.— .._-Й^^£У1У!!и§£ЙЯ81ЬйМ^function YeiAttrinDocCanmcn_lC(handlelC: OleVariant;idAttr: string): boolean;// Проверка существования заданного реквизита среди общих// реквизитов документов:// handlelC - ссылка на 1С,11 idAttr — идентификатор тестируемого реквизита.Листинг 4.31. Проверка существования реквизита среди общих реквизитов=5-^.— .._-Й^^£У1У!!и§£ЙЯ81ЬйМ^function YeiAttrinDocCanmcn_lC(handlelC: OleVariant;idAttr: string): boolean;// Проверка существования заданного реквизита среди общих// реквизитов документов:// handlelC - ссылка на 1С,11 idAttr — идентификатор тестируемого реквизита.— _.
Листинг 4.31. Проверка существования реквизита среди общих реквизитов
=5-^.— .._-Й^^£У1У!!и§£ЙЯ81ЬйМ^
function YeiAttrinDocCanmcn_lC(handlelC: OleVariant;idAttr: string): boolean;
// Проверка существования заданного реквизита среди общих
// реквизитов документов:
// handlelC - ссылка на 1С,
11 idAttr — идентификатор тестируемого реквизита.
Листинг 4.31. Проверка существования реквизита среди общих реквизитов
=5-^.— .._-Й^^£У1У!!и§£ЙЯ81ЬйМ^
function YeiAttrinDocCanmcn_lC(handlelC: OleVariant;idAttr: string): boolean;
// Проверка существования заданного реквизита среди общих
// реквизитов документов:
// handlelC - ссылка на 1С,
11 idAttr — идентификатор тестируемого реквизита.
Var
oleBuf: OleVariant;
begin
Result:=FALSE;
if not VarlsEmpty(handlelC) then begin
idAttr :=Triin( idAttr) ;
if length(idAttr)>0 then begin
oleBuf:.handlelC.Метаданные.обшиЙРекниэитДокумеита(•1♦idAttr);
if oleBuf .Выбрало then begin
Result:=TRUE; end;
end;
end;
end;
end;
Текст этой функции не требует пояснений.
И Н И Н . VarИ Н И Н . VarВ листинге 4.32 представлен текст функции, проверяющей существо» тестируемого реквизита среди реквизитов "шапки" документа заданного ви ^И-Стинг 4.32. Проверка существования реквизита в “шапке" документа function YeeAttrInDocHead_lC(handlelC: OleVariant;idDoc,idAttr: string boolean;
И Н И Н . Var
И Н И Н . Var
Проверка существования заданного реквизита в "шапке" документа: handlelc — ссылка на 1С,
idDoc — идентификатор тестируемого документа, idAttr - идентификатор тестируемого реквизита.
oleBuf: OleVariant;
begin
Result:=FALSE;1
if not VarlsEmpty(handlelc) then begin
idAttr:=Trim<idAttr);
idDoc:=Trim(idDoc);
if (length(idAttr)>0) and (length!idDoc)>0) then begin
oleBuf:=handlelC.Метаданные.Документ(1'+idDoc).РеквизитШапки(''+idAttr);
if oleBuf.Выбран >0 then begin
Result:=TRUE;
end;
end;
end;
end;
Текст этой функции также не требует пояснений.
Вот как в глобальном модуле 1С:Предприятие реализована проверка существования реквизита среди реквизитов табличной части документа (листинг 4.33).
доступ к информации 1С из внешних приложений г^
гЛ*^*^^^
,.ункиия глЕстьРеквизитМнЧ(ИмяРеквизита,ВидЦокумента) Экспорт
--ерем Реквизит;
-ели (ПустоеЗначение(ВидДокумента) = 1) ИЛИ
(ПустоеЗначение(ИмяРеквизита) = 1) Тогда
Возврат 0;
КонеиЕсли ■
реквизит=Метаданные .Документ (ВидДокумента). РеквизитТабличнойЧасти
(ИмяРеквизита) ;
Зозврат Реквизит. Выбран () ;
КокеиФункции И глЕстьРеквизитМнЧ()
В листинге 4.34 представлен текст нашей функции, выполняющей эти же действия.
■ Листинг 4.34. Прр^рахуществования реквизита в табличной.части доку мента ; function YeBAttrInDocTable_lC(handlelC: OleVariant;idDoc,idAttr: string): boolean;
// Проверка существования заданного реквизита в табличной
// (многострочной) части документа:
// handle1С - ссылка на 1С,
// idDoc - идентификатор тестируемого документа,
// idAttr - идентификатор тестируемого реквизита.
Var
oleBuf: OleVariant;
begin
Result:=FALSE;
if not VarlsBrpty(handlelC) then begin
idAttr:=Trim(idAttr);
idDoc :=Trim( idDoc) ;
if (length(idAttr)>0) and (length(idDoc)>0) then begin
oleBuf :=handlelC. Метаданные. Документ ( * ’+idDoc) .Рбгвиз»1Таблична1Ча<ли( ’ ’+idAttr) ;
if oleBuf.Выбран >0 then begin
Result:=TRUE;
end,•
end;
end;
end;
Часть /. 10 и механизм OLE Aut
Текст этой функции также не требует пояснений.
Теперь объединим все три наших функции в одну, которая позволит те вать реквизит в целом по документу (листинг 4.35).
«Листинг 4.35. Проверка существования реквизита в документе
function YesAttrInDoc_lC(handlelC: OleVariant;idDoc,idAttr: string): integer;
// Проверка существования заданного реквизита в документе.
// Входные параметры:
// handlelC - ссылка на 1С,
// idDoc — идентификатор тестируемого документа.
// idAttr — идентификатор тестируемого реквизита.
// Возвращаемое значение:
// 0 - нет такого реквизита,
// 1 — присутствует среди общих реквизитов документов,
// 2 — присутствует среди реквизитов "шапки" документа,
/ / 3 — присутствует среди реквизитов табличной части документа.
begin
Result:=0;
if YeeAttrInDocCc*Tinon_lC (handlelC, idAttr) then begin
Result:=1;
end
else begin
if YeeAttrlnDocHea4_lC(handlelC,idDoc,idAttr) then begin Result:=2;
end
else begin
if YeeAttrInDocTable_lC(handlelC,idDoc,idAttr) then begin Result:=3;
end;
end;
end;
end;
Функция проста и не требует пояснений.
ГиЗ"^ "аШИХ Функииа' *" ^ =W" ‘"Р™”7’ чик события двойной щелчок мышки на списке ListBoxi" (листинг 4.36).
.r₽dure TForml.ListBoxlDblClick(Sender: TObject);
ц проверка работоспособности функции YesAttrInDoc_lC: v Edic3.Text - идентификатор тестируемого документа, // idAttr — идентификатор тестируемого реквизита.
.,. string; // Идентификатор тестируемого реквизита уд string;
NriyPe: integer;
begin
it ListBoxl.ItemIndex>=0 then begin
then beginthen beginidAttr:=Trim(ListBoxl.Items.NAMES[ListBoxl.Itemindex]);
then begin
then begin
if lnputQuery(’Проверка реквизита","Идентификатор1,idAttr) idAttr:=Trim( idAttr);
if length(idAttr)>0 then begin
NrType:=YeeAttrInDoc_lC(OlelC,Edlt3.Text,idAttr);
if NrType=l then begin
Sx: = "Реквизит <"
+idAttr
+'> относится к общим реквизитам документов';
ShowMessage(Sx);
end
else begin
if NrType=2 then begin
Sx:= "Реквизит <*
+idAttr
♦•> принадлежит шапке документа типа <"
♦Edit3.Text*">';
ShowMessage(Sx);
end
else begin
if NrType=3 then begin
Sx:= 'Реквизит <"
♦idAttr
♦•> принадлежит табличной части документа типа +Edit3.Text>">"
ShowMessage(Sx);
end
else begin
Sx:= 'Реквизит <■
+idAttr
+'> не корректен для документа типа <' +Edit3.Text+’>'
ShoviMessage(Sx) ;
end;
end;
end;
end;
end;
end;
end;
Поясним текст обработчика. Здесь все просто.
1.
2.
3.
4.
Из текущей строки списка реквизитов (ListBoxi. items) считываете» идентификатор реквизита:
idAttr:=Trim(ListBoxi.Items.NAMES[ListBoxi.Itemindex]);
Следует запрос на изменение тестируемого идентификатора реквизита: if inputQuery(1 Проверка реквизита','Идентификатор',idAttr) then begin Вызывается функция YesAttrinDoc_lc:
NrType: =YeeAttrInDoc_lC (OlelC,Bdlt3.Text, IdAttr) ;
В зависимости от значения переменной NrType выводится соответствую^ щее сообщение.
Скомпилируем и запустим на выполнение наш проект.
После того как будет получен список реквизитов документа изменениеСо- стоянияФизЛиц (см. ранее), сделаем двойной щелчок на строке, содержащей реквизит комментарий. На экране появится запрос на изменение идентификатора реквизита. Удалим все лишнее кроме слова "Комментарий" и нажмем кнопку ОК (рис. 4.136).
Проверка реквизит а
Идентификатор
| [Ком мент арии]
OK | Cancel
Рис. 4.136. Запрос на изменение идентификатора тестируемого реквизита
4 доступ к информации 1С из внешних приложений
экране появитсясообщение о результате тестирования реквизита ^-4J37'-
торим ту же операцию, но для некорректного (несуществующего) рекви- ^ (рис. 4.138).
эКране появится сообщение о результате тестирования несуществующего ^квизита (рис. 4.139).
pei
inadattrfromdoc
рис. 4.137. Результат тегирования реквизита документа
^Комментарий* относится к
Реквизит
реквизитам документов
Cancel
ОК
[проверка реквизиту
Идентификатор
КомментарииГИП
"Чествующего в документе реквизита
РИС. 4.138. Ввод заведомо несуществующ
корректен для документа типа
sp Joadattrfromdoc
L—"несуществующего реквизита документа
Рис. 4.139. Результат тестирования несущ
реквизит <Ко**нтарийИ 11 1 > ке ^^„емиеСостоянияФизЛиц»
Точно так же протестируем реквизиты: ПриоритетДокумента и НовоеСостоя- ниеФиэЛица.
Убедимся в том, что разработанная нами функция YesAttrinDoc_lc работает корректно. Вернемся к нашему проекту (sp_lCv7_Viewer_via_OLE.DPR) и Доработаем его таким образом, чтобы можно было читать информацию из Документов.
Часть I, 10 и механизм OLE Autoi
Примечание
Исходные тексты этого проекта есть на сопроводительном компакт-диске в папке \Part_1\Chapter_04\sp_1Cv7_Viewer_via_OLE.pas\04.
Для этого добавим новую вкладку и разместим на ней соответствующие поненты (рис. 4.140). Здесь все аналогично вкладке Справочники.
--—-*>еммм^
q С (£); иниц ^ 1ации 1 (^Предприятие: j/DEA1C_example.D8 Справочники Документы ^
1С
г Документ: ——
Идентификатордокумента:(ИзменемиеСостоянияФизЛ
;}Г Табличная часть документе— -
Есть соединение с объектов ■ £ Слисок реквизитов документа: pi
Memo_Head.Doc
Рис. 4.140. Доработка формы проекта для
Есть соединение с i С*.
чтения информации из документов
Вопросы соединения с объектом типа Документ также были рассмотрены pa-i нее. Поэтому уделим внимание именно процессу считывания информации из документов. Поставим перед собой следующую задачу: научиться выбирать нужный документ из списка документов системы 1С:Предприятие в интерак-1 тивном режиме и считывать информацию из выбранного документа (как "шапку" документа, так и его табличную часть).*
Рассмотрим первую часть задачи — выбор нужного документа в интерактивном режиме. Начнем с самого простого варианта. Будем использовать метод । документа Выбрать (или choose). Этот метод вызывает диалоговое ОКНО ДЛЯ । выбора документа и затем позиционирует выбранный документ в качестве I текущего (данный метод может использоваться только для объектов, созданных функцией СоэдатьОбъект). Синтаксис:
Выбрать(<Подсказка», <ФормаЖурнала», <КомуПодч>)
Параметры: <Подскаэка> — текст заголовка окна диалога ввода; <форк» журнала» — строковое выражение идентификатора той формы журнала документа (как он объявлен в Конфигураторе), которая должна использоваться
выбора (если это значение пустое, то используется форма журнала по •молчанию); <комуПодч> (необязательный) — используется при открытии ыбора п0 журналу подчиненных документов, т. е. когда второй параметр
„„адурнала» имеет значение Журнал. Подчиненные (в данном случае в этом параметре передается документ-владелец, по которому следует построить .д3рнал подчиненных документов). Возвращаемое значение (число): 1 — если документ выбран; 0 — если не выбран.
Посмотрим, каким образом можно использовать метод выбрать документа для наших целей. Простейший пример вызова метода Выбрать приведен в листинге 4.37.
№S№S■5■5
№S
№S
■5
■5
Var
ResOpen: integer;
ole_lC_Doc, II Ссылка на документ
ole_lC: OleVariant; И Ссылка на 1С:Предприятие begin
Ik Вызываем 1С:Предприятие,как сервер OLE Automation
ole_lC:= CreateOleObject('V77.Application');
if not VarlsEtapty(ole_lC) then begin
// Инициализация программы
ResOpen:=ole_lC.Initialize(ole_lC.RMTrade, ...);
if ResOpen<0 then begin // Инициализация — успешно
II Создаем ссылку на объект типа "Документ"
ole_lc_Doc: =о1е_1С. Crеа teObj ес t (' Документ. Здесь_Идентификатор_Документа1);
if not VarlsEmpty(ole_lC_doc) then begin
// Вызываем метод "Выбрать" документа
if ole_lC_doc.Выбрать('Выбрать документ')>0 then begin
end;
end;
end;
end;
end;
Как видите, здесь все предельно просто.
142
В данном случае мы вызываем метод выбрать только с одним параметр^ подсказкой для пользователя. На рис. 4.141 представлена форма выбора ' кументов, вызванная при выполнении этого метода. В данном случае пуст, потому что за указанный период (11.07.200^-11.07.2006) не оказЛ ни одного документа.
*^ТОЙ просно трети* для «Я
^ализаиии 7С.п^Х
. Список рек Н и у
Ном
12 07.2006 23
£^£g2Jb документ (11.07.ПбГТ
07.06) (Выбор)
Р"=. 4.141. Вы,„ „Етвд, ВыСрать ^^
— I „Табличная часть документ» :'|Ncrpl*——
, Документ:
. , ификатор документа •
; ГИзмененигС-и. ~
соадии
I Для того чтобы найти нужный нам документ, надо указать корректный период (см. рис. 4.143) в форме выбора документов, нажав соответствующую
I кнопку (см. рис. 4.141 и 4.142).
На экране появится форма ввода нового диапазона дат (рис. 4.143).
-«■ 4., 4г к„™ ад формы № вада ^ ^ ^^
Параметры журнала
[' Интервал журнала , с (оГгёоГ-у По; ,з^
В
Рис. 4.143. Ввод периода,
■| Отмена ( Помощь [
|, за который нужно отобрать документы
л Поступ к информации 1С из внешних приложений гпа^—-
Рис. 4.144. Список документов для выбора при корректно указанном периоде отбора документов
После ввода нового диапазона дат в списке появятся соответствующие документы (рис. 4.144).
Примечание
Окно программы 1 С.-Предприятие (как сервера OLE Automation) по умолчанию остается невидимым. Поэтому диалоговое окно выбора документов (см. рис. 4.141) может быть скрыто другими окнами различных приложений, запущенных в данный момент на компьютере. В этом случае для ‘поиска" диалогового окна можно использовать сочетание клавиш <Alt>+<Tab>.
На рис. 4.50 показана пиктограмма, которую нужно выбрать для того, чтобы диалоговое окно выбора документов появилось поверх остальных окон.
Рис. 4.145. Форма диалога для выбора документов
Для решения нашей задачи вполне подходит метод Выбрать документа. Но при Решении практических задач этого может оказаться недостаточно, хотя бы потому, что трудно будет объяснить конечному пользователю, почему он Должен искать окно формы выбора документов непонятно где и как. Поэтому попробуем разработать свою простую форму выбора документов. Пользова- Дель (при вызове этой формы) должен иметь возможность указать период.
Часть /. 1С и механизм OLE Auto\ список документов за который он желал бы видеть, а также журнал, oq чиваюший выборку документов. Для этого создадим новую форму дщ с именем Dig_sel_Doc (рис. 4.145).
В табл. 4.6 описаны основные компоненты этой формы.
Таблица 4.6. Назначение основных mun/w-■-
Компонент
Edit Datel
Тип
топ'"°в формы выбора докумея
НазначениеJ
Edit_Date2
TEdit
TEdit
Дата начала периода-Н
CB_ListJ
окончания периода1
TComboBox
ListBoxl
_^|нсик Журналов документов~1
TListBox
^ы^е™‘ ’^"-о^^гЧ
SpeedButtonl
—L
aopeeaautton
И ^анны*И%ало^Пе₽и^ом I
м жУРналом документов
11ервое, что нужно сделать. — это создать список идентификаторов журналов: документов, хранящихся в базе данных 1С:Предприятие. В листинге 4.38 приведена часть текста мегода Execute нашей формы, где решается эта задача.) [ Листинг 4.38. Создание списка журналов документов, хранящихся Я Lb базе данных 1С:Предприятие Я ЫЛ1У.:'й<жЗ*.Хм...| 'Axl,.i..VSf»t..b.fl.;‘MW.iM».‘.A£;L..i..-.«M.M..*:eiU..x;..^abU*X.*»4LsJb4^а.~;.A..i/„‘/..-.'l../...Л;л»гийИИ|^В CB_ListJ. Items. Clear; ■ CB_ListJ. Items.ADD(‘Все документы'); ■ CountJ: =Fonnl. ol e_lC. Me та да иные. Журнал * 1; ■ if CountJ>0 then begin | iJ:=0; ■ while iJ<CountJ do
begin m iJ:sU+1;
Sx: =Tr im (Fonni. ole_lC. Метаданные. Журнал (i J * 1) . Идентификатор);
CB_ListJ. Items .ADD (Sx); ■ Application. ProcessMessages; ■ end; 1 CB_ListJ. ItemIndex:=O;
ПояснимПояснимлистинг 4.38. Здесь, как и ранее, мы обращаемся к методам объекталистинг 4.38. Здесь, как и ранее, мы обращаемся к методам объектаметаданные.метаданные.
Поясним
Поясним
листинг 4.38. Здесь, как и ранее, мы обращаемся к методам объекта
листинг 4.38. Здесь, как и ранее, мы обращаемся к методам объекта
метаданные.
метаданные.
В строке:
roUncJ: =Forml. ole_lc.Метаданные.Журнал*!;
вызывается метод" метаданных — журнал без параметров. В этом случае возвращается общее количество журналов, хранящихся в базе данных |С:Предприятие.
В строке:
sx;=Trim(Forml.ole_lC.Метаданные.Журнал(Ы*1) .Идентификатор) ;
метод журнал вызывается с параметром типа integer. При этом возвращается ссылка на журнал как объект, порядковый номер которого соответствует значению параметра. Таким образом можно обратиться к свойству Идентификатор этого объекта.
Все остальное — тривиально.
Следующий шаг: создать фильтр, ограничивающий список документов, согласно заданным условиям (период и журнал).
В листинге 4.39 приведена часть текста обработчика события "нажатие кнопки Открыть нашей формы", где решается эта задача.
Fw^">:"«wn«w«9Листинг 4.39. УFw^">:"«wn«w«9Листинг 4.39. У^..й^..йt^.,.,....,,„.„..„_ , ,;,.._,,„.р,,.у_
Fw^">:"«wn«w«9
Листинг 4.39. У
Fw^">:"«wn«w«9
Листинг 4.39. У
^..й
^..й
в согласно указанному фильтру ■
// Получаем ссылку на объект типа "Документ" неопределенного вида
CleDoc:= Form!.о!е_1С.CreateQbject('Документ');
Yes:=0; // Признак того, что выборка документов произведена успешно
if CB_ListJ.ItemIndex>0 then begin
// Если указан конкретный журнал — вызываем
// соответствующий метод документа:
// "ИспользоватьЖурнал".
//В противном случае фильтрация документов
// будет производиться без учета журнала.
01 eDoc.ИспользоватьЖурнал (* 1 +CB_ListJ. Items (CB_ListJ. Itemindex]); end;
if (length(Edit_Datel.Text)>0) and (length(Edit_Date2.Text)>0) then begin
// Если период дат указан корректно, вызываем
// метод "ВыбратьДокументы" документа и передаем
II в качестве параметров обе даты,
II ограничивающие период выборки документов
•tu-Часть I. IC и механизм OLE Auton if OleDoc.Выбратьдокументы('1+Edit_Patel.Text, 1'+Edit_Date2.Text) then begin
Yes:=l;
end;
end
else begin
// Если период дат не указан, вызываем
И метод "Выбратьдокументы" документа без параметров
II тем самым снимая ограничения в выборке документов //по периоду
if 01eDoc.Выбратьдокументы»О then begin
YeS:=2;
end;
end;
Поясним листинг 4.39.
Сначала создается ссылка на объект типа документ неопределенного вид) (без идентификатора):
OleDoc:= Forml.ole_lC.CreateObject('Документ');
Это связано с тем, что мы не знаем заранее, какие именно условия укажи пользователь для фильтрации документов. То есть в списке могут оказаться разные документы.
Если пользователь указал для фильтрации конкретный журнал из сформиро- ванного ранее списка (листинг 4.38), то вызывается метод Использоватьжурн^ документа, где в качестве параметра передается идентификатор выбранногО| журнала:
OleDoc.ИспольэоватьЖурнал(''*CB_ListJ.Items[CB_ListJ.Itemindex]);
Если пользователь указал корректный диапазон дат. вызывается метод1 выбратьдокументы и в качестве параметров ему передаются обе даты, ограни< чивающие выборку документов соответствующим периодом:
if OleDoc.Выбратьдокументы)''+Edit_Datel.Text,''+Edit_Date2.Text)»0 then! Если пользователь не указал диапазон дат, вызывается метод выбратьдокумен-гад но без параметров:
if 01eDoc.Выбратьдокументы»О then begin
Вот, собственно, и все.
Примечание
Более подробно методы ИспольэоватьЖурнал и Выбратьдокументы ДОКУ мента описаны в специальной литературе по системе 1С:Предприятие.
-1епмоший шаг: сформировать список документов на основе произведенной сборки (см. листинг 4.39). Часть текста обработчика события "нажатие 8цопки Открыть нашей формы", где решается эта задача, приведена в листинге 4.40.
.£ yes>0 ehen begin
// Формируем список, выбирая документы в цикле
while OleDoc.ПолучитьДокумент > 0 do
begin
// Считываем ссыпку на "ТекущийДокумент"
OleBuf:=01eDoc.ТекущийДокумент;
// Формируем (как сами пожелаем) представление документа //в нашем списке документов
Sx:= Trim(01eBuf-Вид)
* ' N '
♦ Trim(oleBuf.НомерДок)
+ ' I'
+ Trim(oleBuf.ДатаДок)
// Вносим документ в наш список ListBoxl.Items.ADD(Sx);
Application.ProcessMessages;
end;
end;
Поясним текст листинга 4.40.
Поскольку выборка документов была уже произведена (листинг 4.39), считываем каждый документ в цикле, используя метод ПолучитьДокумент:
while 01eDoc.ПолучитьДокумент > 0 do
Чтобы получить ссылку на документ, нужно вызвать метод ТекущийДокумент:
OleBuf : =OleDoc. ТекущийДокумент;
Далее формируем представление документа в нашем списке так, как сами пожелаем. В данном случае (упрощенно) для формирования представления Документа используются методы и свойства: вид, НомерДок, датадок.
Метод ТекущийДокумент (или currentDocument) документа позволяет определить значение текущего документа. Синтаксис:
ТекущийДокумент ()
Метод текущийдокумент возвращает значение позиционированного теку документа (в целом как объекта). Данный метод применяется, например, нужно документ передать как параметр в вызове какого-либо метода присвоить какому-либо реквизиту.
На рис. 4.146 представлена форма (в режиме времени выполнения, е венно). когда сформирован список журналов (в данном случае журнал од
* Выбор документа
xxOKOKCancelCancelfe^ |0l 06.2006]зо'о7.2ОО6Р^УРнал: [все документы"fe^ |0l 06.2006]зо'о7.2ОО6Р^УРнал: [все документы"Список дойВсе документыСписок дойВсе документыР"С' 4.146. Вы6ор «,рнала № фтьтрад ^^
x
x
OK
OK
Cancel
Cancel
fe^ |0l 06.2006]зо'о7.2ОО6
Р^УРнал: [все документы"
fe^ |0l 06.2006]зо'о7.2ОО6
Р^УРнал: [все документы"
Список дойВсе документы
Список дойВсе документы
•J^oP Документа
||Период; |01.0в2006 рИРнал: |ж урна л До*, "Список документов. —
Открыть I
130 07 2006130 07 2006уменговФизЛицуменговФизЛиц1|щщщ|щдедщщ^щ^д^
130 07 2006
130 07 2006
уменговФизЛиц
уменговФизЛиц
OKOKJ ИзменениеСосгоянияФизЛиц N 3 [12 07.2006)
OK
OK
Cancel
— . --—
Рис. 4.147. Список документов, сформированный при нажатии кнопки Открыть
На рис. 4.147 представлен список документов, сформированный для вы по указанным выше условиям фильтрации (рис. 4.146).
Примечание
На момент формирования списка документов (см. рис. 4.147) в базе дан 1С:Предприятие было 3 документа и один журнал.
Теперь, когда список документов сформирован, мы можем из выбранио строки выделить идентификатор документа (первое слово) и номер докуме!
третье слово). Часть текста метода Execute нашей формы, где решается эта ^дача. приведена в листинге 4.41.
if ShowModal = mrOk then begin
// Форма закрывается по нажатию кнопки ОК if ListBoxl.ItemIndex>=0 then begin
// Если в списке документов выбрана строка, то
// выделяем из нее идентификатор и номер документа Sx:=ListBoxl.Items[ListBoxl.Itemindex];
// Выделяем из строки идентификатор документа (1-е слово) idDoc : = sp_GetWordFrcxnStrlng ( ' ][',Sx.1);
// Выделяем из строки номер документа (3-е слово)
NumDoc:= sp_GetWordFremString(' ][1,Sx,3);
// Выделяем из строки дату документа (4-е слово) DateDoc:= sp_GetWordFromString(' ](',Sx,4) ;
if (length!idDoc)>0) and (length(NumDoc)>0) then begin Result:=TRUE;
end;
end
else begin
ShowMessage(1 Внимание.Ни один из документов не выбран1); end;
end;
Поясним листинг 4.41. Текст достаточно прост. Единственное, что следует отметить. — в данном случае для идентификации документа в базе данных 1С:Предприятие (в нашей конфигурации) мы ориентируемся на идентификатор документа, его номер и дату, предполагая, что эти два свойства в совокупности являются уникальными для каждого документа.
Для выделения из строки слова по номеру используется функция sP_GetwordFromString. Текст этой функции приведен в файле \sp_Lib\sp_ Lib_Delphi.PAS на сопроводительном компакт-диске книги.
Теперь, когда нужный документ выбран (определен его идентификатор и но- МеР). можно прочитать из него информацию. Рассмотрим этот вопрос более подробно.
В нашем случае, чтобы получить ссылку на выбранный документ как на нужно создать объект типа Документ.Идентфикатор_Выбранного_Локумента! ole_lC_Doc:=ole_lC.CreateQbject('Документ.'♦ Dlg_Sel_Doc.idDoc); Этим самым мы определяем вид документов, среди которых нужно наш документ по номеру.
Затем, воспользовавшись методом документа НайтиПоНомеру, найдем (cri ционируем) сам документ:
Snum := Dlg_Sel_Doc.NumDocj
Sdate:« plg_Sel_Doc.DateDoc;
if ole_lC_doc.НайтиПоНомеру('’+Snum,•'+Sdate)>0 then begin
После этого можно прочитать значения общих свойств документа (не путдц с общими реквизитами), такие как время и позиция документа, признак того, проведен ли этот документ, количество строк в табличной части докум и др. Пример считывания приведен в листинге 4.42.
-г 4.42. Чтение о6щ„х ™йсг. „=.,„„„,
if ole_LC_doc.НайтиПоНомеру(' 4-Dlg_Sel_Doc.NUmDoc)>0 then begin //т
//Прочитаем общие свойства документа
Sx:=Tr im (ole_lC_doc.НомерДох);
Memc_Head_Doc.Lines.ADD('Документ N 1+Sx);
Sx:=Trim(ole_lC_doc.ДатаДох);
Memo_Head_Doc.Lines.ADD('Дата: 1+Sx);
Sx:=Trim(ole_ic_doc.ПолучитьВремя);
Memo_Head_Doc.Lines.ADD('Время: '+Sx);
Sx:=Trim(ole_lC_doc.noJiy4HTwnoSm»ao) ;
Memo_Head_Doc.Lines.ADD('Позиция: 1+Sx);
Sx:=Trim(ole_lC_doc.Вид);
Memo_Head__Doc. Lines. ADD (1 Вид: '+Sx);
Sx:=Trim(ole_lC_doc-ПредставлекиеВида);
Memo_Head_Doc.Lines.ADD('Представление вида: '+Sx);
CountLine:=ole_lC_doc.КоличествоСтрох*1;
Memo_Head—Doc.Lines-ADD('Кол-во строк='+IntToStr(CountLine));
if ole_lC_doc.Проведен»0 then begin
Memo_Head_Doc.Lines.ADD('Проведен'); end
е^е begin
Memo_HeacUDOC.Lines.ADD(1 Не проведен );
ПРИМЕЧАНИЕ
Более подробно методы и свойства объекта типа Документ, используемые в листинге 4.42, описаны в специальной литературе по системе 1С:Предприятие.
Теперь можно считывать значения реквизитов документа (общих, "шапки" н табличной части).
Сначала прочитаем значения общих реквизитов документов для данного до- кумента. На момент считывания информации наверняка неизвестно, какие именно общие реквизиты присутствуют в конфигурации системы. Поэтому нужно получить список идентификаторов общих реквизитов. Для этого воспользуемся функцией Get_DocAttrCommon_to_List (см. листинг 4.26).
Фрагмент исходного текста, решающего эту задачу, приведен в листинге 4.43.
ListBuf : = TStringList.Create;
TRY
//
// Прочитаем идентификаторы общих реквизитов документов
Oet_DocAttxConxnon_to_LiBt (ole_lC, Lis tBuf) ;
if ListBuf.Count>0 then begin
iAttr: = -1;
while iAttr<(ListBuf.Count-1) do
begin
iAttr:=iAttr+l;
idAttr:=Trim(ListBuf[iAttr]);
if length(idAttr)>0 then begin
// Выделим идентифкатор реквизита
idAttr:-ep_GetWordFromStrinfl(' =',idAttr.1);
Sx: = " ;
!/ Прочитаем значение реквизита
Sx:=Trim(ole_lC_doc.ПолучитьАтрибут(''+idAttr));
Memo_Head__Doc. Lines - ADD (idAttr*' =' +Sx) ;
end;
end;
end;
Для считывания значения реквизита по его идентификатору исполь-J метод ПолучитьАтрибут.
В общем случае нельзя присваивать переменной типа string значение вращаемое методом ПолучитьАтрибут. Если реквизит имеет агрегатный это приведет к ошибке. То есть необходимо определить тип значения исо<л. ветствующим образом корректно преобразовать его в строку. Этот вопщ был подробно рассмотрен в разд. 4.1.
В данном случае точно известно, что единственный общий реквизит до$. ментов комментарий имеет тип строка. Поэтому, чтобы не усложнять текст, все проверки и преобразования здесь отсутствуют. Если кто-либо пожелш использовать этот текст для доступа к информации из реальной базы данжи 1С, то нужно либо закомментировать строку:
Sx:=Trim(ole_lC_doc.ПолучитьАтрибут(''+idAttr));
либо самостоятельно написать функцию, которая бы корректно преобра» вывала значение, возвращаемое методом ПолучитьАтрибут, в тип string. , Для считывания значений реквизитов "шапки" и табличной части документ» нужно получить ссылку на текущий документ (т. е. ссылку на спозиционированный документ):
OleTekDoc:=ole_lC_doc.Текуи»«йДокумент;
На момент считывания информации также неизвестно, какие именно рекой- зиты "шапки" присутствуют в документах каждого вида. Поэтому, как и • случае с общими реквизитами, сначала нужно получить список идентифи* торов реквизитов "шапки" для документов выбранного вида. Для этого воспользуемся функцией Get_DocAttrHead_to_List (листинг 4.27). Фрагме^ исходного кода, решающего эту задачу, приведен в листинге 4.44.
ЛИ<?™НГ 4-44- ^У® ?Н®4®^. •-^
ListBuf:= TStringList.Create;
TRY
// Получим ссыпку на текущий (спозиционированный) документ OleTekDoc:=ole_lC_doc.ТекущийДокумент;
// Прочитаем реквизиты "шапки" документа
доступ к информации 1Сиз внешних приложений [/-^"
^AttrHead-tO-Liet (ole_lC, OleTekDoc, ListBuf) ,-
QetJ^
■ stBuf.Count>0 then begin if
^jle iAttr<(ListBuf.Count-1) do
b«in ,.'
jAttr:=iAttr+l;
idAttr :=Trim(ListBuf[iAttr]);
jf length(idAttr)>0 then begin
// Выделим идентифкатор реквизита
idAttr:=8p_GetWordFrcenString(' =',idAttr,1);
// Прочитаем значение реквизита
Sx:=Trim(Get_VlueAttr_fxaBiDoc_etr(ole_lC,OleTekDoc,idAttr));
Memo_Head_Doc.Lines.ADD(idAttr+'=1+Sx);
end;
end;
end;
//--
Среди реквизитов "шапки" документов вида ИзменениеСостоянияФизЛиц присутствуют объекты агрегатного типа (перечисление.ПриоритетДокумента). Поэтому для считывания значений реквизитов и преобразования их в тип string МЫ воспользовались специальной функцией Get_ValueAttr_from_Doc_str. Полный текст этой функции приведен на сопроводительном компакт-диске книги в файле \sp_Lib\sp_Lib_Delphi.PAS.
Примечание
Принципы преобразования значений агрегатного типа в тип string были подробно рассмотрены в разд. 4.1. Для документов этот процесс аналогичен. Поэтому останавливаться на нем не будем.
Теперь посмотрим, как считываются реквизиты табличной части документа Листинг 4.45). Подход здесь такой же. но с учетом того, что считываются -начсния реквизитов строк документа. То есть прежде чем считывать значе- Ние реквизита табличной части документа, нужно "спозиционировать соот- ^ствующую строку документа.
Листинг 4.45. Чтение значений реквизитов табличной части документа
--StBuf := TStringList.Create;
TRY
11 части документов заданного вида
Get_DocAttrTable_to_Liet(ole_lC,OleTekDoc,ListBuf);
if ListBuf .CounOO then begin
//============================================
- И Выберем строки документа,
II прочитаем значения реквизитов табличной части // для каждой строки
if ole_lC_doc.ВыбратьСтроки>0 then begin
// Переберем все строки документа в цикле
while ole_lC_doc.ПолучитьСтроку>0 do begin
// Номер текущей (спозиционированной) строки документа iLine:=ole_lC_doc.HoMepCrpoiai*l;।
И
// Прочитаем значения реквизитов текущей строки iAttr:= -1;
while iAttr<(ListBuf.Count-1) do begin
iAttr:=iAttr+l;
idAttr:=Trim(ListBuf[iAttr]);
M Выделим идентифкатор реквизита
idAttr:=sp_GetWordFroraString(' =',idAttr,1);
// Прочитаем значение реквизита
Sx:=Trim(Get_ValueAttr_fran_Doc_etr(ole_lC,ole_lC_doc,idAttr))Д end;
H
Application.ProcessMessages;
end;■ Я
end;
//================================
Текст этого фрагмента достаточно прост и не требует разъяснений.
Примечание
Более подробно методы ВыбратьСтроки, ПолучитьСтроку и свойств НомерСтроки документа описаны в специальной литературе по систе । 1С:Предприятие.
-ж-ж^д^Доступ к информации 10 из внешних приложений перебора строк документа можно также использовать метод получить ^^куПоНомеру документа. Фрагмент функции, решающей эту задачу, пред- 22» в листинге 4.46.
-ж
-ж
готатаияда?^^
чений реквизитов табличной части документа
*(Ой1ЖлйЛ^&а»:^&-ы^.г.;...;^.М™^-.........>—-.-
Прочитаем количество строк в табличной части // данного документа
CoUntLine: =ole_lC_doc. КоличестжоСтрок-1 ;
LiscBuf:= TStringList.Create;
// прочитаем идентификаторы реквизитов табличной
// части документов заданного вида
Get_DocAttrTable_to_List (ole_lC,01eTekDoc,ListBuf);
if ListBuf .Count>0 then begin
//=======================================
I( Выберем строки документа,
/ / прочитаем значения реквизитов табличной части
// для каждой строки
if о1е_1С_аос.ВыбратьСтроки>0 then begin
iLine:=0;
while iLine<CountLine do
begin
iLine:=iLine+l;
if о1е_1С_бос.ПолучитьСтрокуПоНоыару(iLine‘1)*l>0 then begin
//
// Прочитаем значения реквизитов текущей строки iAttr: = -1;
while iAttrc(ListBuf.Count-1) do
begin
iAttr:=iAttr*l;
idAttr:=Trim(ListBuf[iAttr]);
I/ Выделим идентифкатор реквизита idAttr:=sp_GetWordFromString(' =1,idAttr, 1); // Прочитаем значение реквизита
Sx:=Trim(Get_ValueAttr_fronL_Doc_str(ole_lC,ole_lC_doc1idAttr)); end; //
end;
Application.ProcessMessages; end;
end;
//==========================
Здесь для перебора всех строк документа в цикле используются м< количествоСтрок и ПолучитьСтрокуПоНомеру. Все остальное акало! предыдущему примеру.
На рис. 4.148 представлен результат считывания информации из доку, с номером 1.
Г Документ: ентификатор документа:Г Документ: ентификатор документа:"I гТабличная часть документа—"I гТабличная часть документа—|nctp|■|nctp|■ill Метр]ФизЛицоill Метр]ФизЛицо| НоаоеСост| НоаоеСосте с объектам? 3SSSX8K3^-•Список реквизитов документа:1е с объектам? 3SSSX8K3^-•Список реквизитов документа:1■ Документ N 1I Дега: 28.06.2006' Время: 23:38:42| Позиция: #20060628 8512200002f Вид ИзгленениеСостоянияФизЛицч Представление вида: Изменение состоятКол-во строк =3ПроведенКомменгарий=3десь ■ комментарий’! ПририотетДокумента-Обычный■ Документ N 1I Дега: 28.06.2006' Время: 23:38:42| Позиция: #20060628 8512200002f Вид ИзгленениеСостоянияФизЛицч Представление вида: Изменение состоятКол-во строк =3ПроведенКомменгарий=3десь ■ комментарий’! ПририотетДокумента-ОбычныйИИ2323Аксакалов Аксакал Акса СотрудникОсновной Федоров Федор Федоры СотрудникНеосновт Криогенова Фекла Мари, ВременноНеРаботаАксакалов Аксакал Акса СотрудникОсновной Федоров Федор Федоры СотрудникНеосновт Криогенова Фекла Мари, ВременноНеРабота
Г Документ: ентификатор документа:
Г Документ: ентификатор документа:
"I гТабличная часть документа—
"I гТабличная часть документа—
|nctp|
■
|nctp|
■
ill Метр]ФизЛицо
ill Метр]ФизЛицо
| НоаоеСост
| НоаоеСост
е с объектам? 3SSSX8K3
^-•Список реквизитов документа:1
е с объектам? 3SSSX8K3
^-•Список реквизитов документа:1
■ Документ N 1
I Дега: 28.06.2006
' Время: 23:38:42
| Позиция: #20060628 8512200002
f Вид ИзгленениеСостоянияФизЛиц
ч Представление вида: Изменение состоят
Кол-во строк =3
Проведен
Комменгарий=3десь ■ комментарий
’! ПририотетДокумента-Обычный
■ Документ N 1
I Дега: 28.06.2006
' Время: 23:38:42
| Позиция: #20060628 8512200002
f Вид ИзгленениеСостоянияФизЛиц
ч Представление вида: Изменение состоят
Кол-во строк =3
Проведен
Комменгарий=3десь ■ комментарий
’! ПририотетДокумента-Обычный
И
И
2
3
2
3
Аксакалов Аксакал Акса СотрудникОсновной Федоров Федор Федоры СотрудникНеосновт Криогенова Фекла Мари, ВременноНеРабота
Аксакалов Аксакал Акса СотрудникОсновной Федоров Федор Федоры СотрудникНеосновт Криогенова Фекла Мари, ВременноНеРабота
Рис. 4.148. Результат считывания информациииз документа ИзменениеСостоянияФиэЛиц с номером 1
рДокумент: —рДокумент: —ентификатор документа:|И эменениеСостоянияФ изЛмете с-объектом • . /д.ентификатор документа:|И эменениеСостоянияФ изЛмете с-объектом • . /д.Список реквизитов документа:Документ N 2Дата: 12.07.2006Время 23:26:40Поэзия: #20060712 8440000003Вид: ИзменениеСостоянияФиэЛицПредставление Bt«a: Изменение состо:Кол-во строк=6ПроведенКомментарий=без комментариевПририотетДокумекга=ВысокийСписок реквизитов документа:Документ N 2Дата: 12.07.2006Время 23:26:40Поэзия: #20060712 8440000003Вид: ИзменениеСостоянияФиэЛицПредставление Bt«a: Изменение состо:Кол-во строк=6ПроведенКомментарий=без комментариевПририотетДокумекга=ВысокийЦ.23Ц.23i i- Т абличная часть документа-i i- Т абличная часть документа-ФизЛицоФизЛицо| НовоеСостояниеФ!| НовоеСостояниеФ!I'I'5656Иванов Иван Иванович Сотр|#1ник0сновной Аксакалов Аксакал Аксакале СотрудникОсновной Криогенова Фекла Маринаде ВременноНеРаботает Сидоров Сидор Сидорович СотрудникОсновной Петров Петр Петрович СотрудникОсновной Федоров Федор Федорович СотрудникОсновнойИванов Иван Иванович Сотр|#1ник0сновной Аксакалов Аксакал Аксакале СотрудникОсновной Криогенова Фекла Маринаде ВременноНеРаботает Сидоров Сидор Сидорович СотрудникОсновной Петров Петр Петрович СотрудникОсновной Федоров Федор Федорович СотрудникОсновной
рДокумент: —
рДокумент: —
ентификатор документа:
|И эменениеСостоянияФ изЛ
мете с-объектом • . /д.
ентификатор документа:
|И эменениеСостоянияФ изЛ
мете с-объектом • . /д.
Список реквизитов документа:
Документ N 2
Дата: 12.07.2006
Время 23:26:40
Поэзия: #20060712 8440000003
Вид: ИзменениеСостоянияФиэЛиц
Представление Bt«a: Изменение состо:
Кол-во строк=6
Проведен
Комментарий=без комментариев
ПририотетДокумекга=Высокий
Список реквизитов документа:
Документ N 2
Дата: 12.07.2006
Время 23:26:40
Поэзия: #20060712 8440000003
Вид: ИзменениеСостоянияФиэЛиц
Представление Bt«a: Изменение состо:
Кол-во строк=6
Проведен
Комментарий=без комментариев
ПририотетДокумекга=Высокий
Ц.
2
3
Ц.
2
3
i i- Т абличная часть документа-
i i- Т абличная часть документа-
ФизЛицо
ФизЛицо
| НовоеСостояниеФ!
| НовоеСостояниеФ!
I'
I'
5
6
5
6
Иванов Иван Иванович Сотр|#1ник0сновной Аксакалов Аксакал Аксакале СотрудникОсновной Криогенова Фекла Маринаде ВременноНеРаботает Сидоров Сидор Сидорович СотрудникОсновной Петров Петр Петрович СотрудникОсновной Федоров Федор Федорович СотрудникОсновной
Иванов Иван Иванович Сотр|#1ник0сновной Аксакалов Аксакал Аксакале СотрудникОсновной Криогенова Фекла Маринаде ВременноНеРаботает Сидоров Сидор Сидорович СотрудникОсновной Петров Петр Петрович СотрудникОсновной Федоров Федор Федорович СотрудникОсновной
Рис. 4.149. Результат считывания информациииз документа ИзменениеСостоянияФиэЛиц с номером 2
я 4 Доступ к информации 1С из внешних приложений Гравд^.
н0 сравнить этот результат с той информацией, которую мы внесли Документ в программе 1С:Предприятие (см. рис. 4.113).
пис. 4.149 представлен результат считывания информации из документа
На '
с номером 2.
Примечание -
На сопроводительном компакт-диске книги в папке \Part_1\Chapter_04\sp_1Cv7_ Viewer_via_OLE.PAS\05 есть пример, иллюстрирующий то, что мы здесь вкратце разобрали.
Примечание
Напомню, что представленные выше примеры исходных текстов — это упрощенная иллюстрация к рассматриваемым вопросам. Назначение этих примеров — дать представление о возможном подходе при решении задач информационного обмена с системой 1С:Предприятие. При работе с реальными базами 1С мДжет потребоваться их дальнейшая доработка.
Считывание информации из регистров
Регистры — это средство накопления сводной информации. Существуют два типа регистров:
регистр остатков — предназначен для ведения остатков "ресурсов" на момент времени с привязкой к набору "измерений" регистра;
оборотный регистр — предназначен для подсчета оборота "ресурсов" зазаданный интервал времени с привязкой к набору "измерений" регистра.
Тип регистра задается при настройке конфигурирации системы.
Ресурсы регистра— это информация, по которой ведется численный учет (например, количество детей, сумма выплат и т. д.).
Регистр можно представить в виде многомерного "куба": в таком представлении измерения регистра — это оси координат, на пересечении которых регистр хранит конкретные значения ресурсов.
'Ья дополнительной информации о движении и фильтрации по регистру используются реквизиты регистра.
Примечание
К регистрам нет непосредственного доступа через интерфейс пользователя системы 1С:Предприятие.
Примечание
Более подробную информацию о регистрах можно найти в специальной литературе по системе 1С:Предприятие.
6а» 1064
Сделаем очередные изменения в нашей учебной конфигурации. Для опроем дерево конфигурации и введем регистр УчетИзмененийСосто фшлиц (рис. 4.150).
ЗВВЗВягQ Журка £jЗВВЗВягQ Журка £j|Ноьь1Й Регистр|Ноьь1Й Регистр
ЗВВЗВяг
Q Журка £j
ЗВВЗВяг
Q Журка £j
|Ноьь1Й Регистр
|Ноьь1Й Регистр
Рис. 4.150. Новый регистр в конфигурации системы
Рис. 4.151. Диалоговое окно настройки регистраРис. 4.151. Диалоговое окно настройки регистра
Рис. 4.151. Диалоговое окно настройки регистра
Рис. 4.151. Диалоговое окно настройки регистра
В диалоговом окне настройки регистра (рис. 4.151) создадим структуру этого регистра.!
Измерения:
Фиэ.пИцО — Справочник. ФизЛица
Город — Справочник.ГородаСтранМираI
СоотояниеФиэЛица — Перечисление.СостояниеФизлица
Ресурсы:
Количеству — Число
^визиты:0 КслвоДетей^визиты:0 КслвоДетей— Число— Число-емейноеПоложение—-емейноеПоложение—Перечисление.СемейноеПоложениеПеречисление.СемейноеПоложение
^визиты:
0 КслвоДетей
^визиты:
0 КслвоДетей
— Число
— Число
-емейноеПоложение—
-емейноеПоложение—
Перечисление.СемейноеПоложение
Перечисление.СемейноеПоложение
в дереве конфигурации.в дереве конфигурации.g Пол — Перечисление. Пол
в дереве конфигурации.
в дереве конфигурации.
рис- 4.152 представлена структура регистра
i В S3 УчетИзмемемийСостоямияФизЛиц В Q Измерения
; 1-.*1 Физ Лицо | --«м Город
',। '--а СостояниеФизЛица
В й Ресурсы
i.—ё» Количество
В *- Реквизиты
КолвоДетей
СемейноеПолохенНе
— Пол
Рис. 4.152. Структура регистра в дереве конфигурации системы
Откроем окно настройки свойств документа ИзменениеСостоянияФизЛиц (см. рис. 4.107) и внесем изменения, как показано на рис. 4.153.
Г Ёууйлтерсги» учет .
Г Расчет
Рис. 4.153. Изменения в настройке документа вида ИзменениеСостоянияФизЛиц
>и изменения позволят при проведении документа делать движения по реестрам оперативного учета.Сделаем соответствующие изменения в модуле документа (листинг 4.47).>и изменения позволят при проведении документа делать движения по реестрам оперативного учета.Сделаем соответствующие изменения в модуле документа (листинг 4.47).процедура ОбработкаПроведения()^ Здесь программист должен написать программный код," Реализующий алгоритм проведения документов данного вида ^ратьСтроки () ;“ока Получить Строку () = 1 Циклпроцедура ОбработкаПроведения()^ Здесь программист должен написать программный код," Реализующий алгоритм проведения документов данного вида ^ратьСтроки () ;“ока Получить Строку () = 1 Цикл
>и изменения позволят при проведении документа делать движения по реестрам оперативного учета.
Сделаем соответствующие изменения в модуле документа (листинг 4.47).
>и изменения позволят при проведении документа делать движения по реестрам оперативного учета.
Сделаем соответствующие изменения в модуле документа (листинг 4.47).
процедура ОбработкаПроведения()
^ Здесь программист должен написать программный код,
" Реализующий алгоритм проведения документов данного вида ^ратьСтроки () ;
“ока Получить Строку () = 1 Цикл
процедура ОбработкаПроведения()
^ Здесь программист должен написать программный код,
" Реализующий алгоритм проведения документов данного вида ^ратьСтроки () ;
“ока Получить Строку () = 1 Цикл
160Часть /. 10 и механизм OLE Auton
СтарСостФазлица = * °;
Пол = "*;
Город = ";
СемейноеПоложение = "*;
Если ФизЛицо . Выбран () >0 тогда
СтарСост*излица=ФизЛицо. ПолучитьАтрибут Г Ч‘ СостояниеФизлица") . Получи^ ДатаДок);
КолвоДетей=ЧИСЛО (ФизЛицо. ПолучитьАтрибут (• * * " КолвоДетей *) . Получить ( ДатаДок));
Пол = ФизЛицо. Пол;
Город = ФизЛицо.ПолучитьАтрибут("* + *ГородПроживания"); СемейноеПоложение = ФизЛицо.СемейноеПоложение;
//===================
// Записать новые значения периодических реквизитов УстановитьРеквизитСправочника(
ФизЛицо, "СостояниеФизлица", НовоеСостояниеФизЛица, ДатаДок ),•
/ /=============== //===================
// Записать движения по регистру УчетИзмененийСостоянияФизЛиц И
// Расход по старому состоянию физ.лица
// Измерения
Регистр.УчетИзмененийСостоянияФизЛиц.ФизЛицо = ФизЛицо;
Регистр.УчетИзмененийСостоянияФизЛиц.Город = Город;
Регистр.УчетИзмененийСостоянияФизЛиц.СостояниеФизлица = СтарСостФиэлиц» // Реквизиты
Регистр.УчетИзмененийСостоянияФизЛиц.СемейноеПоложение = СемейноеПоложение;
Регистр.УчетИзмененийСостоянияФизЛиц.Пол = Пол;
Регистр.УчетИзмененийСостоянияФизЛиц.КолвоДетей = КолвоДетей;
// Ресурсы
Регистр.УчетИзмененийСостоянияФизЛиц.Количество = 1;
// Движение: Расход
Регистр.УчетИзмененийСостоянияФизЛиц.ДаижениеРасходВыполиить();
н// приход пон// приход по^ ^лоступ к информацииJCu? внешних приложений.
н
// приход по
н
// приход по
новому состоянию физ.лица
// Измерения
регистр.УчетИзмененийСостоянияФиэЛиц.ФизЛицо = ФизЛицо;
регистр.УчетИзмененийСостоянияФиэЛиц.Город = Город;
Регистр.УчетИзмененийСостоянияФиэЛиц.СостояниеФизЛица =
Ц Реквизиты
Регистр.УчетИзмененийСостоянияФиэЛиц.СемейноеПоложение =
СемейноеПоложение;
Регистр. УчетИзмененийСостоянияФиэЛиц. Пол = Пол,- регистр.УчетИзмененийСостоянияФизЛиц.КолвоДетей = КолвоДетей;
// Ресурсы
Регистр.УчетИзмененийСостоянияФиэЛиц.Количество = 1;
// Движение: Приход
Регистр.УчетИзмененийСостоянияФиэЛиц.ДвижениеПриходВыполнить
//
/ /===================
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Если сравнить текст листинга 4.47 с текстом листинга 4.23, то видно, что добавлены строки, обеспечивающие запись движений по регистру УчетИзмененийСостоянияФиэЛиц.
Здесь для каждой строки документа создаются две записи в регистре: расход и приход (соответственно, методы регистров движениеРасходВыполнить и ДвижениеПриходВыполнить). В данном случае расход производится по "старому" значению реквизита состояниеФиэлица справочника Физлица, а приход— по "новому" значению этого реквизита.
Примечание
Более подробно регистры и механизм проведения документов описаны в специальной литературе по системе 1С:Предприятие.
Теперь нужно сохранить изменения в конфигурации, запустить программу ^ Предприятие и перепровести все документы вида иэменениесостояния-
°ИзЛиц.
Чтобы посмотреть движения по регистру, нужно в списке документов^ брать нужный документ (в нашем случае документ N 1). вызвать вспл щее меню и выбрать пункт Движения документа (см. рис. 4.116). На э появится диалоговое окно для выбора вида движений, созданных да документом (рис. 4.154).
Документом
Если сравнить рис. 4.154 и 4.117. то видно, что появился новый вид движений ПО регистру УчетИэмененийСостоянияФизЛиц.
ФызЛ
'-«стоянка
-" ИСемейши- поло.
Рис. 4.155. Записи
по ос «Работает
На рис. 4.155 представлены все записи движения по этому регистру, созданные данным документом в результате его проведения.
ZlL™ меосмоенп!
I MW ПООСНС
^сдгаповАксака,|1Кил. !|аюекаловД|,гя,
^«та „е pwscg^ £°W« no кеосноено,
Яд^зь^гк (pi зеецема.
(Разошлась! ^Разошелся Ipdioumdcol [ЦНикогда „с состоял |к 1|Никогп1 ле состоял (не
(Файл 1Cv7.D™ рисТ^0Тражены в товаре дан.
T-lCSz
РЮ»
'Отчие! Indssed
10
K-PIkX0D P-SPS3 P-SPSS »»« spec
,».,„ ’’^
I»er*ce# y«eKD.«.wdlCocT.,-„ ^"••‘М/ОЦевт.Ыен,
,,иг IDeecr
'Period «.дне, • <»)♦мжЛицо I (P>Горох I <P> Соевое*,**,,! J <y>Kow4eco»o
''"•'^•“etbl Precision
10
lenelesUssbl,
'Oeser IPlPIOOTPpoP
10
10
10
Helds
lp«U0D.SPS3,SFSS.=p6<
IDBKe*
IP POP
Рис. 4.156. Регистр остатков УчетИэмененийСостоянияФизЛиц.Таблица RG52.DBF. Итоги по регистру с учетом измерений
Ге£>"
Г*£и “° 14ID»*-Г*£и “° 14ID»*-: Регистр (Де. > УчетИжмемемийСосеожммж^квЛмп|TypelVS/O| IDBTebleNa*e I PeUeable: Регистр (Де. > УчетИжмемемийСосеожммж^квЛмп|TypelVS/O| IDBTebleNa*e I PeUeableJH^JH^I регистр (Де. > УчетИжмежеэоАСос 1ЛI регистр (Де. > УчетИжмежеэоАСос 1ЛI BA52I BA52iDescr1 Type 1 Length 1 PrecisionIID Document'*ICIS10iLineSoIB1410lAcctcn Wo-IB1610llleg Debeb/KredltIS11IDI (P)*ияЛицоICIP101 (Р>ГоролIC19101 (P) СостоЯ7о« ♦ияЛхххаICIS10|{p)КоличествоIK11110I {p; КолеоДееейISк101 (p) Сем емкое Положение 1С1910I(9>ПолICIS10Descr1 Unique I IndexedfieldsiDescr1 Type 1 Length 1 PrecisionIID Document'*ICIS10iLineSoIB1410lAcctcn Wo-IB1610llleg Debeb/KredltIS11IDI (P)*ияЛицоICIP101 (Р>ГоролIC19101 (P) СостоЯ7о« ♦ияЛхххаICIS10|{p)КоличествоIK11110I {p; КолеоДееейISк101 (p) Сем емкое Положение 1С1910I(9>ПолICIS10Descr1 Unique I IndexedfieldsI IDDOC. L IB IWO . ACTWOI IDDOC. L IB IWO . ACTWO,ТРА ,.J«»0,ТРА ,.J«»0..-^‘^ pH» pH» pH** ,.5Н= V»» Г«П мш ..—In4ei«:..-^‘^ pH» pH» pH** ,.5Н= V»» Г«П мш ..—In4ei«:,тИ1 !«■' n>»octtimeio,тИ1 !«■' n>»octtimeioЦ-ВНаме I ID LIKIЦ-ВНаме I ID LIKI
Г*£и “° 14
ID»*-
Г*£и “° 14
ID»*-
: Регистр (Де. > УчетИжмемемийСосеожммж^квЛмп
|TypelVS/O| IDBTebleNa*e I PeUeable
: Регистр (Де. > УчетИжмемемийСосеожммж^квЛмп
|TypelVS/O| IDBTebleNa*e I PeUeable
JH^
JH^
I регистр (Де. > УчетИжмежеэоАСос 1Л
I регистр (Де. > УчетИжмежеэоАСос 1Л
I BA52
I BA52
iDescr
1 Type 1 Length 1 Precision
IID Document'*
IC
IS
10
iLineSo
IB
14
10
lAcctcn Wo
-IB
16
10
llleg Debeb/Kredlt
IS
11
ID
I (P)*ияЛицо
IC
IP
10
1 (Р>Горол
IC
19
10
1 (P) СостоЯ7о« ♦ияЛххха
IC
IS
10
|{p)Количество
IK
111
10
I {p; КолеоДееей
IS
к
10
1 (p) Сем емкое Положение 1С
19
10
I(9>Пол
IC
IS
10
Descr1 Unique I Indexed
fields
iDescr
1 Type 1 Length 1 Precision
IID Document'*
IC
IS
10
iLineSo
IB
14
10
lAcctcn Wo
-IB
16
10
llleg Debeb/Kredlt
IS
11
ID
I (P)*ияЛицо
IC
IP
10
1 (Р>Горол
IC
19
10
1 (P) СостоЯ7о« ♦ияЛххха
IC
IS
10
|{p)Количество
IK
111
10
I {p; КолеоДееей
IS
к
10
1 (p) Сем емкое Положение 1С
19
10
I(9>Пол
IC
IS
10
Descr1 Unique I Indexed
fields
I IDDOC. L IB IWO . ACTWO
I IDDOC. L IB IWO . ACTWO
,ТРА ,.J«»0
,ТРА ,.J«»0
..-^‘^ pH» pH» pH** ,.5Н= V»» Г«П мш ..—In4ei«:
..-^‘^ pH» pH» pH** ,.5Н= V»» Г«П мш ..—In4ei«:
,тИ1 !«■' n>»octtimeio
,тИ1 !«■' n>»octtimeio
Ц-ВНаме I ID LIKI
Ц-ВНаме I ID LIKI
Рис. 4.157. Регистр остатков УчетИзмененийСостоянияФизЯиц.
Таблица RA52.DBF. Движение по регистру с учетом измерений и реквизитов
Как видите, для каждого нового регистра остатков создаются две таблицы (два DBF-файла), одна таблица с префиксом RG, другая — с префиксом RA. Более подробно это рассматривается в части II.
Теперь рассмотрим способы считывания информации о регистрах и из регистров. Например, в листинге 4.48 представлен текст функции, позволяющей определить общее количество регистров в данной конфигурации.
tunction Get_CountOfRege(handleIC: OleVariant): integer;
// Получение количества регистров в конфигурации:
П handleic - ссылка на 1С,
И возвращаемое значение - количество регистров в конфигурации begin
Result:=0;
if not VarlsBnpty(handlelC) then begin
Result:=handlelC.Метаданные.Регистр*!;
end;
end.
Как видите, здесь тот же принцип, что и при определении количества Документов в конфигурации (см. разд. 4.2).
Так же. как в случае с другими агрегатными типами данных (рассмотрен ними ранее), информацию из регистра можно получить, обратившись к свои-
Часть I. 1С и механизм OLE Ли,
ствам и методам регистра (как объекта). Для этого нужно знать тификатор регистра. Прочитать список идентификаторов регистров, с вующих в конфигурации, можно следующим способом (листинг 4.49). К®^3=5@В-3 function Get_Reg«_to_Liet(handlelC: OleVariant; NrMode: integer;
ИИИИИИИИList: TStrings): integer;
И
И
И
И
И
И
И
И
Получение списка идентификаторов регистров в конфигурации: handle1С - ссылка на 1С,
NrMode — указывает тип регистров, которые нужно считывать в список:
//1 - только регистры остатков,
//2 - только оборотные регистры,
//0 - все регистры.
// List - здесь формируется список идентификаторов регистров.
//Переменная List должна быть создана в вызывающем модуле
// Возвращаемое значение: количество прочитанных регистров.
Sx: string;
OleBuf: OleVariant;
Yes: byte;
Whatlslt,
iReg,
CountReg: integer; // Количество регистров в кофигурации begin
Result:=0;
if ListoNIL then begin
List.Clear;
if not VarisEmpty(handlelC) then begin
// Определяем количество регистров в конфигурации
CountReg:=handlelC.Метаданные.Регистр-1;
Н Организуем цикл по количеству регистров
for iReg:=l to CountReg do
begin
Whatlslt:=0;
// Получаем ссылку на объект метаданных "регистр"
OleBuf:=handlelC.Метаданные.Регистр(iReg*1);
// Считываем тип регистра
if Sx=AnsiUpperCase('Остатки') then Whatlslt:=l;if sx=AnsiUpperCase('Обороты') then Whatlslt:=2;if Sx=AnsiUpperCase('Остатки') then Whatlslt:=l;if sx=AnsiUpperCase('Обороты') then Whatlslt:=2;4 Доступ к информации 1Сиз внешних приложений Sx:=AnsiUpperCase(Trim(01eBuf.ТипРегаотра));
if Sx=AnsiUpperCase('Остатки') then Whatlslt:=l;
if sx=AnsiUpperCase('Обороты') then Whatlslt:=2;
if Sx=AnsiUpperCase('Остатки') then Whatlslt:=l;
if sx=AnsiUpperCase('Обороты') then Whatlslt:=2;
// Проверяем, нужно ли добавить этот регистр в список Yes:=l;
if NrMode>0 then begin
Yes:=0;
if WhatIsIt=NrMode then Yes:=l;
end;
//
if Yes>0 then begin
// Считываем идентифкатор регистра Sx:=Trim(01eBuf.Идентификатор);
// Добавляем идентификатор в список List.ADD(Sx);
end;
end;
end;
Result:=List.Count;
end;
end;
Здесь все достаточно тривиально. Единственное, что следует отметить: метод Типрегистра (объекта Регистр метаданных) возвращает одно из строковых значений (в зависимости от типа регистра, указанного в конфигураторе):
3 "остатки - — если это регистр остатков;
□ "Обороты- — если это оборотный регистр.
На рис. 4.158 и 4.159 представлен результат использования функции Get_Regs_to_List.
Рис 4 158. Список идентификаторов регистров в "нашей" конфигурации
dK"dK"пор'пор'idRegListidRegListVarVarXXокок№^&4.5b,^—'”—№^&4.5b,^—'”—Получение количестваПолучение количестваhandlelc -handlelc -измерений регистра:измерений регистра:// //// //ссылка на 1с,ссылка на 1с,167167// И И и и и и// И И и и и и
dK"
dK"
пор'
пор'
idReg
List
idReg
List
Var
Var
X
X
ок
ок
№^&4.5b,^—'”—
№^&4.5b,^—'”—
Получение количества
Получение количества
handlelc -
handlelc -
измерений регистра:
измерений регистра:
// //
// //
ссылка на 1с,
ссылка на 1с,
167
167
// И И и и и и
// И И и и и и
Часть I. 1Си механизм Qi e Autn*
• Выбор регистра
[ Список регистров : '[Банк jЗаказы ЗаказыЗаяеки Заявки Касса КиигаЛ скупок книгаЛроааж ОстагкиТМЦ ПартийНалмчие ПартииОтланные ПоаотчетньеЛииа Покупатели 1 оставили Пппллиги
Рис. 4.159. Список идентификаторов регистров в реальной конфигурации Теперь рассмотрим функцию, позволяющую прочитать количество изме ! заданного регистра (листинг 4.50).
К =.™.__lelcl 01mrllnt ldR=g 5trlngl
idReg — идентификатор регистра.
И Возвращаемое значение: количество измерений, begin
Result:=0;
idReg: =Trim (idReg) ;
if length(idReg)>0 then begin
if not VarlsBnptyihandlelC) then begin
Result:=handlelC.Метаданные.Регистр(1*+idReg).Измерение*!; end;
end;
end;
фигурации Листинг448>Тр " ПР" определении количества регистров в ко«’ объектам) и™ ;, еНН0С р™"« «том. J. регистрам (к» нужно обращаться в контексте метаданных (как объекта
, 4 Доступ к информации 1С из внешних приложений —
,теМы 1С:Предприятие), а к измерению (как объекту) регистра нужно
ишаться в контексте регистра (как объекта).
Прочитать список идентификаторов измерений у заданного регистра можно .1еЯуюшим способом (листинг 4.51).
g^HrAS^^^заданногорегастр^^^
function Get_Mea*ureOfRega_to_Li«t (handlelc:OleVariant ;
idReg:string;List:TStrings): integer;
Получение списка идентификаторов измерений регистра: handlelC - ссыпка на 1С,
— идентификатор регистра,
— здесь формируется список идентификаторов
измерений регистра.
Переменная List должна быть создана в вызывающем модуле.
Возвращаемое значение: количество прочитанных измерений.
id: string;
OleBuf: OleVariant;
Yes: byte;
Count: integer;
begin
Result :=0;
if ListoNIL then begin
List.Clear;
idReg: =Trim (idReg) ;
if length(idReg)>0 then begin
if not VarlsEmpty(handlelC) then begin
// Определяем количество измерений в регистре
Count :=handlelC. Метаданные. Регистр (' '+idRegl Измерение"I;
// Организуем цикл по количеству измерений
for i:=l to Count do
begin
// Получаем ссылку на соответствующий объект метаданных OleBuf:=handlelc.Метаданные.Регистр('1+idReg).Измерение(i* 1); // Считываем идентификатор измерения id:=Trim(OleBuf-Идентификатор);
Часть I. 1С и механизм OLE Autoi 11 Добавляем идентификатор в список List.ADD(id);
end;
end;
end;
Result:=List.Count;
end;
end;
Как видите, и здесь принцип обращения к свойствам и методам объектов Измерение такой же, как и к другим объектам метаданных.Н
Точно таким же способом считывается информация по ресурсам и реквизитам регистров. Только слово "Измерение" заменяется словом "Ресурс" или "Реквизит" соответственно.
Примечание
Полный текст функций, решающих эти задачи, приведен в файле \sp_Utt sp_Lib_Delphi.PAS на сопроводительном компакт-диске книги.
На рис. 4.160 представлен результат использования этих функциий.
ИЗМЕРЕНИЯ :
ФизЛицо
Город
СостояниеФизЛица
РЕСУРСЫ:
Количество
КолвоДетей СемейноеЛоложемиеПол КолвоДетей СемейноеЛоложемиеПол РЕКВИЗИТЫ
КолвоДетей СемейноеЛоложемие
Пол
КолвоДетей СемейноеЛоложемие
Пол
в Pe™^^^Реквизитов
Теперь попробуем прочитать информационное содержание движений по ре*« истрам.■
вернемся к нашему Delphi-проекту sp_lCv7_Viewer_via_OLE.DPR.,
Примечаниея
Исходный текст проекта расположен на сопроводительном компакт-диске книг* . в папке \Part_1\Chapter_04\sp_1Cv7_Viewer_via_OLE.PAS\06.
Рис. 4.161. Доработка формы Delphi-проекта для работы с регистрами систмы 1С:Предприятие
Создадим новую вкладку Регистры и расположим на ней соответствующие компоненты (рис. 4.161).
Кнопка с вопросительным знаком (SB_Reg_Select) предназначена для вызова формы (Dlg_sel_Reg) выбора регистра из списка регистров (см. рис. 4.158). Текст функции, создающей список регистров, рассмотрен ранее. А метод Execute формы (где вызывается данная функция и производится выбор из списка реквизитов) тривиален, поэтому его исходный текст здесь не приводится. После того как регистр был выбран из списка, формируется (в свойстве компонента Memo_Reg. Lines) список идентификаторов измерений, ресурсов и реквизитов (рис. 4.160). Текст обработчика события "нажатие этой кнопки" представлен в листинге 4.52).
Кнопка с "бегущими человечками" (ss_Reg_Load_Move) предназначена для считывания движений по выбранному регистру. Этот вопрос требует более детального рассмотрения (см. далее).
3 Кнопка с символом суммы (sB_Reg_Load_sum) предназначена для считывания остатков по выбранному регистру. Этот вопрос также требует разъяснений и будет рассмотрен далее.
Procedure TForml.SBRegSelectClicklSender: TObject) ; Var
List: TStrings;
^ЙШЫ__
ки Часть I. 1Cu механизм OLE Aut iCol.iRow: integer; Sx: string; begin
// Вызываем форму выбора регистра из списка регистров if Dlg_Sel_Reg.Execute then begin
Memo_Reg.Lines.Clear;
SG_In£o_Reg_Clear;
// Идентификатор выбранного регистра Edit_RegID.Text:=Dlg_S«l_Reg.idReg;
List:= TStringList.Create; TRY
II
II Считываем список идентификаторов И измерений регистра
Memo_Reg.Lines.Add(•ИЗМЕРЕНИЯ:') ;
Get_MeaeureOfRage_to_List(ole_lC,Edit_RegID.Text,List);
Memo_Reg.Lines.AddStrings(List); for iCol:=0 to (List.Count-1) do begin
SG_Info_Jteg.ColCount:=SG_Info_Reg.ColCount+1;
SG_In£o_Reg.Cells[SG_Info_Reg.ColCount-l,0]:=List[iCol); end;
H
П
I/ Считываем список идентификаторов // ресурсов регистра
Memo_Reg.Lines.Add(' 1);
Memo_Reg.Lines.Add('РЕСУРСЫ:');
G*t_Re«OfR*ge_to^List(ole_lC,Edit_ReglD.Text,List);
Memo_Reg.Lines.AddStrings(List);
for iCol:=0 to (List.Count-1) do begin
SG_Info_Reg.ColCount:=SG_Info_Reg.ColCount+1;
SG_lnfo_Peg.Cells(SG_info_Reg.ColCount-l,0]:=List[iCol]; end;
//
H
II Считываем список идентификаторов
II реквизитов регистра
Memo_Reg.Lines.Add('');
Memo_Reg.Lines.Add(1 РЕКВИЗИТЫ: ') ;
Get_AttrOfRege_to_Llet(ole_lC,Edit_RegID.Text,List);
Memo_Reg.Lines.AddStrings(List);
for iCol:=0 to (List.Count-1) do
begin
SG_Info_Reg.ColCount:=SG_Info_Reg.ColCount+1;
SG_Info_Reg.Cells[SG_In£o_Reg.ColCount-l,0):=List(iCol); end;
H
SB_Reg_Load_Move.Enabled:=TRUE;
FINALLY
if ListoNIL then begin
List.Clear;
List.Free;
List:=NIL;
end;
END;
end;
end;
Поясним текст обработчика.
Сначала вызывается метод Execute формы Dlg_sei_Reg, где формируется список идентификаторов всех регистров и выбирается один из регистров.
Далее считывается идентификатор выбранного регистра:
Edi t_RegID.Text:=Dlg_8el_Reg.idReg;
Затем поочередно формируются списки:
идентификаторов измерений (Get_MeasureOfRegs_to_List);
идентификаторов ресурсов (Get_ResOfRegs_to_List);
идентификаторов реквизитов (Get_AttrOfRegs_to_List).
В процессе считывания информации из регистров часто требуется преобразо- вать значение агрегатного типа, возвращаемое методом получитьАтрибут (см. далее), в "привычные" значения типа string. Real, integer и т. д. Для этого нужно, прежде всего, определить тип и вид возвращаемого значения. Но чтобы определить тип и вид возвращаемого значения, нужно знать, что именно (измерение, ресурс или реквизит) идентифицирует переменная, передаваемая В качестве параметра методу ПолучитьАтрибут.
регистра:регистра:В листинге 4.53 приведен пример проверки существования в заданном ре стре измерения с заданным идентификатором.
регистра:
регистра:
цмррения в.заданном
function YenMeasureInReg_lC(handlelC: OleVariant; idReg, idMeasure: string): boolean;
" Проверка: существует ли заданное измерение у заданного
handlelC - ссылка на 1С,
////idRegidReg- идентификатор регистра.
//
//
idReg
idReg
// idMeasure — тестируемый идентификатор измерения.
Var
oleBuf: OleVariant;
begin
Result:=FALSE;
if not VarlsEmpty(handlelC) then begin idMeasure:=Trim(idMeasure);
idReg:=Trim(idReg);
if (length(idMeasure)>0) and (length(idReg)>0) then begin
II Получаем ссылку на заданное измерение
OleBuf:=handlelC.Метаданные.Регистр(1'+idReg).Измерение(1'+idMeasure);
II Проверяем корректность ссылки
if oleBuf.Выбраи>0 then begin
Result:=TRUE; // Такое измерение существует end;
end;
end;
end;
Текст функции YesMeasureinReg_ic достаточно прост и не требует поясне ний.
Точно так же проверяется существование ресурса и реквизита. Единственное различие в том, что вместо слова "Измерение" используется слово "Ресурс" ИЛИ "Реквизит" соответственно (тексты ЭТИХ функций — YesResInReg_lC и YesAttrinReg_ic — здесь не приводятся).
Геперь (как и в случае с документами, см. листинг 4.35) объединим все три функции в одну (YesRMAinReg_ic). Текст этой функции приведен в листинге 4.54).
^доь, 4. Доступ к информации 10 из внешних приложений
листинг 4.54. Проверка присутствия заданного идентификатора сред Дарений, рес№сов,ил^ реквизитов $^Щ^^ .^ccion YeBRMAInReg_lC(handlelC: OleVariant;idReg, idRMA: string): integer;
II // // //IIII // // //IIПроверка: присутствует ли идентификатор idRMA
II // // //
II
II // // //
II
Возвращаемое значение:Возвращаемое значение:среди измерений, ресурсов или реквизитов заданного регистра: handlelC - ссыпка на 1С, idReg - идентификатор регистра, idRMA — тестируемый идентификатор.
Возвращаемое значение:
Возвращаемое значение:
////////О -1 -2 -3 -О -1 -2 -3 -заданный идентификатор не корректен для данного регистра,
//
//
//
//
О -
1 -
2 -
3 -
О -
1 -
2 -
3 -
идентификатор присутствует среди измерений регистра, идентификатор присутствует среди ресурсов регистра, идентификатор присутствует среди реквизитов регистра.
begin
Result:=0;
// Проверка присутствия идентификатора среди измерений if YesMeasurelnReg_lC(handlelC,idReg,idRMA) then begin
Result:=1;
end
else begin
// Проверка присутствия идентификатора среди ресурсов if YeeReeInReg_lC(handlelC,idReg,idRMA) then begin
Result:=2;
end
else begin
И Проверка присутствия идентификатора среди реквизитов if Y«AttrInReg_lC(handlelC, idReg, idRMA) then begin
Result:=3;
end;
end;
end;
end;
Текст этой функции прост и не требует пояснений.
• | г n m ь. л п ।« г; ь
Полный текст этих функций приведен в файле \sp_Lib\sp_Ub_De1phLPAS на сопроводительном компакт-диске книги.
Теперь более подробно рассмотрим процесс считывания информации о жении по выбранному регистру.
Как и с другими объектами агрегатного типа (рассмотренными ранее), одЛ ла нужно получить ссылку на объект типа Регистр заданного вида: ole_lC_reg:=о!е_1С.GreateObject(1 Регистр.Здесь_Идентификатор_Регистра' I ' Затем нужно вызвать метод выбратьДвижения регистра, чтобы открыть: И борку по регистру:
// Выбрать все записи о движении
if о1е_1С_гед.ВыбратьДвижения>0 then begin
ИЛИ
// Выбрать записи о движении за период
if о1е_1С_гед.8ыбратъДвижения(''+sDatel,'’+sDate2)>0 then begin
Далее следует организовать цикл для считывания записей движения по регистру из выборки, используя метод ПолучитьДвижение:
while о1е_1С_гед.получитьДвижеиие>0 do
Внутри цикла, используя соответствующие методы и свойства объекта, надо прочитать информацию о движении из текущей записи.
Например, так можно определить, приход это или расход: if о1е_1С_гед.П}>иход*1>0 ehen begin
SG_Info_Reg.Cells[0,SG_Info_Reg.RowCount-1]:='+'; end
else begin
SG_Info_Reg.Cells[0,SG_Info_Reg.RowCount-1]:='-'; end;
А так — прочитать номер строки документа (создавшего эту запись движения^ SG_Info_Reg.Cells[4,SG_Info_Reg.RowCount-1]:=
Trim(ole_lC_reg.НомерСтроки);
Чтобы прочитать информацию о документе, создавшем эту запись, нужно получить ссылку на этот документ. Для этого используется свойство ТекущийДокумент:I
OleTekDoc:= ole_lc_reg.ТекущийДокумент;
После этого можно с помощью свойств и методов документа получить дополнительную информацию. Например, прочитать номер, дату и время документа-" SG_Info_Reg.Cells[1,SG_Info_Reg.RowCount-1]:=
■N '+Тгип(о1еТекОос.НамерДок);1
SG_Info_Reg.Cells[2,SG_Info_Reg.RowCount-1]:=Trim(oleTekDoc.ДатаДок);
SG_Inf o_Reg.Cells[3,SG_Info_Reg.RowCount-1]:=
Tr im (о1eTekDoc.ПолучитьВремя);
Получить значения измерений, ресурсов и реквизитов из текущей записи мо*но так:
.1#Buf: = о1е_1С_гед.ПолучитъАтрибут(' *+ldRMA) ;
^деСЬ idRMA — идентфикатор измерения, ресурса или реквизита.
ПРИМЕЧАНИЕ
Метод ПолучитьАтрибут возвращает не само значение (в виде строки или числа), а ссылку на объект (типа oieVariant). Чтобы можно было оперировать ■привычными* в Delphi значениями, нужно конвертировать полученное значение в тип string, Real или Integer. Этот вопрос детально рассматривался ранее.
Применительно к регистрам можно отметить следующие отличия:
|. Сначала нужно определить, что именно идентифицирует переменная idRMA (измерение, ресурс или реквизит). Для этого можно использовать функцию, текст которой приведен в листинге 4.54):
// Определим, что именно идентифицирует переменная idRMA:
// измерение, ресурс или реквизит?
Kr:=YeeRMAInReg_lC(handlelC,Trim(ole_lC_reg.Вид).idRMA);
Получить ссылку на этот регистр (как объект метаданных): oleBufl:^handlelC.Метаданные.Регистр(''+Тг1т(о1в_1С_гед.Вид))
Определить тип и вид полученного значения:
if Nr = 1 then begin
sType:=Trim(oleBufl.Измерение!''+idRMA).Тип);
sKind:=Trim(oleBufl.Измерение!1'+idRMA).Вид);
end;
if Nr = 2 then begin
sType:=Trim(oleBufl.Ресурс(‘'+idRMA).Тип);
sKind:=Trim(oleBufl.Ресурс(1 '+idRMA) .Вид) ;
end;
if Nr = 3 then begin
sType:=Trim(oleBuf1.Реквизит(‘'+idRMA).Тип);
sKind:=Trim(oleBuf1.Реквизит(''+idRMA).Вид);
Наконец, в зависимости от значений переменных sType и sKind нужно привести прочитанное значение oleBuf к типу string, integer, real и т. п. Этот момент был рассмотрен в предыдущих разделах.
Примечание
Текст функции Get_ValueRMA_from_Reg_str, решающей эту задачу. прД| ден в файле \sp_Lib\sp_Lib_Delphi.PAS на сопроводительном компакт-ди« книги.
Текст обработчика события "нажатие кнопки Прочитать движения регистру (sB_Reg_Load_Move)" приведен в листинге 4.55.
procedure TForml.SB_Reg_LoadJ*av*Cllck(Sender: TObject);
Var
oleBuf,
oleTekDoc, // Ссылка на текущий документ
ole_lC_reg: OleVariant; // Ссыпка на регистр
iRow,iCol: integer;
idRMA, // Идентификатор измерения,ресурса или реквизита
Sx: string;
begin
if not VarIsEmpty(ole_lC) then begin
// Получаем ссылку на выбранный регистр
ole_lC_reg:=ole_lC.CreeteObject('Регистр.1+Trim(Edit_ReglD.Text));
if not VarlsEnpty(ole_lC_reg) then begin
// Открываем выборку движения no регистру
// if 01е_1С_гед.ВыбратьДви*еиия('01.01.2003','03.01.2003')>0 then begin I
if о1е_1С_гед.ВыбратьДвижекия>0 then begin
SB_Reg_Load_Move.Enabled:=FALSE;
GroupBox_Reg.Caption: = 'Движение по регистру: ' + Trim(Edit_RegID.Text); ’
II Организуем цикл получения записей из выборки
iRow:=0;
while о1е_1С_гед.ПолучитьДвижение>0 do
begin
iRow:=iRow+l;
if iRow>l then begin
SG_Inf o_Reg. Recount: =SG_Inf o_Reg. RowCount*! ;
end;
II
II Считываем тип движения (приход или расход)
if о1е_1С_гед.Пре<ход'1>0 then begin
SG_Info_Reg.CelIs[0,SG_Info_Reg.RowCount-1):=’+';
end
else begin
SG_Info_Reg.Cells[0,SG_Info_Reg.RowCount-1] end;
// r—
^/^олучаем ссыпку на текущий документ
oleTekDoc := о1е_1С_гед.ТекущийДокумент;
g3_infоЛед.CeliaU.SG_In£o_Seg.^(oleTekDoc .Н«*рДоЮ
* Trim(oleTekDoc.Вид);
SG_Info_Reg.Cells [2, SG_Info_Reg.RowCount-1]: = Trim!oleTekDoc. ДатаДок) ;
SG_Info_Reg. Cells [3,SG_Info_Reg.RowCount-1]: =
Tr im (oleTekDoc. ПолучитъВреия) ;
"'^o^
//
// Считываем значения всех измерений, ресурсов и реквизитов
И текущей записи
for iCol:=5 to (SG„Info_Reg.ColCount-l) do
begin
// Считываем идентификатор из заголовка колонки таблицы idRMA;=SG_Info_Reg.Cells[iCol,0] ;
U Считываем значение для idRMA
Sx: =Get__ValueRHA_f год_Квд_асг (ole_lC, ole_lC_reg, idRMA) ;
II Записываем значение в ту же колонку, где idRMA
// но в с"троку, соответствующую текущей записи движения регистра SG_Info._Reg.Cells (iCol, SG_Info_Reg. RowCount-1) : =Sx;
end;
Application. ProcessMessages;
end;
end;
end;
end;
end;
Приведенный текст обработчика события содержит исчерпывающий к<( ментарий. Единственное, что следует отметить: считывание значения из1 рения (ресурса или реквизита)
OleBuf:= ole_lC_reg.ПолучитьАтрибут('*+idRMK);
производится внутри функции Get_ValueRMA_from_Reg_scr.
На рис. 4.162 приведен результат считывания движения по регистру Учет мененийСостоянияФизЛиц из "нашей" (учебной) конфигурации.
b^™«'»’> ™ регистру: УчетИэм^емийСостояимяФизЛ^ f*Л |Т«*иийДоиум*{Дагв [время 1Нст1Ф4ЫЪ^~
N 1 Из
Т-—--^^ЕЕ^З^^^^Ок^^Септейноеп
28.06 2006 2 338:42 1Аксакалов < Киев Сотрцднм^Неоа 1
N 1 ИэменемиеСс 28.06 2006 23.3842 1
N 1 ИэменемиеСс 28.06 2006 2338:42 2
N1 ИэменемиеСс 28.06 2006 23 3842 2
N 1 ИэменемиеСс 28.06.2006 23:38.42 3
N 1 ИэменемиеСс 28.06 2006 23.3842 3
Аксакалов / Киев СспруднжОсно11
Федоров Ф Киев ВременмоНеРу 1
Федоров Ф Киев СотрданикНеоа 1
Криогемсеа Гоме/ Сатр^дмикОснос 1
Криогемсва Гоме/ВреметоНеРа.‘1
3
3
2
2
Разведен Разведем Разошелся Разошелся
5
5
1
НикогдаНеСосЖ*
НикогдаНеСосЖея
Рис. 4.162. Движение по регистру УчетИзмененийСостоянияФизЛиц
На рис. 4.163 приведен результат считывания движения по регистру парт наличие из реальной конфигурации 1С:Предприятие.
Движем* по регистру ■ П«еп*^м~*
1е>уип«щ<*уммг
|Л"«|Вр-Н^уЧмОП|Ном«л^[с;^„и||Сол^с1Д^ Г<«ММ1М1>Па' °' 06^'’^nunoBowHKKa M.CbWi 64.58 87183I
1VJJUUQUQ2 riocryinet^eДспРу 01 01 06 QQ • 0
0X0000121 ПолуплемкТМЦ 01 01 06 01 11
«80000075 ПеоемсщмеТМЦ 01 01 КОТИ
1 «80000075 Перв«еш***ГМи I *00000076 Перемме^-ТМО 0000030076 Перелей, ениеТМО 0000000709 ПеремвшеннГМи 00(8000709 ПвремешенеТми 0000000826 ПосемешемеГМЦ 0008000626 ПврвиешевеТМЦ
01 01 060121 0101 0601 41 01 01 06 01 41 0101 06:01.(1 01010601*1 0101 06 02(1 Old 0602(2
0*0 Ч Гевау Питоеожке « М.Съеье ОАО ЧГабауПилаиетернал М.Слеье ОАО '1 Б** Ст в» ясом М.Сжсеа ОАО 'I Гвбд, Ста» листов» М.Све* ОАО Ч Бурм Ут»«еи<те» I М_Си« ОАО Ч Габоу Ытяжешта» t М.Сшрва
039414 88
7286 207651
72652 5
32845 73
173042 5
99 9» 2412030 41 2014110 01
99.94 162
162
ОАО Ч Бери/(уавииы ваги М_Слоиодо«о 20
ОАО Ч Шаба Рукаеады ваш М .Спеиме» 20
ОАО 1 Лам Бабе» терем М.Смм120
ОАО Ч Лам Ввод лабе»* М.Слеве2
2412030 41 2014110 01 232991 2 194076 232831 2 ,194076
3*/»аИ** ДслсжелеВН
•, . .'-в ~ee-»W4>4* Пер» ЯШ ем
898.26
896 26-
34214 4
129688
74569
74563
29512
10624
Перемешена
Перемеше*
ВесдИ-веие
Рис. 4.163. Движение по регистру ПартииНаличиеиз реальной конфигурации 1 С:Предприятие
-читывание информации с использованием механизма OLE Automation—- есь.ма .медленный процесс. Крайне рекомендуется при программировании читывать это и предоставлять пользователю возможность считывать ин- юрмацию в ограниченном объеме (например, за некоторый период или олько то, что привязано к какому-то документу).
g данном случае (см. рис. 4.163) из регистра считывалась не вся информация
0 движении:
if о1е_1С_гед.ВибратьДвихения>0 then begin а только за небольшой временной период: if о1е_1С_гед.ВыбратъДвижения('01.01.2003','03.01.2003')>0 then begin Иначе пришлось бы ожидать окончания процесса несколько часов...
Как уже говорилось, регистр остатков предназначен для ведения остатков ресурсов. То есть из регистра можно получить информацию не только о движении, но и об остатках ресурсов как в целом, так и в разрезе измерений.
Здесь следует отметить, что программирование считывания остатков (посредством механизма OLE Automation), в отличие от считывания движения, существенно затруднено по той причине, что обращение к методам остаток и сводныйОстаток регистра описанным в документации способом не приводит к ожидаемому результату. Достаточно корректным и оптимальным выходом из этой ситуации может быть использование комбинированного способа считывания остатков из регистра. Суть его сводится к тому, что в глобальном модуле конфигурации штатными средствами системы 1С:Предприятие создаются соответствующие функции (с ключевым словом "Экспорт"), реализующие алгоритмы получения остатков по регистру. А во внешнем приложении эти функции вызываются (посредством OLE Automtion) с помощью метода EvaiExpr. Таким образом, функция глобального модуля конфигурации корректно производит всю обработку информации. А внешнее приложение получает результат, возвращаемый этой функцией.
Рассмотрим этот способ на конкретном примере. Для этого вновь внесем изменения в конфигурацию, введя:
два новых перечисления (рис. 4.164);
новый регистр остатков учетВыплатФизЛицам (рис. 4.165);
новый документ выплатыФизЛицам (рис. 4.166).
а Й СпособВ ыплатыФ из Л щам ■ ЧерезКассу н ЧерезБанк
■ ПоПочте
3 й ВиаВыппатФизЛщами Зарплата
■ Аванс
■ Премия
■ МатПомощь
Рис. 4.164. Новые перечисления.
■обслуживающие" регистр УчетВыплатФизЛицам
Е И УчетВыплатФизЛицам
В Q Измеренияы Горойёа Физ Лицо— и ВидВыплат
В й Ресурсы
• м СуммаНачислено да СуммаУдержано «а СуммаВыплачено Е ■- Реквизиты
■ СпособВ Ы1 латы
Рис. 4.165. Новый регистр УчетВыплатФизЛицам
ЕЗ Й ВыплатыФиэЛицам|
S И ШапкаЬ |
-1 Город
В ЕЗ Табличная часть■ |
_i ФизЛицоw
। СуммаНачисленоI
1 СуммаУдержано
1 СуммаВыплачено|
!- _j ВидВыплат■
г Способа оплаты|
Рис. 4.166. Новый документ,|
"обслуживающий" регистр УчетВыплатФизЛицам
В документе ВыплатыФиэЛицам установим признак оперативного учета (флажок Оперативный учет на рис. 4.153). Создадим форму документа, как уже делали это (см. рис. 4.108 и 4.109). И изменим соответствующим образом । текст процедуры проведения документа (листинг 4.56).
'™НГ4-б6-ПроЦедура ОбрабтхаЛрожедения документов вида
[ЛаТМФичПкгтам .Ь- и^-й'< . .*• 1'’*
/ / Обработка проведения документов вида "ВыплатыФизЛицам Процедура ОбработкаПроведения()
Если Город.Выбран()>0 Тогда
ВыбратьСтроки();
Пока ПолучитьСтроку() = 1 Цикл
ПривяэыватьСтроку(НомерСтроки);
Если ФизЛицо.Выбран()>0 тогда
//
// Приход по старому состоянию физ.лица
// Измерения
Регистр.УчетВыплатФизЛицам.ФизЛицо = ФизЛицо;
Регистр.УчетВыплатФизЛицам.Город = Город;
Регистр.УчетВыплатФизЛицам.ВидВыплат = ВидВыплат;
И Реквизиты
Регистр.УчетВыплатФизЛицам.СпособВыплаты = СпособВыплаты;
И Ресурсы
Регистр.УчетВыплатФизЛицам.СуммаНачислено = СуммаНачислено;
Регистр.УчетВыплатФизЛицам.СуммаУдержаяо =.СуммаУдержано;
Регистр.УчетВыплатФизЛицам.СуммаВыплачено = СумыаВыплачено;
// Движение: Приход
Регистр.УчетВыплатФизЛицам.ДвижениеПриходВыполнить();
//
Иначе
Сообщить("ФизЛицо не указано");
КонецЕсли;
КонецЦикла;
Иначе
Сообщить(‘Город не указан’);
КонецЕсли;
КонецПроцедуры
Как видите, в рамках этого документа будут создаваться только записи типа Приход по регистру УчетВыплатФизЛицам. Это связано с тем, что для нас (в данный момент) неважно, насколько правильным будет такой подход С точки зрения бухучета. Для нас важна корректность с точки зрения темы этой книги (програмимирование информационного обмена с системой 1С:Предприятие). Поэтому достаточно будет только "прихода .
Откроем глобальный модуль конфигурации (рис. 4.167).
И в глобальном модуле напишем функцию, которая выбирает остаток по регистру УчетВыплатФизЛицам с фильтром по физическому лицу (листинг 4.57).
Mi .
;* Конфигуратор - Задача
1 Файл ; Действия Конфигурация Конструкторы
.Q@ 5-'?ый.'■тенны1ns
-0 Удалить олеиеитDel
. j Нс ^ Редактировать элемент
ЕЙ .^ ГесеитьCtrl-f-X
®^Запомнить'Ctrl-iC
[Глобальный модуль
Рис. 4.167. Чтобы открыть глобальный модуль, нужно сначала открыть конфигурацию,а затем выбрать соответствующий пункт меню
Г”"ттгту-з®"-тг'™ч1”!"Г"''=?^3"'Я”Ч'чгоетгт'-№№"»:^-ЧГЭДМ s Листинг 4.57. Функция глобального модуля, возвращающая остаток ресурсам ; СуммаВыплачено регистра УчетВыплатФизЛицам ' <С:Я
// Получение суммы выплат по физ.лицу из регистра "УчетВыплатФизЛицам". // Функция предназначена для вызова из внешних приложений (и не только) Функция гл9_ПсшучитьСуммуВыплат_для_ФизЛица(КодФизЛица) Экспорт
Сумма = 0; // Переменная, значение которой вернет эта функция.
// Поскольку в функцию передается код физ.лица, // а для фильтрации нужен элемент справочника, // мы должны найти этот элемент в справочнике “ФизЛица".
СпрФизЛиц = СоздатьОб-ьект("Справочник.ФизЛица");
Если СпрФизЛиц.НайтиПоКоду(""+СокрЛП(КодФизЛица),0)> 0 Тогда
// Получаем ссылку на свойство "ТекущийЭлемент"
// справочника "ФизЛица"
ФизЛицо = СпрФизЛиц.ТекущийЭлемент!);
// Получаем ссылку на регистр
Per = Регистр.УчетВыплатФизЛицам;
II Указываем идентификатор ресурса, по которому
11 будем получать остаток•
idRes = "СуммаВыплачено";
II Получаем остаток по ресурсу "СуммаВыплачено"
// в разрезе измерения "ФизЛицо"
Сумма = Per.СводныйОстаток(,ФизЛицо,,""+idRes);
И
II Эти строки — только для отладки и иллюстрации.
^aj- Доступ к информации 10 из внешних приложений //Их нужно закомментировать.
ТекстПредпр = "Сумма выплат для *
+• СокрЛП(ФизЛицо.Наименование)
+ СокрЛП(Сумма);
Предупреждение(ТекстПредпр);
//
Иначе
Предупреждение("ФизЛицо с кодом="+СокрЛП(КодФизЛица)+" не найдено");
КонецЕсли;
// Возвращен значение остатка
Возврат Сумма;
КонецФункции
Здесь требуются некотрые пояснения. Дело в том, что если пользоваться только штатными средствами 1С, то вместо кода Физлица можно было бы передать значение агрегатного типа (ссылка на элемент справочника Физлица). Но в случае доступа из внешних приложений такая возможность отсутствует. Поэтому в функцию передается код элемента справочника.
Здесь, в строке
Сумма = Per. СводныйОстаток (, ФизЛицо, , " " +idRes) ;
перед значением физлицо оставлено "пустое место" перед запятой. Это не ошибка. Дело в том, что когда мы создавали регистр УчетВыплатФизлицам, первым измерением был город (см. рис. 4.165). В данном случае нас интересует остаток ресурса в разрезе измерения ФизЛицо (которое следует вторым в списке). Синтаксис встроенного языка программирования системы •С:Предприятие допускает такое обращение.
Примечание
Более подробно назначение используемых в функции гл9_ПолучитьСуммуВыплат_ для_ФизЛица свойств и методов описано в специальной литературе по системе 1С:Предприятие.
Аналогично нужно написать функции, возвращающие значения остатков по Другим измерениям регистра УчетВыплатФизлицам (здесь тексты этих функций не приводятся).
Сохраним изменения в конфигурации, запустим программу 1 С:Предприятие и затем создадим и проведем три документа вида выплатыФизЛицам (рис. 4.168—4.170).
НомерДом f
1
^аДок. |l 4.07.06
Город:
IC
Д^аДа [isozoe Q
Рис. 4.169. Второй новый документ
300
Город:(Одесса
100
200
ФмзЛнио
■"ваное Иван Иванов
внове Фжла >.
Слое
ПоПочте
ПсЛочг.
930у ЗарПлета
23|МатПомошь 1л,г 2971Ппем„а
ыплат
991Аванг
^еЛМагПомошь
вида ВыплатыФиэЛица
СуемаН «числено} с,,
WI
(НомерДок; f ~
Рис. 4.168. Первый новый документ нИп= о
кумент вида ВыллатыФизЛицам
щи
3
Физ Л
Петров Петр Петр
Рис. 4.170. Третий новый документ
Q Комм*тгарий;1 *
Го₽°“ Барановичи
рейс... вг
IUOC
300
=5255111 Способе
99011 Аванс
ПоПочте
Лвгва* (НобоГ Q
297ЦПремия
вида ВыллатыФизЛицам
L |ТекищийДо*
^'Выплата 14 07 2006 |2ао. ,
*<1 Выплету 14.07 2006 1200 2
Н2Выплеты<Ри15 07 2006 11:53 1
жжение по регистру: Очет^ыплятФизЛииам ~~~~■-
Дата^^Врёч^Нс^гёраУфйэОтаЗ^^
29 06 2006 1 2 26:1 Бареж Петрос Г Цане1000’"
N 3 ВыплзтыФр 29 06 2006 1 2.26 2 Барах КриогежГммия N 1 Выплат^®-’'"”""•
Во-гогАксамл,^^
«тт,^; .“Z^'^-
1000
10
990
ЧереаКассу
300
3
297
ПоПочте
1000
10
390
ПоПочте
.30
1
.29
ПоПочте
300
3
297
ЧарезБ®*
100
1
99
ПоПочте
200
2
198
ПоПочте
'Д^СуммаВ ып| СлссобВт
Рис. 4.171. Движение по регистру УчетВыплатФизЛицам.
Закроем программу 1С:Предприятие. Запустим наш проект на выполнение и прочитаем движение по регистру УчетВыплатФизЛицам. Результат представлен на рис. 4.171.
Здесь — ничего нового (получили то, чт> и должно было быть).
,еПерь посмотрим, каким образом мы можем получить остатки ресурсов ре- истра УчетВыплатФиэЛииам по любому физическому лицу с использованием азработаННЫХ ранее функций (гл9_ПолучитьСуммуВыплат_для_ФизЛица и дру- ГИХ. аналогичных).
в 1истинге4.58 приведен текст обработчика события "нажатие кнопки с СИМВОЛОМ суммы (SB_Reg_Load_Sum) ".
I»'I»'Листинг 4.58. Обработчик события "нажатие кнопки с символом суммы (вв^ед^ьоасувит)-- .^^лд^^к^^
I»'
I»'
procedure TForml.SpeedButtoalClick(Sender: TObject);
Var
oleBuf: OleVariant;
sCode,
Sx: string;
begin
if not VarlsEmpty(ole_lC) then begin
sCode:='5';
// Укажем код элемента справочника ФизЛица, для которого
//мы желаем получить информацию
if InputQuery('Получить сумму выплат','для сотрудника с кодом',«Code) then begin
sCode:=Trim (sCode);
if length(sCode)>0 then begin
// Получим остаток по ресурсу "СуммаВыплачено"
Sx: =' гл9_ПолучитьСуммуВыплат_для_*изЛица ( ' г«Codeг' ) ';
oleBuf:=ole_lC.EvalKxpr(''+Sx);
ShowMessage('Выплаты для ФизЛица с кодом '+sCode+'='
♦ Trim(oleBuf));
// Получим остаток по ресурсу "СуммаНачислемо"
Sx: ='глЭПолучитьСуммуНачислении _дляФизЛица(1♦«Coder') '; oleBuf:=ole_lC.EvalKxpr(''*Sx);
ShovMessage('Начисления для ФизЛица с кодом '+sCode+’=' +Trim(oleBuf));
// Получим остаток по ресурсу "СуммаУдержаяо"
Sx: = ’гл9 ПолучитьСуммуУдержаний_для_ФизЛица(1 г«Coda*1) '; oleBuf:=ole_lC.lvalExpr(''+Sx);
ShowMessage(1 Удержания для ФизЛица с кодом '+sCode+' = '
end;
end;
end;
end;
♦TrimtoleBuf));♦TrimtoleBuf));Как мне кажется, комментарии здесь требуются только для фун] EvaiExpr, но ее мы подробно рассмотрим чуть позже.У ”
♦TrimtoleBuf));
♦TrimtoleBuf));
лагающеелагающеедля сотраоника с кодомдля сотраоника с кодомОК |ОК |[Получить сумму выплат[Получить сумму выплатРис. 4.172. Запрос на ввод кода физического лицаРис. 4.172. Запрос на ввод кода физического лицаЗапустим проект на выполнение. Создадим соединение с 1С:ПредприяЖ и нажмем кнопку с символом суммы. На экране появится окно запроса, пред. паго^м.;2 ввести код физического лица, для которого нужно получить ост», ки (рис. 4.172).
лагающее
лагающее
для сотраоника с кодом
для сотраоника с кодом
ОК |
ОК |
[Получить сумму выплат
[Получить сумму выплат
Рис. 4.172. Запрос на ввод кода физического лица
Рис. 4.172. Запрос на ввод кода физического лица
После ввода кода на экране появится соответствующее сообщение (рис. 4.173). Это — результат работы функции гл9_ПолучитьСуммуВыплат_для_ФизЛица.
хх1С Предприятие
х
х
4> Сунна выплат для Аксакалов Аксакал Аксакалоеич-1019
:_ФизЛииа:_ФизЛииаРис. 4.173. Результат работы функции гл9_ПолучитьСуМмуВыплат_для.
:_ФизЛииа
:_ФизЛииа
Примечание
остаезы^еышш^ ^КЭК сервера 0LE Automation) по умолчанию жет бы" скпыт л2. °ЗТ°МУ диалоговое окно, показанное на рис 4.173 мо- момент на комль^теоеразличных приложений, запущенных в данный использовать ™!Р 3 °М СЛучае для "поиска' Диалогового окна можно Фам2а ТВИШ <А,1~<ТаЬ> На рис. 4.50 показана пикто- поверх остальных*окон° 8Ь'браТЬ ДЛЯ того- чтобы Диалоговое окно появилось
Г* 1 sneedButtonlClick. 1?с^- р
lev7 viewer„via.ole
Выплаты для ФиЩица с кодом 5=1019
РИС. 4.174. Это сообщение выведено инструкцией ShowMessageобработчика TForml. speedButtonlClick
Таким образом, будут поочередно показаны остатки по всем ресурсам регистра УчетВыплатФизЛицам.
Примечание
Исходные тексты проекта, где реализованы вопросы считывания информации из регистров, находятся в палке \Part_1\Chapter_04\sp_1Cv7_Viewer_via_OLE.PAS\06 на сопроводительном компакт-диске книги.
Примечание
Представленные примеры исходных текстов — это упрощенная иллюстрация к рассматриваемым вопросам. Назначение этих примеров — дать представление о возможном подходе при решении задач информационного обмена с системой 1С:Предприятие. При работе с реальными базами 10 может потребоваться их дальнейшая доработка.
Доступ к информационной структуре базы данных 1С
Доступ к информационной структуре с использованием механизма OLE Automation
В процессе разработки программного обеспечения для обмена информацией с любым "чужим" программным продуктом (информационная структура которого может гибко и достаточно часто меняться) программист, как правило, стре- мится в максимальной степени уйти от жестких привязок (в исходных текстах) к конкретной (текущей) реализации "чужой" информационной структуры.
^ данном случае, применительно к системе 1С:Предприятие. мы имеем такую же ситуацию. В процессе производственной эксплуатации информаци-
онная структура базы данных системы 1С:Предприятие может периодичеок и существенно изменяться.я
В этом разделе будут рассмотрены различные аспекты процесса считывав информационной структуры с использованием механизма OLE Automation Частично, по ходу изложения, эти вопросы были рассмотрены в предыдуД разделах. Здесь мы попытаемся разработать некое более универсальное сред ство для считывания информационной структуры базы данных систем 1С:Предприятие.
Запустим Delphi и создадим новый проекте именем sp_LoadStruclure_lC.DpR (или любым другим по желанию).
Примечание
Исходные тексты этого примера есть на CD в папке \Part_1\Chapter_04\Topic 4 * sp_LoadStructure_1 C.PAS.
□□□□□□Функционально наш проект должен "уметь":
□
□
□
□
□
□
обеспечивать соединение с системой 1С:Предприятие (сервер OLE Automation); считывать информационную структуру базы данных открытой конфигурации системы в том объеме, какой требуется пользователю;
сохранять прочитанную структуру в текстовом файле для того, чтобы потом можно было работать с этой информацией без соединения с 1С.
На рис. 4.175 представлен вид формы проекта. Ее основные компоненты кратко описаны в табл. 4.7.
Таблица 4.7. Назначение основных компонентов в форме проекта sp_LoadStructure_ 1C.DPR
Компонент
Тип
Описание
Liscwhat
TCheckListBox
Расположен в правой части формы, содержит список типов метаданных, информация о которых будет считываться
ListStr
TTreeView
Расположен в центре формы, предназначен для размещения полученной информации о • структуре базы данных системы 1С:Предприятие в виде дерева___,
SpeedButton2
TSpeedButton
Кнопка Структура; при ее нажатии происходит соединение с программой 1С:Предприятие как сервером OLE Automation
SpeedButton6
TSpeedButton
Кнопка §], предназначена для экспорта информационной структуры в специфичный формат (в виде INI-файла). Этот файл понадобится нам в части IIJ
33'^Струтяра! ^Г ^'^Струтяра! ^Г ^ОХОХJ Справочники ■' Свойства2 Реквизиты Документы3 СвойстваJ НаОснованииП Шатка□ ТаблЧасть □ Константы5 СвойстваГЗ Регистры г? Свойства [_; Измерения П Ресурсы П Реквизиты 'J ПеречисленияЗначенияJ Справочники ■' Свойства2 Реквизиты Документы3 СвойстваJ НаОснованииП Шатка□ ТаблЧасть □ Константы5 СвойстваГЗ Регистры г? Свойства [_; Измерения П Ресурсы П Реквизиты 'J ПеречисленияЗначения
3
3
'^Струтяра! ^Г ^
'^Струтяра! ^Г ^
ОХ
ОХ
J Справочники ■' Свойства
2 Реквизиты Документы
3 Свойства
J НаОсновании
П Шатка
□ ТаблЧасть □ Константы
5 Свойства
ГЗ Регистры г? Свойства [_; Измерения П Ресурсы П Реквизиты 'J Перечисления
Значения
J Справочники ■' Свойства
2 Реквизиты Документы
3 Свойства
J НаОсновании
П Шатка
□ ТаблЧасть □ Константы
5 Свойства
ГЗ Регистры г? Свойства [_; Измерения П Ресурсы П Реквизиты 'J Перечисления
Значения
Базы Данный 1С
Настройка на 1C:'Iy77 Appicaton “ Стром инициал -l^EMC_e*ampla^B
■ ■■ ■|есть соединенна с ,с|есть соединенна с ,сИмя1С[мксар*рач*^^-—
■ ■
■ ■
|есть соединенна с ,с
|есть соединенна с ,с
РИС. 4.175. форма проекта sp_LoadStructure_lC.DPR
Вся функциональность по считыванию информационной структуры сосредоточена в обработчике события "нажатие кнопки Структура (speedButton2)". Текст обработчика представлен в листинге 4.59.
4 59 Mp.6»S собьни. -««=«« ккопхи Структур.
procedure TForml.SpeedButtcn2Cllck(Sender: TObject);
// Считывание информационной структуры системы 1С:Предприятие
Var
CountCcmmcnRekvDoc, iRekv: integer;
Sx: string;
UstBuf: TStrings;
°le_lc_App:=UnAssigned;
°i*_lC_J4pp:-ConnectTolC(Edit_LCinit .Text); // Соединяемся с 1С if not VarlsEmpty(О1е_1С_Лрр) then begin
’1» 1064
ListBuf:=TStringList.Create;
TRY
ListStr.Items.Clear;
H
// Считываем общую информацию о конфигурации
ListBuf.Add('ОбщаяИнформация [1+DateTimeToStr(NOW)*']•);
Sx:=Trim(01е_1С_Арр.Метаданные.Идентификатор);
ListBuf.Add(#9+'Идентификатор='+Sx);
Sx:=Tr im (О1е_1С_Арр.Метаданные.ПолныйИдентификатор);
ListBuf.Add(#9+1ПолныйИдентификатор='+Sx);
Sx:=Trim(01е_1С^Арр.Метаданные.Синоним);
ListBuf.Add(#9+'Синоним='+5х);
Sx:=Trim(01е_1С_Арр.Метаданные.Комментарий);
ListBuf.Add(#9+'KoMMeHTapM&='+Sx) ;
Sx:=Trim(01е_1С_Арр.Метаданные.Пароль);
ListBuf.Add(#9+'Пароль='+5х);
Sx:=Trim(01е_1С_Арр.Метаданные. АвторКороткаяИнформациз*);
ListBuf.Add(#9+'АвторКороткаяИнформация=1+Sx);
Sx:=Tr im (01е_1С_Арр.Метаданные.Язык);
ListBuf.Add(#9+*Язык='+Sx);
Sx:=Trim(О1е_1С_Арр.Метаданные.Округление);
ListBuf.Add(#9+'Округление='+Sx);
Sx:=Trim(01е_1С_Арр.Метаданные.НепосредствеяноеУдалекиеОб'ъектов);
ListBuf.Add(#9+'НепосредственноеУдаление06ъектов='+Sx);
И
//
// Считываем общие реквизиты документов
Application.ProcessMessages;
CountCcranonRekvDoc: =01е_1С_Арр. Метаданные. ОбшийРеквизитДокумента ;
Sx:=IntToStr(CountConmonRekvDoc);
ListBuf.Add(#9+1ОбщийРеквизитДокумента='+Sx);
if CountConinonRekvDooO then begin
for iRekv:=l to CountConmonRekvDoc do begin
Sx:=Trim(01e_lC_App.Метаданные.ОбшийРеквизитДокумента(iRekv).Идентификатор) •
ListBuf.Add(#9+#9+Sx) ;
Sx:=Trim(01e_lC^App.Метаданные.ОбшийРеквизитДокумента(iRekv).Синоним); ListBuf.Add(#9+#9+#9+1Синоним='+Sx);
Sx:=Trim(Ole_lC_App.Метаданные.ОбщийРеквизитДокумента(iRekv).Тип);
ListBuf.Add!#9+#9+#9+'Тип='+Sx);
Sx:=Trim(Ole_lC_App.Метаданные.ОбщийРеквизитДокумента(iRekv).Вид);
ListBuf.Add(#9+#9+#9+'Вид='+Sx);
У;Trim(Ole_lC_App.Метаданные.ОбщийРеквизитДокумента(iRekv) .Длина) ;
ListBuf.Ас1а(#9+#9+#9+'Длина='+5х);
У =rrim(01.e_lC_App.Метаданные.ОбщийРеквизитДокумента (iRekv) .Точность) ;
ListBuf.Add(#9+#9*#9+1Точность='+Sx);
g,,. дгип(О1е_1С_Арр. Метаданные. ОбимйРеквизитДокдоента (iRekv) .НеОхриддтелыай) ;
ListBuf.Add(#9+#9+#9+1НеОтрицательный=1+Sx);
Sx;=Trim(Ole_lC_J^p.Метаданные.ОбщийРеквизитДокумента(iRekv). РаздалятьТриада) ;
ListBuf.Add(#9+#9+#9+'РазделятьТриады='+Sx);
Sx:=Trim(Ole_lC_App.Метаданные.ОбщийРеквизитДокумента(iRekv).Комментарий)
ListBuf .Add(#9+#9+#9+ 1 Коко4ентарий=1 +Sx) ;
Application.ProcessMessages;
end;
end;
//
//
// Считываем константы
if ListWhat.Checked[8] then begin Application.ProcessMessages;
GetStructConstante(ListBuf);
end;
//
//
// Считываем перечисления
if ListWhat.Checked[15] then begin
Application.ProcessMessages;
QetStructEnumlListBuf);
end;
//
Ц
// Считываем справочники
if ListWhat.Checked[0] then begin
Application.ProcessMessages;
QetStructRoference(ListBuf);
end;
И
И
// Считываем документы
Application.ProcessMessages;
if ListWhat.Checked(3] then begin
Applicat ion.ProcessMessages;
GetStructDocumente(ListBuf);
end;
//
//
И Считываем регистры
Application.ProcessMessages;
if ListWhat.Checked[10] then begin
Application.ProcessMessages;
GetStructRegietera(ListBuf);
end;
//
//
// Сохраняем информацию на диска
ListBuf.SaveToFile(MainDir+nf„ListStr);
И
//.
// Загружаем информацию с диска
Lis tStr. LoadFrcxnFil e (MainDir+nf _ListStr);
//
FINALLY
if ListBufoNIL then begin
ListBuf.Clear;
ListBuf.Free,■
ListBuf:=NIL;
end;
END;
//
// Открываем дерево конфигурации
L i s t S tr. Pul 1 Expand ;
ListStr.Selected:=ListStr.Iterns[ 0 ];
ListStr.SetFocus;
^unAseigned. // Разрываем соединение с 1С
| роясним текст обработчика (листинг 4.59).
Здесь следует отметить следующее. Вся информация, что будет прочитана, умещается в переменной Listauf (типа Tstrings) в текстовом формате. Это сделано для того, чтобы эту информацию можно было сохранить в текстовом файле на диске и загружать (в компонент Liststr) по мере необходимости. без подключения к 1С. Символы табуляции (#9) в строки добавлены с целью обеспечить иерархическую структуру (в виде дерева) при загрузке текстового файла в компонент Liststr.
Сначала считываются общие свойства конфигурации (в данном случае мы считываем далеко не все свойства из имеющихся), затем общие реквизиты документов и их свойства. Далее, в зависимости от того, что именно было отмечено флажком в списке Listwhat, считываем другие объекты метаданных и их свойства (функции GetStructConstants, GetStructEnum, GetStrucrReterence, GetStructDocuments, GetStructRegisters).
После считывания информация сохраняется в текстовом файле:
ListBuf . SaveToFile (MainDir+nf_ListStr) ;
А затем информация из текстового файла загружается в компонент Liststr:
Liststr .LoadFrcxnFlle(MainDir+nf_ListStr) ;
Соединение с 1С разрывается. Вот, собственно, и все.
Примечание
Способы считывания идентификаторов справочников и их реквизитов подробно рассматривались в предыдущих разделах. Поэтому здесь будут представлены только те вопросы, которых мы еще не касались.
^"^^—ент функции, считывающей свойства справочки иного вида ' ' - / -^"^^—ент функции, считывающей свойства справочки иного вида ' ' - / -function TForml.GetStructReference(Lines: TStrings): integer beginResult:=0;function TForml.GetStructReference(Lines: TStrings): integer beginResult:=0;Так же. как и ранее, всю информацию получаем, обращаясь к свойствам и методам объекта метаданные системы 1С:Предприятие. В листинге 4.60 представлен фрагмент функции, считывающей основные свойства справочников заданного вида.
^"^^—ент функции, считывающей свойства справочки иного вида ' ' - / -
^"^^—ент функции, считывающей свойства справочки иного вида ' ' - / -
function TForml.GetStructReference(Lines: TStrings): integer begin
Result:=0;
function TForml.GetStructReference(Lines: TStrings): integer begin
Result:=0;
// Получаем ссыпку на объект типа "Справочник* метаданных //по его порядковому номеру
OleO:=О1е_1С_Арр.Метаданные.Справочник(iRef*1);
H
// Читаем свойства справочника
Sx:=Trim(01eO.Идентификатор);
Sx: =Trim(OleO.СинонимI;
Sx:=Tr im (OleO.ОсновноеПредставлеиие);
Sx:=Tr im(OleO.КонтрольУникалъности);
Sx:=Trim(01eO.СерииКодов);
Sx:=Trim(01eO.АвтоНумерация);
5х:=Тгып(О1е0.КоличествоУровмей);
Sx:=Trim(01eO.ГруппыВпереди);
Sx:=Trim(OleO.СпособРедактирования);
SX:=Trim(OleO.ЕдинаяФормаЭлемента);
Sx: =Trim (OleO. Комментарий) ;
//
//
// Читаем свойства кода элементов справочника
5х:=Тгйп(01еО.ТипКода);
5х:=Тг1т(01еО.ДлинаКода);
Sx:=Tr im(OleO.СерииКодов);
И
Ц
// Читаем свойства наименования элементов справочника Sx: =Tr im (OleO. ДлинаНаименования) ;
И
end;
В листинге 4.61 представлен фрагмент функции, считывающей основные свойства реквизитов справочника.
Листинг 4.61. Фрагмент функции, считывающей свойства реквизитов справе
function TForml.GetStructReference(Lines: TStrings): integer; begin
Result:=0;
^д 4. Доступ к информации 1С из внешних приложений
/ Получаем ссылку на объект типа "Реквизит* справочников
., заданного вида по его порядковому номеру
giel:=О1е_1С_Лрр.Метаданные.Справочник(iRef*1).Реквизит(iAttr
//
I/ Читаем свойства реквизита справочника gczTrimtOlel.Идентификатор);
^.sTrim(01el.Синоним);
5х:=Тгип(01е1.Вид) ;
Sx;=Trim( Olel. Тип) ;
Sx:=Trim(Olel.Длина) ;
Sx: =Trim(01el.Точность);
Sx: =Trim(Olel.Периодический);
Sx: =Triin(01el. Сортировка) ;
Sx:=Trim(Olel .Отбор);
Sx:=Trim (Olel.Использование);
Sx: =Tr im(01e1.ИзненяетсяДокумеятами);
Sx:=Trim(01el.РучноеИзменение);
Sx:=Trim(Olel .Неотрицательный) ;
Sx: =Tr im (01 e 1.РазделятьТриады);
Sx:=Trira(01el .Ксмнеитарий);
end;end;И
end;
end;
,Лункции. считывающей основные
В листинге 4.62 представлен фрагмент фу свойства документов заданного ви
Листинг 4.62. Фрагмент функции, считывающей свойства документов ,- ^амноговида-л'
Eunction TForml.GetStructDocwnents(Lines: TStrings): integer;
begin
"Документ" метаданных"Документ" метаданныхResult:=0;
"Документ" метаданных
"Документ" метаданных
// Получаем ссылку на объект типа
// по его порядковому номеру
OleO:=01е_1С_Арр.Метаданные.Документ(iDoc*l);
sDoc:=Trim(OleO.Идентификатор);
sDoc:=Trim(OleO.Синоним);
196 Часть I. 1С и механизм OLE Auton^k 1 sDoc:=Trim(OleO.Комментарий);
sDoc:=Tr im (OleO.ОперативныйУчет);a
SDoc:=Trim(OleO.ПериодичностьНонера);
sDoc:=Trim(OleO.ДлинаНомера);,
sDoc:=Trim(01eO.ТипНомера);
sDoc:=Tr im (OleO.Автонумерация);
sDoc:=Tr im(OleO.КонтрольУникальности);
sDoc:=Trim(01eC.БухгалтерскийУчет);
sDoc:=Trim(OleO.Расчет);
зОос:=Тг1т(01еО.Со8даватъОперацию);
sDoc:=Trim(01eO.АвтонумерацияСтрок);
sDoc:=Trim(01eO.АвтоудалениеДвижений);
sDoc:=Trim(01eO.РедактированиеОпераций);
sDoc:=Trim(OleO.РаэрешитьЛроведение);
sDoc:=Trim(OleC.ОснованиеДляЛюбогоДокумекта);
end;
В листинге 4.63 представлен фрагмент функции, считывающей список доку* ментов, вводимых на основании документов заданного вида.
-;....,
^Листинг 4.63. Фрагмент функции, считывающей список документов, вводимых»
function TForml.GetStructDocumanta(Lines: TStrings): integer;
begin
Result:=0;
// Получаем ссыпку на объект типа "Документ" метаданных по его номеру • OleO:=О1е_1С_Арр.Метаданные.Документ(iDoc*1);
Ц
// Считываем документы, вводимые на основании
CountAttr:=О1е0.ВводимыеНаОсновакииДокументы.Количество;
if CountAttr>0 then begin
for iAttr:= 1 to CountAttr do
begin
sDoc:=О1е0.ВводимыеНаОсновакииДокументы.Получить(iAttr).Идентификатор,
л доступ к uhiл доступ к uhi.мянии /С из внешн^припож^.мянии /С из внешн^припож^Получить(iAttr).Представление;Получить(iAttr).Представление;. . ;01еО. ВводимыеНаОснованииДокументы. Application.ProcessMessages;
л доступ к uhi
л доступ к uhi
.мянии /С из внешн^припож^
.мянии /С из внешн^припож^
Получить(iAttr).Представление;
Получить(iAttr).Представление;
end;
//-
end;end;В листинге 4.64 представлен фрагмент функции, считывающей свойства реквизитов "шапки" документов заданного вида Листинг 4.64. Фрагмент функции, считывающей свойства реквизитов =шап eMeH™^.^a-H”°".e^a-....i:^ function TFonnl.QetStruotDocuments(Lines: TStrings): integer;
end;
end;
begin
по его номерупо его номеруResult:=0;
по его номеру
по его номеру
01вО:=01е_1С^-Метадан^^
//
// Считываем свойства реквизитов "шапки" документа sDoc:=Trim(OleO.РеквиаитШапки(iAttr).Идентификатор); sDoc:=Trim(01eO.РеквизитШапки(iAttr).Тип);
sDoc: =Triin(OleO.РеквизитШапки(iAttr) .Вид) ;
sDoc:=Trim(OleO.РеквизитШапки(iAttr).Длина);
sDoc:=Trim(OleO.РеквизитШапки(iAttr;.Точность); sDoc:=Trim(OleO.РеквизитШапки(iAttr).Неотрицательный);
SDoc:=Trim(01eO.РеквизитШапки(iAttr).РазделитьТриады);
И
end;
Точно так же считываются свойства ^КВИЗ™УДб™у^ ^рашатьи к ме- Только вместо метода РеквизитШапки (ЛИСТИНУ
ТОду РеквизитТабличнойЧасти.
В листинге 4.65 представлен фрагмент функции, считмеаклией осно.ные
свойства регистров.
НКЦИИ| счить'вающей свойства регистра
function TForml.GetStructR^leter.(Lines: TStrings): integer; begin
Result:=0;
// Получаем ссылку на объект типа "Регистр- метаданных по его номеру OleO:=01е_1С_Арр.Метаданные.Регистр(iC*l)•
//
U Считываем основные свойства регистров Sx:=Trim{01еО.Синоним);
Sx:=Trim(Ole0.ТипРегистра);
Sx:=Tr im(OleO.БыстраяОбработкаДвижений);
Sx: =Tr im (OleO. МиграцияЗапрещана) ;
Sx:=Tr im (OleO.Комментарий);
//
end;
В листинге 4.66 представлен фрагмент функции, считывающей основные свойства измерения регистра.
^**№2^**№2r:-” -- -, ................. .——_,— _B^S*£”®5н°йства измерения регистr:-” -- -, ................. .——_,— _B^S*£”®5н°йства измерения регистfunction TForml.GetStructRegietere(Lines: TStrings): integer- begin'
^**№2
^**№2
r:-” -- -, ................. .——_,— _
B^S*£”®5н°йства измерения регист
r:-” -- -, ................. .——_,— _
B^S*£”®5н°йства измерения регист
Result:=0;
II Получаем ссылку на объект типа "Регистр" метаданных по его номеру OleO:=01е_1С_Арр.Метаданные.Регистр(iC*1);
И
// Считываем свойства измерения регистра по его номеру
Sx:=Trim(OleO.Измерение(iA*l).Идентификатор);
Sx:=Trim(01eO.Измерение(iA*l).Синоним);
Sx:=Trim(01eO.Измерение(iA*l).Тип);
8х:=Тгцп(01еО.Измерение(1А*1).Вид);
5х:=Тгип(О1е0.Иэмерение(1А*1).Длина);
=Tr im(OleO.Измерение(iA'l) .Точность) ; У'
. -Trim(OleO.Измерение(iA*1).Неотрицательный);
^^TrimfOleO.HaMepeHneliA*!) .РаэделятьТриады) ;
-Trim (OleO .Измерение (1А*1) .ОтборДвижений) ;
^.zTrimlOleO.HBMepeHMetiA*!) .ОтборИтогов) ;
у.=Trim(01eO.Измерение (iA*l) .Комментарий) ;
и
end;
g листинге 4.67 представлен фрагмент функции, считывающей основные свойства ресурса регистра.
«■рягст?|&яЕ»ужяиа1^^
['Листинг 4.67. Фрагмент функции, считывающей свойства ресурса регистра j
function TForml.GetStructRegiater»(Lines: TStrings): integer;
begin
Result :=0;
И Получаем ссылку на объект типа "Регистр" метаданных по его номеру
OleO: =О1е_1С_Арр.Метаданные.Регистр(iC*l);
//
И Считываем свойства ресурса регистра по его номеру
Sx:=Trim(01eO ,Pecypc(iA*l) .Идентификатор) ;
Sx :=Trim (OleO. Ресурс (iA*l).Синоним);
Sx :=Trim(OleO.Ресурс(iA*l).Тип);
Sx:=Trim(Ole0.Ресурс(iA*l).Вид);
Sx:=Trim(oleO.Pecypc(iA*l).Длина);
Sx: =Trim(OleO.Ресурс(iA*l).Точность);
Sx: =Trim(OleO.Ресурс(iA*1).Неотрицательный);
Sx:=Trim(Ole0.Pecypc(iA*l).РазделятьТриады);
Sx: =Trim(01eO.Ресурс(iA*l).Комментарий);
//
End;
n
° листинге 4.68 представлен фрагмент функции, считывающей основные
Свойства реквизита регистра.
function TForml.GetStructRegi.fr.(Lines: TStrings): integer- begin3 '
Result:=0;
II Получаем ссылку на объект типа "Регистр" метаданных по его номеру 01*0:=01е_1С_Ар₽•Метаданные.Регистр(iC*l);
И
И Считываем свойства реквизита регистра
Sx:=Trim(OleO.Реквизит(iA*1).Идентификатор);
Sx:=Trim (OleO.Реквизит(iA*l).Синоним);
Sx:=Trim(OleO.Реквизит(iA*l).Тип);
Sx:=Trim(OleO.Реквизит(iA*l).Вид);
Sx:=Trim(OleO.Реквизит(iA*l).Длина);
Sx:=Trim(01eO.PeKBH3HT(iA*l).Точность);
Sx:=Trim(OleO.Реквизит(iA*l).Неотрицательный); 8х:=Тгмп(01еО.Реквизит(1А*1).РазделятьТриады); Sx:=Trim(OleO.Реквизит(iA*l).Сортировка);
Sx:=Trim(OleO.Реквизит(iA*l).Комментарий);
//
end;
считывающей основныесчитывающей основныеВ листинге 4.69 представлен фрагмент функции свойства константы.
считывающей основные
считывающей основные
»№»№:нт функции, считывающей свойства константы:нт функции, считывающей свойства константы
»№
»№
:нт функции, считывающей свойства константы
:нт функции, считывающей свойства константы
function TForml.GetStructCcnatante(Lines: TStrings): integer- begin
Result:=0;
// Получаем ссылку на объект типа "Константа" метаданных по его номеру OleO:=01е_1С_Лрр.Метаданные.Константа(iConst*1);
,/ считываем свойства константы
^.=TrIm(OleO.Идентификатор) ;
S^.zTrimtOleO.Синоним) ;
у. =Trim(Ole0.Периодический) ;
-X^Trim (OleO .Тип) ;
^^TrimtOleO .Вид) ;
gx;=Trim(Ole0.Длина) ;
Sx:=Trim(Ole0.Точность) ;
gx:=Trim( OleO. Неотрицательный) ;
Sx: =Trim (OleO . Раз делить Триады) ;
Sx:=Trim(01eO .Область Распространения);
Sx: =Tr im (OleO.Комментарий);
,,
end;
В листинге 4.70 представлен фрагмент функции, считывающей информационную структуру перечислений. Этот тип агрегатных данных нужно рассмотреть более детально.
Во-первых, здесь есть некоторые нюансы, которых не было в рассмотренных ранее объектах. Во-вторых, в части II нам предстоит обращаться к базе данных, минуя программу ЮПредприятие. Как отмечалось в разд. 4.1.1, перечисления хранятся в файле 1Cv7.MD, информацию из которого нельзя считать какими-либо стандартными способами. А в таблицах базы данных (в данном случае в DBF-файлах) значения перечислений представлены внутренними (системными) идентификаторами, алгоритм генерации которых не Документирован. Эти идентификаторы являются, мягко говоря, "загадочными” (см. рис. 4.11).
В этом разделе мы рассмотрим возможность создания соответствий между штатными" идентификаторами значений перечислений (листинг 4.70) и системными идентификаторами этих же значений.
function QetStructEnum (Lines: TStrings): integer; begin
Result:=0;
пеРечисленийпеРечисленийв конфигурациив конфигурацииII Определяем количество перечислений CountEnum: =О1е_1С_7фр .Метаданные. Пере' if CountEnum>0 then begin// Организуем цикл с перебором всех iEnum:=0;while iEnum<CountEnum do beginiEnum:=iEnum+l;II Определяем количество перечислений CountEnum: =О1е_1С_7фр .Метаданные. Пере' if CountEnum>0 then begin// Организуем цикл с перебором всех iEnum:=0;while iEnum<CountEnum do beginiEnum:=iEnum+l;Ч-22^1^механизмЧ-22^1^механизм203203в 4. Доступ к информации 1С из внешних приложений
пеРечислений
пеРечислений
в конфигурации
в конфигурации
II Определяем количество перечислений CountEnum: =О1е_1С_7фр .Метаданные. Пере' if CountEnum>0 then begin
// Организуем цикл с перебором всех iEnum:=0;
while iEnum<CountEnum do begin
iEnum:=iEnum+l;
II Определяем количество перечислений CountEnum: =О1е_1С_7фр .Метаданные. Пере' if CountEnum>0 then begin
// Организуем цикл с перебором всех iEnum:=0;
while iEnum<CountEnum do begin
iEnum:=iEnum+l;
Ч-22^1^механизм
Ч-22^1^механизм
203
203
11 Получаем ссылку на объект типа "Регистр" метаданных // по его порядковому номеру в конфигурацииOleO:=О1е_1С_Лрр.Метаданные.Перечисление(iEnum*1);// Считываем идентифкатор перечисленияidEnum:=Trim(Ole0.Идентификатор);И11 Получаем ссылку на объект типа "Регистр" метаданных // по его порядковому номеру в конфигурацииOleO:=О1е_1С_Лрр.Метаданные.Перечисление(iEnum*1);// Считываем идентифкатор перечисленияidEnum:=Trim(Ole0.Идентификатор);ИИII Получаем ссылку на заданное идентифкаторомII перечисление как объект,II принадлежащий глобальному контексту конфигурацииOlel:=О1е_1С„Арр.Перечисление.ПолучитьД’’"-—-—■•'+idEnum) ;//ИII Получаем ссылку на заданное идентифкаторомII перечисление как объект,II принадлежащий глобальному контексту конфигурацииOlel:=О1е_1С„Арр.Перечисление.ПолучитьД’’"-—-—■•'+idEnum) ;//////// Теперь вычисляем количество значений данного перечисления, //обращаясь к его соответсвующим методамCountVal:= Olel.КоличествоЗначений*1;И// Теперь вычисляем количество значений данного перечисления, //обращаясь к его соответсвующим методамCountVal:= Olel.КоличествоЗначений*1;И// Организуем никл для перебора всех значений перечисления for iVal:=l to CountVal dobeginl! Теперь можно использовать методы конкретного значения // как объекта и прочитать его "штатный" идентификатор idVa1:=Trim(Olel.ЗначениеПоНомеру(iVal*1).Идентификатор);end;//end;// Организуем никл для перебора всех значений перечисления for iVal:=l to CountVal dobeginl! Теперь можно использовать методы конкретного значения // как объекта и прочитать его "штатный" идентификатор idVa1:=Trim(Olel.ЗначениеПоНомеру(iVal*1).Идентификатор);end;//end;^сним текст функции GetstructEnum (листинг 4.70). Здесь следует отме- ь что система 1С:Предприятие позволяет, с одной стороны, обратиться Перечислению как объекту метаданных, а с другой стороны — как к объек- 1 г-1обального контекста задачи. То есть среди свойств объекта Метаданные устемы ЮПредприятияесть объект типа Перечисление. Поэтому мы можем щучить как количество всех перечислений, так и полный список их центификаторов (как мы делали это со справочниками, документами, цистрами).
11 Получаем ссылку на объект типа "Регистр" метаданных // по его порядковому номеру в конфигурации
OleO:=О1е_1С_Лрр.Метаданные.Перечисление(iEnum*1);
// Считываем идентифкатор перечисления
idEnum:=Trim(Ole0.Идентификатор);
И
11 Получаем ссылку на объект типа "Регистр" метаданных // по его порядковому номеру в конфигурации
OleO:=О1е_1С_Лрр.Метаданные.Перечисление(iEnum*1);
// Считываем идентифкатор перечисления
idEnum:=Trim(Ole0.Идентификатор);
И
И
II Получаем ссылку на заданное идентифкатором
II перечисление как объект,
II принадлежащий глобальному контексту конфигурации
Olel:=О1е_1С„Арр.Перечисление.ПолучитьД’’"-—-—■•'+idEnum) ;
//
И
II Получаем ссылку на заданное идентифкатором
II перечисление как объект,
II принадлежащий глобальному контексту конфигурации
Olel:=О1е_1С„Арр.Перечисление.ПолучитьД’’"-—-—■•'+idEnum) ;
//
//
//
// Теперь вычисляем количество значений данного перечисления, //обращаясь к его соответсвующим методам
CountVal:= Olel.КоличествоЗначений*1;
И
// Теперь вычисляем количество значений данного перечисления, //обращаясь к его соответсвующим методам
CountVal:= Olel.КоличествоЗначений*1;
И
// Организуем никл для перебора всех значений перечисления for iVal:=l to CountVal do
begin
l! Теперь можно использовать методы конкретного значения // как объекта и прочитать его "штатный" идентификатор idVa1:=Trim(Olel.ЗначениеПоНомеру(iVal*1).Идентификатор);
end;
//
end;
// Организуем никл для перебора всех значений перечисления for iVal:=l to CountVal do
begin
l! Теперь можно использовать методы конкретного значения // как объекта и прочитать его "штатный" идентификатор idVa1:=Trim(Olel.ЗначениеПоНомеру(iVal*1).Идентификатор);
end;
//
end;
цо объект Перечисление является также частью глобального контекста рограммы 1 С:Предприятие. И в этом качестве этот объект имеет метод по- учитьАтрибут, позволяющий получить доступ К объекту Перечисление кон- ретного вида ПО его идентификатору. Объект Перечисление конкретного мда обладает такими свойствами, как перечень значений (каждое из которых аюке является объектом) И методами КоличествоЗначений, ЗначениеПоНомеру И ЗначениеПоИдентификётору.
У каждого значения перечисления (как объекта) есть собственные методы Зил, ПредставлениеВида. Выбран, Порядковый Номер, Идентификатор.
В строке
01е0:=О1е_1С_Арр.Метаданные.Перечисление(IJEnum*!) ;
| листинга 4.70 мы получаем ссылку на объект метаданных типа Перечисление по его порядковому номеру в конфигурации.
Затем, используя соответствующий метод объекта, получаем его идентификатор:
idBium: = Trim (OleO. Идентификатор) ;
Далее обращаемся к объекту Перечисление глобального контекста конфигурации по идентификатору и получаем ссылку на перечисление конкретного вида:
Olel: =О1е_1С_Арр. Перечисление. ПолучитьАтрибут ( 1 ' +idEnum) ;
Теперь мы можем использовать методы перечисления (как объекта) для того, чтобы получить список идентификаторов его значений. Сначала получим количество значений перечисления:
CountVal: = Olel.КоличествоЗначений"1;
А затем (в цикле) получаем ссылку на конкретное значение (как объект) перечисления и (обратившись к его соответствующему методу) его идентификатор:
idVal: =Trim(Olel. ЗначениеПоНомеру (iVal*1) .Идентификатор) ;
Эту строку можно для ясности разбить на две строки:
// Получаем ссылку на объект "Значение перечисления°
О1е2:= Olel.ЗначениеПоНомеру(iVal• 1) ;
// Обращаемся к методу "идентификатор" этого объекта
idVal:=Tr im (О1е2.Идентификатор);
Скомпилируем наш проект, запустим его на выполнение и нажмем кнощ Структура. На рис. 4.176 представлен результат считывания информацио ной структуры "нашей" конфигурации.
Рис. 4.176. Результат считывания информационной структуры "нашей" конфигурации
Общие свойства конфигурации не исчерпываются набором свойств, значения которых здесь представлены. Но в рамках данного раздела перед нами не стоит задача разработать полномасштабное программное средство для работы с информационной структурой системы 1С:Предприятие.
На рис. 4.177 представлена часть информационной структуры справочника Физлица (свойства справочника).
достщк-гФ»^,с р;^—^^достщк-гФ»^,с р;^—^^Тк^ма-Число*»'ДлаиКопа-бТк^ма-Число*»'ДлаиКопа-б
достщк-гФ»^,с р;^—^^
достщк-гФ»^,с р;^—^^
Тк^ма-Число*»
'ДлаиКопа-б
Тк^ма-Число*»
'ДлаиКопа-б
5 Сге*»*-и(31 1g ФюЛш И Км
С^сдоа-вПреи^ор*»"-
Е на—ом~»
13 Свойства
Сиюны-Сгвчдж физических ли, I ' Оспое-оеПраоставлане-ВВ-ееНаи I ‘ Конгротьиних-альности-!
1 L CapHXaioe-ynp^enaxTiaa*»»*# , | АатоНу*оаииа-2
I , Кола*ствоЫ|хенеа-2
Грутебперыи.1
। 1 Сгтосов’м*п*ов»*м-ВДиалого
ЕдиияФермаЭ.темента-0
Ксммаит арий-Прмер
. часть «нфер-ац-онкей струстурч =4»""»"“
РИС. 4.177. часть инФсправ0ЧНика
3 ФизЛта
№ Коо
$. Наименее#**
Эл Свойства
у реквизиты (8) у ДатаРождения
; Синоним-Дата рождения В*-
’ Тип-Дата
; 1Г Д»*а-С
Точность-0 Перноаический-О
Отбсе-С
Испо»меание. ДпиЗ помойте
; РуаювИзменен*»!
* . Неотриивтельный-О РааавлятьТ риады-0 Коммеитарий-
Е-З Состо»»еФиз1киа
/ Синоним-Состоние ФизлицаВид-СостоямеФизгтаТямПеречклем»
; ’ Длича-0
;- То-носта-О
| j- Периоаичесхий-1
; , СоргуфоекаЧ)
Отбор-О
И спользооание-ДляЭ цементаJ ИзмонаетсяДолумеитами-!
1 j РуаюеИзмене«е-1Нестрицвтельиый-СРвзпелятъТ риааы-0Комментарий-
-справочника ФизЛииа.
Рис. 4.178. Часть ^₽7аЦрХ°зитов справочника
d*e*
Часть I. 10 и механизм OLE Autoir, Как видите, здесь отражены все те настройки справочника Физлица. что сделали в предыдущих разделах.
На рис. 4.178 представлена часть информационной структуры справочн ФизЛица (свойства реквизитов справочника).
Аналогично представлена информационная структура по документам и j гистрам.
На рис. 4.179 представлена информационная структура перечислений "i шей" конфигурации.
Рис. 4.179. Информационная структура перечислений ‘нашей" конфигурации Я папке \Part_l\Chapter_04\Topic_4_4 на сопроводительном компакт-диске I 'иги есть два текстовых файла: j lC_example_DB_structure_OO.TXT — информационная структура, выгру* 1 женная "штатными" средствами системы 1 С:Предприятие;lC_example_DB_structure_01.TXT — информационная структура, полу- J ченная в результате наших экспериментов.Рис. 4.179. Информационная структура перечислений ‘нашей" конфигурации Я папке \Part_l\Chapter_04\Topic_4_4 на сопроводительном компакт-диске I 'иги есть два текстовых файла: j lC_example_DB_structure_OO.TXT — информационная структура, выгру* 1 женная "штатными" средствами системы 1 С:Предприятие;lC_example_DB_structure_01.TXT — информационная структура, полу- J ченная в результате наших экспериментов.В Перечисления [61 Й Пол [2); - Мужской Женский Й СемейноеПоложем [7]НикогдаН еСостоялВ Б раке! ,_г—-.—В Перечисления [61 Й Пол [2); - Мужской Женский Й СемейноеПоложем [7]НикогдаН еСостоялВ Б раке! ,_г—-.—; • иосгоитВЗарегистриробанномБра1 СостоигВНеЗарегистрироеанномБ|
Рис. 4.179. Информационная структура перечислений ‘нашей" конфигурации Я папке \Part_l\Chapter_04\Topic_4_4 на сопроводительном компакт-диске I 'иги есть два текстовых файла: j lC_example_DB_structure_OO.TXT — информационная структура, выгру* 1 женная "штатными" средствами системы 1 С:Предприятие;
lC_example_DB_structure_01.TXT — информационная структура, полу- J ченная в результате наших экспериментов.
Рис. 4.179. Информационная структура перечислений ‘нашей" конфигурации Я папке \Part_l\Chapter_04\Topic_4_4 на сопроводительном компакт-диске I 'иги есть два текстовых файла: j lC_example_DB_structure_OO.TXT — информационная структура, выгру* 1 женная "штатными" средствами системы 1 С:Предприятие;
lC_example_DB_structure_01.TXT — информационная структура, полу- J ченная в результате наших экспериментов.
В Перечисления [61 Й Пол [2)
; - Мужской Женский Й СемейноеПоложем [7]
НикогдаН еСостоялВ Б раке
! ,_г—-.—
В Перечисления [61 Й Пол [2)
; - Мужской Женский Й СемейноеПоложем [7]
НикогдаН еСостоялВ Б раке
! ,_г—-.—
j ; ГражданскийБрак i I J- Разведен
1 [ Разошелся
; Вдовец
; 8 СсстояниеФизлица (3) СотруоникОсновной Сотрудник еосновной
j -- ВременноНеРаботает : 8 ПририсгетДокумента [3] Высокий
I Обычный
Низкий
Q СпособВыплатыФизЛицам [Э[ ЧерезКассу ЧерезБанк
ПоПочте
8 ВидВыплягФизЛицам!»] Зарплата
Аванс Премия
_ь следует отметить, что мы (в рамках этого раздела) не ставили перед ^0Й исЛЬ ПОЛУЧИТЬ исчерпывающую информацию о структуре конфигурации поэтому сравнивать оба эти файла следует с известной долей понимания, ^рнемся к вопросу идентификации значений перечислений вне контекста системы I С: Предприятие.
Как отмечалось ранее, при использовании механизма OLE Automation считы- 53ЮТСЯ те же ("штатные") идентификаторы значений перечислений, что были определены при конфигурировании системы, тогда как в таблицах базы данных хранятся системные (внутренние) идентификаторы значений перечислений. Это налагает определенные трудности при считывании информации из таблиц базы данных вне контекста системы 1 С:Предприятие.
Попробуем решить эту проблему комбинированным способом. То есть при считывании информационной структуры с использованием механизма OLE Automation установим соответствие между "штатным" идентификатором значения перечисления и его системным идентификатором, а затем будем использовать это соответствие при доступе к базе данных вне контекста системы 1С:Предприятие (в части HY
Среди средств встроенного языка программирования системы 1С:Предприятие есть функция ЗначениеВСтрокуВнутр (ИЛИ ValueToStringlnternal). Ее назначение — преобразование значения объекта агрегатного типа из внутреннего представления в строковое. Как следует из описания функции, строковое представление агрегатного типа данных имеет специальный системный формат. Данный системный формат использует внутренний системный идентификатор данных. Функция принимает один параметр, который может принимать значения любого типа данных (как базовых, так и агрегатных), кроме тех типов данных, которые не имеют собственно значения (например, Периодический, Таблица И Т. Д.).
Попробуем применить эту функцию в рамках нашей задачи, т. е. к агрегатному типу данных перечисление. Вспомним, что в явном виде (используя механизм OLE Automation) мы не можем обмениваться объектами агрегатного типа с системой 1 С:Предприятие. Следовательно (как в случае с регистрами, см. ранее), нам нужна функция (в глобальном модуле конфигурации), на вход которой можно было бы передать идентификатор перечисления и порядковый номер значения этого перечисления, а она должна обеспечить соответствующие преобразования. Эта функция должна располагаться в глобальном модуле конфигурации и быть доступной для внешних приложений (т. е. Должна быть с ключевым словом Экспорт).
Откроем Конфигуратор системы 1С:Предприятия и создадим в глобальном модуле функцию (листинг 4.71).
И
И
И
Функция, которая находит у заданного
и вызывает для найденного Здесь:
перечисления значение по и.
значения функцию 'ЗначениеВСтрокуВнутр-.
идПеречисления - идентификатор перечисления (вид), НомерЗначения - номер значения перечисления.
НомерЗначения) Экспорт id = "";
НомЗнач = ЧИСЛО(НомерЗначения);
Если НомЗнач»0 Тогда
LДляПеречисления(идПеречисления,
G = Перечисление.ПолучитьАтрибут(*"+СокрЛП(идПеречисления));
Колво = G.КоличествоЗначений();
Если НомЗнач<=Колво Тогда
Объект = С.ЗначениеПоНомеру(НомЗнач*!);
id = ЗначениеВСтрокуВнутр(Объект);
КонецЕсли;
КонецЕсли;
Возврат id;
екст этой функции достаточно прост и не нуждается в дополнительных" эмментариях. Все методы (кроме ЗначениеВСтрокуВнутр) МЫ уже ИСПОЛЬЗО- ши в этом разделе.
опробуем обратиться К функции гл9_ЗначениеВСтрокуВнутр_лля_ПеречислениЯ
1 нашего проекта. Для этого разместим в форме проекта какую-нибудь юпку (speedButton?) и напишем обработчик события "нажатие этой кнопки истинг4.72).
.„.._...._ ...._,...„...„.„....,..„ ..,....,..........•-
истинг 4.72. Обработчик события "нажатие кнопки вызова функции ; п9_ЗначениеВСтрокуВнутр_для_Перечисления“;
ocedure TForml.SpeedButton7Cllck(Sender: TObject);
r
с: string;
-el: OleVariant;
un: integer; // Номер тестируемого значения перечисления lEnum, II Идентификатор тестируемого перечисления
.= 4. Доступ к информации 1С из внешних приложений
^а1, // "Штатный" идентификатор тестируемого значения перечисления
//
результат, который возвращает функция
,/ ■гл9_ЗначениеВСтрокуВнутр_лля_Перечисления"
idValSys: string; k
begin
01е_1С_Арр: =ConnectTolC (Edi t_lCinit. Text) ;
if not VarIsBnpty(01e_lC_App) then begin
// Идентификатор тестируемого перечисления idEnum:=1СостояниеФизлица1;
// Номер тестируемого значения
ншп:=1;
II Получаем ссылку на перечисление как объект
// глобального контекста программы 1С:Предприятие
Olel:=О1е_1С_Арр.Перечисление.ПолучитьАтрибут(''+idEnum);
// Получаем "штатный" идентификатор значения перечисления
idVal:=Trim(01el.3Ha4eKHenoHoMepy(Num*l).Идентификатор);
// Формируем строку для вызова функции
// "гл9_ЗначениеВСтрокуВнутр_лля_Перечисления"
Sx: = 'гл9_ЗначениеВСтрокуВнутр_для-Перечисления(°'
idEnum
+ IntToStr(Num)
')';
// Вызываем функцию
11"гл9_ЗначениеВСтрокуВнутр_лля_Перечисления* idValSys:=Trim(01e_lC_App.EvalExpr(Sx);
// Результат выводим на экран в виде сообщения ShowMessage('Перечисление='
+ idEnum
+ '; НомерЗначения=1
♦ IntToStr(Num)
+ '; id='
+ idVal
+ '; ЗначениеВСтрокуВнутр=1
+ idValSys);
end;
end;
Результат, возвращаемый функцией тлЭ-ЗначениеВСтрокуВнутр^^перечи пр™Тр„НЖ
Structure of DB (IC)
£’X“XZSw^
Уок
Рис. 4.180. Результат, возвращаемый функциейгл9-ЗначениеВСтрохуВнутр_для_Перечисления
Если сделать соответствующие изменения в тексте функции GetstruccEm» (см. листинг 4.70) и вновь прочитать информационную структуру перечислений, то получим результат, приведенный на рис. 4.181.
а СемейноеЛоложение [7|
22 ")22 ")НикогдаНеСостоялВБракеЧ"Е"."0"."0"."21","0"."0"," 22 "}
22 ")
22 ")
CocтoитBЗapefиcтpиpoвaннoмБpaкe•{"E"."0■7X)"."2Г’."0".■■0,',"
СостоигВНеЗарегистриро8аннсмБраке»('Т"."0'7'0‘72Г7'0,7,0".'
■ •ГражданскийБракМ"Е".,1ГЖ^25 ")
Paэaeдeи-('E■7'0•7■0‘77r■;V7'0■7, 26 ")
Paзoшeлcя-(,Г7V7^r;21T0■7,0•7, 27 ")
__Jnoeeu-£E21Z223!2^^
23 "}24 ")23 "}24 ")гЛ9Р1|с* ^■1*Г-Рвзульта.. возвращаемый функцией
23 "}
24 ")
23 "}
24 ")
-Зн.чени8встро,ув„,тр_л„,_п=речис„е„„ №. lcex ,H|W nepe4„meH„,f
(Если внимательно посмотреть на рис. 4.181, то видно, что системный иден- ггификатор располагается в самом конце строки (последний "член" в строке), обрамленной фигурными скобками. Наша задача — выделить его и конвергировать соответствующим образом.
Зновь запустим конфигуратор системы 1С:Предприятие и в глобальном моду- ie "нашей" конфигурации создадим еще три функции (листинги 4.73—4.75).
Листинг 4.73. Функция глобального модуля, инвертирующая строку символе
/ Инвертирование строки символов
[нкция гл9_ИнвертироватъСтроку(ИсхСтрока)
Перем Res; // Строка
Перем i;
Res="";
Если СтрДлмна(ИсхСтрока)>0 Тогда
1=0;
Пока 1<СтрДлина(ИсхСтрока) Цикл
Il считываем очередной символ иа строки 51=фед(ИсхСтрока, i.l) ;
Res=Sl+Res; // Инвертируем
КонецЦикла;
КоненЕсли;
Возврат Res;
КонеиФункЦИИ
функция гл9_ИнвертироватьСтроку (листинг 4.73) просто "переворачивает" строку символов (первый символ строки становится последним, а последний — первым). Ее текст достаточно прост и не требует пояснений.
I■■
' Листинг 4.74. Функция глобального модуля, возвращающая системный
идентификатор объекта
// Получение внутреннего (системного) идентификатора объекта Функция глЭ_0бпект_Получить8у8П)(Тестируемый0бъект) Экспорт id = ”; И Здесь будет системный идентификатор
// Преобразуем значение объекта агрегатного типа
// из внутреннего представления в строковое 5=ЗначаниеВСтрокуВнутр(ТестируемыйОбъект);
// Заменяем двойные кавычки на пробелы
S = СтрЗаменить!S, Сима(34), " *);
// Заменяем правые фигурные скобки на пробелы
//и удаляем конечные пробелы из строки
S = СокрЛП(СтрЗаменить(S, *}*, * *});
// Инвертируем строку (последний "член" становится первым)
S = гл9_ИнвертироватъСтроку(S);
// Получаем номер позиции первой запятой в инвертированной строке НомерПозицииЗапятой = Найти(S,*,•);
Если НомерПоэицииЗапятой>1 Тогда
U Если есть запятая, выделяем все, что расположено слева до нее, // удаляем конечные пробелы и опять инвертируем строку.
// Это и будет самый последний "член"
S = глЭ-ИнвертироватьСтроку(СокрЛП(Лаж(S, НомерПозицииЗапятой-1))I // Конвертируем его в системный идентификатор объекта id = _IdToStr(S);
КонецЕсли;
Возврат id;
КонецФункции
Функция гл9_0бъект_Получитьзузю (листинг 4.74) получает на входе о ект, преобразует его значение из внутреннего представления в строковое, тем выделяет последний "член" из строки и конвертирует его в системн (внутренний) идентификатор.
На основе текста функции гл9_ЗначениеВСтрокуВнутр_для_Перечисленмя (листинг 4.71) создадим функцию, которая будет получать в качестве входных параметров идентификатор перечисления и номер значения перечисления, а возвращать — системный (внутренний) идентификатор. Текст этой функции приведен в листинге 4.75.
^..„„....^..^^.„^....„.....(-.„..^..........---да,..,....,.,,....,™,.,,^,^^,.^.,.™^...,...,.....,,..,..^,-...,.-
ГЛистинг.4.75. Функция глобального модуля, возвращающая системный идентификатор значения перечисления ; ?f-
// Получение системного идентификатора значения перечисления
Функция гл9_Перечисление_Получить_8увП)_
ЗначенияЛоНомеру(идПеречисления,НомерЭначения) Экспорт
II идПеречисления - идентификатор тестируемого перечисления
// НомерЭначения — номер тестируемого значения перечисления id = --;
НомЗнач = ЧИСЛО(НомерЭначения);
Если Ном3нач>0 Тогда
G = Перечисление.ПолучитьАтрибут("”+СокрЛП(идПеречисления));
Колво = С.КоличествоЗначенийО ;
Если НомЗнач<=Колво Тогда
Объект = О.ЗначениеПоНомеру(НомЗнач*1);
id = гл9. Обо^кт_ПолучитьВужЮ(Объект) ;
КонецЕсли;
КонецЕсли;
Возврат id;
КонецФункции
^ButtonT (см. листинг 4.72).
(ля этого две строки:
, • гл9_ЗначениеВСтрокуВнутр_для_Перечисления’ „.- ' гл9_ЗначениеВСтрокуВнутр_для_Перечислеи
уценим двумя другими:
/’гл9_Перечисление_Получить_5узЮ_ЗначенияПоНомеру"
1учить_8увП>_ЗначенияЛоНомеру ("'
1 гл!1 гл!Sx:Sx:OK"OK"у nirture о< РЧу nirture о< РЧРис. 4.182. Результат , возвращаемый функцией гл9_Перечисление_Получить_5уэ10_ЗначенияПоНомеруРис. 4.182. Результат , возвращаемый функцией гл9_Перечисление_Получить_5уэ10_ЗначенияПоНомеруСистеиныйИдентификатор 13СистеиныйИдентификатор 13Скомпилируем проект и запустим на выполнение. По нажатию кнопки speedButcon? на экране появится сообщение, показанное на рис. 4.182.
1 гл!
1 гл!
Sx:
Sx:
OK"
OK"
у nirture о< РЧ
у nirture о< РЧ
Рис. 4.182. Результат , возвращаемый функцией гл9_Перечисление_Получить_5уэ10_ЗначенияПоНомеру
Рис. 4.182. Результат , возвращаемый функцией гл9_Перечисление_Получить_5уэ10_ЗначенияПоНомеру
СистеиныйИдентификатор 13
СистеиныйИдентификатор 13
Теперь внесем изменения в функцию GetstructEnum (см. листинг 4.70), чтобы дополнительно прочитать значения системных (внутренних) идентификаторов значений перечислений (листинг 4.76).
"1- - - '- — / ■ т;'1
Листинг 4.76.Фрагмент текстафункции GetstructEnum-
function TForml.GetstructEnum(Lines: TStrings): integer;
begin
Result:=0;
for iVal:=l to CountVal do
ЬХ^хТг^еГЗначениеПоНо^^-Идек^фихатор);
Sx:= •и,9_Перечисл^_Получ»г1._8у-П)_3*ачеки*ПоНомеру C'
* idEnum
IntToScrliV»1’
* ') ' ;
idValSye: =Tri.T.(01e„lC_App.EvalExpr(Sx) ;
Lines.Add(#9+#9+idVal+1=1+idValSye); end;
end
На рис. 4.183 представлен результат считывания с учетом сделанных изменений.
информационнойинформационнойструму^струму^В Перечисления [6]
информационной
информационной
струму^
струму^
Й- Пол [2]
Мужской*]
Женский-К.
: В СемейноеП сложение [7] НикогдаНеСостоялВБ раке=М
:'—Состоите ЗарегистрированномБраке=М
: ; СостоигВНеЗарегистрированномБраке-0 ; ; •- ГражданскийБрак=Р
1 ' ! - Разведен=О
। : I- Разошелся-А
‘ : -- Вдовец=5
; В- Состояние^ излица [3)
;; j- Сотрудник0сноеной=13
<• СотрудникНеосновной-14
;•'- ВременноНеРаботает«15
; Е ПририотетДокумента (3)
Высокий=20 : ; !- 06ычняй»21
Низкий=22
Б ■ СпособВ ыплатыФ иэЛ ицам [3]
'1- ЧерезКассу-2В
ЧерезБанк-2Е
-- ПоПочге=20
В ВиоВыплагФизЛицам |4]- ЗарПлата=21
Аванс=2]
।1 Премия=2К
МатПомощь=2С
Рис. 4.183. Результат считывания информационной структуры перечисленийс учетом системных идентификаторов значений перечислений
Сопоставив информацию, представленную на рис. 4.183, с рис. 4.4, 4.1®и 4.11, можно сделать уже вполне определенные, полезные выводы. Предо-
ставлю это читателю (в части II мы вернемся к этому вопросу).
ПРИМЕЧАНИЕ
В папке \Part_1\Chapter_O4\Topic_4_4 сопроводительного компакт-диска книги есть текстовый файл 1C_example_DB_structure_02.TXT, содержащий информационную структуру, фрагмент которой представлен на рис. 1.183.
Исходные тексты этого примера (проект sp_LoadStructure_1C.DPR) содержатся на сопроводительном компакт-диске книги в папке: \Part_1\Chapter_04\Topic_4_4\ sp_LoadStructure_1 C.PAS.
ПРИМЕЧАНИЕ
Напомню, что представленные выше примеры исходных текстов — это упрощенная иллюстрация к рассматриваемым вопросам. Назначение этих примеров — дать представление о возможном подходе при решении задач информационного обмена с системой 1 (^Предприятие. При работе с реальными базами 1С может потребоваться их дальнейшая доработка.
Doc-файлы
(хранилища структурированной информации).
Файл конфигурации системы 1С:Предприятие — 1Cv7.MD
Doc-файл (DocFile, compound file, составной файл, хранилище структурированной информации, structured storage) — это средство для хранения структурированной информации в виде единого файла. Структура файла организована в виде дерева по аналогии с файловой системой. При этом эквивалентом каталога (папки) является хранилище, а эквивалентом файла — поток. Doc-файлы ориентированы на хранение разнородных данных (текст, видео, графика, звук и т. д.). Doc-файлы широко используются в среде Windows для хранения наборов свойств OLE. составных документов и контейнеров OLE. В качестве примера можно привести такие приложения, как MS Word, MS Excel, MS PowerPoint и др.
Физически Doc-файл организован по кластерному типу (наподобие файловой £истемы FAT). Первые 4 байта Doc-файла: DOh, crh, iih, EOh (по этому признаку можно визуально оценить, является ли данный файл Doc-файлом).
клее подробно организация Doc-файлов описана, например, в статьях:
^ Климентьев К. Е. "Внутренний формат документов MS Word" <http://www.uinc.ru/articles/39/);
^ Новодворский С. "Доступ к MD-файлам при помощи VBA" (http://www.klerk.ru/soft/lc/72429, http://www.hare.ru/kb/know-how/ article.html?id=59).
Часть I. 1С и механизм OLEA.
Логически Doc-файл состоит из следующих элементов.
Хранилище (storage) — аналог каталогов файловой системы. Здесь хре.и ся ссылки на информационные "потоки". Как и любая древообр^ структура, Doc-файл имеет корневой каталог (root storage).
Поток (stream) — структурированная информация (аналог файлов).
Блокированные данные (lock-bytes) — неструктурированная информаций
Примечание
Создание Doc-файлов сложной структуры и считывание информации из и» подробно описаны в специальной литературе.'
В системе 1С:Предприятие эта технология используется для хранения информационной структуры (метаданные) каждой конфигурации (базы данных) в файле 1Cv7.MD, который представляет собой Doc-файл (хранилище струк- турированной информации).
Рассмотрим процесс считывания информационной структуры базы данных 1С:Предприятие из файла 1Cv7.MD на простом примере.
Запустим Delphi и создадим новый проект с именем Read_from_lCv7. MD.DPR.
Примечание
.и=ж
На рис. 4.184 представлена форма проекта.
Рис. 4.184. Форма Delphi-проекта ReadJrom_1Cv7_MD.DPRРис. 4.184. Форма Delphi-проекта ReadJrom_1Cv7_MD.DPR
Рис. 4.184. Форма Delphi-проекта ReadJrom_1Cv7_MD.DPR
Рис. 4.184. Форма Delphi-проекта ReadJrom_1Cv7_MD.DPR
В листинге 4.77 lCv7.md".В листинге 4.77 lCv7.md".представлен текст обработчика события "нажатие кнопЮ*представлен текст обработчика события "нажатие кнопЮ*"""г-~■”:г--—-:-—г.т,г-,-.-,;.., ® °_?ОМ°1ЦЬЮ ФУнкиии StgleStorageFile"""г-~■”:г--—-:-—г.т,г-,-.-,;.., ® °_?ОМ°1ЦЬЮ ФУнкиии StgleStorageFileprocedure TFonnl.BuctonlClick(Sender: TObject); beginprocedure TFonnl.BuctonlClick(Sender: TObject); beginOD1. Fil eName: =fn_10v7_jnd;OD1. Fil eName: =fn_10v7_jnd;
В листинге 4.77 lCv7.md".
В листинге 4.77 lCv7.md".
представлен текст обработчика события "нажатие кнопЮ*
представлен текст обработчика события "нажатие кнопЮ*
"""г-~■”:г--—-:-—г.т,г-,-.-,;..,
® °_?ОМ°1ЦЬЮ ФУнкиии StgleStorageFile
"""г-~■”:г--—-:-—г.т,г-,-.-,;..,
® °_?ОМ°1ЦЬЮ ФУнкиии StgleStorageFile
procedure TFonnl.BuctonlClick(Sender: TObject); begin
procedure TFonnl.BuctonlClick(Sender: TObject); begin
OD1. Fil eName: =fn_10v7_jnd;
OD1. Fil eName: =fn_10v7_jnd;
£1£14 доступ к информации IC из внешних приложенийInitialDir:=ExtractFilePath(fn_lCv7jnd) ;4 доступ к информации IC из внешних приложенийInitialDir:=ExtractFilePath(fn_lCv7jnd) ;if о01' fnjif о01' fnj.Execute then begin icv7_jnd: =OD1. Filename ;.Execute then begin icv7_jnd: =OD1. Filename ;Capt i °n: = f n_lCv7_pid ;jf stgl«StorageFile(PWideChar(fn_lCv7_pd)) = ShowMessage(ExtractFileName (fn_lCv7_pd) +1Capt i °n: = f n_lCv7_pid ;jf stgl«StorageFile(PWideChar(fn_lCv7_pd)) = ShowMessage(ExtractFileName (fn_lCv7_pd) +1S_OK then begin — это Doc-файл')S_OK then begin — это Doc-файл')
£1
£1
4 доступ к информации IC из внешних приложений
InitialDir:=ExtractFilePath(fn_lCv7jnd) ;
4 доступ к информации IC из внешних приложений
InitialDir:=ExtractFilePath(fn_lCv7jnd) ;
if о01' fnj
if о01' fnj
.Execute then begin icv7_jnd: =OD1. Filename ;
.Execute then begin icv7_jnd: =OD1. Filename ;
Capt i °n: = f n_lCv7_pid ;
jf stgl«StorageFile(PWideChar(fn_lCv7_pd)) = ShowMessage(ExtractFileName (fn_lCv7_pd) +1
Capt i °n: = f n_lCv7_pid ;
jf stgl«StorageFile(PWideChar(fn_lCv7_pd)) = ShowMessage(ExtractFileName (fn_lCv7_pd) +1
S_OK then begin — это Doc-файл')
S_OK then begin — это Doc-файл')
end,
el‘sb^3=M=®=««>-11’M“,£»-1Cv7-mi,‘' " ’" “ °°С‘*‘ЙЛ’’
end;
end;
end;
. после того, как файл был выбран, с помощью функции stgisStorageFiie £"- является ли выбранный файл. ^-файлом. Результаты тестирования этой функции представлены на рис. 4.185 и 4.186.
. г B\tt. Book-ready—1. г B\tt. Book-ready—11Cv7.md1Cv7.mdDot filesDot filesхх
. г B\tt. Book-ready—1
. г B\tt. Book-ready—1
1Cv7.md
1Cv7.md
Dot files
Dot files
х
х
!Cv7.MD- 1TO Doc-файл
Рис. 4.185. Тестирование функции StgisStorageFiie (положительный результат проверки)Рис. 4.185. Тестирование функции StgisStorageFiie (положительный результат проверки)•Г В\1•Г В\1cready— НИ 13Oocfilescready— НИ 13Oocfiles1Cv7.md |1Cv7.md |dfl.dcu-это не Doc-файл Idfl.dcu-это не Doc-файл IРис. 4.186. Тестирование функции StgisStorageFiie (отрицательный результат проверки)Рис. 4.186. Тестирование функции StgisStorageFiie (отрицательный результат проверки)
Рис. 4.185. Тестирование функции StgisStorageFiie (положительный результат проверки)
Рис. 4.185. Тестирование функции StgisStorageFiie (положительный результат проверки)
•Г В\1
•Г В\1
cready— НИ 13
Oocfiles
cready— НИ 13
Oocfiles
1Cv7.md |
1Cv7.md |
dfl.dcu-это не Doc-файл I
dfl.dcu-это не Doc-файл I
Рис. 4.186. Тестирование функции StgisStorageFiie (отрицательный результат проверки)
Рис. 4.186. Тестирование функции StgisStorageFiie (отрицательный результат проверки)
Добавим в форму проекта Delphi-компонент rrreeview (рис. 4.187).
Изменим текст обработчика события "нажатие кнопки !Cv7.md следующим образом (листинг 4.78).
ИЕК®?®®ИЕК®?®®Е^в^'Е^в^'
ИЕК®?®®
ИЕК®?®®
Е^в^'
Е^в^'
procedure TForml.ButtonlClicktSender: TObject); Var
Node: TTreeNode;
stgRoot: istorage;
0D1.FileName:=fn_lCv7_md;
GDI.InitialDir:=ExtractFilePath(fn_lCv7_jnd);
if GDI.Execute then begin
f n_lCv7_jnd: =OD1. FileName;
Caption:=fn_lCv7_md;
if StgleStorageFile(PWideChar(fn_lCv7_jnd))=S_OK then begin
M ShowMessage(ExtractFileName(fn_lCv7_nid)+l — это Doc-файл');
OleCheck(StgQpenStorage(EWideChar(fn_lCv7_md), nil, stgrn_read or stgm_share_exclusive, nil, 0,
BtgRoot));
TreeViewl.Items.BeginUpdate;
try
TreeViewl.Items.Clear;
Node:=TreeViewl.Items.Add(nil,'<Root>');
OetNaxtStorage(Node,etgRoot);
Node.Expand(true);
finally
TreeView1.Items.EndUpdate;
atgRoot:=nil;
end;
end
else begin
ShowMessage(ExtractFileName(fn_lCv7_pid)+' — это не Doc-файл');
end;
end;
end;
Здесь Doc-файл открывается для чтения с помощью функции stgopenstorage. В случае успеха в переменной stgRoot: istorage,- возвращается указатель на интерфейс корневого каталога (root storage) открытого хранилища информации.
С помощью методов интерфейса istorage (каталога, по аналогии с файловой системой) можно прочитать список его элементов, которые представляют собой "подкаталоги" и "файлы" (по аналогии с файловой системой).
Таким образом, комбинируя методы Openstorage и EnumElements интерфейса istorage. можно "пролистать" всю структуру Doc-файла. В листинге 4.79 приведен текст рекурсивной функции GetNextstorage, которая выполняет эти действия.
И^ггт-;-г"-:г|^--;?-т';-:•■•—:гг-:^----.--'™:г^^
, Л*п,,г 4.79. функция g-tK^tstor». оро.,0. ;
Procedure TForml GetNextstorage(pn: TTreeNode; stg: istorage);
Var
ESS: lEnumStatStg;
StatStg: TStatStg;
NodeName: string;
cn: TTreeNode;
ctgChild: istorage ;
Sx: string;
begin
°lecheck.(atg.EnuinBlemente(O,nil,O,ESS)) ;
'«hile ESS.Next(1,StatStg,nil) = S_OK do begin
NodeName:=StatStg.pwcaName;
Sx:=■???•;
if StatStg.dwType = STGTY_.STORAGE then Sx:='STORAGE';
if StatStg.dwType = STGTY_STREAM then Sx:='STREAM’;
if StatStg.dwType = STGTY_PROPERTY then Sx:='PROPERTY';
if StatStg.dwType = STGTY_LOCKBYTES then Sx:='LOCKBYTES’;
cn:=TreeViewl.Items.AddChild(pn,NodeName+'=’+Sx+'
if (StatStg.dwType = stqty_STORAGE) then begin 01eCheck(Stg.QpenStorage(StatStg.pwcsName, nil, stgnuread or stgrn_share_exclusive, nil, 0, ctgChild));
Q«tSext8torage(cn,ctgChild);
end;
end;
end;
);
1Cv7.md"
В <RooO
Э Report-STORAGE
Container.Conlents-S TREAM
S CelcVer-STORAGE
:- Container Contents-STREAM
9-Journals TORAGE
j В Journal_Number45-STORAGE
■ I HAVorkBook-STORAGE
' --Page.l-STREAM
> Dialog Slream-STREAM
; ; I MD Programmtext-STREAM
'- Container Profie-STREAM
Container. Contents-STREAM
- ContainerCcotenti-STREAM I !- Container. Contents-STREAM
S Picture-STORAGE
Galery-STREAM
- ■ Container Contents-STREAM
В SubUtt-STORAGE
Conia.net Contents-STREAM
В UserOef-STORAGE
' Й Page 1-STORAGE
Container Contents-STREAM
В Page.2-ST0RAGE
; Pagel-STREAM
I Cortana Contents-STREAM
• Container Contents-STREAM
S Documenl-STORAGE
Рис. 4.188. Результат считывания структуры файла 1Cv7.MD "нашей" конфигурации
ПРИМЕЧАНИЕ
Подробное описание назначения соответствующих методов интерфейсов iStorage и lEnumStatstg можно найти в специальной литературе.
царис. 4188 представлен результат считывания информационной структуры ^.файла (1Cv7.MD) "нашей" конфигурации.
ПРИМЕЧАНИЕ
Исходные тексты этого примера есть на сопроводительном компакт-диске книги в папке \Part_1\Chapter_04\Topic_4_4\Read_from_1Cv7_MD_01.PAS.
МодифицируемМодифицируемнаш проект, добавив на форму Delphi-компонент типа тметонаш проект, добавив на форму Delphi-компонент типа тмето(рис. 4.189).(рис. 4.189).Рис. 4.189. Форма Delphi-проекта Read_from_1Cv7_MD.DPRРис. 4.189. Форма Delphi-проекта Read_from_1Cv7_MD.DPR
Модифицируем
Модифицируем
наш проект, добавив на форму Delphi-компонент типа тмето
наш проект, добавив на форму Delphi-компонент типа тмето
(рис. 4.189).
(рис. 4.189).
Рис. 4.189. Форма Delphi-проекта Read_from_1Cv7_MD.DPR
Рис. 4.189. Форма Delphi-проекта Read_from_1Cv7_MD.DPR
Добавим обработчик события "нажатие левой кнопки мыши на компоненте Freeview" (ЛИСТИНГ 4.80).
Procedure TForml .TreeViewlClick(Sender: TObject); VerProcedure TForml .TreeViewlClick(Sender: TObject); Ver
Procedure TForml .TreeViewlClick(Sender: TObject); Ver
Procedure TForml .TreeViewlClick(Sender: TObject); Ver
ParentNodeName, NcdeName: WideString; Slt: string;
DooStorage.
Stg:istorage;
Strin: IStream;I
Datastream: TOleStream;J
begin
Memol.Lines.Clear;л
if TreeViewl.SelectedoNIL then beginл
NodeName: =TreeViewl. Selected. Text ; Sx:=Trim (sp_GetWordFromString(1 =', NodeName,2)); if Sx= 'STREAM' then begin И Выбранный узел должен быть
// потоком!"файлом")|
ParentNodeName:=TreeViewl.Selected.Parent.Text;
Sx:=Trim(sp_GetWordFromString(' = ', ParentNodeName,2));I
II Родитель выбранного узла должен быть хранилищем ("каталоге#»® if (Sx= 'STORAGE') or (Sx= •') then begin И Открываем Doc-файл (1CV7.MD)
0leCheckIStgOpenStorage(PWideChar(fn_lCv7_md), nil,Я
stgit\_read or STGM_DIRECT
or stgnuahare_exclusive, nil, 0, Stg)); try
I/ Определяем имя родителя выбранного узла TTreeView
11 (первое слово в имени узла). Это должен быть "каталог" ParentNodeName:=Trim(sp_GetWordFromString(' =', ParentNodeName, DM // Открываем "каталог* в хранилище с именем ParentNodeName
if Stg.OpenStorage(POleStr(ParentNodeName),J
nil, stgnuread or STGM_DIRECT or STGN_SHARE_EXCLUSIVE, ( nil, 0. DocStorage) <> S_OK then Exit;
II Определяем имя выбранного узла TTreeView
II (первое слово в имени узла). Это должен быть поток("файл°> NodeName:=Trim (sp_GetWordFromString(’ =', NodeName, 1));
if DocStorage.QpenStrearatPOleStr(NodeName), nil, stgn\_read or STGN_DIRECT or STGM_SHARE_EXCLUSIVE,
О,
Strm) о S_OK then Exit;
II Считываем данные из потока ("файла")
DataStreem: -TOleStream. Create(Strm) ;
try
SetLength(Sx, Datastream.Size);
Datastream.ReadBuffer(Pointer(Sx)A, Datastream.Size);
Memol.Lines.Add(Sx) ;
finally
Datastream.free;
Datastream:=NIL;
Strm:=nil;
end;
//
finally
stg:=nil;
end;
end
else begin
Memol.Lines.Add(NodeNamet'; ожидалось, что родитель STORAGE1);
end;
end
else begin
Memol.Lines.Add(NodeName+': нужно выбрать STREAM');
end;
end;
end;
Здесь определяется и запоминается имя выбранного узла (NodeName) компонента TTreeview и его родителя (ParentNodeName). Затем открываются Doc- файл (функция StgOpenStorage), "каталог" С именем ParentNodeName (метод St9-Openstorage) И ПОТОК (NodeName) "каталога" ParentNodeName (метод Docstorage.OpenStream). Из потока NodeName считываются данные (С ПОМОЩЬЮ методов объекта Datastream). На рис. 4.190 представлен результат считыва- Ния данных из потока Main MetaData stream файла 1Cv7.MD. Такое по- ^Роение текста обработчика связано с тем, что Doc-файл открывается только ^а период считывания структуры файла и только при считывании данных из ВЬ|бранного потока.
Г t:\IC_Book-ready.My\CD\Chapter l\Top« 1 4\lteni 1 HBQ
1Cv7.mdJ
S Metadata-STORAGE GUIDData-STREAM TagStream-3 TREAM Contamei Contents»?TREAM
IS ProvList.STORAGEContainer Contents-? TREAMGm —C MainDataContDeT'l13"."1001Г77120").I TaskJiem",IS ProvList.STORAGEContainer Contents-? TREAMGm —C MainDataContDeT'l13"."1001Г77120").I TaskJiem",(Т’.-Зааача".™/-" ('•GenJmfHDef'.(МУ '.'Комментарий' ("DocSefiefObj"). ("DocNumDef").("Const»".("112"."Whatlslt"."".'- ("SbCnls".(Т’.-Зааача".™/-" ('•GenJmfHDef'.(МУ '.'Комментарий' ("DocSefiefObj"). ("DocNumDef").("Const»".("112"."Whatlslt"."".'- ("SbCnls".VVVVIF/T.Tr}).1''."Комментарий",'?"."64"."0"."Д','Х)"."0",'Т)")),VVVVIF/T.Tr}).1''."Комментарий",'?"."64"."0"."Д','Х)"."0",'Т)")),"s-.no-'jvvavvvxrvo"»."s-.no-'jvvavvvxrvo"».Lp2' •''фиэЛица",'Т1ример''.''Сг11сок Физических лиц"."0‘,.,У."2"."2".,?‘ "St" I । deems ,Lp2' •''фиэЛица",'Т1ример''.''Сг11сок Физических лиц"."0‘,.,У."2"."2".,?‘ "St" I । deems ,'{'•15"'{'•15". "ДатаРождения"."“."Дата рождения".,'0".'’0"."0".,‘0'.''Д|.‘1Т'.‘1^ |("42".'"СостояниеФ из лица""". "Состояние Физлица"."Е"."0"."0"."38"."0"."0".' 'XoлeoДeтeй".'■".■Kol>1чecтвoдeтcй".•^Г"1ff'.'Д'VV,^"Г ороаПрожиеания"."".Торон гхюживания"."В"."0"."0"."35"."0"."0"."0""ДомашнийАдрес"."'."Домашний tvTPec"."S"."S4"."0".'"0"."0".‘tr'."0"."l ("29"."Пол".""."Пол"."Е"."0"."0".'"17'."0"."0"."0"."1"."0"."0".'1"."0"."0"}, ("30"."СемвйноеПоложение".""."Семейнов положение"."Е"."0"."0"."21"."0".’ ("31"."ДолоЛ№<гвльнаяИнформация","","Дополнительная информация","?". ("Form".. "ДатаРождения"."“."Дата рождения".,'0".'’0"."0".,‘0'.''Д|.‘1Т'.‘1^ |("42".'"СостояниеФ из лица""". "Состояние Физлица"."Е"."0"."0"."38"."0"."0".' 'XoлeoДeтeй".'■".■Kol>1чecтвoдeтcй".•^Г"1ff'.'Д'VV,^"Г ороаПрожиеания"."".Торон гхюживания"."В"."0"."0"."35"."0"."0"."0""ДомашнийАдрес"."'."Домашний tvTPec"."S"."S4"."0".'"0"."0".‘tr'."0"."l ("29"."Пол".""."Пол"."Е"."0"."0".'"17'."0"."0"."0"."1"."0"."0".'1"."0"."0"}, ("30"."СемвйноеПоложение".""."Семейнов положение"."Е"."0"."0"."21"."0".’ ("31"."ДолоЛ№<гвльнаяИнформация","","Дополнительная информация","?". ("Form".{'•43-'{'•43-'("37'("16"("37'("16"[('ПЗ^ФормаСписка"."".""))).("ЗЗ'.ТтракяМира ".""."Страны мира".’"0".'"5"."2",'‘2"."г'."Б4".'Т^^^[('ПЗ^ФормаСписка"."".""))).("ЗЗ'.ТтракяМира ".""."Страны мира".’"0".'"5"."2",'‘2"."г'."Б4".'Т^^^
IS ProvList.STORAGE
Container Contents-? TREAM
Gm —
C MainDataContDeT'l13"."1001Г77120").
I TaskJiem",
IS ProvList.STORAGE
Container Contents-? TREAM
Gm —
C MainDataContDeT'l13"."1001Г77120").
I TaskJiem",
(Т’.-Зааача".™/-" ('•GenJmfHDef'.
(МУ '.'Комментарий' ("DocSefiefObj"). ("DocNumDef").
("Const»".
("112"."Whatlslt"."".'- ("SbCnls".
(Т’.-Зааача".™/-" ('•GenJmfHDef'.
(МУ '.'Комментарий' ("DocSefiefObj"). ("DocNumDef").
("Const»".
("112"."Whatlslt"."".'- ("SbCnls".
VVVVIF/T.Tr}).
1''."Комментарий",'?"."64"."0"."Д','Х)"."0",'Т)")),
VVVVIF/T.Tr}).
1''."Комментарий",'?"."64"."0"."Д','Х)"."0",'Т)")),
"s-.no-'jvvavvvxrvo"».
"s-.no-'jvvavvvxrvo"».
Lp2' •''фиэЛица",'Т1ример''.''Сг11сок Физических лиц"."0‘,.,У."2"."2".,?‘ "St" I । deems ,
Lp2' •''фиэЛица",'Т1ример''.''Сг11сок Физических лиц"."0‘,.,У."2"."2".,?‘ "St" I । deems ,
'{'•15"
'{'•15"
. "ДатаРождения"."“."Дата рождения".,'0".'’0"."0".,‘0'.''Д|.‘1Т'.‘1^ |("42".'"СостояниеФ из лица""". "Состояние Физлица"."Е"."0"."0"."38"."0"."0".' 'XoлeoДeтeй".'■".■Kol>1чecтвoдeтcй".•^Г"1ff'.'Д'VV,^
"Г ороаПрожиеания"."".Торон гхюживания"."В"."0"."0"."35"."0"."0"."0"
"ДомашнийАдрес"."'."Домашний tvTPec"."S"."S4"."0".'"0"."0".‘tr'."0"."l ("29"."Пол".""."Пол"."Е"."0"."0".'"17'."0"."0"."0"."1"."0"."0".'1"."0"."0"}, ("30"."СемвйноеПоложение".""."Семейнов положение"."Е"."0"."0"."21"."0".’ ("31"."ДолоЛ№<гвльнаяИнформация","","Дополнительная информация","?". ("Form".
. "ДатаРождения"."“."Дата рождения".,'0".'’0"."0".,‘0'.''Д|.‘1Т'.‘1^ |("42".'"СостояниеФ из лица""". "Состояние Физлица"."Е"."0"."0"."38"."0"."0".' 'XoлeoДeтeй".'■".■Kol>1чecтвoдeтcй".•^Г"1ff'.'Д'VV,^
"Г ороаПрожиеания"."".Торон гхюживания"."В"."0"."0"."35"."0"."0"."0"
"ДомашнийАдрес"."'."Домашний tvTPec"."S"."S4"."0".'"0"."0".‘tr'."0"."l ("29"."Пол".""."Пол"."Е"."0"."0".'"17'."0"."0"."0"."1"."0"."0".'1"."0"."0"}, ("30"."СемвйноеПоложение".""."Семейнов положение"."Е"."0"."0"."21"."0".’ ("31"."ДолоЛ№<гвльнаяИнформация","","Дополнительная информация","?". ("Form".
{'•43-'
{'•43-'
("37'("16"
("37'("16"
[('ПЗ^ФормаСписка"."".""))).
("ЗЗ'.ТтракяМира ".""."Страны мира".’"0".'"5"."2",'‘2"."г'."Б4".'Т^^^
[('ПЗ^ФормаСписка"."".""))).
("ЗЗ'.ТтракяМира ".""."Страны мира".’"0".'"5"."2",'‘2"."г'."Б4".'Т^^^
Рис. 4.190. Результат считывания информациииз потока Main MetaData Stream файла 1Cv7.MD
Здесь следует отметить, что такой способ считывания информации (л№ тинг 4.80):
SetLengthlSx, DataStream.Size);
DataStream.RaadBuffer(Pointer(Sx)A, DataStream.Size);
Memol.Lines.Add(Sx);
может не сработать в том случае, если в потоке есть символы, "усекают** строку.
Более надежный способ (хотя и более медленный):
Var1
Yes: byte;
i; integer;
yffer: PChar;
^?in
" getMemlBuffer, Datastream.Size) ;
OataStream.ReadBuffer(Buffer*,Datastream.Size);
Sx: = "* 1
for i:=0 to (DataStream.Size-1) do
begin
Yes:=0;
// Пропускаем только "читабельные" символы
if (ORD(CHAR(Buffer[i])) in [32..2551) then Yes:=1;
if (ORD(CHAR(Buffer[i])) in (9,10,131) then Yes:=1;
if Yes>0 then begin
Sx:=Sx+CHAR(Buffer(iJ);
end;
end;
Memol.Lines.TEXT:=Sx;
finally
FreeMemtBuffer) ;
end;
end;
Примечание
Исходные тексты этого примера приведены на С0^Р°в0ДИ7^н°м Т^де' диске книги в папке \Par1_1\Chapter_04\Topic_4_4\Read Jrom_lCv7.MD_02.PAS.
Как видите, в потоке Main MetaData stream файла !Cv7.MD хранятся данные об информационной структуре конфигурации базы данных 1 С:Предприятие. В данном случае — информационная структура "нашей" конфигурации.
Примечание
Полное содержание потока приведено на сопроводительном компакт-диске книги в текстовом файле \Part_1\Chapter_04\Topic_4_4\1Cv7_md_Main_MetaData_
Stream.TXT.
Даже простейший визуальный анализ данных из потока Main MetaData Д“еат (Файл lCv7_md_Main_MetaData_Stream.TXT) и данных из файла !Cv7.DD по-
казывает (например, для справочника ФизЛица) следующие закономепн (табл. 4.8).н
Таблица 4.8. Результаты сравнения словаря данных (1Cv7.dq, и потока данных Main MetaData stream для справочника Физлиц, , а
Категория
Поток Main MetaData Stream
Файл 1CV7.DD
Идентификатор справочника
12
Первый член в строке:
{“12", "ФизЛица","Пример", "Список физических лиц"...}
SC12 (имя таблицы)
Строка:
Т=8С12 |
Справочник ФизЛица
Идентификатор реквизита:
ДатаРождения
15
Первый член в строке:
{"15","ДатаРождения","*, "Дата рождения","D",...}
SP15 (имя поля)
Строка:
F=SP15|
(Р)ДатаРождения|D...
Идентификатор реквизита:
Пол
29
Первый член в строке:
("29","Пол","","Пол","Е","0°
, "0", "17" ...}
SP29 (имя поля)
Строка:
F=8P29|(Р)Пол|С
Идентификатор реквизита:
ДомашнийАдрес
16
Первый член в строке:
("16","ДомашнийАдрес","", •Домашний адрес","S","64"...}
SP16 (имя поля)
Строка:
F=SP16|
(Р)ДомашнийАдрес|с|64
ели проанализировать восьмой член в строках потока Main MetaData streaa. о видно, что его значение "чудесным образом" "коррелируется" со значе- ием первого члена строк потока. Например, для регистра Учети.зменений остоянияФизЛиц:
"52","УчетИзмененийСостоянияФизЛиц". ...J.
строке:
'53","ФизЛицо"," *, "", "В", "О", "О","12","О","О","О","О"),
•ачение восьмого члена равно 12, а это соответствует первому члену строки:
12","ФизЛица","Пример",...
га информация будет крайне полезной в том случае, если доступ к базе дая-
■IX 1С:Предприятие осуществляется вне контекста программы 1С. т. е. при |ямых SQL-запросах к таблицам базы данных. Нам эта информация погреется в части II данной книги.
4 доступ к информации 1С из внешних приложений
ПРИМЕЧАНИЕ
Файл 1Cv7.MD содержит значительно больше полезной информации, чем мы здесь охватили. Более подробную информацию о структуре файла 1Cv7.MD можно получить, например, на сайтах Интернета (табл 4.10— далеко не полный список).
Таблица 4.9. Интернет-ресурсы, где можно получить информацию о файле 1uv7.MD
Сайт
Адрес
.—
Гендин, ru
•icv7 MD. Knowledge Ваве::База Знании
http://gendin.ru/md/lndex.html
Т^рсональная страница Федора Езеева
http://1 c.alterplast.ru/1 cv7md/
TuProiect. Open Source
http ://1 Lw4b.ru/
Доступ к данным V7 из других систем. Исследование MD
http ://1 c.proclub.ru/modules/kb/ print.php?storyid=18
•Structured Storage*. The binary structure
of Ole/Compound Documents
(структура Doc-файлов на низком уров
не)
http://user.cs.tu-erlin.de/%7Eschwartz/ pmh/guide.html
■Внутренний формат документов MS WORD', статья
http://www.uinc.ru/articles/39/
•Доступ к MD-файлам при помощи VBA", статья
http://www.klerk.ru/sofV1 c/?2429, http://www.hare.ru/kb/know-how/ article.html?id=59
Доступ к данным V7 из других систем. Исследование MD
http://www.erp-volga.com/hare/kb/
artlcle-8.html|
Примечание
Знания о структуре файла 1 Cv7.MD, доступные сейчас, — результат работы многих людей, сделавших это на общественных началах и безвозмездно. Поэтому список сайтов по данной тематике может быть существенно расширен. Приношу глубочайшие извинения тем авторам сайтов (по данной тематике), которые внесли свой вклад в данный процесс, но не попали в эту таблицу.
Существуют программные модули, ориентированные на работу с Doc- файлами и, в частности, с файлом !Cv7.MD. Например (неполный список):
° DocFile Browser is plugin for FAR Manager. DocFile Browser allows browsing, viewing and changing contents of compound files;
3 compound.dll — внешний компонент для 1С:Предприятие 7.7 (предназначен для работы с compound файлами *.ERT. *.MD);
(1Cv7.MD) в набор текстовых файлов и обратно;(1Cv7.MD) в набор текстовых файлов и обратно;□ gcomp.EXE — инструмент для преобразования файла конфигурации X (1CV7.MD) в набор текстовых Дайлов и пбпатмп-^
(1Cv7.MD) в набор текстовых файлов и обратно;
(1Cv7.MD) в набор текстовых файлов и обратно;
□□□□□□MDtoText.EXE— программа "Конвертор модулей метаданных", npenj знамена для автоматического извлечения текстов модулей из файла мел. данных 1С:Прсдприятия во внешние файлы и обратного преобразован» информации из внешних файлов в файл метаданных (!Cv7.MD);
□
□
□
□
□
□
ExtractMd.EXE— распаковщик MD-файла (создает в текущем каталоге набор файлов/каталогов — точно воспроизводящий все содержимое МО); mdxtractor.EXE — распаковщик MD-файла (разворачивает дерево мели данных).
Все^эти программы имеют статус freeware (бесплатные) и доступны в Интер.
Примечание
Приношу глубочайшие извинения другим разработчикам ПО (freeware), которые внесли свой вклад в этот процесс, но их программы не попали в этот список.
Примечание
Напомню, что приведенные в книге примеры исходных текстов — это упрощенная иллюстрация к рассматриваемым вопросам. Назначение этих примеров — дать представление о возможном подходе при решении задач информационного обмена с системой 1С:Предприятие. При работе с реальными базами 1С может потребоваться их дальнейшая доработка.
4.5. Метод EvalExpr
Система 1С:Предприятие (как сервер OLE Automation) предоставляет полный доступ к своему глобальному контексту. Поэтому объект OLE-сервер 1 С:Предприятие в качестве своих методов может иметь системные процеду- )ы и функции, а также процедуры и функции глобального программного мо- 1уля, объявленные с ключевым словом Экспорт. Кроме того, у OLE-сервера С Предприятие есть три дополнительных метода: initialize, EvalExpr.
:xecuteBatch.
’анее мы уже обращались к методу EvalExpr для решения ряда задач. В этом азделе метод EvalExpr будет рассмотрен более детально.
1етод EvalExpr позволяет вычислить переданное в параметре выражение на строенном языке системы 1С: Предприятие. Синтаксис:
[valExpr (<Параметр>^
Здесь <параметр>— выражение, записанное на встроенном языке ^•Предприятие (тип — Строка). Возвращаемое значение — результат выделенного выражения (число, строка, дата или значение любого агрегатного ^па данных). Результат с неопределенным типом данных преобразуется к строковому типу.
Создадим новый Delphi-проект с именем sp_EvaIExpr_lC.DPR.
Функционально программа sp_EvalExpr_lC.EXE должна обеспечивать соединение с системой 1 С:Предприятие и вызов метода EvaiExpr с заданным параметром. Результат, возвращаемый методом EvaiExpr, должен конвертироваться в тип string и сохраняться в буфере.
НВ ИНВ Иформа проекта представлена на рис. 4.191.
НВ И
НВ И
4>; Вызов метода EvaiExpr
[-Подключение к 1С:*_———
! Имя 1С(как сервера-автоматизации) • V77.Appicaiion
j Соединить | Строка инициал - |/DEA1C_example.DB
г м ^ЗД EvaiExpr:*
Выполнить | lE»_EvaExp<
^Результат:
RE_Fesull
Рис. 4.191. Форма проекта sp_EvalExpr_1C.DPR
Как видите, здесь нет ничего нового по сравнению с тем, что мы делали ранее. По нажатию кнопки Соединить производятся действия, подробно рассмотренные в главе 3. По нажатию кнопки Выполнить вызывается метод EvaiExpr с параметром, значение которого хранится в Edit_EvalExpr.Text. Результат сохраняется в RE_Result.Lines.
Текст обработчика события "нажатие кнопки Выполнить" приведен в листинге 4.81.
Procedure TForml.SpeedButton2Cllck(Sender: TObject) ;
Var
oleRes: OleVariant;// Результат, возвращаемый методом EvaiExpr
sRes: string;
Sx: string;
begin
if not VarlsEhpty (01e_lC_App> then beginI
// Строка-параметр для метода EvalExpr
Sx:=Trim(Edit_EvalExpr.Text);1
if length(Sx)>0 then begin1
// Вызов метода EvalExpr'
oleRee:=Ole_lC_App.EvalExpr(Sx) ;
Конвертируем результат в встроку।
sRes:=Trim (oleRee);
RE_Result. Lines . ADD ( 11 ) •
RE_Result.Lines.ADD('EvalExpr = '-f-Sx);
RE_Result.Lines.ADD(1Result = '+sRes);
end;
Edit_EvalExpr.SetFocus;
end
else begin
ShowMessage('Нет соединения с IC');
end;a
end;
Текст обработчика достаточно прост и пояснений не требует.
ПримечаниеI
Исходный текст проекта sp_EvalExpr_1C.DPR приведен на сопроводительном компакт-диске книги в папке \Part_1\Chapter_04\Topic_4_5\sp_EvalExpr_lC.PAS.
Прежде чем запустить проект sp_EvalExpr_lC.DPR на выполнение, откроем <онфигуратор системы 1С:Предприятие и в глобальном модуле создадим две функции, текст которых приведен в листингах 4.82 и 4.83.
Листинг 4.8^hi метода evЛистинг 4.8^hi метода ev
Листинг 4.8^hi метода ev
Листинг 4.8^hi метода ev
■ункция гл9_А_плюс_Б(А,Б) Экспорт Возврат А+Б;
(онецфункции
нгж^^®^^
|ЯТ0ДаЕУ.1ВФ;|ЯТ0ДаЕУ.1ВФ;Н, W.VU. W у Л.Г ',f_^<.-2klMtetiiSfc?4'.1:>w.'-; "'VV-ti.-V-piS.rVi»^^
|ЯТ0ДаЕУ.1ВФ;
|ЯТ0ДаЕУ.1ВФ;
Функция гл9. ах_плюс_Ь(а,х,Ь) Экспорт доэврат а*х+Ь;
КОнеиФУН!<иии
Как видите, текст обеих функций прост. Каждая из них выполняет простейшую математическую операцию.
Сохраним конфигурацию (см. рис. 2.17).
Теперь запустим наш проект на выполнение, введем в Edit_EvaiExpr.Text значение параметра для EvaiExpr:
гл9_А_ллюс_Б(5, 7)
и нажмем кнопку Выполнить.
Повторим то же самое для другого значения параметра:
гл9_ах_ллюс_Ь (2, 0.5, 2)
«г Вызов метода tvalExpr«г Вызов метода tvalExprВИ 13IIВИ 13IIРезультат представлен на рис. 4.192 и комментариев не требует.
«г Вызов метода tvalExpr
«г Вызов метода tvalExpr
ВИ 13II
ВИ 13II
■ П одкjлючвмте к 1С:,
Имя 1С (как сервера-автоматизации) • |У77 Application
Соединил» | Строка инициал. ■ |/DE:\1C_exampte.DB
Метод EvaExpr: —"Т^—
|| Выпоить | |гл9_ах_плюс.Ь(2.05,2]
Результат:
EvaiExpr - гл9_А_плюс_Б(5.7) Resul-12
Е vaExpt ■ rn9_ax_ruioc_b(Z 0.5,2]
Result - 3
Рис. 4.192. Результат выполнения функций глобального модуля,вызов которых производился с использованием метода EvaiExpr
в табл. 4.10 приведены другие примеры вызова некоторых функций системы ^Предприятие (с использованием метода EvaiExpr) и результаты их выполнения.
232
Таблица 4.7
Значение параметра
Pjlpp^'1' как дела ?????",’ [Кодиимв( * * • )"
, Симв(42)"
—сть1‘ 1С и механизм OLE Aut^^ о. Примерь, истпмовтияEvi
— I РезУльтат выполненияЧ
е’Р^^^^ I как дела ?"
^|<2___
Макс(5, 1, 7 ТЧТ~Л
рин(5, 1, 7 3~ЦЛ
Е°л°н1
[ Перечисление.Сост. фИз. лица •
СостояниеФизлица.неосновному месту паТ*”^ 1
1 СотрудникНеосновной!")ес?У работы
| РабочаяДата()'4 I
Е=™тьме=,„, -22,07,205^—4^—^=^1
Е^Е^паТЧТГотГгооб7) ~7—:—]
EEEEEE1L22. о74оо44L^T^OOeJ
ЕЕЕ^^ГоТРТобл 4-П
HoMeDfto^^7Zr77TZ~rIJ3-07.2006 -J
_ '“^al «12.07.2006")
[ Ka талогИБЛ
1 Ka талогПрограммы(,
p^^^^^
Ц2^льныйРежим()
зо— J
1 Квартал 2006 г^1
^~^^xainpl^?D^1
F:\1Cv77\BIN\j
XDOCUME'l\Sergey\LOCALS-l\Temp|
ОсновнойЯзыкЛ
й^155^^
j^EEEEE^г*
2^ЕЕЕ1рЕЕ^~—'—Ц
^лучитьТАЛ ~- —
и
1
»«игест ос"о->" «=" -
адс^*0”" 0С"°«М — - вП£анномСЯ ЭНеШНЯЯ программа ^Данном случае Notepad.ехе) 5-07.2006
: 2 6:2 8*
-07.06 12:26:28
g предыдущих разделах мы столкнулись с тем, что при считывании инфор- уации из базы данных системы 1 С:Предприятие нужно предпринимать до- п0Лнительные меры, чтобы конвертировать значения агрегатного типа в строку (например, в разд. 4.1.4, листинг 4.12). Эту проблему можно решить проше, если создать в глобальном модуле соответствующую функцию, кото- рая будет преобразовывать значение переданного ей параметра (любого типа) в строку. Текст функции приведен в листинге 4.84.
^':_ШШ&
// Получить строковое представление объекта
U для вызова через EvalExpr
//с использованием механизма OLE Automation
Функция гл9_ОбъектКояеертироватъВСтроку(Объект) Экспорт
Возврат СокрЛП(Объект);
КонецФункции
Текст функции гл9_ОбъектКонвертироватьвстроку достаточно прост, пояснения не требуются. В листинге 4.85 приведены примеры вызова этой функции. а на рис. 4.193 — результат выполнения.
гл9_0бъектКонвертироватьВСтроку("325.75")
гл9_СбъектКонвертироватьВСтроку ("12.01.2006")
"л9_О5ъектКонвертироватьВСтроку (Перечисление. СемейноеПоложение. НикогдаНеСостоялВБраке)
Метод EvalExpf;:■
Выполнить I 6"л9_06ьектКонеертироеать8Строку(Пере*мсление Семейное
['Результат; —
Е*аСчх - гл9 0 6ъектКо«еертирооггь8Строк1)("325.75")
RetuK - 325.75
EvalExpf-гл9 ОбъектКонвертировзтьВСтрок;М"12.01.2006 )
Ае-.а. 12.01.2006
fvdEwTrrflo^^
^etuk- Никогда не состоял (не состояла в браке)—
Рис. 4.193. Результат выполнения функций глобального модулягл9_ОбъектКонвертироватьВСтроку
Во всех приведенных примерах использования метода EvalExpr в качеств параметра передается значение (но не переменная). Кроме этого, кажд^ вызов метода EvalExpr производится вне зависимости от предыдущих в^, зовов. Это существенное ограничение при его практическом использов^ нии. Чтобы решить эту проблему, объявим в глобальном модуле "наше#* конфигурации переменную (массив длиной 100) с ключевым словом экспорт (листинг 4.86).
■lR4z*№W$esre«9asi№i^ модуле для использо■lR4z*№W$esre«9asi№i^ модуле для использо
■lR4z*№W$esre«9asi№i^ модуле для использо
■lR4z*№W$esre«9asi№i^ модуле для использо
U Для внешних обращений через OLE (методы EvalExpr и ExecuteBatch)
Перем гл9Буф*рДляОЬЕ(ЮО] Экспорт;
Теперь мы можем вызывать метод EvalExpr с сохранением результата в элементе массива глЭБуферДляоьв, а во всех последующих вызовах метода EvalExpr использовать значение этого элемента массива в виде входного параметра. В листинге 4.87 приведен простой пример, иллюстрирующий этот способ.
нг 4.87. Пример использования переменной глЭБуферДляоьвисло) . ..,.'^^М'
ВвестиЧисло(гл9БуферДляОЬЕ(1], "Введите какое-нибудь число", 12, 2, 60) гл9_ОбъектКонвертироватьВСтроку(глЭБуферДляОЬХ[1])
Результат вызова метода ВвестиЧисло приведен на рис. 4.194.
["МетодEvaExpr:у ■. • :" ■-■ ■ ■■[ | Выловить |в вестиЧ ис ло(гл9Б аферД ляО LE11L "Ваёдк["МетодEvaExpr:у ■. • :" ■-■ ■ ■■[ | Выловить |в вестиЧ ис ло(гл9Б аферД ляО LE11L "ВаёдкГ Результат :Г Результат :Рис. 4.194. Вызов метода ВвестиЧисло с использованием метода EvalExpr и переменной глЭБуферДляОБЕРис. 4.194. Вызов метода ВвестиЧисло с использованием метода EvalExpr и переменной глЭБуферДляОБЕ
["МетодEvaExpr:у ■. • :" ■-■ ■ ■■
[ | Выловить |в вестиЧ ис ло(гл9Б аферД ляО LE11L "Ваёдк
["МетодEvaExpr:у ■. • :" ■-■ ■ ■■
[ | Выловить |в вестиЧ ис ло(гл9Б аферД ляО LE11L "Ваёдк
Г Результат :
Г Результат :
Рис. 4.194. Вызов метода ВвестиЧисло с использованием метода EvalExpr и переменной глЭБуферДляОБЕ
Рис. 4.194. Вызов метода ВвестиЧисло с использованием метода EvalExpr и переменной глЭБуферДляОБЕ
Примечание
Напомню, что диалоговые окна, которые вызываются при обращении к программе 1С:Предприятие (в качестве сервера OLE Automation), могут быть скрыты окнами других приложений. Для их ‘поиска" можно использовать сочетание клавиш <Alt>+<Tab>.
результат выполнения команд (листинг 4.87) приведен на рис. 4.195.
-Т=ТТ7Т=^
'л^ОЛлктКонв^т^^'л^ОЛлктКонв^т^^Метод EvaExpc
'л^ОЛлктКонв^т^^
'л^ОЛлктКонв^т^^
Выполнить I - Результат:
EvaiExpr - ВвестиЧисло(гл9БуФерДляО1£(11. "Введите какое+ыбудь число". 12.2.60)
Result-1
EvaiExpr - m3 06ьектКо«ертироеатьВСтр<жу(глЖуФерДля01Е|1В
Rest» -321.79
РИС. 4.195. Результат выполнения команд, приведенных в листинге 4.87
2],"Выберите Физ.Лицо из списка", ВвестиЗначение (гл9БуферДпяОьЕ121н2],"Выберите Физ.Лицо из списка", ВвестиЗначение (гл9БуферДпяОьЕ121н"Справочник.ФизЛица")"Справочник.ФизЛица")гл9_0бъектКонвертироватьВСтроку(гл9БуферДляОЪЕ.,гл9_0бъектКонвертироватьВСтроку(гл9БуферДляОЪЕ.,ТИНГ 4.88.СпрТИНГ 4.88.СпрРезультат выполнения командыРезультат выполнения командыТочно так же можно использовать переменную глЭБуферДляОЬЕ для хранения значений агрегатного типа. В листинге 4.88 приведены команды, иллюстрирующие выбор значения типа Справочник и сохранение этого значения в элементе Массива глЭБуферДляОЬЕ.
2],"Выберите Физ.Лицо из списка", ВвестиЗначение (гл9БуферДпяОьЕ121н
2],"Выберите Физ.Лицо из списка", ВвестиЗначение (гл9БуферДпяОьЕ121н
"Справочник.ФизЛица")
"Справочник.ФизЛица")
гл9_0бъектКонвертироватьВСтроку(гл9БуферДляОЪЕ.,
гл9_0бъектКонвертироватьВСтроку(гл9БуферДляОЪЕ.,
ТИНГ 4.88.
Спр
ТИНГ 4.88.
Спр
Результат выполнения команды
Результат выполнения команды
окно для выбора значения агрегатного типаокно для выбора значения агрегатного типаВвестиЗначение представлен на рис. 4.196.
окно для выбора значения агрегатного типа
окно для выбора значения агрегатного типа
На экране появилось диалоговое Справочник (ВИД ФизЛица). Результат выполнения команд (листинг 4.88) приведен на рис. 4.197. Особенностью метода EvaiExpr является отсутствие возможности выполнения команд вроде следующей:
^alExprCA - 5 + 7")
Ото может быть существенным ограничением при выполнении цепочки последовательных вызовов метода EvaiExpr. Например, нет возможности выполнить метод создатьОбъект. Эту проблему можно легко решить, создав 8 глобальном модуле конфигурации соответствующую функцию (листинг 4.89).
|"Метод EvaExpr ;■—:—-.-....l:;|| | Вытолнить |бвестиЗначегке(гл9БуферДляО1Е[21"Вы6еритс Фиэ.Лицоиз|"Метод EvaExpr ;■—:—-.-....l:;|| | Вытолнить |бвестиЗначегке(гл9БуферДляО1Е[21"Вы6еритс Фиэ.Лицоиз1ГРезультат: —1ГРезультат: —е Фи1.Лицо из списка (Выбор) (22.07.06) (Все)е Фи1.Лицо из списка (Выбор) (22.07.06) (Все)Выбор.Выбор.u au aСлисок Физических. 1□ Группа-1J Группа-22J Группа-3Слисок Физических. 1□ Группа-1J Группа-22J Группа-3**НаименованиеАксакалов Аксакал АхсакаловичГрута-1Грулпа-2НаименованиеАксакалов Аксакал АхсакаловичГрута-1Грулпа-21 ЭЦГруппа-З1 ЭЦГруппа-З№1 №1 № Ml№1 №1 № MlИванов Иван ИвановичИванов Иван ИвановичБ Ц Крког ейоваФехгиМаринмоё^^^^™—I П строе Петр Петрович Сидоров Сидор Сидорович Федоров Федор ФедоровичБ Ц Крког ейоваФехгиМаринмоё^^^^™—I П строе Петр Петрович Сидоров Сидор Сидорович Федоров Федор Федорович^^
|"Метод EvaExpr ;■—:—-.-....l:;
|| | Вытолнить |бвестиЗначегке(гл9БуферДляО1Е[21"Вы6еритс Фиэ.Лицоиз
|"Метод EvaExpr ;■—:—-.-....l:;
|| | Вытолнить |бвестиЗначегке(гл9БуферДляО1Е[21"Вы6еритс Фиэ.Лицоиз
1ГРезультат: —
1ГРезультат: —
е Фи1.Лицо из списка (Выбор) (22.07.06) (Все)
е Фи1.Лицо из списка (Выбор) (22.07.06) (Все)
Выбор.
Выбор.
u a
u a
Слисок Физических. 1
□ Группа-1
J Группа-2
2J Группа-3
Слисок Физических. 1
□ Группа-1
J Группа-2
2J Группа-3
*
*
Наименование
Аксакалов Аксакал Ахсакалович
Грута-1
Грулпа-2
Наименование
Аксакалов Аксакал Ахсакалович
Грута-1
Грулпа-2
1 ЭЦГруппа-З
1 ЭЦГруппа-З
№1 №1 № Ml
№1 №1 № Ml
Иванов Иван Иванович
Иванов Иван Иванович
Б Ц Крког ейоваФехгиМаринмоё^^^^™—I П строе Петр Петрович Сидоров Сидор Сидорович Федоров Федор Федорович
Б Ц Крког ейоваФехгиМаринмоё^^^^™—I П строе Петр Петрович Сидоров Сидор Сидорович Федоров Федор Федорович
^
^
Рис. 4.196. Вызов метода ВвестиЗначение (для агрегатного типа Справочник)с использованием EvalExpr и переменной гл9БуферДля0ЬЕ
^етод EvaExpc;
Выполнить | |М_06ъектКонеертироеатьВСт1)ок14г.в£»^'
’езультат.;
Si’ ВвестиЗначвн1е(гл9БуФеРДляО1Е[21. "Выберите Физ. Лицо из стека-СправочникФизЛица")
^и^0и^Тиво^Г^Ст^
Рис. 4.197. Результат выполнения команд, приведенных в листинге 4.88
зЫ-зЫ-:тимг 4.89. Функ
зЫ-
зЫ-
ДатьОб-ьект
(ункция "СоэдатьОбъект* для вызова через EvalExpr использованием механизма OLE Automation
ция гл9_Совдатъ0б»ехт(Имя0бъекта,НомерЭлементаМассива) Экспорт 3 = 0;
и СтрДлина(СокрЛП(ИмяООъекта))>0 Тогда
КолвоЭлем=Разм(глЭБуферДляОЬЕ);
Если (НомерЭлементаИассива>0) И (НомерЭлементаМассива<=КолвоЭлем)
7огЯа
-деуферДляОЬЕ[НомерЭламентаМассива]=СоЗдать0б»ект(""+СокрЛП(ИмяОбъекта))
Res = 1;
КоненЕсли;
КоненЕсли;
Возврат Ree;
КонеиФУнкнии
Поясним текст функции гл9_Создать0бъект.
Входные параметры функции:
имяОбъекта— полное имя объекта (как оно объявлено в конфигурации), включая имя типа данных и идентификатор объекта (например. Справочник.ФизЛица);
номеоЭлементаМассива — номер элемента массива гл9БуферДляоьв, которому будет присвоен результат функции создатьОбъект.
В строке
КолвоЭлем=Разм(гл9БуферДляОЬЕ) ;
получаем размер массива (переменная глэвуфердлясьв).
Далее проверяем корректность значения входной переменной номерЭлемен- таМассива:
Если (Но.мерЭлементаНассива>0) И (НомерЭлементаМассива<=КолвоЭлем) Тогда
И, наконец, вызываем метод СоздатьОбъект. Результат сохраняем в заданном элементе массива глЭБуферДляОЕЕ:
глЭБуферДдяОЬЕ [НсмерЭленантаМассива] =СоздатьОб-ьект (*" +СокрЛП (ИияОбъокта)) ;
В листинге 4.90 приведен пример вызова функции гл9_создать0бъект.
BvalExpr = гл9_СсздатьО6»ект("Справочник.ФизЛица", 1)
Result = 1
EvalExpг = ТипЗначеиия(гл9БуферДляОЬЕ[1])
Result = 11
EvalExpr = ТипЗкачокияСтр(гл9БуферДляОЬЕ[1]) Result = Справочник
238
|3десь сначала создается объект справочник.Физлица. Ссылка на объект^ храняется в элементе с номером 1 массива глЭБуферДляоьв. Затем опреду,^ рте я тип значения элемента с номером 1 массива гл9БуферДляоьв.
ропробуем решить с помощью разработанных функций глобального моду^ 5олее прикладную задачу, например, попытаемся прочитать ФИО "физиче. ркого лица" с заданным кодом (аналог того, как мы это делали ранее, — лис- "инг 4.5). В листинге 4.91 представлен перечень команд, решающих эту задачу
Листинг 4.91. Пример использования функции гл9_сбвдать05»ехт:'чтенйеЭ;;^
п9_Соэдать06-*ект("Справочник.ФизЛица", 1)
*естиЧиопо(гл9БуферДляОЬЕ[2], "Введите код физ. лица", 10, 0, 60)- ’
19БуферДляОЬЕ(1].НайтиПоКоду(ЧИСЛО(глЭБуферДляОЬЕ(2]),0)
1
,есь (как и в предыдущем примере) создается объект Справочник.ФизЛица, ллка на который сохраняется в элементе с номером 1 массива ЭБуферДляоьв. Затем с помощью метода ВвестиЧисло вводится код "физи- жого лица" (например 5, рис. 4.198).
Физ лица". гРеэцльтег::—-Физ лица". гРеэцльтег::—-' EvalExpi - гл9_Создвть06ьект("Спрдвочник ФизЛица"' EvalExpi - гл9_Создвть06ьект("Спрдвочник ФизЛица"Выполнить |Число(гл9БуферДляОЕЕ[2]. "Введите код
Физ лица". гРеэцльтег::—-
Физ лица". гРеэцльтег::—-
' EvalExpi - гл9_Создвть06ьект("Спрдвочник ФизЛица"
' EvalExpi - гл9_Создвть06ьект("Спрдвочник ФизЛица"
Рис. 4.198. Ввод кода ‘физического лица" (листинг 4.91)
р-9!) приведен на рис. 4.199.р-9!) приведен на рис. 4.199.е с помощью метода НайтиПоКоду справочника позиционируем спра- к на элементе справочника с кодом 5. Затем вызываем функцию . .^к^онвертиРоватьВстроку. В качестве параметра передаем ей зна- шпеМСНТа массива гл9БуферДляоьЕ[1) (это справочник, который лози- ва» на элементе с кодом 5). Результат выполнения команд (лис-
р-9!) приведен на рис. 4.199.
р-9!) приведен на рис. 4.199.
РИС. 4.199. Результат выполнения команд, приведенных в листинге 4.91РИС. 4.199. Результат выполнения команд, приведенных в листинге 4.91
РИС. 4.199. Результат выполнения команд, приведенных в листинге 4.91
РИС. 4.199. Результат выполнения команд, приведенных в листинге 4.91
Посмотрим, каким образом можно использовать объект СписокЗначений (при обращении через метод EvalExpr). Добавим в глобальный модуль конфигурации еще одну функцию гл9_СписокЗначений_лобавитьЗначение. Ее назначение — вызов "штатного" метода ДобавитьЗначение объекта СписокЗначений. Текст функции приведен в листинге 4.92.
И Функция вызывает метод "ДобавитьЗначение* для объекта "СписокЗначений Функция гл9_СписокЗначений_ДобааитьЗначениа(СписЗнач,Знач,ЗначСтр=° *)И Функция вызывает метод "ДобавитьЗначение* для объекта "СписокЗначений Функция гл9_СписокЗначений_ДобааитьЗначениа(СписЗнач,Знач,ЗначСтр=° *)
И Функция вызывает метод "ДобавитьЗначение* для объекта "СписокЗначений Функция гл9_СписокЗначений_ДобааитьЗначениа(СписЗнач,Знач,ЗначСтр=° *)
И Функция вызывает метод "ДобавитьЗначение* для объекта "СписокЗначений Функция гл9_СписокЗначений_ДобааитьЗначениа(СписЗнач,Знач,ЗначСтр=° *)
Экспорт
res = 0;
СписЗнач.ДобавитьЗначение(Знач,ЗначСтр);
res = 1;
Возврат res;
КонецФункции
Текст функции достаточно прост и пояснений не требует.
Теперь (используя метод EvalExpr) последовательно выполним следующие команды (листинг 4.93).
fc^?^
^Э-СоздатьОбъект("Справочник.ФизЛица", 1)
плЭСоздатьОб-ъект (* СписокЗначений", 2) гл9БуферДляОЬЕ[ 1) .НайтиПоКоду(1,0)
счиЧасть I. 1С и механизм OLE dufo^
гл9_СписокЗначемий_ДобавитьЗначекие(глЭБуферДляОЬЕ[ 2 ],|
глЭБуферДляОЬЕ[1].ТекущийЭлемент())
глЭБуферДляОЬЕ(1].НайтиПоКоду(2,0)
гл9_СписокЗначений_ДобавитьЗначение(глЭБуферДляОЬЕ[2],
глЭБуферДляОЬЕ[ 1).ТекущийЭлемент())
гл9БуферДляОЬЕ[1].НайтиПоКоду(3,0)-
1гл9_СписокЗначений_ЛобавитьЗначение(глЭБуферДляОЬЕ[2], глЭБуферДляОЬЕ(1) .ТекущийЭлемент())
глЭБуферДляОЬЕ[2].ВыбратьЗначенив(глЭБуферДляОЬЕ[3]) ",л9_0б'ъектКон»ертироватьВСтроку (глЭБуферДляОЬЕ [ 3 ])
(десь создаются объекты Справочник.ФизЛица и СписокЗначений. Затем справочник Физлица поочередно позициионируется на элементах справочника кодами 1, 2 И 3. Каждый раз СВОЙСТВО ТекущийЭлемент добавляется в список начений:
1п9_СписокЗначений_ДобавитьЗкачение(глЭБуферДляОЬЕ[2], глЭБуферДляОЬЕ[1] .ТекущийЭлемент())
алее вызывается метод ВыбратьЗначенив объекта СписокЗначений. результате на экране появится диалоговое окно (рис. 4.200).
ЦЦЩЦх]
ок
Петров Петр Петрович~™*
Сидоров Сиаор Сидорович
Отмена
Помощь
Рис. 4.200. Результат вызова метода ВыбратьЗначенив объекта СписокЗначений | еле выбора какой-либо строки из списка значений в элементе массива 'БуферДляоьЕ(з) будет храниться ссылка на соответствующий "текущий мент" справочника Физлица. Здесь следует отметить, что в гл9БуфердляоьЕ(3] I нится именно ссылка на объект агрегатного типа ТекущийЭлемент спра- ника. Го есть в дальнейшем мы можем обращаться ко всем свойствам етодам этого объекта.I
ее вызывается функция гл9_ОбъектКонвертироватьвстроку, которой честве входного параметра передается ссылка на выбранный текущий | <ент справочника. В результате получим ФИО соответствующего "физи- 4 <ого лица":
pit = Иванов Иван Иванович
При использовании метода EvalExpr и массива глЭБуферДляоьЕ может по- ^оваться функция, которая позволит присвоить элементу массива двуферДляоьв заданное значение. В листинге 4.94 представлен текст функ
ции гл9_ПрисвоитьЗначениеЭлементуМассива.
^стинг^^и^
ива гл!
ц присвоение значения элементу массива для вызова через EvalExpr
// с использованием механизма OLE Autonation
- ""в ПомсеоитьЗначеииеЭламентуМассижа(Объект,НомерЭлементаМассива)
Экспорт
Res = 0;
КолвоЭлем=Разм(глЭБуферДляоьЕ);
Если (НомерЭлементаМассива>0) И (НомерЭлементаМассива<=КолвоЭлем) Тогда глЭБуферДляОЬЕ[НомерЭлемектаМассива] = Объект;
Res = 1;
КонецЕсли;
Возврат Res;
КонецФункции
функцию4.95 пред-функцию4.95 пред-Посмотрим, каким образом можно использовать гл9_ПрисвоитьЗначениеЭлементуМассива на практике. В листинге ставлен пример выбора значения перечисления.Посмотрим, каким образом можно использовать гл9_ПрисвоитьЗначениеЭлементуМассива на практике. В листинге ставлен пример выбора значения перечисления.гл9 ПрисвоитьЗначениеЭлемеятуМассива(*СостояниеФиалица*, 1)ВвестиПеречисление(глЭБуферДляОЬЕ[1],*Выберите перечисление*)гл9 ПрисвоитьЗначениеЭлемеятуМассива(*СостояниеФиалица*, 1)ВвестиПеречисление(глЭБуферДляОЬЕ[1],*Выберите перечисление*)гл9.ОбъектКонввртироватьВСтроку(глЭБуферДляОЬЕ[1])гл9.ОбъектКонввртироватьВСтроку(глЭБуферДляОЬЕ[1])
функцию
4.95 пред-
функцию
4.95 пред-
Посмотрим, каким образом можно использовать гл9_ПрисвоитьЗначениеЭлементуМассива на практике. В листинге ставлен пример выбора значения перечисления.
Посмотрим, каким образом можно использовать гл9_ПрисвоитьЗначениеЭлементуМассива на практике. В листинге ставлен пример выбора значения перечисления.
гл9 ПрисвоитьЗначениеЭлемеятуМассива(*СостояниеФиалица*, 1)
ВвестиПеречисление(глЭБуферДляОЬЕ[1],*Выберите перечисление*)
гл9 ПрисвоитьЗначениеЭлемеятуМассива(*СостояниеФиалица*, 1)
ВвестиПеречисление(глЭБуферДляОЬЕ[1],*Выберите перечисление*)
гл9.ОбъектКонввртироватьВСтроку(глЭБуферДляОЬЕ[1])
гл9.ОбъектКонввртироватьВСтроку(глЭБуферДляОЬЕ[1])
По определению, в "штатную" функцию ВвестиПеречисление передается переменная, которая должна содержать значение типа перечисление или иден- тификатор соответствующего перечисления. Поэтому сначала вызывается Функция гл9_ПрисвоитьЗначениеЭлементуМассива, где элементу массива пРисваивается идентификатор нужного перечисления (в данном случае с°етояниеФизлица). В результате элементу с номером 1 массива рл9БуферДдяоьЕ будет присвоено значение СостояниеФизлина типа строка.
242242[Выберите перечне пение[Выберите перечне пениеосновному мест'основному мест'Временно не работаетВременно не работаетунищо неосноеномчунищо неосноеномчокОтменаПомощьокОтменаПомощьРис. 4.201. Выбор значения пер,числени„ ^„„„.^^Рис. 4.201. Выбор значения пер,числени„ ^„„„.^^
242
242
[Выберите перечне пение
[Выберите перечне пение
основному мест'
основному мест'
Временно не работает
Временно не работает
унищо неосноеномч
унищо неосноеномч
ок
Отмена
Помощь
ок
Отмена
Помощь
Рис. 4.201. Выбор значения пер,числени„ ^„„„.^^
Рис. 4.201. Выбор значения пер,числени„ ^„„„.^^
Часть I. 1Си механизм OLE Autom^^ Затем вызывается функция ввестиПеречисление, куда передается иденти*# катор перечисления (переменная гл9ВуферДляоьЕ[1]). В результате на экр^ появится диалоговое окно выбора значения перечисления (рис. 4.201).
Метод —■
^«^Jnep^^Выберите переч*^
тлел । ицжкатор перечисления можно вводить интерактивно, в диалого кне. Для этого вместо функции:
л9_ПрисаоитьЗначекивЭлвментуМассиеа("СостсяниеФизлиц.1 °,1)
листинге 4.95 нужно использовать функцию:
идентификатор перечисления",64)идентификатор перечисления",64)(гл9ВуферДляОЬЕ[1],"Введите
идентификатор перечисления",64)
идентификатор перечисления",64)
окно для ввода значений типа Строокно для ввода значений типа Строрис. 4.202 представлено диалоговое
окно для ввода значений типа Стро
окно для ввода значений типа Стро
^Метод EvaExpr;*•-:
^^_иАемтиФик<чор перечислений
оямиеФизлиц^
| ОК ~| Отмена [ Помощь |Рис. 4.202. Интерактивный ввод идентификатора перечисления
<чение любого типа данных, доступного в конфигурации, можно сохра- ь в файле (функция ЗначениеВФайл), а затем прочитать из файла (функция чениеИзФайла). Так можно сохранять значения элементов массива
дкуферДляОЬЕ (если в этом будет необходимость) между сеансами работы с системой I С: Предприятие. Пример приведен в листинге 4.96.
нгнггЛ9БуферДляОЬЕ[2].ВибратьЗначеииа(гл9БуферДляОЬЕ[3])здачениеВФайл("С:\1С_ЗначениеВФайл.dat",гл9БуферДляОЬЕ[3])гЛ9БуферДляОЬЕ[2].ВибратьЗначеииа(гл9БуферДляОЬЕ[3])здачениеВФайл("С:\1С_ЗначениеВФайл.dat",гл9БуферДляОЬЕ[3])
нг
нг
гЛ9БуферДляОЬЕ[2].ВибратьЗначеииа(гл9БуферДляОЬЕ[3])
здачениеВФайл("С:\1С_ЗначениеВФайл.dat",гл9БуферДляОЬЕ[3])
гЛ9БуферДляОЬЕ[2].ВибратьЗначеииа(гл9БуферДляОЬЕ[3])
здачениеВФайл("С:\1С_ЗначениеВФайл.dat",гл9БуферДляОЬЕ[3])
гЛ9_ССъектКонвертироватьВСтроку (ЗначениаИзФайпа ("С: \ 1С_ЗначениеВФайл. dat"))
Еше одно полезное применение метода EvaiExpr может быть в том. чтобы открывать отчеты и другие внешние формы (обработки). Для этого используется функция открытьФорму системы 1С:Предприятие. Но чтобы открытая форма была доступна пользователю, нужно открыть главное окно программы 1С:Предприятие. Этот вопрос мы рассмотрим в следующем разделе.
Метод ExecuteBatch
В предыдущем разделе мы подробно рассмотрели метод EvaiExpr. Все бы хорошо, но каждую строку команды приходится выполнять отдельно кроме того, невозможно использовать управляющие конструкции и операторы. В этом разделе мы рассмотрим метод ExecuteBatch, свободный от этих недостатков.
Мегод ExecuteBatch позволяет выполнить заданную входным параметром по- следовательность операторов на встроенном языке системы 1С:Предприятие. Синтаксис:
ExecuteBatch(<СтрокаОператоров>)
Параметр: <строкаОператоров>— строковое выражение (текст программы на встроенном языке 1С:Предприятие). Метод возвращает значение логического типа: true— если последовательность операторов выполнена успешно; false — если нет.
Примечание
В OLE Automation true и false имеют соответственно значения -1 (минус единица) и 0.
244
На основе предыдущего проекта (sp_EvalExpr_iC.DPR) создадим новц| Delphi-проект с именем sp_ExecuteBatch_lC.dpr. Форма проекта представлен^ на рис. 4.203.
ВВЕЗВВЕЗ^ Вызов метода ExecuteBatch
ВВЕЗ
ВВЕЗ
Г Подключение к 1С:-""' ' *
j Имя 1С (как серверааетоглатизации) ■ [wTAppiicaiion
Соединить Строка инициал. = |/DEA1C_example.DB
j Показать Скрыть |
Г Метод EvaExpi:
Выполнить |Ed<_EvaExpt
--Результат:т:——? —;—
t RE_Resuit
•*** • " ■ - ’-~ -~ nn~n~Ff*iSA£iA гМетод ExecuteBatch; — I Выполнить [ гТекст:
'4'4|RE_ExecuteBatch
'4
'4
Рис. 4.203. Форма проекта sp_ExecuteBatch_1C.DPR
как видите, здесь появились две новые кнопки Показать и Скрыть (группа исключение к 1С), а также новая группа Метод ExecuteBatch.
ак уже говорилось, в некоторых случаях (например, вызов "штатной" функ- 1и ОткрытьФорму) необходимо, чтобы окно программы 1С:Предприятие режиме сервера OLE Automation) было открыто (по умолчанию в этом ре- име оно скрыто). Рассмотрим процесс визуализации окна программы :Предприяте более подробно.
кекцию public главной формы нашего Deiphi-проекта внесем новое своЙ- РО hwic (листинг 4.97).
Истинг4.97.
mblic
( Public declarations )
// Ссылка на IC, как сервер OLE Automation Ole_lC_App: OleVariant;
// Дескриптор главного окна приложения 1С hWlCs hWND;
end;
Для того чтобы открыть окно любого приложения в среде Windows, нужно п0Лучить дескриптор окна. Зная дескриптор окна приложения, можно вызвать функцию showwindow с соответствующими параметрами. Синтаксис:
gOCL Showwindow (
HWND hwnd, И Дескриптор окна приложения
int ncmdShow И Режим визуализации окна приложения
);
Из всех допустимых значений параметра ncmdShow в данном случае будем использовать два значения:
sw_SHowr— показать окно приложения;
sw_hide — скрыть окно приложения.
Остается только каким-то образом получить дескриптор окна запущенной программы 1С:Предприятие. Возможный способ— получить список всех окон приложений, находящихся в памяти компьютера, и выбрать то окно, заголовок которого совпадает с искомым. В листинге 4.98 представлен текст функции, формирующей список окон запущенных приложений.
function ep_GetListOfWindcwsNemoB (List: TStrings): integer;
И Получение списка окон запущенных приложений.
// Список окон формируется в переменной List (список).
Ч Возвращаемое значение - число строк в списке List.
Const
Sep = '_[=>';
Var
hW: hWND;
Exit99: byte;
Sx: string;
CCC: array [0..255] of char;
begin
Result:=0;
if ListoNIL then begin
List.Clear;
246246Часть I. 1Си механизм OLF Aut
246
246
hW:-GetTopWindow(0) ;
if hW >32 then begin
Exit99:=0;
while Exit99<=0 do begin
hW: =GetNextWindow (hW, GW_HWNDNEXT) ;
if hW>32 then begin
GetWindowText(hW,CCC,SizeOf(CCC)) Sx:=StrPAS(CCC);
Sx:=Trim(Sx);
List.Add(Sx+Sep+IntToStr(hW));
end
else begin Exit99:=l;
end;
end;
end;
Result:=List.Count;
2nd;
1;
:сь для формирования списка окон и их дескрипторов используются си» !НЫе функции Windows GetTopWindow, GetNextWindow И GetWindowText.
Примечание
Функция sp_GetListOfwindowsNames не ориентирована исключительно на систему 1С, скорее, она имеет общесистемный характер. Поэтому подробно рассматривать ее мы не будем.
-ловок окна программы 1С:Предприятие начинается с цепочки символов Предприятие". То есть среди списка окон, сформированных функцией ietListofwindowsNames, нужно искать окно, заголовок которого начина- с этой цепочки символов. Эту операцию выполняет функций etHandieThiswindow, текст которой здесь не приводится по причине его иальности, но его можно найти в файле \sp_Lib\sp_Lib_Delphi.PAS на оводительном компакт-диске книги.
ним обработчик события "нажатие кнопки Соединить" следующим об*
1 (листинг 4.99).
procedure TForml.SpeedButtonlClick(Sender: TObject); Il соединение с IC
begin
01e_lC_App:=UnAssigned;
// обнуляем значение переменной,
// содержащей дескриптор окна 1С:Предприятие
ЫПС:=0;
Edit_lCsrv.Color:=clWhi te;
Edit_lCinit.Color:=clWhite;
// Соединяемся с IC
01e_lC_App: =ConnectTolC (Edi t_lCinit. Text} ;
if not VarlsEmpty(Ole_lC^App) then begin
Edit_lCsrv.Color:=c1Yellow;
Edit_lCinit.Color:=clYellcw;
Edit_EvalExpr.SetFocus;
//
// Найдем окно запущенного приложения 1С и получим
// дескриптор главного окна приложения 1С
hWlC:=»p_QetHandleThi «Window( ' IC:Предприятие•, 1,TRUE,TRUE);
if hWlC<=32 then begin
hW!C:=0;
ShowMessage('Главное окно приложения IC не найдено !'); end;
И_
end;
end;
Поясним текст обработчика.
После того как программа 1С:Предприятие запущена в режиме сервера OLE Automation, производится поиск (функция sp_GetHandleThisWindow) °кна программы, заголовок которой начинается с цепочки символов "1С:Предприятие". Значение дескриптора найденного окна присваивается переменной hwic.
Создадим обработчики события "нажатие кнопки" для кнопок Показать и Скрыть (листинги 4. КХ) и 4.101 соответственно).
r^S"r^S"ЭМИК®ЭМИК®
r^S"
r^S"
ЭМИК®
ЭМИК®
Часть I. 1С и механизм OLE Auto
procedure TForrnl. SpeedButton3Clic)c (Sender: TObject) ; eg in
if not VarlsBnpty(Ole_lC_App) then begin
if hWlC>32 then begin
// Показать главное окно приложения IC
ShowWindow(hWlC,SW_SHOT);
end;
end;
edure TForml.SpeedButton4Click(Sender: TObject); in
if not VarlsErapty(Ole_lC^App) then begin
if hWlC>32 then begin
II Скрыть главное окно приложения IC ShowWindow (hWlC, SW_HHe) ;
end;
nd;
>боих случаях вызывается системная функция showwindow с соотв |щим параметром.
Примечание
Исходные тексты проекта sp_ExecuteBatch_.1C.DPR есть в папке \Part_1\Chapter_OA
Topic_4_6\sp_ExecuteBatch_1C.PAS на сопроводительном компакт-диске книги.
ерь можно проверить, как работает наш проект.
Примечание
Для поиска окна программы 1С:Предприятие мы использовали тот факт, что за* головок окна программы начинается с цепочки символов *1С:Предприятие'- Если в среде Windows запущено несколько приложений, окна которых начинаются с такой же цепочки символов, то обработчик SpeedButtoniclick (листинг 4.99) сработает некорректно. На самом деле заголовок окна программы 1С:Предприятие имеет значительно больше символов и на практике для болев точной идентификации окна программы нужно использовать этот факт.
10В10ВВВЕЗВВЕЗ| Текст;| Текст;Д1 (/.Предприятие - ЗадачаД1 (/.Предприятие - ЗадачагМетсй Executes ai Г Выполнить УгМетсй Executes ai Г Выполнить У। Метод EvaExpi;Г 8ылолнить[ °™Раиии СерВИ‘ -- -Разжат; h ^ Ц? й ' s ,Ъ ^*4 S С ^। Метод EvaExpi;Г 8ылолнить[ °™Раиии СерВИ‘ -- -Разжат; h ^ Ц? й ' s ,Ъ ^*4 S С ^Для гюпучеиия подсказки нажмите F1Для гюпучеиия подсказки нажмите F1Рис 4.204. Открытое окно программы 1С:Предприятие (в режиме сервера OLE Automation)Рис 4.204. Открытое окно программы 1С:Предприятие (в режиме сервера OLE Automation)
10В
10В
ВВЕЗ
ВВЕЗ
| Текст;
| Текст;
Д1 (/.Предприятие - Задача
Д1 (/.Предприятие - Задача
гМетсй Executes ai Г Выполнить У
гМетсй Executes ai Г Выполнить У
। Метод EvaExpi;
Г 8ылолнить[ °™Раиии СерВИ‘ -- -
Разжат; h ^ Ц? й ' s ,Ъ ^*4 S С ^
। Метод EvaExpi;
Г 8ылолнить[ °™Раиии СерВИ‘ -- -
Разжат; h ^ Ц? й ' s ,Ъ ^*4 S С ^
Для гюпучеиия подсказки нажмите F1
Для гюпучеиия подсказки нажмите F1
Рис 4.204. Открытое окно программы 1С:Предприятие (в режиме сервера OLE Automation)
Рис 4.204. Открытое окно программы 1С:Предприятие (в режиме сервера OLE Automation)
= "я"5«^
крывать, естественно.
пипуем проект и запустим на выполнение. Нажмем кнопку Соеди- ^"TZm кнопку Показав. Результат представлен на рис. 4.204.
■г -Вызов методе ExecuteBMrh
M^Z^^^- f^=
Совд^пь | Строка итмииал - |/DEMC_exam( Показать | Скрыть ]
Здесь комментарии излишни.
По нажатию кнопки Скрыть окно программы 1С:Предпритяие исчезнет с экрана.
Закроем нашу программу и создадим обработчик события нажатие кнопки Выполнить" (для ExecuteBatch). В листинге 4.102 представлен текст обработчика.
; Листинг 4.102. Обработчик события "нажатие кнопки Выполнить"
Procedure TForml.SpeodButtonSCllck(Sender: TObject); begin
if not VarlsEnpty(Ole_LC_App) then begin
^^^
Часть I. 1Си механизм OLE Aut<
if hWlC>32 then begin
// Показать главное окно приложения IC
ShowWindow(hWlC,SW_SHCW);
end;
//
И Вызываем метод ExecuteBatch
if Ole_lC_App-ExecuteBatch(RE_ExecuteBatch.Text)*l>=0 then begin SbowMessage('Ошибка выполнения метода ExecuteBatch');
end;
H
> пояснения не требуются.
рь можно проводить эксперименты. Для начала попробуем воспроизве- последовательность команд, выполненных в предыдущем разделе ющью метода EvaiExpr (листинг 4.93). Для этого введем те же команды е Текст для ExecuteBatch (в нашей программе) и в конце добавим строку;
ять(глЭБуферДляОВЕ[ 3));
Примечание
В отличие от метода EvaiExpr, в методе ExecuteBatch каждую команду нужно отделять точкой с запятой. То есть нужно абсолютно точно придерживаться синтаксиса встроенного языка программирования системы 1С:Предприятие.
ExecuteBatch
|_Со1дать0б»ект("Справочник.ФизЛица", 1);
_Соэдать06ъект("СписокЗначений", 2);
БуферДляОЬЕ[1].НайтиПоКолу(1,0);
_СписокЗначений_До6авитьЗначение(пл9БуферДляОЬЕ[2],гл9БуферДляОЬЕ[1].ТекуиийЗленент()) ’ БуферДля01Е[1].НаЙ1иПоКоду(2,0);
_СписокЗнвчений_ДобавитъЗначенме(гл9БуферДлх0ДЕ[2],гл9БуферДл10ЬЕ[1).ТекукийЭленент О)•
БуферДляОЬЕ[1).Нах1иПоКоду(3,0);
_СписокЗначений_ДобавитьЗначение(гл9БуферДляОЬЕ[2),рл9БуферДляО1Е[1].ТекужийЗленентО) S
БуферДляOLE[2].ВибратьЗначение(рлЗБуферДля ОLE[3 3)р
_06»ектКонаертироеатьВСтроку(гл9БуферДля0ЬЕ[3));
(щ«ть(гл9БуферДляО1Е[3]);
Рис. 4.205. Текст последовательности команд (листинг 4.93)для их выполнения с помощью метода ExecuteBatch
упустим этот набор команд на выполнение (кнопка Выполнить). Если все делано без ошибок, то на экране появится диалоговое окно для выбора стро- кИ и3 списка значений (рис. 4.206).
Рис. 4.206. Результат выполнения команды выбора строки из списка значений
Эго "сработала" строка:
глЭБуферДляОЬЕ [ 2 ] . ВыбратьЗначение (глЭБуферДляОЬЕ (3 ]);
В окне сообщений программы 1С:Предприятие (рис. 4.207) появится строка с ФИО выбранного "физического лица".
Рис. 4.207. Окно сообщений программы 1 С: Предприятие
Результат можно сравнить с получаемым при поочередном выполнении этих же команд с помощью метода EvalExpr.
Теперь посмотрим, каким образом мы можем использовать управляющие конструкции и операторы в тексте, выполняемом методом ExecuteBatch. Поставим перед собой следующую задачу:
Т Создать объект списокЗначений и разместить в нем ссылки на все элементы справочника Физлица, кроме групп.
Т Из списка значений вывести в окно сообщений программы 1 С:Предприятие информацию о коде, ФИО и городе проживания отобранных "физических лиц".
В листинге 4.103 представлен текст для метода ExecuteBatch, решающий эту задачу.
н*°Р^и°нихво^^
лститьОкноСообщений();
эбшить(“Список физ. лиц");
Создаем список значений.
Ссылка на список значений будет храниться в элементе массива глЭБуферДпяОЬЕ[2].
9_Создать0бъект('СписокЗначаиий’, 2) ;
Создаем объект "Справочник.ФизЛица“. Ссылка на справочник будет храниться в элементе массива глЭБуферДпяОЬЕ[11. |_Создать0бъект("Справочник.ФизЛица", 1);
Ьбщить("Выбираем из справочника:");
Выбираем из справочника всех "физических лиц" так же, как мы это делали ранее
БуферДляОЬЕ[ 1) .ВыбратъЭлаианты(1) ;
а гл9БуферДпяОЬЕ(1).ПолучитьЭламент()>0 Цикл
Если глЭБуферДпяОЬЕ[1). ЭгоГруппаО<=0 Тогда
// Ссылка на текущий элемент справочника
// будет храниться в элементе массива глЭБуферДпяОЬЕ[3) глЭБуферДпяОЬЕ(31 = глЭБуферДпяОЬЕ[11.Текуи»<йЭломент(); // Выводим сообщение в окно сообщений 1С
Сообщить(СокрЛП(глЭБуферДпяОЬЕ[31-Код)*" "
♦СокрЛП (ГлЭБуферДпяОЬЕ[3])) ;
// Сохраняем ссылку на текущий элемент справочника // в списке значений
гл9_СписокЗкачаиий ДобааитьЗначение(глЭБуферДпяОЬЕ(2 ] , глЭБуферДпяОЬЕ(3));
онецЕсли;
цЦикла;
|ТЬ (|ТЬ (");
|ТЬ (
|ТЬ (
дошить (’") ;
.^а^ить("Выбираем из списка значений:") ;
и
ц Теперь сканируем весь список значений
,у и поочередно выбираем из него ц ссылки на текущий элемент справочника.
// определяем количество строк в списке значений глЭБуферДляОЬЕ [10] = глЭБуферДляОЬЕ[2] .РаамерСписка() ;
ц Это будет "счетчик циклов" глЭБуферДляОЬЕ [11] = 0;
Пока глЭБуферДляОЬЕ[11]<глЭБуферДляОЬЕ[10] Цикл
// Увеличиваем значение счетчика циклов на 1 глЭБуферДляОЬЕ[11]=гл9БуферДляОЬЕ[11]+1;
// Считываем из списка значений ссылку // на текущий элемент справочника
■глЭБуферДляОЬЕ [ 12 ] =
глЭБуферДляОЬЕ[2]. ПолучитьЗначекие(глЭБуферДляОЬЕ[11]);
// Выводим в окно сообщений 1С
Сообщить (СокрЛП(глЭБуферДляОЬЕ[12] .Код)
+СокрЛП(глЭБуферДляОЬЕ[1211
+ • ("
+СокрЛП(глЭБуферДляОЬЕ[12].ГородПрохиваяия) +")");
КонецЦикпа;
//
Сообщить (” ==================");
Поясним текст листинга 4.103. В принципе, здесь нет ничего такого, чего мы Не делали ранее, кроме, разве что, функции ОчиститьОкноСообщений и метода ПолучитьЗначекие объекта списокЗначений. Непривычным, возможно, являет- с” использование элемента массива глЭБуферДляОЬЕ в качестве счетчика циклов (элемент массива глЭБуферДляОЬЕ [ и ]). В остальном этот текст ничем не отличается от того, что рассматривалось в разд. 4.1 и 4.5, потому углубляться 8 него не будем.
Результат выполнения этого кода в методе ExecuteBatch представлен на Рис. 4.208.
,3*‘ 1064
Рис. 4.208. Результат выполнения кода из листинга 4.103
Программный текст, представленный в листинге 4.103, полезен тем. что показывает, каким образом можно реализовать довольно сложные алгоритмы получения информации из базы данных 1 С:Предприятие (используя меха? низм OLE Automation), не создавая при этом дополнительных программ.
С практической точки зрения, вывода информации в окно сообщений про граммы 1С:Предприятие может оказаться недостаточно. В листинге 4.104 представлен программный текст, который "делает" то же самое, что и в предыдущем примере, но сохраняет результат в текстовом файле.
ОчиститьОкноСообщений();
// Имя начального каталога гл9БуферДляОЬЕ[51] = "С:\"; // Имя файла
гл9БуферДляОЬЕ[50) = "lC_ExecuteBatch_0001.txt:";
// Выбираем файл для сохранения списка "физических лиц"
-ели *С.Выбрать*айл(1,
гл9БуферДляОЬЕ[50),
гл9БуферДляОДЕ[51), "Сохранить в файл", "Текстовые файлы ( *.txt )l*.txt", , ) = 1 Тогда
Сообщить("Результат будет сохранен в файле: "
+гл9БуферДляОЬЕ[51]+гл9БуферДляОЬЕ[5О]);
^обшить ("Список физ. лиц"); ,сОбШИТЬ ( " ==================
//
ц создаем объект типа "Текст", // ссыпка на который будет храниться II в элементе массива глЭБуферДляОЬЕ[2] гЛ9_СоздатьОбъе кт (" Текст", 2) ;
И и
ц Создаем объект "Справочник.ФизЛица", ц ссылка на этот справочник будет храниться // в элементе массива гл9БуферДляОЬЕ(11 гл9_СоэдатьОбъект("Справочник.ФизЛица", 1) ;
Сообщить ("Выбираем из справочника:") ;
И
// Выбираем из справочника всех "физических лиц"
И так же, как мы это делали раньше глЭБуферДляОЬЕ (1 ] . ВыбратнЭлемек-т (1) ;
Пока глЭБуферДляОЬЕ[1).ПолучитьЭлемант()>0 Цикл
Если глЭБуферДляОЬЕ[1].ЭтоГрупла()<=0 Тогда
// Ссылка на текущий элемент справочника
// будет храниться в элементе массива глЭБуферДляОЬЕ[3] глЭБуферДляОЬЕ[31 = глЭБуферДляОЬЕ[ 1 ] .ТекущииЗламант();
// Формируем строку для вывода
глЭБуферДляОЬЕ(51 = СокрЛП(гл9БуферДляОЬЕ[3]-Код)
+СокрЛП(глЭБуферДляОЬЕ[3));
/ / Выводим строку в окно сообщений 1С
Сообщить(глЭБуферДляОЬЕ[5]);
// Добавляем строку в объект типа "Текст", ссылка на который
// хранится в элементе массива глЭБуферДляОЬЕ[2] гл9БуферДляОЬЕ[2],Доба»итьСтроку(гл9БуферДляОЬЕ[51);
КонецЕсли ;
КонецЦикла;
//
Сообщить (•=================") i
И Сохраняем содержимое объекта глЭБуферДляОЬЕ[21 типа "Текст"
Рис. 4.209 Окно выбора файла (метод ВыбратьФайл объекта ФС)Рис. 4.209 Окно выбора файла (метод ВыбратьФайл объекта ФС)
Рис. 4.209 Окно выбора файла (метод ВыбратьФайл объекта ФС)
Рис. 4.209 Окно выбора файла (метод ВыбратьФайл объекта ФС)
// в файле на диске
гл9БуферДляОЬЕ[2].Записать(глЭБуферДляОЬЕ[51]+гл9БуферДляОЬЕ[50])•
// Очищаем содержимое объекта глЭБуферДляОЬЕ[2]
глЭБуферДляОЬЕ[ 2 ] .Очистить();
// Прочитаем сохраненную информацию из файла с помощью
И метода 'Открыть* объекта глЭБуферДляОЬЕ[2]
глЭБуферДляОЬЕ[2]. Открыть(глЭБуферДляОЬЕ[51]+гл9БуферДляОЬЕ[50]);
И Устанавливаем режим "Только просмотр"
ГлЭБуферДляОЬЕ[2].ТолькоПросмотр(1);
// Отображаем содержимое файла в диалоговом окне
глЭБуферДляОЬЕ[2].Показать("Список физ.лиц");
КонецЕсли;
Поясним текст листинга 4.104. Новым здесь является использование объектов фс (файловая система) и Текст. Прежде всего, в результате вызова метода ВыбратьФайл объекта ФС:
Если •С.Выбрать*айл(1,
на экране появляется диалоговое окно выбора имени файла для (рис. 4.
}алее создается объект типа Текст: л9_СоэдатьОбъект("Текст", 2); также объект Справочник.Физлица.
м следует отбор всех элементов справочника, соответствующих "физи- ^м лицам". Для каждого "физического лица" формируется соответст- ^отая строка:
_^БуферДляОЬЕ[5] = СокрЛП(гл9БуферДляОЬЕ[3]-Код)
+■+СокрЛП(глЭБуферДляОЬЕ[ 3 ]);
ПРИМЕЧАНИЕ
В отличие от объектов СписокЗначений и ТаВлицаЗначений, объект Текст не может хранить значения никаких иных типов данных, кроме строк.
Затем сформированная строка записывается в объект типа Текст: глЭБуферДляОЬЕ 12]. ДобавитьСтроку (глЭБуферДляОЬЕ [ 5 ] ) ;
н выводится в окно сообщений программы 1С:Предприятие (рис. 4.210).
Рис. 4.210. Результат выполнения кода из листинга 4.104
По окончании считывания всех элементов справочника из выборки содержимое объекта Текст сохраняется в указанном файле: гл9БуферДляОЬЕ[2] .Записать(глЭБуферДляОЬЕ[51] +гл9БуферДляОЬЕ[50]) ;
Здесь: ГлЭБуферДляОЬЕ [51] — имя каталога (папки); глЭБуферДляОЬЕ[50] — имя файла.
Содержание объекта типа Текст (для чистоты эксперимента) после этого очищается:
ГлЭБуферДляОЬЕ [2] .Очистить () ;
Информация, сохраненная в файле, вновь считывается в объект типа Текст.
ГлЭБуферДляОЬЕ [2] .Открыть (глЭБуферДляОЬЕ[51] +гл9БуферДпяОЬЕ[50)) ;
Устанавливаем режим толькоПросмотр для объекта типа Текст:
ГлЭБуферДляОЬЕ[ 2 ] .ТолькоПросмотр(1) ;
И содержание выводится на экран в диалоговом окне (рис. 4.211):
гЛ9ВуферДляОЬЕ[2] .Показать("Список физ.лиц") ;
й Список физ.яиц C:\tC EMecuteBatch 0001.txt * ВВЕЗ
Аксакалов Аксакал Аксакалович
Иванов Иван Иванович
Пееров Петр Петрович
Сидоров Сидор Сидорович
Федоров Федор Федорович
Криогенова Фекла Маринадовна
Рис. 4.211. Результат выполнения метода Показать объекта типа ТекстРис. 4.211. Результат выполнения метода Показать объекта типа Текст
Рис. 4.211. Результат выполнения метода Показать объекта типа Текст
Рис. 4.211. Результат выполнения метода Показать объекта типа Текст
Вот. собственно, и все.
Существенный интерес представляет возможность формирования и выпал- нения "штатных" запросов системы 1С:Предприятие к базе данных.
Определение
Запрос — это средство для выполнения обращений к документам, регистрам, справочникам и журналам расчетов с целью получения сводной информации при формировании выходных отчетов.
С помощью "запросов" можно фильтровать информацию по различным критериям, создавать группировки отфильтрованной информации, получать сводную информацию. "Запросы" можно использовать не только в рамках отчетов, но и как самостоятельные объекты. Если учесть, что в системе 1 С:Предприятие есть "штатное" средство для построения отчетов, в рамках которого автоматизирован процесс построения запросов (их тексты можно использовать впоследствии), то ясно, насколько полезным может быть нс* юльзование "запросов" при доступе к информации базы данных системы |С:Предприятие.
Примечание
Объект Запрос, его методы и свойства являются достаточно сложными и "объемными", чтобы рассматривать их в рамках данной книги. Подробную инфор- мацию о ‘запросах* можно найти в специальной литературы по систе 1С:Предприятие.
1есь мы рассмотрим использование запроса для выборки информации ПО fартииНаличие стандартной конфигурации 1 С:Предприятие. Это еМ‘ 410 КЗК пРавил°) на всех предприятиях имеется существенное л чество записей движения по регистру ПартииНаличие, поэтому выполне- емой теме П° ^“^ РегистРУ будет хорошей иллюстрацией к рассматри*
л nncmvn к информации 1С из внешних приложений^
'
иСтинге4.105 представлен пример формирования и выполнения запроса регистру ПартииНаличие стандартной конфигурации 1С:Предприятие Использованием метода ExecuteBatch.
^стятьОкноСообщений () ;
Сообщить ("Начало") ;
ц „===============================
//Задаем период дат для отбора движений
гл9БуферДляОЬЕ [ 5 ] = "01.01.2003";
глЭБуферДляОЬЕ [6] = "31.01.2003";
Сообщить (" Период:" +СокрЛП (глЭБуферДляОЬЕ [ 5))
*" +СокрЛП(глЭБуферДляОЬЕ[ 6 ]));
//Формируем Запрос
//Создать объект Запрос
глЭБуферДляОЬЕ [1] = СоздатьОбъект ("Запрос") ;
И Текст запроса (глЭБуферДляОЬЕ[2])
ГлЭБуферДляОЬЕ [2] =
"//((ЗАПРОС(Сформировать)
|Период с '"+глЭБуферДляОЬЕ[5] + "' по '"+ глЭБуферДляОЬЕ[6]+"1;
|МОЛ = Регистр.ПартииНаличие.МОЛ;
| Номенклатура = Регистр.ПартииНаличие.Номенклатура ;
| Партия = Регистр.ПартииНаличие.Партия;
|ДатаПартии = Регистр.ПартииНаличие.ДатаПартии;
I Количество = Регистр.ПартииНаличие.Количество;
|СуммаРуб = Регистр.ПартииНаличие.СуммаРуб;
I Функция КоличествоПриход = Приход(Количество);
I Функция СуммаРубПриход = Приход(СуммаРуб);
IФункция КоличествоРасход = Расход(Количество);
IФункция СуммаРубРасход = Расход(СуммаРуб);
I Группировка МОЛ без групп;
IГруппировка Номенклатура без групп;
I"//)}ЗАПРОС
Н в окно сообщений 1С
Сообщить("Текст Запроса: ");
Сообщить(глЭБуферДляОЬЕ[2]);
//==========================
// Запускаем запрос на выполнение
Если глЭБуферДляОЬЕ[ 1 ] .Выполнить(глЭБуферДляОЬЕ(21) = 0 Тогда // Возврат; //С этим не работаем
КонецЕсли;
//============хх=х===============с========
//ыххжжхаяжххахххвжжхжяжжххжхххжххжххжжхжх
// Создаем таблицу значений
глЭБуферДляОЬЕ[3]=СоздатьОбъект("ТаблицаЗначекий'');
// Выгружаем Запрос в таблицу значений
глЭБуферДляОЬЕ[ 1 ] .Выгрузить(глЭБуферДляОЬЕ[ 3 ]);
// Для контроля отображаем в диалоговом окне глЭБуферДляОЬЕ[ 3) . ВыбратьСтроку();
/ /=========х======х====х=========х======
Поясним листинг 4.105. Сначала создается объект типа Запрос:
глЭБуферДляОЬЕ[ 1 ] = СоздатьОбъект("Запрос");
Затем формируется текст запроса (переменная гл9БуферДляОЬЕ(2]). Фильтрация производится по диапазону дат (переменные глЭБуферДляоьв[51 и глЭБуферДляОЬЕ[6]). Информация выбирается по ресурсам количество И Сумма Руб регистра И Группируется ПО измерениям Номенклатура и мол регистра. Далее (для контроля), в строке:
Сообщить(глЭБуферДляОЬЕ[21);
текст запроса выводится в окно сообщений (рис. 4.212).
Наконец, вызывается метод Выполнить объекта Запрос:
Если глЭБуферДляОЬЕ(11.Выполнить(глЭБуферДляОЬЕ[2]) = 0 Тогда в результате которого формируется соответствующим образом отфильтрованная и сгруппированная информация.
Затем создается объект ТаблицаЗначений:
глЭБуферДляОЬЕ(3]=Создать0бъект("ТаблицаЗначений”);
куда выгружается результат выполнения запроса (с помощью метода выгрУ' зить объекта Запрос):
глЭБуферДляОЬЕ[1] .Выгруаить(глЭБуферДляОЬЕ[3] ) ;
мм^;»^;»й8й8НачалоПериод: 01 01 2003 31.01 2003Текст Запроса://((ЗАПРОС|Сформирсеать)Периоа с '01.01.2003 по 31.01.2003;МОЛ - Регистр.Парп»*1аличие.М0Л;Номенклатура » Регистр.ПартииНаличие.Номеиклатура. Партия « Регистр.ПартииНаличие. Партия.ДатаПартии - Регистр.ПартииНаличиеДатаЛартии; Количество • Регистр.ПартииНаличие Количество, СуимаРуб • Регистр ПартииНаличмв СуммаРуб; Фикция КоличествоПриход - Приход!Количество); Функция СуммаРубПриход ■ Прихаа|СуммаРу6]; Функция Количество? асход - Расход(Количество1; Функция СуммаРубРасход = Расход(СуммаРуб1;Грутпировка МО Л без групп;Грулпироека Номенклатура без групп;НачалоПериод: 01 01 2003 31.01 2003Текст Запроса://((ЗАПРОС|Сформирсеать)Периоа с '01.01.2003 по 31.01.2003;МОЛ - Регистр.Парп»*1аличие.М0Л;Номенклатура » Регистр.ПартииНаличие.Номеиклатура. Партия « Регистр.ПартииНаличие. Партия.ДатаПартии - Регистр.ПартииНаличиеДатаЛартии; Количество • Регистр.ПартииНаличие Количество, СуимаРуб • Регистр ПартииНаличмв СуммаРуб; Фикция КоличествоПриход - Приход!Количество); Функция СуммаРубПриход ■ Прихаа|СуммаРу6]; Функция Количество? асход - Расход(Количество1; Функция СуммаРубРасход = Расход(СуммаРуб1;Грутпировка МО Л без групп;Грулпироека Номенклатура без групп;Выбор строкиВыбор строкиРИС. 4.212. Текст запроса, выведенный в окно сообщений 1С:ПредприятиеРИС. 4.212. Текст запроса, выведенный в окно сообщений 1С:Предприятие(сличаете!(сличаете!чоме*чоме*МОЛМОЛАбб Абб- Абб... Абб- Абб.. .Абб. Абб- Абб- Абб„, Абб- Абб...Абб.. Ани... Ани...Аш. Ани... Аии...Абб Абб- Абб... Абб- Абб.. .Абб. Абб- Абб- Абб„, Абб- Абб...Абб.. Ани... Ани...Аш. Ани... Аии...Ветошь
м
м
^;
»
^;
»
й8
й8
Начало
Период: 01 01 2003 31.01 2003
Текст Запроса:
//((ЗАПРОС|Сформирсеать)
Периоа с '01.01.2003 по 31.01.2003;
МОЛ - Регистр.Парп»*1аличие.М0Л;
Номенклатура » Регистр.ПартииНаличие.Номеиклатура. Партия « Регистр.ПартииНаличие. Партия.
ДатаПартии - Регистр.ПартииНаличиеДатаЛартии; Количество • Регистр.ПартииНаличие Количество, СуимаРуб • Регистр ПартииНаличмв СуммаРуб; Фикция КоличествоПриход - Приход!Количество); Функция СуммаРубПриход ■ Прихаа|СуммаРу6]; Функция Количество? асход - Расход(Количество1; Функция СуммаРубРасход = Расход(СуммаРуб1;
Грутпировка МО Л без групп;
Грулпироека Номенклатура без групп;
Начало
Период: 01 01 2003 31.01 2003
Текст Запроса:
//((ЗАПРОС|Сформирсеать)
Периоа с '01.01.2003 по 31.01.2003;
МОЛ - Регистр.Парп»*1аличие.М0Л;
Номенклатура » Регистр.ПартииНаличие.Номеиклатура. Партия « Регистр.ПартииНаличие. Партия.
ДатаПартии - Регистр.ПартииНаличиеДатаЛартии; Количество • Регистр.ПартииНаличие Количество, СуимаРуб • Регистр ПартииНаличмв СуммаРуб; Фикция КоличествоПриход - Приход!Количество); Функция СуммаРубПриход ■ Прихаа|СуммаРу6]; Функция Количество? асход - Расход(Количество1; Функция СуммаРубРасход = Расход(СуммаРуб1;
Грутпировка МО Л без групп;
Грулпироека Номенклатура без групп;
Выбор строки
Выбор строки
РИС. 4.212. Текст запроса, выведенный в окно сообщений 1С:Предприятие
РИС. 4.212. Текст запроса, выведенный в окно сообщений 1С:Предприятие
(сличаете!
(сличаете!
чоме*
чоме*
МОЛ
МОЛ
Абб Абб- Абб... Абб- Абб.. .
Абб. Абб- Абб- Абб„
, Абб- Абб...
Абб.. Ани... Ани...
Аш. Ани... Аии...
Абб Абб- Абб... Абб- Абб.. .
Абб. Абб- Абб- Абб„
, Абб- Абб...
Абб.. Ани... Ани...
Аш. Ани... Аии...
Вкладыш меховой
Канат стальной ф25 Г-1-Н-Т-1770 ГОСТ 3079-80
Канат стальной ФбДГД-К-Н-Т-1880 ГОСТ 2688-80
КлючКТГУ-73
Мыло хозяйственное 65%
Ремень клиновой В(Б J-3000
Рукавицы ватные
Рукавицы защитные КР
Электрод ОЗС-4 ГОСТ 9466-75.9467-75 фЗ мм
Элемент пакера резиновый 4ПВМ (Х)1 -122/130
Бензин А-7Б
Бензин Аи 92
Бумага для ксерокса А4
Газ кислород
1117 75718006 110 344 7130 6418 0 о о1117 75718006 110 344 7130 6418 0 о оОК. | Отмена ) Помощь
1117 75
71
800
6 1
10 3
44 71
30 6
418 0 о о
1117 75
71
800
6 1
10 3
44 71
30 6
418 0 о о
Рис. 4.213. Результат .ь.оеа метода ВыОр.тьСтроку об».. т.«э—«»
После окончания выгрузки содержимое объекта таблицаЗначений можно посмотреть, обратившись к его методу ВыбратьСтроку:
г-т9БуферДляОЬЕ [ 3 ] . ВыбратьСтроку () ;
На рис. 4.213 представлено диалоговое окно (как результат вызова метода
ВыбратьСтроку объекта ТаблицаЗначений).
Примечание
Можно достаточно легко (с помощью встроенного языка программирование системы 1С:Предприятие) написать универсальную функцию выгрузки сода? жимого объекта ТаОлицаЗначений в текстовый файл, в DBF-файл или в Excel. Если поместить эту функцию в глобальный модуль конфигурации с кпю. чевым словом Экспорт, то можно во внешнем приложении сформировать прос, выполнить его (используя метод ExecuteBatch) и выгрузить результат запроса сначала в таблицу значений, а потом, например, в файл Excel или в DBF-файл. И далее воспользоваться средствами Delphi для работы с этим DBF-файлом по своему усмотрению.
Вернемся к методу EvalExpr, который был подробно рассмотрен в предыду. щем разделе. Как было отмечено, метод EvalExpr можно использовать ди "запуска" отчетов и других внешних форм (обработок). Но чтобы открытая форма была доступна пользователю, нужно открыть главное окно программы I С:Предприятие. В этом разделе мы можем вернуться к этому вопросу.
Откроем "нашу" конфигурацию и создадим внешнюю обработку. На рис. 4.214 представлена форма обработки.
Пример внешней формы для иллюстрации
метода EvalExpr
Имя Файле: [ИмяФайла
Список Физ. лиц:• :,Л
, СоаержаниеФайла*1
СоаержаниеФайла
СоаержаниеФайла
СоаержаниеФайла
СоаержаниеФайла
СоаержаниеФайла
Сформировать, Закрыть [
Рис. 4.214. Форма внешней обработки для просмотра текстовых файлов.
Здесь СодержаниеФайла — это элемент управления типа "список". имяФай- ла — это элемент управления типа "однострочный редактор").
Форма может получить имя текстового файла при запуске, через параметр фопмы
р0 нажатию кнопки Сформировать проверяется, существует ли заданный файл- И если существует, то считывается его значение.
я®7».я®7».5@В®5@В®0 листинге 4.106 представлен текст обработчика события "нажатие кнопки Сформировать" (рис. 4.214).
я®7».
я®7».
5@В®
5@В®
Процедура Сформировать ()
// Очищаем элемент управления "СодержаниеФайла" СодержаниеФайла.УдалитьВсе();
// проверяем, существует ли заданный файл
Если ФС.Существует*айл(ИмяФайла)>О Тогда
И
// Считываем содержание файла с именем,
// хранящимся в элементе управления "ИмяФайла" ТекстБуф = СоздатьОбъект("Текст");
ТекстБуф.Открыть(ИмяФайла) ;
И
Ц
II Копируем прочитанное содержание файла
//из объекта "ТекстБуф" в элемент управления
// "СодержаниеФайла"
Колво = ТекстБуф.КоличествоСтрок();
1 = 0;
Пока 1<Колво Цикл
i = i + 1;
Sx = ТекстБуф.ПолучитьСтроку(i);
СодержаниеФайла.ДобавитьЗначеяие(Sx,Sx) ;
КонецЦикла;
Ц
Иначе
Предупреждение("Файл: <"+ИмяФайла+"> не найден");
КонецЕсли;
КонецПроцедуры
Вкратце поясним текст обработчика (листинг 4.106).
Как было сказано выше, сначала проверяется существование заданного фай Ла (метод СуществуетФайл объекта фс). Далее создается объект типа Текст
куда считывается текстовый файл (метод Открыть объекта ТекстБуф). тем информация из объекта ТекстБуф копируется в элемент управлен^ СодержаниеФайла.■
При интерактивном открытии формы система 1С:Предприятие автоматик ски вызывает предопределенную процедуру приоткрытии, если она имеете в тексте модуля данной формы. При этом, если при "запуске" данной фор^ был передан параметр, он может быть прочитан и проанализирован в про- ЦСДуре ПриОткрытии С ПОМОЩЬЮ свойства Форма . Параметр.
В листинге 4.107 представлен текст предопределенной процедуры Приоткрытии для созданной формы.
®ЮЙЙ
Процедура ПриОгкрытии()
Yes=0;
И Получаем параметр, переданный форме
Парам = Форма.Параметр;
// Очищаем элемент управления "ИмяФайла" ИмяФайла = "*;
// Счищаем элемент управления "СодержаниеФайла* СодержаниеФайла.УдалитьВсе();
// Проверяем, соответствует ли тип переданного
// параметра типу *Строка"
Если ТипЗначения(Парам)=2 Тогда
// Тип переданного значения - "Строка"
Парам = СокрЛП(Парам);
Если СтрДлина(Парам) >0 Тогда
М Имя файла передано
ИмяФайла = Парам;
Yea=l;
КонецЕсли;
КонецЕсли;
Если Yes>0 Тогда
// Если все ОК — считываем содержание
// файла (имя передано в параметре форьм) Сформировать();
Иначе
Предупреждение("ОшибкаПредупреждение("Ошибкапри инициализации отчета(форкы)");при инициализации отчета(форкы)");II Иначе — сообщение об ошибке
Предупреждение("Ошибка
Предупреждение("Ошибка
при инициализации отчета(форкы)");
при инициализации отчета(форкы)");
цонецЕсли;
// статусВозврата(0);
// Возврат;конеи-Проиедуры
Кратко поясним текст обработчика (листинг 4.107). Здесь проверяется тип значения переданного параметра. Если тип значения — Строка, и она не пус- та. то ее значение присваивается элементу управления имяФайла и вызывается обработчик события "нажатие кнопки Сформировать".
ПРИМЕЧАНИЕ
Файл этой формы на сопроводительном компакт-диске \1С_ехатр1е.ОВ\Ех1Еогт8\ВнешняяФорма_для_Еуа1Ехрг.ЕНТ.
книги:
Теперь запустим наш проект (sp_ExecuteBatch_lC.DPR) на выполнение, создадим соединение с 1С и сделаем окно программы 1С видимым, а затем введем в поле значения параметра для EvaiExpr строку: ОгкрытьФориу ("Отчет#", "C:\lC_ExecuteBatch_0001.txt",
"Е: \1С_ехатр1е.ОВ\ЕхСЕоппз\ВнешняяФорма_для_ЕУа1Ехрг.егС")
и нажмем кнопку Выполнить. Результат представлен на рис. 4.215.
Е
Е:\ 1С example РВ\Ех1Еогт4\ВнешняяФорн^^В0В
6* а г ^
■ЮРИЧ
Пример внешней формы для иллюстрации метода EvaiExpr
Список физ. лиц:
г. АгСУ :
Иванов Иван Иванович
Петров Петр Петрович
Сидоров Сидор Сидорович
Федоров Федор Федорович
Криогенова Фекла Маринадоона
С$ори^омть Закрыть
Рис. 4.215. Просмотр содержания
текстового файла во внешней обработке
То есть было прочитано содержание текстового файла, сформированное в процессе выполнения программного кода (см. листинг 4.104).
Примечание
Естественно, предполагается, что файлы C:\1C_ExecuteBatch_000l.Т)№ и Е:\1С_ехатр1е.ОВ\Ех1Рогт8\ВнешняяФорма_для_Еуа1Ехрг.еП существуют"
использо.использо.Вместо указания полного пути к файлу вызываемой формы можно вать функцию каталогиво (ее мы рассматривали в разд. 4.5Y
использо.
использо.
ОтхрытьФориу("Отчет#“, "C:\lC_ExecuteBatch_0001.txt",
КаталогИБ () +" ЕхСЕогтв\ВнешняяФорма_^я_Еуа1Ехрг. ert")
Изменение информации
в базе данных 1С
В предыдущих разделах мы коснулись вопросов считывания информации из базы данных системы 1С:Предприятие с использованием механизма QI.F, Automation. Чаще всего именно эти действия бывает нужно выполнить при обмене данными с системой 1С:Предприятие. Тем не менее, иной раз возникает необходимость редактировать базу данных 1С:Предприятие. В этом разделе мы рассмотрим вопросы записи информации в базу данных на конкретных примерах.
Редактирование элементов справочников
Для начала рассмотрим редактирование непериодических реквизитов справочника.
Запустим Конфигуратор 1С:Предприятие и внесем новый (непериодический) реквизит Состоитвпрофсоюзе типа Число (рис. 4.216).
:. 4.216. Новый реквизит типа Число в справочнике ФизЛица:. 4.216. Новый реквизит типа Число в справочнике ФизЛица
:. 4.216. Новый реквизит типа Число в справочнике ФизЛица
:. 4.216. Новый реквизит типа Число в справочнике ФизЛица
Г1$ваДДоступ кГ1$ваДДоступ к•ТигНии•ТигНииинформации 1С из внешних приложений |В Д Справочники
Г1$ваДДоступ к
Г1$ваДДоступ к
•ТигНии
•ТигНии
■ ДатаРождения'
ДР Состоянне<Ризлица
■Я КолвоДетей
> ■ ГородПрожиаания
г - ■ Домашниййдрес
! I ;- ■ Пол
СемейноеПсложение
СосгоитВПрофсоюэе
2■ ДоаолнительнаяИнформация
Рис. 4.217. Список реквизитов справочника ФизЛица
На рис. 4.147 представлен список реквизитов справочника ФизЛица.
Нужно внести также соответствующие изменения в форму редактирования элемента справочника ФизЛица, как мы это делали в разд. 4.1.2 (см. рис. 4.16). Сохраним изменения в конфигурации, запустим программу 1С:Предприятие и внесем значения реквизита Состоитвпрофсоизе в справочник Физлица так,
как указано в табл. 4.11.
Таблица 4.11. Справочник ФизЛица. Значение реквизита Состоитвпрофсоюзе,
Код
5
ФИО
Аксакалов Аксакал Аксакалович
Значение признака
0
1
6
Иванов Иван Иванович
Криогенова Фекла Маринадовна
1 0
2
Петров Петр Петрович
1
3
Сидоров Сидор Сидорович
4
Федоров Федор Федорович
1—1
Откроем Delphi и создадим новый проект с именем (например) sP_EditAttrInRef.DPR.
Примечание
Исходники этого примера (проект sp_EditAttrinRef.DPR) находтся на CD в папке \Part_1\Chapter_04\Topic_4_7\ltem_4_7_1\sp_EditAttrlnRef.PAS\01.
Форма проекта представлена на рис. 4.218.
В табл. 4.12 приведено назначение элементов управления на форме проекта.
Соединить с1С | |V77 ApplICation
«5*.
р Строка инициализации - i ,1 Открыть справочник
Найти по коду
Наименование
"Реквизиты:
/DEA1C_example.DB
ФизЛица
tdrt.Name
•-_ Состоит8Про»союзе | | Ё сй Pint
; ДомашнийАдрес j?dH_Addr .„СемеймоеПоложение )ЁД_Рат .. ГорааЛроживания [Edt Gotod
^
ДополнигелыияИмФормация I
Мето1 """
Рис. 4.218. Форма проекта sp_EditAttrlnRef.DPR
Элемент управления
Кнопка Соединить с 1С
Кнопка Открыть справочник
Кнопка Найти по коду
Счетчик
(поле ввода с кнопками)
Кнопка Наименование
Идентификатор
1 Назначение
Buttonl:
TButton
Соединение с программой 1 С:Предприятие
SpeedButtonl: TspeedButton
Открытие справочника
Физлица
SpeedButton9:
TspeedButton
Вызов метода НайтиПоКоду Справочника ФизЛица для поиска элемента с кодом SE_Code.Value
SE_Code:
TspinEdit
Код элемента справочника
SpeedButton7:
TspeedButton
Редактирование свойства
Наименование элемента справочника
Таблица 4.12. Назначение элементов управления .8 ч^Рме проекта sp_EditAttrlnRef.DPR
Таблица 4.12 (окончание)
"элемент управления
Идентификатор
Назначение
Однострочный редактор
Edit_Name:
TEdit
Значение свойства
Наименование элемента справочника
——>.
Кнопка ДатаРождения
SpeedButton2: TSpeedButton
Редактирование реквизита
ДатаРожденияэлемента справочника
Однострочный редактор
Edit_DR:
TEdit
Значение реквизита ДатаРожденияэлемента справочника
Кнопка СостоитВПрофсоюзе
SpeedButtonS: TSpeedButton
Редактирование реквизита
СостоитВПрофсоюзе элемента справочника
Однострочный редактор
Edit_Pro£:
TEdit
Значение реквизита
СостоитВПрофсоюзе элемента справочника
Кнопка ДомашнийАдрес
SpeedButton4:
TSpeedButton
Редактирование реквизита ДомашнийАдресэлемента справочника
Однострочный редактор
Edit_Addr:
TEdit
Значение реквизита
ДомашнийАдресэлемента справочника
Кнопка СемейноеПоложение
SpeedButtonS:
TSpeedButton
Редактирование реквизита
СемейноеПоложение элемента справочника
Однострочный редактор
Edit_Fam:
TEdit
Значение реквизита
СемейноеПоложение элемента справочника
Кнопка ГородПроживания
SpeedButtonS: TSpeedButton
Редактирование реквизита
ГородПроживанияэлемента справочника
Однострочный редактор
Edit_Gorod:
TEdit
Значение реквизита
ГородПроживания элемента справочника
Кнопка ДополнительнаяИнформация
SpeedButtonS:
TSpeedButton
Редактирование реквизита
ДополнительнаяИнформация элемента справочника
Многострочный редактор
Memol: TMemo
Значение реквизита
ДополнительнаяИнформация элемента справочника
Примечание
Вопросы соединения с программой 1С:Предприятие, открытия справоч и позиционирования на элементах справочника были подробно рассмо- в предыдущих разделах.
В листинге 4.108 представлен исходный текст обработчика события "нал кнопки Найти по коду".
^Листинг 4.108. Визуализация элемс^Ь^^'♦изз&а4*”' v: ^ ^
procedure TForml. SpeedButtcnSClick(Sender: TObject);
11 Обработчик события "нажатие кнопки "НайтиПоКоду" // Визуализация элемента справочника begin
Edit_Name.Text: = *???' ;
Edit_DR.Text:='???';
Edit_Prof.Text:='???';
Edit_^ddr.Text:='???';
Edit_Fam.Text:='???';
Edit_Gorod.Text:='???';
Memol.Lines.Clear;
GroupBox_Attr.Visible:=TRUE;
// Проверяем, существует ли ссылка на справочник
if not VarlsErrpty(ole_Ref) then begin
// Позиционируем справочник на элементе с заданным кодом
if (ole_Ref.НайтиПоКоду(SE_Code.Value,0)*1)>0 then begin
I/ Проверяем, является ли элемент справочника группой
if (ole_Re£.»roI^ynna*l)<=0 then begin
// Это — не группа (показываем реквизиты) GroupBoK-Attr.Visible:=TRUE;
//
// Читаем информацию из справочника
Edit_Name.Text:=Trim(ole_Ref.Наименование);
Edit_DR.Text:=Trim(ole_Ref.ДатаРожденив);
Edit_Prof.Text:=Trim(ole_Ref.СостоитВПрофсоюзе);
Edit_Addr. Text: =Trim (ole_Ref. ДомашнийАдрес) ;
Edit_Fam. Text: =Tr im (ole_Ref.СемейноеПоложекие.Идентификатор);
Edit_Gorod.Text:=Trim(ole_Ref.ГородПроживакия.Наименование);
Memol.Text:=Trim (ole_Ref.ДополнительнаяИкформация);
end
else begin
// Это - группа (скрываем реквизиты)
GroupBox_Attr.Visible:=FALSE;
у/ читаем из справочника только наименование ^t_J** ^ext:=Triin(oleJ<ef .Наименование);
end;
end
else beginсправочника c KonoM='+SE_Code.Text
ShowMessage( Элемент сора^ ^ кайден , ■),
end;
end
else begin
ShowMessage(1 Справочник не открыт ),
end;
end;
н, рис. 4.219 представлен вид фермы „ри .позиции элемент, сПр„=ч„и- кас кодом I.
Рис. 4^19. Визуализация элемента справочника ФизЛица
Для сравнения на рис. 4.220 представлена визуализация этого же элем*», в программе 1 С:Предприятие.
Рис. 4.220. Визуализация элемента справочника ФизЛица в программе 1С:Предприятие
1 листинге 4.109 представлен текст обработчика события "нажатие кнопки
(аименовамие элемента справоч
-••‘..^..„.«.•.:.Аа. ..„^..-.a.—.........™", „.,.„ .....,
rocedure TForml.SpeedButton7Click(Sender: TObject);
/ Редактирование свойства "Наименование*
/ элемента справочика "ФизЛица" аг
Sx: string;
egin
// Проверяем, существует ли ссылка на справочник if not VarlsEmpty(ole_Ref) then begin
.-зава
(рева.
SX: -Edit _Name. Text ;
// Вводим новое значение
if inputQuery((Sender as TSpeedButton).Caption, 1 Новое значение1,
Sx) then begin
Sx:=Trim(Sx);.
II Редактируем значение в справочнике
ole_Ref.Наименование:=Sx;
// Записываем изменения в справочнике в базу данных ole.Ref. Записать ;
// Вновь читаем значение из справочника
Edit_Name•Text:=Tr im(ole_Ref.Наименование);
end;
end
else begin
ShowMessage('Справочник не открыт1);
end;
end;
Поясним текст обработчика.
В строке:
if InputQuexy( ... ) then begin
вводится новое значение свойства наименование.
В строке:
ole_Ref. Наименование: =Sx;
свойству Наименование элемента справочника присваивается новое значение.
В строке:
°le_Ref.Записать;
записываем изменения в элементе справочника в базу данных. Вот, собственно, и все.
В листинге 4.110 представлен текст обработчика события "нажатие кнопки ДатаРождения".
Procedure TForml.SpeedButton2Click(Sender: TObject); /z Редактирование реквизита -ДатаРождения"
V»r
Sx: string;
beginJ
// Проверяем, существует лиссылка на справочник|
if not VarlsEmpty(ole_Ref) then begin
Sx:=Edit_DR.Text;Я
// Вводим новое значениеД
if InputQueryt(Sender as TSpeedButton).Caption,Д
'Новое значение', Sx) then beginД
Sx:=Trim(Sx);■
// Редактируем значение реквизита ole_Ref.ДатаРохдения:=SX;Я
11 Записываем изменения в справочникевбазу данныхя
ole_Ref.Записать;|
// Вновь читаем значение реквизита из справочника Ed±t_DR.Text:=Trim(ole_Ref.ДатаРохдения);п
end;Я
end else begin1
ShowMessage(1 Справочник не открыт1); end; end;™
Реквизит ДатаРохдения имеет тип Дата. Как видите, способ редактирование непериодических реквизитов такого типа аналогичен способу редактирования свойства наименование. По такому принципу можно редактировать реквизиты всех базовых типов (число, дата. Строка), хотя для реквизитов типа число корректнее использовать вариант:
ole_Ref.СостоитВПрофсоюзе:= StzToInt(Sx);
В случае, если нужно отредактировать реквизит типа строка неограниченно» длины, можно создать соответствующую форму (пример приведен на рис. 4.221).
При редактировании реквизита такого типа сначала значение реквизита при* сваивается свойству Lines Delphi-компонента Memol:
Dlg_Edit_AttrStringO.Memol.Text:= ole_Ref.ДополнительнаяИнформация;
Затем вызывается метод Execute диалоговой формы и производится редактирование значения. После этого новое значение присваивается реквизиту: ole_Ref.ДополнительнаяИнформация:= Dlg_Edit_AttrStringO.Hanoi.Text;
??????|мето1??????|мето16$ Редактирование строки неораниченной длины НИ D6$ Редактирование строки неораниченной длины НИ DРис. 4.221. Форма Dlg_Edit_AttrStringO для редактирования реквизитов типа Строка неограниченной длиныРис. 4.221. Форма Dlg_Edit_AttrStringO для редактирования реквизитов типа Строка неограниченной длины
???
???
|мето1
???
???
|мето1
6$ Редактирование строки неораниченной длины НИ D
6$ Редактирование строки неораниченной длины НИ D
Рис. 4.221. Форма Dlg_Edit_AttrStringO для редактирования реквизитов типа Строка неограниченной длины
Рис. 4.221. Форма Dlg_Edit_AttrStringO для редактирования реквизитов типа Строка неограниченной длины
Изменения сохраняются в базе данных:
ole_Ref. Записать ;
То есть все аналогично предыдущему случаю.
Здесь следует отметить, что значения реквизитов агрегатного типа нельзя редактировать "напрямую" так. как мы это делали с реквизитами базового типа (используя функцию inputQuery). Поэтому нам нужен инструментарий для выбора значения агрегатного типа. Например, для реквизита типа Перечисление понадобится средство выбора конкретного значения заданного перечисления (среди штатных средств системы 1С:Предприятие для этого есть метод ввестиПеречисление). Используя наработки, полученные в разд. 4.4, создадим (для "тренировочных" целей) простую диалоговую форму, которая ПОЗВОЛИТ нам эмулировать штатный метод системы 1С:Предприятие ВвестиПеречисление.
На рис. 4.222 представлен внешний вид формы диалогового окна для выбора значения перечисления.
Рис. 4.222. Форма для выбора значения заданного перечисления
™::.^‘l0^— —й — — —
^^Ж^Ж ^ *^0^38
type
TDlg_8elect^ueO£Enum = class(TForm)
public
{ Public declarations }
// Идентификатор выбранного значения перечисления idValueEnum: string;
// Ссылка на выбранное значение oleValueEnum: oleVariant;
перечисления как
объект
// Объявление метода Execute формы
boolean-^0" "-^‘-'«e-lC^PP: olw.^t,
; idEnum,
end;
idEnumVal: string)t
inpiementation
'""“" «Uteu,!.,»..^(ole ^:
oleVariant;
idEnum, idEnumVal: string): boolean;
II О1е_1С_Арр — ссылка на IC как сервер автоматизации OLE // idEnum — идентификатор перечисления
// idEnumVal — идентификатор значения перечисления по умолчанию Var
OleEnum: oleVariant; i,CountVal: integer; idVal: string;
begin
Result:=FALSE;
ListBoxl.Items.Clear;
Label_Enum.Caption:='???';
Label_EnumVal.Caption:='???'; idValueEnum:='';
oleValueEnum:= UnAssigned;
II проверяем, есть ли ссылка на 1С
£# пос VarlsQnpty(Ole_lC_JAFp) then begin idEnumVal:=Tr im (idEnumVal);
idEnum:=Trim(idEnum) ;
if length(idEnum)>0 then begin Label_Enum.Caption:=idEnum;
Label_BnumVal.Caption:=idEnumVal;
// Получаем ссылку на объект “Перечисление* (идeнтификaтop=idEnum)
OleEnum:=О1е_1С_Арр.Перечисление.ПолучитъАтрибут(''tidEnum);
// Получаем количество значений перечисления
CountVal:= 01 eEnum. КоличестаоЗначенийЧ;
for i:=l to CountVal do
begin
// Получаем идентификатор очередного значения перечисления idVal:=Trim(OleEnum.ЗначениеПоНомеру(i *1).Идентификатор);
// Помещаем идентификатор в список
ListBoxl.Items.ADD(idVal);
Application.ProcessMessages;
end;
// Позиционируем курсор в списке на значении idEnumVal ListBoxl.Itemindex:=ListBoxl.Items.IndexOf(idEnumVal);
if ShowModal = mrOk then begin
if ListBoxl.Itemlndex>=0 then begin
И Идентификатор выбранного значения перечисления IdValueEnum: =Trim(ListBoxl.Items[ListBoxl.Itemindex));
// Ссылка на выбранное значение перечисления как объект oleValueEnum:= OleEnum.ЗначениеПоИдентификатору(''+idValueEnum); Result:=TRUE;
end;
end;
end;
end;
end;
end.
Здесь особых пояснений не требуется, поскольку эти вопросы (связанные с перечислениями) мы подробно рассматривали в разд. 4.4.
В листинге 4.112 представлен текст, иллюстрирующий способ редактирования реквизитов типа Перечисление.
procedure TForml.SpeedButtonSClick(Sender: TObject) ; II Редактирование реквизита "СемейноеПоложение" begin
J J Проверяем, существует ли ссылка на справочник
if not VarlsEtipty (ole_Ref) then begin
// Вызываем диалог для выбора значения перечисления
if Dlg_Seleot_ValueOfEnum.Execute(ole_lC,М
'СемейноеПоложение',Edit_Fam.Text) then begin
II Редактируем значение реквизита
ole_Ref.СемейноеПоложение:=Dlg_Select_ValueOfEnum.oleValueKnua;
II Записываем изменения в справочнике в базу данных ole_Ref.Записать;
// Вновь читаем значение реквизита из справочника
Edit_Fam.Text:=Trim(ole_Ref.СемейноеПоложение.Идентификатор);
end;- J
end
else beginI
ShowMessage{'Справочник не открыт1);1
end;
end;
Как видите, подход здесь такой же, как и при редактировании реквизитов базовых типов. Единственное отличие— вместо функции inputQuery мы используем разработанную нами диалоговую форму для выбора значения перечисления (рис. 4.222). Здесь следует отметить важную деталь. В данном случае мы присваиваем реквизиту (агрегатного типа) справочника значение, хранящееся в переменной типа olevariant (или Variant), не заботясь о том, каким образом происходит его "трансформация" в соответствующее значение объектного типа (в контексте системы 1 С:Предприятие):
°le_Ref.СемейноеПоложение:=Dlg_Select_ValueOfEnum.oleVaJ.ueEnum;
Точно так же редактируются реквизиты типа Справочник. Только для выбора значения реквизита (из множества элементов соответствующего справочника) нужно использовать метод выбрать того справочника, откуда выбираются значения для реквизита (или написать собственное средство для выбора соответствующего значения). Здесь мы на этом останавливаться не будем»
н0 в рамках данного примера разработана форма (для "тренировочных" це- 16Й) выбора значений для реквизитов типа справочник.
g листинге 4.113 представлен текст, иллюстрирующий способ редактирования реквизитов типа Справочник.
procedure TForml.SpeedButton6Cllck(Sender: TObject);
D редактирование реквизита ТородПроживания” begin
// проверяем, существует ли ссылка на справочник
if not VarIsEmpty(ole_Ref) then begin
// Вызываем диалог для выбора элемента справочника
if Dlg_Select_El«nFrcxnRef. Execute (ole_lC,
'ГородаСтрамМира1,
ole_Ref.ТородПроживания.Код) then begin
// Редактируем значение реквизита
ole_Ref.ТородПроживания:=Dlg_Select_ElemFromRef.oleKlemSel;
// Записываем изменения в справочнике в базу данных
ole_Ref.Записать;
// Вновь читаем значение реквизита из справочника Edit_Gorod.Text:=Trim(ole_Ref.ТородПроживания.Наименование);
end;
end
else begin
ShowMessage(1 Справочник не открыт1); end;
end;
Здесь для выбора нового значения реквизита типа справочник вызывается метод Execute класса TDlg_select_ElemFromRef. В остальном — все то же самое (новое значение присваивается реквизиту):
°ie_Ref . ТородПроживания: =Dlg_Select_ElemFromRef .oleElemSel;
Скомпилируем наш Delphi-проект, запустим его на выполнение (см. Рис. 4.219) и попробуем изменить значения реквизитов элемента справочника скодом 1.
На рис. 4.223 представлен процесс редактирования свойства наименование элемента справочника (см. листинг 4.109).
280
#Г Йннлггирпминстле
Соединить с 1С | jv77.Application
Открыть справочник | (ФизЛица
Найти по коду Р
Наименование | (Иванов Иван Иванович
Рис. 4.223. Редактирование свойства Наименование элемента справочника ФизЛица
л доступ к информации 1С из внешних приложений
СемейноеПоложение
ГородПроживания
] (СостоитВ Зарегистрированном ]
,f Выбор значения перечи^^НВВ
СемейноеПоложение
ДополнительнаяИнфс СосготпВЗарегистрироааннймБраке |НикогдаНеСостоялВБраке а СостоитВ ЗарегистрированномБрак! I СостоитВНеЗарегист рированномБ|з
Это многострочное пол
Это строка N 1
Это строка N 2
i-Г ражданскийБрак
Разведен
Разошелся
I Вдовец
OK ~| Cancel |
281
.е
раке
Рис. 4.225. Редактирование реквизита СемейноеПоложениеэлемента справочника ФизЛица
н. «ь 4.226 предстами процесс редактировав реквизита городпрсиваки, элемента справочника (см. листинг 4.113).
На рис
ГородПроживания
ПополнигельнаяИнФормация
Выберите элемент спраеоч!
*
На рис. 4.224 представлен процесс редактирования реквизита ДатаРождения элемента справочника (см. листинг 4.110).
Л Реквизиты:
Рис. 4.224. Редактирование реквизита ДатаРождения элемента справочника ФизЛица
ДатаРождения | |01.01Л 971
На рис. 4.155 представлен процесс редактирования реквизита СемейноеПолоз жение элемента справочника (см. листинг 4.112).
Это многострочное поле неограниче
Это строка N 1
Это строка N 2
[ЯТЯ
4
не
2
не
1
НВ
3
Усинск
Наименование
Волгоград
Москва
Рис. 4.226. Редактирование реквизита ГородПроживанияэлемента справочника ФизЛица
На Р„с. 4.227 представлен процесс редактирования реквизита довеять яаяИнФормация элемента справочника.
Дополнительная!'
| Ито многострочное ФизЛица
Редактирование строки ИС°Р^^^*
Гт°оХаП 1 дополнительнаяинфо£мация
I Это строка М2
Cancel
ОК
Это многострочное поле неограниченной длин
Это строка N 1
Это строка М 2
Это строка N 3
Это строка N 4.
Рис. 4.227. Редактирование реквизита ДополнительнаяИнформация элемента справочника ФизЛица
i
На рис. 4.228 представлен вид формы при визуализации элемента справокка с кодом 1 после редактирования.1
Зго многострочное поле неограниченной длины
Это строка М 1
>.
Рис. 4.228. Визуализация элемента справочника ФизЛица после редактирования
При конфигурировании информационной структуры 1С: Предприятие для реквизитов справочников может быть указан тип Неопределенный. Это значит, что такому реквизиту можно программно назначить как базовый тип (Число, Строка, Дата), так и агрегатный (Справочник, Перечисление, Документ и т. д.). По метаданным такой реквизит будет всегда "проходить" как реквизит неопределенного типа (или вида), но тип (вид) его значения для каждого элемента справочника может отличаться.
Откроем Конфигуратор 1 С:Предприятие и в "нашей" конфигурации создадим новый справочник (рис. 4.229).
d ^ CnpaBO'*4«CHeonpeee>WHbi*W3««визитами
Ре*вюит_Неолреае ленный
Реквизиг_СлравочмикНеопределемный
Рег.визит_ДокумектНеопредленный
Примечание
Рис. 4.229. Новый справочник СправочникСНеопределеннымиРеквизитами.Реквизиты неопределенного типа
Таблица 4.13. Реквизиты справочника
СправочникСНеопределеннымиРеквизитами
'реквизит
Тип
'^визит_Неопределенный
Неопределенный
'^^^ит_СправочникНеопределенный
Справочник неопределенного вида
'^^зитЩокументНеопредленный
документ неопределенного вида
Приме ча ние
Строка (64 символа)
Сохраним изменения в конфигурации, запустим программу 1 С:Предприятие И создадим 6 элементов в справочнике СправочникСНеопределеннымиРеквизи- тами (рис. 4.230).
^2
Накмен,.
Элемент-1 3 лемект-2
Реквизит, Не..: |
Реквизит Док... ]
5
3
Элемент-3
н
4
5
Элемент-4
Элемент-5
у
6
Элемент-6
—
—
—
Рис. 4.230. Элементы справочника СправочникСНеопределеннымиРеквизитами
Попробуем, ради интереса, ввести какие-то значения в столбец реквизита Реквизит_неопределенный. Думаю, что это вряд ли получится (до тех пор, пока тип реквизита — Неопределенный)...
Создадим новый Delphi-проект (sp_EditAttr!nRef_2.DPR).
Примечание
Исходные тексты находятся на сопроводительном компакт-диске книги в папке \Part_1\Chapter_04\Topic_4_7\ltem_4_7_1\sp_EditAttrlnRef_2.PAS\01.
По аналогии с проектом sp_EditAttr!nRef.DPR попробуем визуализировать справочник СправочникСНеопределеннымиРеквизитами (листинг 4.114).
Procedure TForml.SpeedButtongClick(Sender: TObject) ; // Обработчик события "нажатие кнопки "НайтиПоКоду* * * Визуализация элемента справочникаProcedure TForml.SpeedButtongClick(Sender: TObject) ; // Обработчик события "нажатие кнопки "НайтиПоКоду* * * Визуализация элемента справочника
Procedure TForml.SpeedButtongClick(Sender: TObject) ; // Обработчик события "нажатие кнопки "НайтиПоКоду* * * Визуализация элемента справочника
Procedure TForml.SpeedButtongClick(Sender: TObject) ; // Обработчик события "нажатие кнопки "НайтиПоКоду* * * Визуализация элемента справочника
beginbeginЧасть I. 1С и механизм OLEAutom^
begin
begin
П
// Читаем информацию из справочника
Edit_Name.Text:=Trhn (ole_Ref.Наименование>;
Edit_N.Text:=Trim(ole_Ref.Реквизит_Наопределемный);
Edit_NR.Text:=
Trun(ole_Ref.Реквизит_СлражочнихНеопределенный.Наименование),
N •
* Trim (ole_.4ef. Рекхизит^ДокумеитНеопределеммый. КомерДок)
+ Tr im (ole_Ref.Реквизит^ЦокументНеопределенный.ДатаДок)
Edit_Prim.Text:=Trim(ole_Ref.Примечание);
//
end
Рис. 4.231. Форма проекта sp_EditAttrlnRef_2.DPRРис. 4.231. Форма проекта sp_EditAttrlnRef_2.DPR<<
Рис. 4.231. Форма проекта sp_EditAttrlnRef_2.DPR
Рис. 4.231. Форма проекта sp_EditAttrlnRef_2.DPR
<
<
Результат будет плачевным (рис. 4.232).
Причина очевидна. И простого решения здесь, вероятно, нет.
Рис. 4.232. Попытка прочитать значения реквизитов неопределенного типа
Один из возможных вариантов решения этой проблемы (далеко не идеальный) — создать в глобальном модуле конфигурации функцию, считывающую значение реквизита справочника и конвертирующую его в строковое значение, а затем вызывать эту функцию (в контексте метода EvalExpr) для всех реквизитов (или только для тех, которые по метаданным "проходят" как реквизиты неопределенного типа).
Возможный вариант такой функции представлен в листинге 4.115.
®S='"-' ■”nc!^15i,4!Ssa!®=pwG^—^-™.,™....„-;—;-"т^--т™::«кчлЛ!|днв
ГЛистинг 4.115. Функция в глобальном модуле 1 С, очитывающаязначение рек-
^^=П^°Ж^
// Вызов функции гл9_СокрЛПдляЗначРеквизитаСправочника():
// идСправочника — идентификатор справочника,
11 идреквизита — идентифкатор реквизита,
** КодЭлемента — код элемента справочника,
11 ФлагПоиска:
110 — во всем справочнике,
— внутри родителя,
1'2 - по полному коду (с учетом всех родителей).
функция гл9_СокрЛПдляЗначРеквизитаСлравочника (идСправочника,
идРеквизита,
КодЭлемента,
ДатаДляПериод=* *,
ФлагПоиска=0) Экспорт
'03*« 1064
Wn । .
Res = *•;
идСправочника = СокрЛП(идСправочника);
идРеквиэита = СокрЛП(идРеквизита);
Если (СтрДпина(идСправочника)>0) И (СтрДпина(идРеквизита)>0) Тогда // Проверяем существовние справочника <идСправочника> Если Метаданные.Справочник("••«■идСправочника) .Выбран()>0 Тогда // Проверяем существовние реквизита <идРеквизита> // справочника <идСлравочника>
МвтаРеквизит =
Метаданные.Справочник(**«-идСпражочкиха).Реквизит(** -гидРеквизита);.
Если МетаРекаивит.Выбран()>0 Тогда
Спр = СовдатьОбъект("Справочник.* -«идСправочника);
Если Спр.НайтиЛоКоду(КодЭлемента,ФлагПоиска)>0 Тогда
Если МетаРеквизит.Периодичесхий>0 Тогда U Если реквизит периодический - нужно установить дату, // на которую следует выбрать значение sDate = ДАТА(ДатаДляПериод);
II Проверяем параметр (дату) на корректность Если ДатаГод(sDate}<=0 Тогда
// Дата не корректна — установим дату на "текущую дату1 sDate = ТекущаяДата();
КонецЕсли;
И Установим дату выборки значения период, реквизита Спр. ИспольвобватьДату (sDate, 1);
КонецЕсли;
// Читаем значение реквизита из справочника
ЗкачРеже=Спр.ПолучитьАтрибут(*"+идРекжизита);
И Применяем СокрЛП()
Res = СокрЛП(ЗначРекж);
Если стрДпина(Res)<=0 Тогда
II Если значение - пустая строка, формируем // строковое представление по типу значения ТипЗн=ТипЗначения(ЗначРекв);
Если ТипЗн=0 Тогда
Res=’ < Неопределенный ” ;
КонецЕсли;
Если ТипЗн=10 Тогда
Res=’<Перечисление>";
КонецЕсли;
Если ТилЗн=11 Тогда
Res="<Справочник»*;
КонецЕсли;
Если ТипЗн=12 Тогда
Res="<Документ»*;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
Возврат Res;
КонецФункции И гл9_СокрЛПдпяЗначРеквизитаСправочника
В листинге 4.116 представлен пример вызова функции глобального модуля конфигурации (гл9_сокрЛПдляЗначРеквизитасправочника) из Delphi для нашего примера.
procedure TForml.SpeedButtcndClicklSender: TObject); // Обработчик события "нажатие кнопки "НайтиПоКоду" // Визуализация элемента справочника
Var
sEvalExpr: string; // Параметр для <EvalExpr> begin
Edit_Name.Text:=Trim(ole_Ref.Наименование);
sEvalExpr:='гл9_СокрЛПдляЗначРеквизитаСправочниха(';
SEvalExpr:=sEvalExpr+'"'+Edit_RefName.Text+'",';
SEvalExpr:=sEvalExpr+• ■ ' +'Реквизит.. Неопределенный1+'",';
SEvalExpr:=sEvalExpr+SE_Code.Text*',*;
SEvalExpr:=sEvalExpr+‘ *",';
SEvalExpr:=sEvalExpr+'O';
SEvalExpr:=sEvalExpr+')';
Mit_N.Text:=Trim(ole_lC.KvBlExpr(sEvalExpr));
sEvalExpr:='гл9_СокрЛПдляЗкачРекживитаСправочкика(';
sEvalExpr:=sEvalExpr+‘* 1+Edi t_RefName.Text+* *,' ;
sEvalExpr:=sEvalExpr+'"'+'Рехживит_СправочнихНеопределенный■+'",1 sEvalExpr:=sEvalExpr+SE_Code.Text+',';
aEvalExpr:=sEvalExpr+'"*, 1;
sEvalExpr:=sEvalExpr+' 0 •;
sEvalExpr:=sEvalExpr+') ' ;
Edit_NR.Text:=Trim (ole_lC.EvalExpr(sEvalExpr));
sEvalExpr:='гл9_СокрЛПдляЗначРеквизитаСправочкика(';
SEvalExpr:=sEvalExpr+1"'+Edit_RefName.Text+'“,';
sEvalExpr:=sEvalExpr+'"’ +'Реквиэит_ДокументНеопредаленимй• * * " ,';
sEvalExpr:=sEvalExpr+SE_Code.Text+',';
sEvalExpr: =sEvalExpr+ '"*,';'i
sEvalExpr:=sEvalExpr+'O';
SEvalExpr:=sEvalExpr+')';
Edit_ND.Text:=Trim(ole_lC.EvalExpr(sEvalExpr));
SEvalExpr: =' гл9_СокрЛПдляЗначРеквизитаСправочника (' ;
sEvalExpr:=sEvalExpr+'"’+Edi t_RefName.Text*'", *;
sEvalExpr:=sEvalExpr+'* 1 + 'Примечания'+",';
sEvalExpr:=sEvalExpr+SE_Code.Text*1,';
sEvalExpr: =sEvalExpr+ '*",';
sEvalExpr:=sEvalExpr+'01;
sEvalExpr:=sEvalExpr+■)';
Edit_Prim.Text:=Trim(ole_lC.EvalBxpr(sEvalExpr));
end,
На рис. 4.233 представлен результат визуализации справочника СправочникСНеопределеннымиРеквизитами С ПОМОЩЬЮ функции гл9_СокрЛПдляЗначРеквизитаСлравочника.
Среди штатных средств языка программирования ^.Предприятие есть функции ТипЗначенияСтр И ТипЗначеиия. Этим фунКЦИЯМ В Качестве пара* метра передается какое-то значение (реквизита или переменной). После вызова обе эти функции возвращают тип значения. Можно было бы этим воспользоваться, чтобы при визуализации "обходить" реквизиты, значения которых имеют неопределенный тип. Но вызвать эти функции посредством механизма OLE Automation, написав что-то вроде:
о1е_1С.ТипЗначенияСтр(...) ;
о1е_1С.ТипЗначеиия(...);
не получится.
Рис. 4.233. Визуализация справочника с помощью функции гл9_СокрЛПдляЗначРеквизитаСправочника
Можно для их вызова воспользоваться методом EvaiExpr, но, опять же, явно передать в качестве параметра значение агрегатного типа (oievarianc) этим функциям нельзя.
Одно из возможных решений (тоже далеко не идеальное) — создать в глобальном модуле конфигурации соответствующую функцию, которую можно было бы вызывать (через OLE Automation) с помощью метода
EvaiExpr.
Возможный вариант такой функции приведен в листинге 4.117.
КГ"',,,„.....,.,;,.;,..-4V...... „,„.,„„.„.„.., .„,..,.,.... .„„„.„^„..^y.,...-^..V:-._.....™.,.™V,„1№„^
Г Листинг 4.117. Функция в глобальном модуле 1С, определяющая типзначен
1®^?!З^Я^^..............V...LV™
И Вызов функции гл9_ТипЗначения_ДляЗначРеквизитаСправочника():
// идСправочника - идентификатор справочника, Н идРеквиэита — идентифкатор реквизита,
/ / КодЭлемента — код элемента справочника, / / ФлагПоиска:
И0 - во всем справочнике,
Ч1 - внутри родителя,
//2 - по полному коду (с учетом всех родителей).
Н Возвращаемое значение:
•■ -1 - некорректые входные параметры
И >=о — код типа данных (как его возвращает функция "ТипЗначения").
Функция гл9Функция гл9
Функция гл9
Функция гл9
идСправочника, идРеквизита, КодЭлемента, ДатаДляПериод=*", ФлагПоиска=0) Экспорт
идСправочника = СокрЛП(идСправочника); идРеквизита = СокрЛП (идРеквизита);
Если (СтрДлина(идСправочника)>0) И (СтрДлина(идРеквизита)>0) Тогда // Проверяем существование справочника <идСправочника>
Если Метаданные. Справочник (’" -i-идСправочника) . Выбран {} > 0 Тогда
// Проверяем существование реквизита <идРеквизита> справочника МатаРекжизит=
Метаданные.Справочник(""+идСправочника).Реквизит(■*+идРеквизита) Если МетаРеквизит.Выбран() >0 Тогда
Спр = СоздатьОбъект("Справочник."+идСпрааочника);
// Находим элемент справочника с соответствупцим кодом
Если Спр.НайтиПоКоду(КодЭлемента,ФлагПоисха)>0 Тогда
Если МатаРекнизит.Периодический:-0 Тогда
И Если реквизит периодический — нужно установить дату, // на которую следует выбрать значение sDate = ДАТА(ДатаДляПериод);
И Проверяем параметр (дату) на корректность
Если ДатаГод(sDate)<=0 Тогда
// Дата не корректна — будем ориентироваться // на 'текущую дату’
sDate = ТекущаяДата();
КонецЕсли;
// Установим дату выборки значения период, реквизита
Спр.ИспольвоватьДату(sDate,1);
КонецЕсли;
И Читаем значение реквизита из справочника
V = Спр.ПолучитьАтрибут(’"+идРеквизита);
// Определяем его тип
Кев = ТипЗначеяия(У);
KoнeцEcли;
КонецЕсли,-
ХонеиЕсли;
КонеиЕсли;
удерат Ree;
^ленФункции U гл9_ТипЗначения_ДляЗначРеквизитаСправочника
вызывая эту функцию с помощью метода EvaiExpr:
sgvalExpr: = * гл9_ТипЗначения_ДляЗначРехжизитаСпражочн><ка (' ;
sEvalExpr: =sEvalExpr+ ■ • • +Edit_RefName.Text+• *,' ;
sEvalExpr:=sEvalExpr+ " ' + ■Реквизит_Неопределенный•*'•,';
sEvalExpr:=sEvalExpr+SE_Code.Text+',';
sEvalExpr: =SEvalExpr+ '**,';
sEvalExpr: =sEval£xpr+ ■ 0' ;
sEvalExpr :=sEvalExpr+ 1) ' ;
NrType: = ole_lC. EvalBxpr (sEvalExpr) *1 ;
If NrType>0 Chen begin
end;
можно игнорировать реквизиты, значения которых имеют ТИП Неопределенный. Еще один вариант частичного решения проблемы — использование Delphi- функции varType. Функция varType (модуль system.PAS) в качестве параметра принимает значение типа olevarianc (или variant) и возвращает результат типа integer (множество значений которого определено в виде констант
в модуле system.PAS).
Перепишем фрагмент текста (см. листинг 4.114), как показано в листинге 4.118.
истине 4.118. Визуализация справочника)^истине 4.118. Визуализация справочника)^WiTOra^tF'STO
истине 4.118. Визуализация справочника)^
истине 4.118. Визуализация справочника)^
Procedure TForml.SpeedButton9Cllck(Sender: TObject) ; // Обработчик события "нажатие кнопки "НайтиПоКоду" // Визуализация элемента справочника begin
// Читаем тип данных, которые возвращает функция "VarType"
Edic_Name.Text:=IntToStr(VarType(ole_Ref.Наименование));
Edit_N.Text:=IntToStr(VarType(ole_Ref.Реквизит^Неопределеккый))
ПримечаниеПримечаниеэлементов справочникэлементов справочникIntToStr(VarType(ole_Ref.Реквизит_СлравочникНеопред Edit_№.Text:=IntToStr(VarType(ole_Ref.Реквизит_СлравочникНеопред Edit_№.Text:=IntToStr(VarType(ole_Ref.Реквизит„ДокументНеопредал Edit_Pr im.Text:=IntToStr(VarType(ole_Ref.Примечание)); //IntToStr(VarType(ole_Ref.Реквизит„ДокументНеопредал Edit_Pr im.Text:=IntToStr(VarType(ole_Ref.Примечание)); //i Строка инициализации - [ ;■_ Открыть справочник ( |i l'*_' Найти по кода I ("1 ; _. Наименование I |бi Строка инициализации - [ ;■_ Открыть справочник ( |i l'*_' Найти по кода I ("1 ; _. Наименование I |бendend_Реквизиг.Док^н^.^_Реквизиг.Док^н^.^IFIF
Примечание
Примечание
элементов справочник
элементов справочник
IntToStr(VarType(ole_Ref.Реквизит_СлравочникНеопред Edit_№.Text:=
IntToStr(VarType(ole_Ref.Реквизит_СлравочникНеопред Edit_№.Text:=
IntToStr(VarType(ole_Ref.Реквизит„ДокументНеопредал Edit_Pr im.Text:=IntToStr(VarType(ole_Ref.Примечание)); //
IntToStr(VarType(ole_Ref.Реквизит„ДокументНеопредал Edit_Pr im.Text:=IntToStr(VarType(ole_Ref.Примечание)); //
i Строка инициализации - [ ;■_ Открыть справочник ( |i l'*_' Найти по кода I ("1 ; _. Наименование I |б
i Строка инициализации - [ ;■_ Открыть справочник ( |i l'*_' Найти по кода I ("1 ; _. Наименование I |б
end
end
_Реквизиг.Док^н^.^
_Реквизиг.Док^н^.^
IF
IF
Часть I. 1С и механизм OLE Auti
Edi t_NR. Text : =
Результат представлен на рис. 4.234.
Рис. 4.234. Результат использования функции VarType для справочника СправочникСНеопределеннымиРеквизитами Проведем тот же эксперимент со справочником Физлица (проект sp_EditAttrInRef.DPR). Результат представлен на рис. 4.235.
В табл. 4.14 приведены константы, соответствующие значениям, которые функция VarType вернула в нашем случае.
Таблица 4.14. Результат, коп
юрый вернула функция VarType
| Значение
2<онстанта (в модуле system.PAS)
varEmpty*"
varDouble"
I $0000 [$000?
Тип реквизита справочника
Неопределенный
$0007
$0008
$0009
varDate
varoieStrI
varDispatchг
Дата Строка Агрегатный
Рис. 4.235. Результат использования функции VarType для справочника ФизЛица
То есть с помощью функции VarType можно при визуализации исключить обращение к реквизитам, значения которых имеют тип Неопределенный. Более того, для значений реквизитов, имеющих базовый тип, функция VarType возвращает однозначный результат, что можно использовать при визуализации справочников.
Для того чтобы можно было редактировать реквизит неопределенного типа, нужно сначала назначить ему какой-то тип (базовый или агрегатный). Ранее было сказано, что реквизиту неопределенного типа можно назначить какой-либо ТИП с помощью метода назначитьТип (или setType) справочника. Его синтаксис: НазначитьТип(<ИмяРеквиэита>, <ИмяТипа>, <Длина>, <Точность>)
Параметры: <ИмяРеквизита> (строковое выражение) — идентификатор Реквизита (неопределенного типа) справочника, как он назван в Конфигураторе; <ИмяТипа> (строковое выражение)— тип данных (или Вид сУбконто), который назначается реквизиту справочника (например: Строка, Число, Справочник. Товары, Документ. РасходнаяНакладная И Т.П.)", <Длина> (числовое выражение, необязательный) — длина поля представления данных (имеет смысл только при задании числового или строкового типа); <Точность> (числовое выражение; необязательный)— количество знаков
после десятичной точки (имеет смысл только при задании числового типу Метод НаэначитьТип позволяет назначить тип для реквизита, которой В Конфигураторе назначен ТИП Неопределенный.
Внимание!
Естественно, что перед вызовом метода НаэначитьТип ссылка на справочц» должна быть корректной и справочник должен быть спозиционирован на менте, к реквизитам которого применяется метод НаэначитьТип.
В листинге 4.119 приведены примеры вызова метода НаэначитьТип справочника для реквизитов неопределенного типа.
#»ж-#»ж-ole_Ref.НаэначитьТип('4idAttr, *' 4-’ Число', 10, 2);ole_Ref.НаэначитьТип('4idAttr, *' 4-’ Число', 10, 2);ole_Re£.НаэначитьТип('Ч-idAttr, 'Ч'Строка', 25, 0);ole_Re£.НаэначитьТип('Ч-idAttr, 'Ч'Строка', 25, 0);
#»ж-
#»ж-
ole_Ref.НаэначитьТип('4idAttr, *' 4-’ Число', 10, 2);
ole_Ref.НаэначитьТип('4idAttr, *' 4-’ Число', 10, 2);
ole_Re£.НаэначитьТип('Ч-idAttr, 'Ч'Строка', 25, 0);
ole_Re£.НаэначитьТип('Ч-idAttr, 'Ч'Строка', 25, 0);
01е_Де£.НаэначитьТип(11+idAttr, ''+'Дата', 0, 0);
ole_Ref.НаэначитьТип(1Ч-idAttr, 'Ч'Справочник.ФизЛица', 0, 0) ;
ole_Ref.НаэначитьТип(•4idAttr, ''+'Документ.ВыплатыФизЛицам*, 0, 0); ole_Re£.НаэначитьТип(*Ч-idAttr,
' ' +'Перечисление.СпособВыплатыФизЛицам', 0, 0);
ole_Re£.НаэначитьТип(’1+idAttr, " +'Неопределенный', 0, 0);
// Изменения в элементе справочника должны быть
// записаны в базу данных
о1е_1С_ге£.Записать;
Поясним листинг 4.119. Здесь:
oie_Ref — ссылка на какой-то справочник (переменная типа olevariant);
idAttr — идентификатор реквизита неопределенного типа.
В общем-то, как видно, ничего сложного здесь нет в том случае, если МЫ точно знаем, что для данного справочника (oie_Ref) реквизит id_Attr имеет ТИП
Примечание
Для значений реквизитов неопределенного типа в 1С отведено только 22 символа. Поэтому команда (листинг 4.11):
ole_Ref.НаэначитьТип(‘ Ч-idAttr, ‘ Ч 'Строка', 25, 0);
выполнится, но реально под 22 символа. Более подробно обвыполнится, но реально под 22 символа. Более подробно обзначение реквизита будет выделено только этом 'феномене- — в части II этой книги.
выполнится, но реально под 22 символа. Более подробно об
выполнится, но реально под 22 символа. Более подробно об
^Доступ к информации 1С из внешних приложений^
Модифицируем наш Delphi-проект (sp_EditAttrInRef_2.DPR).
ПРИМЕЧАНИЕ
Исходные тексты находятся на сопроводительном компакт-диске книги в папке \Part_1\Chapter_04\Toplc_4_7\llem_4_7_1\sp_EditAttrlnRef_2.PAS\02.
добавим в форму проекта кнопку Тип (рис. 4.236).
Рис. 4.236. Форма проекта sp_EditAttrlnRef_2.DPRРис. 4.236. Форма проекта sp_EditAttrlnRef_2.DPR
Рис. 4.236. Форма проекта sp_EditAttrlnRef_2.DPR
Рис. 4.236. Форма проекта sp_EditAttrlnRef_2.DPR
Ее назначение— вызов метода назначитьТип справочника для реквизита Реквиэит_Неопределенный. Текст обработчика события "нажатие кнопки
Тип" представлен в листинге 4.120.
Procedure TForml.SpeedButtcn6Click(Sender: TObject);
// Вызов метода "НазначитьТип"
Var
sType: string; // Тип значения реквизита
sEvalExpr: string; //Параметр для EvalExpr
CountChar,//Количество символов
Precis ; integer; // Точность (количество знаков после запятой)
Yes: byte;//Вспомогательная переменная
Sx: string;//Вспомогательная переменная
°egin
* * Проверяем, существует ли ссылка на справочник
if not VarlsBnpty (ole-Kef) then begin
Yes:=0;
CountChar:=0;
Precis:=0;
II
it Определяем текущий тип значения реквизита
sEvalExpr:='гл9_ТипЗначенияСтр__ДпяЗначРеквизитаСлравочиика(1;
sEvalExpr:=sEvalExpr*'* 1+Edit_RefName.Text+'", ' ;
sEvalExpr:=sEvalExpr+'"'+'Рекеизит_Неопределенимй' * ",1;
sEvalExpr:=sEvalExpr+SE_Code.Text+',';
sEvalExpr:=sEvalExpr+'"",';
sEvalExpr:=sEvalExpr+'0,';
sEvalExpr:=sEvalExpr+11';
sEvalExpr:=sEvalExpr+1)’;
II ShowMessage(sEvalExpr);
■Type:=Trim(ole_lC.EvalExpr(sEvalExpr));
// ShowMessage(sType);
//•
//
// Указываем новый тип реквизита
if InputQuery!‘НазначитьТип*,
'Новый тип',«Туре) then begin
sType:=Trim(sType);
if length(sType)>0 then begin
Yes:=l;
if Uppercase(sType)=UpperCase('Число') then begin
// Новый тип реквизита - "Число"
Yes:=0;
Sx:='10';
if InputQuery('Тип <Число>‘, 'Кол-во цифр всего',Sx) then begin
Sx:=Trim(Sx);
CountChar:=StrToInt(Sx);
if CountChar>0 then begin
Sx:='2';
if InputQuery( "Тип <Число>', 'Кол-во цифр после запятой',Sx) then begin
Sx:=Trim(Sx);
Precis:=StrToInt(Sx);
Yes:=l;
end;
end;
end;
end;
if Uppercase(sType)=UpperCase('Строка') then begin // Новый тип реквизита - "Строка" Yes:=0;
Sx:='25';
if Inpu tQuery ( "Гил <Строка>', ’Кол-во символов всего',Sx) then begin Sx:=Trim(Sx);
CountChar:=StrToInt(Sx);
if CountChar>0 then begin
Yes:=1;
end;
end;
end;
end;
end;
//
if Yes>0 then begin
// Назначаем новый тип реквизита ole_Ref.НазначитьТип(''+'Реквиэит_Нвопределанный',
"+вТуре, CountChar*!, Preoie*!};
// Записываем изменения в базу данных
ole_Ref.Записать;
// Вновь визуализируем элемент справочника SpeedButton9.Click;
end;
end;
•hd;
Поясним текст обработчика.
Сначала определяем текущий тип значения реквизита справочника. Для этого бываем (с помощью метода EvalExpr) функцию глобального модуля ТипзначенияСтр_ДляЗначРеквизитаСправочника (ее текст приведен далее).
Затем вводим новый тип реквизита (как показано в листинге 4.121). Если но. вый тип число или Строка, то запрашиваем количество символов и точност, (для типа число). Далее вызываем метод справочника НазначитьТип и изме, нения в элементе справочника записываем на диск. Вот, собственно, и все
Обратите внимание на вызов метода НазначитьТип:
ole_Ref.НазначитьТип('•+1Реквизит_Неопределенный',
••+sType, CountChar*!, Precis*!);
Здесь (как и раньше) нужно в передаваемых параметрах указывать явно, что строковый параметр — это строка (параметр предваряется одинарными кавычками), а параметр типа integer — это число (умножаем на 1).
// Вызов функции гл9_ТипЗначенияСтр_ДляЗначРеквиэитаСправочника(): // идСправочника — идентификатор справочника, // идРеквиэита - идентификатор реквизита, II КодЭлемента — код элемента справочника, И ФлагПоиска: //0 — во всем справочнике,
II1 — внутри родителя,
II 2 — по полному коду (с учетом всех родителей).
// ВозвращатьВид — если >0, то для агрегатных типов возвращается Вид (через точку после типа).
II Примеры: // Дата //Перечисление.СостояниеФизлица
// Справочник.ГородаСтранМира Функция гл9_ТипЗначенияСтр_ДпяЗначРеквизитаСправочника( идСправочника, идРеквиэита, КодЭлемента, ДатаДляПериод="•, ФлагПоиска=0, ВоэвращатьВид=0) Экспорт
Res = ■*;
идСправочника = СокрЛП(идСправочника); идРеквиэита = СокрЛП(идРеквиэита);
если (СтрДлина(идСправочника)>0) И (СтрДлина(идРеквизита)>0) Тогда // проверяем существовние справочника "идСправочника"
Если Метаданные.Справочник(п"+идСправочниха).Выбран()>0 Тогда
// Проверяем существовние реквизита "идРеквизита*
// справочника "идСправочника*
ураРеквиэит = Метаданные.Справочник("*+идСправочника).Реквизит
(•"+идРеквизита);
Бели МетаРеквизит.Выбран()>0 Тогда
Спр = СоздатьОб'ьехт("Справочник."+идСправочника);
Если Спр.НайтиПоКоду(КодЭлемента,ФлагПоиска)>0 Тогда
Если МетаРеквизит.Периодический»0 Тогда
// Если реквизит периодический — нужно установить дату, //на которую следует выбрать значение
sDace = ДАТА(ДатаДпяПериод);
// Проверяем параметр (дату) на корректность
Если ДатаГод(sDate)<=0 Тогда
// Дата не корректна — будем ориентироваться
//на "текущую дату"
sDate = ТекущаяДата();
КонецЕсли;
// Устанавливаем дату выбора значения
// периодического реквизита
Спр.ИслользоватъДату(sDate,1);
КонецЕсли;
// Читаем значение реквизита из справочника
V = Спр.ПолучитьАтрибут(""+идРеквизита);
// Определяем тип значения
Res = ТипЗначенияСтр(V);
Если СтрДлина(Res)<=0 Тогда
Res="Неопределенный";
КонецЕсли;
Если ЧИСЛО(ВоэврашдтьВид)>0 Тогда
// Нужно вернуть "Вид" значения, // если значение имеет агрегатный тип
ТипЧ = ТипЗначения(У);
Если ТипЧ>3 Тогда
// Вычисляем "Вид* значения агрегатного типа
Res = Res+*."+СокрЛП(У.Вид());
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
Возврат Res;
КонецФункции // гл9_ТипЗначенияСтр_ЛляЗначРеквизитаСправоч.чика
Посмотрим, как все это работает. Скомпилируем проект и запустим его на выполнение (рис. 4.237).
Рис. 4.237. Визуализация элемента справочника
СправочникСНеопределеинымиРеквизитами
Нажмем кнопку Тип и введем новый тип Дата (рис. 4.238).
На рис. 4.239 представлен результат визуализации элемента справочника после применения метода НазначитьТип для реквизита Реквизит_Неопределенный.
Если теперь открыть справочник СправочникСНеопределеннымиРеквизитами в Программе 1С:Предприятие, то реквизит Реквизит_Неопределенный ДЛЯ элемента справочника с кодом 1 будет доступен для редактирования.
Запустим нашу программу sp_EditAttrInRef_2.EXE и для разных элементов справочника назначим реквизиту Реквизит_неопределенный разные типы (табл. 4.15).
ЙЯРнечтрвЛд*^^■ЙЯРнечтрвЛд*^^■Р Соединиться IСтрока инициализации •Открыть справочникР Соединиться IСтрока инициализации •Открыть справочникj |V77 Applicationj |V77 ApplicationНайти по коруНайти по коруНаименованиеНаименованиеСправочникСНеолраделенныкиРеквиэитамиСправочникСНеолраделенныкиРеквиэитамиИИЗлемент-1Злемент-1-Реквизиты;Рек.визит Н еопределемный-Реквизиты;Рек.визит Н еопределемныйРеквизит СправочникН еопредеРеквизит СправочникН еопреде*.?<;% 7^->*.?<;% 7^->j Тип ^Неопределенный)j Тип ^Неопределенный)НазначитьТипНазначитьТипXXРеквизит, ДокументН еопреде*
ЙЯРнечтрвЛд*^^■
ЙЯРнечтрвЛд*^^■
Р Соединиться I
Строка инициализации •Открыть справочник
Р Соединиться I
Строка инициализации •Открыть справочник
j |V77 Application
j |V77 Application
Найти по кору
Найти по кору
Наименование
Наименование
СправочникСНеолраделенныкиРеквиэитами
СправочникСНеолраделенныкиРеквиэитами
И
И
Злемент-1
Злемент-1
-Реквизиты;
Рек.визит Н еопределемный
-Реквизиты;
Рек.визит Н еопределемный
Реквизит СправочникН еопреде
Реквизит СправочникН еопреде
*.?<;% 7^->
*.?<;% 7^->
j Тип ^Неопределенный)
j Тип ^Неопределенный)
НазначитьТип
НазначитьТип
X
X
Примечание
ОК |ОК |Новый тип |Датг(Новый тип |Датг(Рис. 4.239. Визуализация элемента справочникаСправочникСНеопределеннымиРеквизитами после изменения типа реквизита Реквизит_НеопределенныйРис. 4.239. Визуализация элемента справочникаСправочникСНеопределеннымиРеквизитами после изменения типа реквизита Реквизит_НеопределенныйРис. 4.238. Назначение нового типа значению реквизита неопределенного типа
ОК |
ОК |
Новый тип |Датг(
Новый тип |Датг(
Рис. 4.239. Визуализация элемента справочника
СправочникСНеопределеннымиРеквизитами после изменения типа реквизита Реквизит_Неопределенный
Рис. 4.239. Визуализация элемента справочника
СправочникСНеопределеннымиРеквизитами после изменения типа реквизита Реквизит_Неопределенный
Таблица 4.15. Тип реквизита Реквизит_Неопределенный для разных элементов справочника
од элемента правочника
Тип
1
Число (длина 10, точность 2)
2
Строка (длина 25)
3
Дата
4
Справочник.ФизЛица
5
Документ.ВыплатыФизЛицам
6
Перечисление.ВидВыплатФизЛицам
is.is.Запустим программу 1С:Предприятие, откроем справочник Справочнику
is.
is.
Ви.Ви.определеннымиРеквизитами и отредактируем значение реквизита рек зит_Неопределенный следующим образом (рис. 4.240).
Ви.
Ви.
|Код
Наймем...
Реквизит Неопределенный
Элемент-1
125.32
2
Элемент-2
Это строка
3
Элемент-3
24.09.06
Элемент-4
Иванов Иван Иванович
b
Элемент-5
ВыплатыФизЛицам 2
а
ь
Элемент-6
Премия
Рис. 4.240. Справочник СправочникСНеопределеннымиРеквизитами.РеквизитРеквизит_Неопределенный
Вновь запустим нашу программу и, перемещаясь по элементам справочника, убедимся, что "все работает".
Теперь посмотрим, как можно редактировать значения реквизитов неопределенного типа (по метаданным), если конкретным значениям этих реквизитов назначен какой-либо тип. В рамках проекта sp_EditAttr!nRef.DPR мы рассмотрели вопросы редактирования реквизитов разного типа. По сути эти наработки (в целом) применимы и здесь.
Откроем наш проект (sp_EditAltr!nRef_2.DPR) и создадим обработчик события: "нажатие кнопки Реквизит_Неопределенный" (листинг 4.122).
procedure TForml.SpeedButton2Click(Sender: TObject); Var
Sx: string;// Вспомогательная переменная
sKind: string; H Вид значения агрегатного типа NrType: integer; H Тип значения реквизита sEvalExpr: string; // Параметр для EvalExpr oleBuf, oleDoc: oleVariant; // Ссыпка на объект типа "Документ" begin
// Проверяем, существует ли ссылка на справочник
if not VarIsanpty(ole_Ref) then begin
H
// Определяем текущий тип значения реквизита
sEvalExpr:='гл9_ТипЗначения_ДляЗначРеквивитаСправочника(';
sEvalExpr:=sEvalExpr+1"'+Edit_RefName.Text*’",';
sEvalExpr:=sEvalExpr+■■'+'Рек»изит_Неопределениый■*"■, ';
sEvalExpr:=sEvalExpr+SE_Code.Text*', *;
sEvalExpr:=sEvalExpr+"•.';
sEvalExpr: =sEvalExpr+' 01,-
sEvalExpr:=sEvalExpr+') ' ;
NrType:=ole_lC.BvalExpr(sEvalExpr)*1;
U
if NrType <= 0 then begin
ShowMessage('Сначала нужно реквизиту назначить тип');
end;
if (NrType in [1..3]) then begin
// Базовый тип
Sx:=Trim(ole_Ref.Реквизит-Неолределенный);
if InputQuery!'Реквизит_Неопределенный','Новое значение',Sx) then begin
Sx:=Trim(Sx) ;
// Редактируем значение реквизита
ole_Ref.Реквизит„Неопределенный:=Sx;
// Записываем изменения в справочнике в базу данных
ole_Ref.Записать;
// Вновь визуализируем элемент справочника
SpeedButton9. Click;
end;
end;
if NrType = 10 then begin
// Перечисление
aKind:=Tr im(ole_Ref.РекзизитНеопределэнный.Вид);
Sx:=Trim(ole_Ref.Рекжизит.Heoпредеденный.Идентификатор);
if Dlg_Select_ValueOfEnum.Execute(ole_lC,sKind,Sx) then begin
// Редактируем значение реквизита
ole_Ref. Реквивит_Неопределенный: =
Dlg_Select_ValueOfEnum.oleValueEnum;
// Записываем изменения в справочнике в базу данных
ole_Ref.Записать;
// Вновь визуализируем элемент справочника
SpeedButton9.Click;
end;
end;
if NrType = 11 then begin
// Справочник
sKind:=Trim (ole_Ref.Реквизит_Неопредвленный.Вид);
Sx:=Trim(ole_Ref.Реквизит_Неопределенный.Код);
if Dlg_Select„EHemFrcinRef.Execute (ole_lC, sKind, Sx) then begin
// Редактируем значение реквизита
ole_Ref.РеквизитНеопредпленный:=
Dlg_Select_ElemFromRef.olaElemSel;
// Записываем изменения в справочнике в базу данных
ole_Ref.Записать;
// Вновь визуализируем элемент справочника
SpeedButton9.Click;
end;
end;
if NrType = 12 then begin
// Документ
sKind:=Trim(ole_Ref.Реквизит..Неопределенный. Вид);
oleDoc:=ole_lC.CreateObjact(1Документ.'+sKind);
if (oleDoc.Выбрать(1 Выберите документ')*l)>0 then begin
// Читаем ссылку на текущий документ
oleBuf:=oleDoc.ТекущийДокумент;
// Еще раз назначаем тип
// (без этого работает некорректно)
ole_Ref.НазначитьТип(1РаквиэитНеопределениый','Документ.'+sKind, 0,0);
//
И Редактируем значение реквизита.
// Такое присвоение не всегда работает корректно:
// ole_Ref.Реквизит-Неопределенный:=oleDoc.ТекушийДокумент: U Тогда можно использовать такой вариант:
ole_Ref.РеквизитНеопределениый:=oleBu£;
// ч
// Записываем изменения в справочнике в базу данных ole_Ref.Записать;
// Вновь визуализируем элемент справочника SpeedButton9.Click;
end;
end;
end;
Поясним текст обработчика.
Сначала вызываем функцию гл9_ТипЗначения_ЛляЗначРеквизитаСправочника в контексте метода EvalExpr. Эта функция возвращает в переменной Nr-туре код типа значения реквизита.
Далее, в зависимости от типа значения реквизита, вызываются различные способы редактирования значения реквизитов (все они, кроме редактирования значений реквизитов типа Документ, были подробно рассмотрены ранее). Редактирование значений типа документ нужно рассмотреть более детально.
Как видите, код.типа значения документ равен 12. Сначала мы определяем вид (идентификатор) документа:
sKind:=Trim(ole_Ref.Реквизит_Неопределенный.Вид);
Затем создаем объект типа документ заданного вида:
oleDoc:=ole_lC.CreateObject('Документ.'+sKind);
С помощью метода выбрать документа (как объекта) выбираем документ (в качестве нового значения для реквизита Реквизит_неопределениый):
if (oleDoc.Выбрать!'Выберите документ')*1)>0 then begin
Получаем ссылку на выбранный документ:
QleBuf:=oleDoc.ТекущийДокумент;
Затем вновь назначаем соответствующий тип значению реквизита справочника (хотя он был уже назначен ранее):
Ole_Re£.НазкачитьТип('Реквизит_Неопределенный',"Документ.'+sKind, 0,0);
Без этого тоже почему-то присвоение работает некорректно.
И, наконец-то, присваиваем реквизиту новое значение:
°le_Ref.Реквизит_Неопрвделанныи:=oleBuf;
Изменения в элементе справочника, как обычно, записываем в базу данных.
°le_Ref.Записать;
Скомпилируем наш проект, запустим его на выполнение и отредактируем значения реквизита Реквизит_неопределенный для всех элементов справоч-
1 **ИКа СправочникСНеопределеннымиРеквизитами (рис. 4.241).
Откроем справочник СправочникСНеопределеннымиРеквизитами в программе ^Предприятие и убедимся, что все, что мы напрограммировали, работает (рис. 4.242).
23^23^tPAasHswfbt:tPAasHswfbt:Реквиэит Неопределенный] Тип Ц125 32Реквиэит Неопределенный] Тип Ц125 32Реквкзит СправочникН еопределенньРеквкзит СправочникН еопределенньРеквизит_НеопределенныйРеквизит_Неопределенныйхх
23^
23^
tPAasHswfbt:
tPAasHswfbt:
Реквиэит Неопределенный] Тип Ц125 32
Реквиэит Неопределенный] Тип Ц125 32
Реквкзит СправочникН еопределеннь
Реквкзит СправочникН еопределеннь
Реквизит_Неопределенный
Реквизит_Неопределенный
х
х
Реквизит Д окуме ^Неопределенны и значение
ПримечаниеПримечание^^^■^■^^■^^^^■"■■^■■*^^—^—*—™™^—-^^—^*^*—*—I UWU рПЧ < И ' V
Примечание
Примечание
[эззоц
СК I Cancel |
Рис. 4.241. Редактирование значения реквизита Реквизит_Неопределенный
1 lk»A 1 Наименование |
Реквизит Неопределенный'"
Элемент-1
999 01
Wil
2
Злемент-2
Это строка•2
Ml
3
Элемент-3
28.09.06
psill
4
Элемент-4
Криогеном Фекла Иаринадовна
Mil
5
Элемент-5
ВыплатыФизЛицам 3
№1
6
Элеменг-Б
МатПомощь
Рис. 4.242. Реквизит Реквиэит_Неопределенный после редактирования в "нашей" программе
Теперь посмотрим, как можно редактировать значение реквизита типа Справочник неопределенного вида (Реквизит_СправочникНеопределенный в справочнике СправочникСНеопределеннымиРеквизитами). Такой реквизит позволяет хранить значения, которые могут быть элементами справочников любого типа. Для того чтобы указать, элемент какого именно справочника следует хранить в данном реквизите, нужно вызвать функцию НазначитьВид программы 1С:Предприятие. Синтаксис:
НазначитьВид(<3начение>, <Вид>)
Параметры: <3начение> (ТИП Документ/Справочник/Счет неопределенного вида)— обычно реквизит документа, справочника или диалога формы; <вид> — тип Строка (вид значения может быть задан строкой, содержащей идентификатор конкретного справочника, документа, плана счетов) или вид субконто (вид значения может быть задан видом субконто, который имеет тип соответственно конкретного справочника, документа, счета).
Процедура НазначитьВид (или SetKind) позволяет установить конкретный вид ДЛЯ значений типа Документ неопределенного вида, Справочник неопределенного вида. Счет неопределенного вида. При ЭТОМ, если сущеСТВуЮШее значение не соответствует вновь установленному виду, оно очищается.
Данная процедура используется обычно для значений реквизитов в диалогах форм. В качестве первого параметра передается значение типа справочник.
кУмент или счет, в котором нужно установить вид. Во втором параметре Называется вид в качестве строки — идентификатора или вида субконто.
л иную процедуру можно использовать в сочетании с методом НеИзменять- ™ элемента формы. Это возволяет регулировать программно собственно вИД а для самого значения предоставить пользователю возможность интерактивного выбора.
Внимание!
Естественно, что перед вызовом функции НазначитьВид ссылка на справочник должна быть корректной, и справочник должен быть спозиционирован на элементе, к реквизитам которого применяется метод НазначитьВид.
Здесь следует отметить один момент: после вызова функции НазначитьВид нужно сразу же присвоить реквизиту соответствующее значение и вызвать МеТОД справочника Записать.
В листинге 4.123 приведен текст обработчика события "нажатие кнопки реквизит_СправочникНеопрсделенный" (редактирование значения реквизита элемента справочника).
procedure TForml.SpeedButton3Click(Sender: TObject);
// Редактирование реквизита "Реквизит_СправочникНеопределенный"
Var
Sx: string; 7/ Вспомогательная переменная
sKind: string; // Вид значения агрегатного типа-
begin
7/ Проверяем, существует ли ссылка на справочник
if not VarlsEmpty(ole_Ref) then begin Sx:="';
Il Читаем "Вид” значения реквизита
■Kind:=Trim(о1е_Де£.Реквизит_СлравочникНоопределеияый.Вид);
if length(sKind)>0 then begin
ll Если вид реквизита указан, значит значение корректно U и можно прочитать его код (как элемента справочника) Sx:=Trim(ole_Ref.Реквизит_СправочникНеопределенный.Код);
end;
if InputQuexyl'Реквиэит_СправочникНеопределенный','Новый Вид',«Kind)
then begin
SKind :=Trim( sKind);
// Вызываем функцию "НаэначитьВид()" для данного реквизита
о1е_1С.НаэначитьВид(ole_Ref.Раквизит_СправочникНаопраделвнный,1•+ак1пд)
// Выбираем элемент справочника (как новое значение
II для реквизита "Реквизит_СправочникНеопределенный")
if Dlg_Select_ElemFr<xnRaf.Execute(ole_lC, sKind, Sx) then begin
// Редактируем значение реквизита
ole_Re f.Реквизит_СправочникНеопределенный: =
Dlg_Select_ElemFrc*nRef. oleElemSel ;
И Записываем изменения в справочнике в базу данных
ole_Ref. Записать ;
// Вновь визуализируем элемент справочника
SpeedButton9.Click;
end;
end;
end;
end;
Поясним текст обработчика.
В данном случае мы точно знаем тип значения реквизита (агрегатный тип). Следовательно, значение этого реквизита имеет свойство Вид (идентификатор справочника). Мы его считываем в строке:
sKind: =Trim(ole_Ref.Реквизит_СправочникНеопределенный.Вид);
Запрашиваем новый вид справочника для данного реквизита (данного элемента данного справочника):
if InputQuery('Реквизит_СправочникНеопределенный','Новый Вид*,eKind)
then begin
Вызываем метод справочника НаэначитьВид для данного реквизита:
о1е_1С.НаэначитьВид(ole_Ref.Реквиэит.Справочники«определенный,''+sKind) ;
Далее вызываем диалоговое окно для выбора нового значения реквизита (из множества элементов справочника заданного вида):
if Dlg_Select_ElemFromRef.Execute(ole_lC, sKind, Sx) then begin
Редактируем значение реквизита:
ole_Ref.Реквиэит_СправочникНеопредаленный:=
Dlg_Select_ElemFroniRef. oleElemS»11
Изменения в элементе справочника записываем в базу данных:
ole_Ref.Записать;
компилируем наш проект и запустим его на выполнение.
Проведем тестирование кода (листинг 4.123) на примере элемента (с кодом 0) справочника СправочникСНеопределеннымиРеквизитами.
33Назначим значению реквизита Реквизит_СправочникНеопределенный новый вИд физЛица (рис. 4.243).
3
3
Реквизит_СправочникНеопределенный
Новый ВивЙ}фиэЛица|
I ОК | Cancel |
*
Рис. 4.243. Новый вид для реквизита Реквизит_СправочникНеопределенный
Затем выберем новое значение для реквизита Реквизиту справочникНеопределенный из множества допустимых значений (элементов справочника Физлица) — рис. 4.244.
Результат представлен на рис. 4.245.
|'Ь риогениьз Фекла Марннадоьна|'Ь риогениьз Фекла МарннадоьнаНаименованиеГруппа-1Г рулпа-2Группа-3 НаименованиеГруппа-1Г рулпа-2Группа-3
|'Ь риогениьз Фекла Марннадоьна
|'Ь риогениьз Фекла Марннадоьна
Наименование
Группа-1
Г рулпа-2
Группа-3
Наименование
Группа-1
Г рулпа-2
Группа-3
Рис. 4.244. Выбор нового значениядля реквизита Реквизит_СправочникНеопределенный
'Реквизиты: -
Рвквизит_Неопраде ленный
Тип
i
999.01!
Реквизит_СпраеочникНеопределенный
К,
Криогенова Фекла МаринадовнаI
Реквизит_ДокументНеопрейеленный
< Документ)
Примечание
Рис. 4.245. Новое значение присвоено реквизитуРеквизит_СправочникНеопределенный
Теперь для этого же элемента справочника назначим этому же реквизиту ^Угой вид (идентификатор справочника) — рис. 4.246.
[-Реквизиты:""[-Реквизиты:""Реквиэиг НеопределеннЫйРеквиэит_СпрааочникН еопределемныйРеквизит,ДокументНеопредвленный IРеквиэиг НеопределеннЫйРеквиэит_СпрааочникН еопределемныйРеквизит,ДокументНеопредвленный IТип [999^7Тип [999^7|t'.pnorснова Фекла Маринааовна|t'.pnorснова Фекла МаринааовнаРеквиэиТ-СправочникНеопределенныйРеквиэиТ-СправочникНеопределенныйа.а.ПримечетеПримечетеНовый Вид|Г ородаСтранМираI оГ1 1—Новый Вид|Г ородаСтранМираI оГ1 1—] С***1 |] С***1 |Рис. 4.246. Новый вид для реквизитаРеквизит_СправочникНеопределенныйРис. 4.246. Новый вид для реквизитаРеквизит_СправочникНеопределенныйИ выберем новое значение из множества допустимых справочника городаСтранМира) — рис. 4.247.И выберем новое значение из множества допустимых справочника городаСтранМира) — рис. 4.247.значений (элементовзначений (элементовРезультат представлен на рис. 4.248.Результат представлен на рис. 4.248.НВВЧКНВВЧК№1 №11 №11 №111 Mil №111 №111№1 №11 №11 №111 Mil №111 №1113 Ильиче вок3 Ильиче вок2|Киев Минск 2 Москва1 Одесса1 Санкт-Петербург2|Киев Минск 2 Москва1 Одесса1 Санкт-Петербург|| Усинск|| УсинскРис. 4.247. Выбор нового значениядля реквизита Реквизит_СправочникНеопределенныйРис. 4.247. Выбор нового значениядля реквизита Реквизит_СправочникНеопределенныйРис. 4.248. Новое значение присвоено реквизиту Реквизит_СправочникНеопределенныйРис. 4.248. Новое значение присвоено реквизиту Реквизит_СправочникНеопределенный
[-Реквизиты:""
[-Реквизиты:""
Реквиэиг НеопределеннЫй
Реквиэит_СпрааочникН еопределемный
Реквизит,ДокументНеопредвленный I
Реквиэиг НеопределеннЫй
Реквиэит_СпрааочникН еопределемный
Реквизит,ДокументНеопредвленный I
Тип [999^7
Тип [999^7
|t'.pnorснова Фекла Маринааовна
|t'.pnorснова Фекла Маринааовна
РеквиэиТ-СправочникНеопределенный
РеквиэиТ-СправочникНеопределенный
а.
а.
Примечете
Примечете
Новый Вид
|Г ородаСтранМира
I оГ
1 1—
Новый Вид
|Г ородаСтранМира
I оГ
1 1—
] С***1 |
] С***1 |
Рис. 4.246. Новый вид для реквизита
Реквизит_СправочникНеопределенный
Рис. 4.246. Новый вид для реквизита
Реквизит_СправочникНеопределенный
И выберем новое значение из множества допустимых справочника городаСтранМира) — рис. 4.247.
И выберем новое значение из множества допустимых справочника городаСтранМира) — рис. 4.247.
значений (элементов
значений (элементов
Результат представлен на рис. 4.248.
Результат представлен на рис. 4.248.
НВВЧК
НВВЧК
№1 №11 №11 №111 Mil №111 №111
№1 №11 №11 №111 Mil №111 №111
3 Ильиче вок
3 Ильиче вок
2|Киев Минск 2 Москва
1 Одесса
1 Санкт-Петербург
2|Киев Минск 2 Москва
1 Одесса
1 Санкт-Петербург
|| Усинск
|| Усинск
Рис. 4.247. Выбор нового значениядля реквизита Реквизит_СправочникНеопределенный
Рис. 4.247. Выбор нового значениядля реквизита Реквизит_СправочникНеопределенный
Рис. 4.248. Новое значение присвоено реквизиту Реквизит_СправочникНеопределенный
Рис. 4.248. Новое значение присвоено реквизиту Реквизит_СправочникНеопределенный
Думаю, что здесь комментарии излишни.
Точно такой же подход можно применить и в отношении реквизита типа Л° кумент неопределенного вида.
В листинге 4.124 „ради текст обработчика события "нажатие кнопки ВекиизитЛокументНеопределенный" (редякгирояаиие значения реквн°иг" элемента справочника). реквизита
procedure TForml. SpeedMttcniCllck(Sender: TObject);
j! редактирование реквизита "Реквизит_ДокументНеопределенный" Var
sKind: string; II Вид значения агрегатного типа
oleBuf: oleVariant; II Вспомогательная переменная
oleDoc: oleVariant; // Ссылка на объект типа "Документ"
begin
// Проверяем, существует ли ссылка на справочник
if not VarIsEnpty(ole_Ref) then begin
// Читаем "Вид" значения реквизита
eKind: =Tr im (ole_Ref. Реквизит^ПокументНеопределенный. Вид) ;
if XnputQuery (' Реквизит-ДокументНеопределенный1, 'Новый Вид *,sKind) then begin
sKind: =Trim(sKind) ;
II Вызываем функцию "НазначитьВид()" для данного реквизита
01е_1С.НазначитьВид(ole_Ref-Реквизит—ДокумектНеопределомный,'’+sKind);
// Создаем объет типа "Документ" // и получаем ссылку на него
oleDoc:=о1е_1С.CreateObjeot('Документ.14-sKind);
II Выбираем документ (как новое значение для реквизита
II "Реквизит-ЛокументНеопределенный")
if (oleDoc.Выбрать('Выберите документ')*1)>0 then begin II Читаем ссылку на текущий документ
И И U И иИ И U И иoleBuf:=oleDoc.ТекущийДокумент;
И И U И и
И И U И и
Редактируем значение реквизита.
Это не всегда работает корректно:
ole_Ref.Реквизит_ДокументНеопределенный:=oleDoc.ТекущийДокумент;
Тогда можно попробовать так:
ole_Ref.Реквизит . ДокумантНеопределенный:=oleBuf;
//
II Записываем изменения в справочнике в базу данных ole_Ref.Записать;
II Вновь визуализируем элемент справочника SpeedButtonS.Click;
end;
end;
end;
end;
Скомпилируем наш проект и запустим его на выполнение. Проведем тести- рование кода (листинг 4.124) на примере элемента (с кодом 0) справочника СправочникСНеопределеннымиРеквизитами.
Назначим значению реквизита Реквизит_ДокументНеопределенный новый вид ИзменениеСостоянияФиэЛиц (рис. 4.249).
Выбираем новое значение из множества допустимых значений (документов
вида ИзменениеСостоянияФиэЛиц) — рис. 4.250.
tfrRWJ-1^7&^^ ——т— ’,.'' -L.;‘ Реквизит_Нволределенный ’
К—
Реквизит Спраеочни|Л еопределетый
к’ РеквизитЛокумекгНеслрвбелекный
Примечание
Новый ВтНовый ВтРис. 4.249. Новый вид ДЛЯ реквизита РеквиэитЛокументНеопределенныиРис. 4.249. Новый вид ДЛЯ реквизита РеквиэитЛокументНеопределенныи
Новый Вт
Новый Вт
Рис. 4.249. Новый вид ДЛЯ реквизита РеквиэитЛокументНеопределенныи
Рис. 4.249. Новый вид ДЛЯ реквизита РеквиэитЛокументНеопределенныи
-Реквизиты-Реквизиты>./, Реквизит_НеопределенньйРекеизит СлравочникНеопре41еленньйРеквизит,ДокументНеопределанныйПримечете>./, Реквизит_НеопределенньйРекеизит СлравочникНеопре41еленньйРеквизит,ДокументНеопределанныйПримечетеТ^ |ВыллётыФизЛ|идем 3,Аксакалов Аксакал АксакаловичТ^ |ВыллётыФизЛ|идем 3,Аксакалов Аксакал Аксакалович| < Документ)| < Документ)Рииннзит ДокуметНеопредсленныйРииннзит ДокуметНеопредсленный
-Реквизиты
-Реквизиты
>./, Реквизит_Неопределенньй
Рекеизит СлравочникНеопре41еленньй
Реквизит,ДокументНеопределанный
Примечете
>./, Реквизит_Неопределенньй
Рекеизит СлравочникНеопре41еленньй
Реквизит,ДокументНеопределанный
Примечете
Т^ |ВыллётыФизЛ|идем 3
,Аксакалов Аксакал Аксакалович
Т^ |ВыллётыФизЛ|идем 3
,Аксакалов Аксакал Аксакалович
| < Документ)
| < Документ)
Рииннзит ДокуметНеопредсленный
Рииннзит ДокуметНеопредсленный
Новый Вид -:■ •
[Измене ниеСсстоянияФ из Ли;
^.У"? '."У'-5
| OK | Cancel |
Рис. 4.250. Выбор нового значениядля реквизита Реквизит_ДокументНеопределенный
Рис. 4.251. Новое значение присвоено реквизиту Реквизит_ДокументНеопределенный
Результат представлен на рис. 4.251.
До настоящего момента мы редактировали значения реквизитов справочников. обращаясь к реквизиту непосредственно:
ole_Ref.ДатаРождения:=Sx;
ole_Ref.ДополнительнаяИнформация:= Dlg_Edit_AttrStringO.Memol.Text;
ole_Ref.СемейноеПоложение:=Dlg_Select_ValueOfEnum.oleValueEnum;
ole_Ref.ГородПроживания:=Dlg_Select_ElemFromRef.oleElemSel;
ole_Ref.Реквизит_Неопределенный:=Sx;
ole_Ref.Реквизит_Неопределенный:=Dlg_Select_ValueO£Enum.oleValueEnum;
01e_Re£.Реквизит_СправочникНеопределенный:=
Dlg_Select_ElemFromRef.oleElemSel;
ole_Ref.Реквизит_ЛокументНеопределенный:=oleBuf;
^o приемлемо в том случае, если мы точно знаем, какие именно реквизиты есть в справочнике, и свои программные средства жестко привязываем * Информационной структуре конкретной базы данных 1С:Предприятие. В общем случае такой подход будет некорректным.
Объект типа Справочник позволяет изменять значения реквизитов элементов справочников (с помощью метода УстановитьАтрибут), обращаясь к ним через идентификаторы реквизитов.
Метод УстановитьАтрибут (или SetAttrib) позволяет установить значение Реквизи га по идентификатору, как оно задано в Конфигураторе. Синтаксис: УстановитьАтрибут(<ИмяРеквизита>, <3начение>)
Параметры: <ИмяРеквизита*— строковое выражение, содержащее имя р(.к визита, как оно задано в Конфигураторе; <3начение>— вь,раженце содержащее устанавливаемое значение реквизита.
Посмотрим, каким образом мы можем применить этот метод при доступ к значениям реквизитов элементов справочников через механизм OLE Automation. Вернемся к нашему проекту sp_EditAttrInRef.DPR и моди фицируем его исходный код.
Примечание
Пример есть на сопроводительном компакт-диске книги в папке \Part_1\Chapter_04\Topic_4_7\ltem_4_7_1\sp_EditAttrlnRef.PAS\02.
Изменим обработчик события "нажатие кнопки ДатаРождения" следующим образом (листинг 4.125).
ИДистанг4,125. Обработчик события "нажатие кнопки ДатаРожаония"
procedure TForml.SpeedButton2Click(Sender: TObject) ;
// Редактирование реквизита "ДатаРождения"
Var
Sx: string;
begin
// Проверяем, существует ли ссылка на справочник
if not VarIsanpty(ole_Ref) then begin
Sx:=Edit_DR.Text;
// Вводим новое значение
if inputQueryf(Sender as TSpeedButton).Caption,1 Новое значение',Sx) then begin
Sx:=Trim (Sx) ;
// Редактируем значение реквизита
ole^Ref.УстановитьАтрибут(1'+'ДатаРождения',''+Sx);
II Записываем изменения в справочнике в базу данных
ole_Ref.Записать;
// Вновь читаем значение реквизита из справочника
Edit_PR.Text:=Trim(ole_Ref.ПолучитьАтрибут (' '+•ДатаРождения')) •" end;
end
else begin
ShowMessage('Справочник не открыт1);
end;
end;
Поясним текст обработчика. Здесь практически то же самое, что и в "старом1 варианте (листинг 4.110), кроме двух строк. Строка
oje Ref .ДатаРождениям Sx;
заменена строкой
ole_Ref.УстановитьАтрибут(" +'ДатаРождения', ' •+Sx);
астрока
gdic_DR.Text:=Trim(ole_Ref.ДатаРождения);
строкой
gjjt_DR.Text:=Trim(ole_Ref.ПолучитьАтрибут(''+'ДатаРождения'));
Точно так же редактируются реквизиты других базовых типов (строка, число). Пример редактирования реквизита ДополнительнаяИнформация (строка неограниченной длины) приведен в листинге 4.126.
Sx:=Dlg_Edit_AttrStringO.Memol.Text;
, ole_Ref.УстановитьАтркбут(1'+'ДополнительнаяИнформация',''+Sx>;
Sx:=Trim(ole_Ref.ПолучитьАтрибут(1' +'ДополнительнаяИнформация')); Memol.Text:=Sx;
Реквизиты агрегатного типа следует рассмотреть подробнее. В листинге 4.127 представлен обработчик события "нажатие кнопки СемейноеПоложение" (редактирование реквизита типа Перечисление).
КЕГЗГ—^г^5^
ЙИстинг 4.127. Редактирование реквизиталипа Перечисление
Procedure TForml.SpeedButtonSClick(Sender: TObject);
** Редактирование реквизита "СемейноеПоложение"
Var
idAttr: string;// Идентификатор реквизита begin
// Проверяем, существует ли ссылка на справочник
if not VarisBnpty(ole_Ref) then begin
// Вызываем диалог для выбора значения перечисления
[ if Dlg_8elect_Value0fbium.Execute(о1е_1С,
'СемейноеПоложение1,
Edit_Fam.Text) then begin
// Редактируем значение реквизита
idAttr:=’СемейноеПоложение';
ole_Ref .УстановитьАтрибут!1 Ч-idAttr,
Dla_8elect_ValueOfEnxsn.oleValueEnum| .
И Записываем изменения в справочнике в базу данных
ole_Ref.Записать;
// Вновь читаем значение реквизита из справочника
Edit_Fam.Text:=
Trim(ole_Ref.ПолучитьАтрибут(' Ч-idAttr).Идентификатор) ■ end;
end
else begin
ShowMessage('Справочник не открыт');
end;
end;
Этот текст был подробно рассмотрен ранее (см. листинг 4.123). Единственное ОТЛИЧИе — использование методов УстановитьАтрибут И ПолучитьАтрибут справочника.
Здесь следует отметить только один момент. В некоторых случаях передача переменной типа olevariant (или variant) в качестве параметра для метода УстановитьАтрибут может не сработать. Тогда можно использовать другой вариант. Среди штатных средств языка программирования системы 1 С:Предприятие есть функции ЗначениеВСтроку и ЗначениеИзСтроки.
Функция ЗначениеВСтроку (или valueTostring) преобразует значение из внутреннего представления в строковое. Синтаксис:
ЗначениеВСтроку(<Обьект>1
Параметр: <о&ьект>— значение, которое требуется перевести в строковое представление. В качестве параметра данной функции допускается передавать значения как базовых, так и агрегатных типов данных, за исключением тех типов данных, которые не имеют собственно значения (это касается таких объектов, как Периодический, Таблица, ФС, Запрос, XBase ИТ. П.). Возвра щаемое значение — строковое представление переданного значения.
Функция ЗначениеИзСтроки (или ValueFromString) выполняет обратное Пр€ образование из строкового системного представления во внутреннее значе ние объекта. Синтаксис:
ЗначениеИзСтроки(<СистСтрока>)
Параметр: <СистСтрока> строковое выражение, содержащее представле- нИе объекта, полученное ранее при помощи функции значениевстрску. функция возвращает значение, полученное из строкового системного пред- ^гавления.
Примечание
Более подробную информацию о функциях ЗначениеВСтроку и ЗначениеИзСтроки и методах работы с ними можно найти в специальной литературе по 1С.
Обе эти функции предназначены, в частности, для использования при обмене информацией посредством механизма OLE Automation.
Попробуем применить эти функции в контексте метода EvalExpr.
В листинге 4.128 представлен модифицированный текст (из предыдущего листинга), где реализован этот способ редактирования реквизитов справочника типа Перечисление.
лйнг 4.128. Редактирование.реквизита типалеречислени ^ниеИзСтро^и)
procedure TForml.SpeedButtonSClick(Sender: TObject);
// Редактирование реквизита "СемейноеПоложение"
Var
Sx,Sl,S2: string,-// Для метода EvalExpr
idEnum: string; H Идентификатор перечисления (вид)
idAttr: string; // Идентификатор реквизита
begin
// Проверяем, существует ли ссылка на справочник
if not VarIsErrpty(ole_Ref) then begin
И Идентификатор (вид) перечисления
idEnum: = 'СемейноеПоложение';
// Вызываем диалог для выбора значения перечисления
if Dlg_Select_ValueOfEnum.Execute(ole_lC,idEnum,Edit_Fam.Text) then begin
11 Редактируем значение реквизита idkttr:='СемейноеПоложение1;
/ / =======================================
// Вариант с использованием метода EvalExpr
//'
// Формируем строку для выполнения с помощью метода EvalExpr()
SI:= Dlg_Select_ValueOfEnum. idValueZnum;
RS*. I ом
Sx: =' Перечисление. ПолучитьАтрибут ( * 1 +idltrnmn-' *) ' ;
Sx:=Sx+1.ЗначекиеПоИдентификатору("'+S1+'")';
SX:='ЗначениеИэСтроки(ЗначениеВСтроку('+Sx+') ) ' ;
//
// Изменяем значение реквизита с помощью метода EvalExpr() ole_Ref.УстакожитьАтрибут(''+idAttr,ole_lC.EvalExpr(Sx)); //===========================================
// Записываем изменения в справочнике в базу данных
ole_Ref.Записать;
// Вновь читаем значение реквизита из справочника
Edit_Fam.Text:=
Trim (ole_Ref.ПолучитьАтрибут!''*idAttr)-Идентификатор): end;
end
else begin
ShowMessage('Справочник не открыт');
end;
end;
Здесь дополнительные пояснения излишни.
Сделаем небольшое дополнение в исходном тексте (листинг 4.128):
//
// Формируем строку для выполнения с помощью метода EvalExprО
Sl: = Dlg_Select_ValueOfEnum.idValueEnum;
Sx:='Перечисление.ПолучитьАтрибут("1+idEnum+1") 1;
Sx:=Sx+'.ЗначекиеПоИдентификатору(‘•+S1+'")' ;
Sx: ='ЗначениеВСтроку('+Sx+')';
Sx :=Trim(ole_lC. EvalExpr (Sx));
InputQuery ('ЗначениеВСтроку*,'Значение перечисления*,Sx);
И
Теперь можно посмотреть результат, который возвращает метод ЗначениеВСтроку для значения реквизита типа Перечисление. В данном случае, например, функция вернула следующее значение:
{“Перечисление",“СемейноеПоложение","ГражданскийБрак")
Если тип редактируемого реквизита— Справочник, то можно испол^0" вать такой же подход (функцию ЗначениеИэСтроки), как и в случае с тип , перечисление. Но здесь есть нюанс. Дело в том, что метод EvalExpr может в числить выражение, но не выполнить набор команд. В случае с перечислен"1
^ожно было скомбинировать вызов методов (для вычисления нового значе- ция реквизита справочника) таким образом, чтобы все они представляли еди- ^ выражение. Для реквизитов типа Справочник это невозможно. Но подходящий вариант, как всегда, найдется.
^и провести некоторые эксперименты с функцией Значениевстроку при- ценительно к элементам справочника, то получается вот что.
। Если справочник не иерархический и у него нет владельца, то строковый эквивалент элемента справочника включает в себя 3 слова:
первое слово— тип объекта (в данном случае всегда будет справочник);
второе слово — идентификатор справочника (вид);
третье слово — код выбранного элемента справочника.
Пример 1:
Справочник:Странымира.
Код элемента: 1.
Строковое представление: ("Справочник","СтраныНира", "1").
Если справочник иерархический и у него нет владельца, то строковый эквивалент элемента справочника включает в себя 3 слова;
первое слово— тип объекта (в данном случае всегда будет Справочник);
второе слово — идентификатор справочника (вид);
третье слово:
О если у элемента справочника есть родитель, то формат следующий: кодРодителя/кодЭлемента (разделитель — косая черта);
О если у элемента справочника нет родителя, то просто кодЭлемента.
Пример 2:
Справочник:Физлица.
Код элемента: 6.
Код родителя: нет родителя.
Строковое представление: ("Справочник", "ФизЛица", "6°}.
Пример 3:
Справочник: Физлица.
t Код элемента: 1.
Код родителя: 7.
Строковое представление: {“Справочник", "ФизЛица", "7/1“}.
Если справочник иерархический и у него есть владелец, то строковый эк вивалент элемента справочника включает в себя 4 слова:
первое слово — тип объекта (в данном случае всегда будет справоч ник);
второе слово — идентификатор справочника (вид);
третье слово:
О если у элемента справочника есть родитель, то формат следующий: КодРодителя/КодЭлемента (разделитель — косая черта);
О если у элемента справочника нет родителя, то просто кодЭлемента.
четвертое слово — код владельца выбранного элемента справочника.
Пример 4:
Справочник: ГородаСтранМира.
Код элемента: 3.
Код родителя: нет родителя.
Код владельца: 1.
Строковое представление: {"Справочник","ГородаСтранМира"," 3 *," 1 ’}.
Пример 5:
Справочник: Новый2_Подч.
Код элемента: 3.
Код родителя: 1.
Код владельца: 2.
Строковое представление: { "Справочник", " Новый2_Подч " , "1/3", "2“}.
--'...........,„,.,,,■.■.--*-/•">-.... -•■-л-^;,»^-^" - :(Delphi) —аналог функции |--'...........,„,.,,,■.■.--*-/•">-.... -•■-л-^;,»^-^" - :(Delphi) —аналог функции |То есть формат строки прост, и не составляет труда сформировать такую строку средствами Delphi (не обращаясь к функции 1С ЗначениеВСтроку), чтобы потом передать эту строку в качестве параметра в функцию ЗначениеИзСтроки. Текст функции (Delphi), решающей эту задачу, представлен в листинге 4.129.
--'...........,„,.,,,■.■.--*-/•">-.... -•■-л-^;,»^-^" - :
(Delphi) —аналог функции |
--'...........,„,.,,,■.■.--*-/•">-.... -•■-л-^;,»^-^" - :
(Delphi) —аналог функции |
СТИНГ 4.129. Функция sp_ValueToString_Ref . фоКуг0с:Предприятие)^
function »p_ValueToString_Ref(handlelC, oleCurltemRef: oleVariant): string;
// Аналог функции "ЗначениеВСтроку" программы IC:Предприятие
И ИИИИ ИИИ//// ////// //(для элементов справочника):
И И
И
И
И И
И
И
//
// //
//
// //
handlelC - ссылка на 1С, oleCurltemRef - ссылка на элемент справочника (который конвертируем в строку).
формат результирующей строки:
("Справочник*,'ИдентСправочника","КодРодителя/КодЭлемента",
"КодВладельца“}
//#в==========™х™=,
Var
idRet: string; // Идентификатор справочника
// (для значения oleCurltemRef)
CodeCurItemRef: string; // Код элемента справочника oleCurltemRef
CodeParentCurltemRef: string;
И Код элемента справочника-родителя // для oleCurltemRef
CodeOwnerCurltemRef: string;
// Код элемента справочника-владельца // для oleCurltemRef
oleBuf: oleVariant; // Вспомогательная переменная idType: string; // Тип значения oleCurltemRef
begin
Result:=‘ 1 ;
// Тип значения (в данном случе — всегда "Справочник")
idType:=’Справочник1;
CodeOwnerCurltemRef:=11;
CodeParentCurltemRef:='';
// Проверяем, есть ли ссыпка на 1С
if not VarlsEmpty(handlelC) then begin
// Проверяем, корректна ли ссылка на элемент справочника
if not VarlsEmpty(oleCurltemRef) then begin
// Идентификатор справочника
idRaf:=Trim(oleCurItemRef.Вид);
Il Код элемента справочника oleCurltemRef x CodeCurlteroRef: =Trim(oleCurltemRef .Код) ;
// Проверяем, есть ли владелец у этого справочника
oleBuf:=handlelC.Метаданные.Справочник!1 Ч-idRef).Владелец;
if oleBuf.Выбран>0 then begin
II Владелец есть
М Код элемента справочника-владельца
" Часть I. 1С и механизм OLE Automat^
CodeOwnerCurltecoRef :=Trim(oleCurItemRef .Владелец.Код) ;
end;
// Проверяем, является ли справочник иерархическим oleBuf:=handlelC.Метаданные.Справочник('1+idRaf);
if (oleBuf.КоличествоУровней*1)>1 then begin
// Справочник иерархический
И Код элемента справочника-родителя
CodePazentCurItemRa f: =Trim (oleCurltemRaf. Родитель. Код) ;
end;
II
И Формируем результат.
// Двойные кавычки нужно дублировать, потому что
// в 1С:Предприятие в двойные кавычки заключаются
// строковые константы.
if length(CodeParentCurltemRef)<=0 then begin
// Справочник HE иерархический
if length(CodeOwnerCurltemRef)>0 then begin
// Есть владелец
Result: = '{""'+idType+'"",' + '*"'+idRef+'“",”' ♦CodeCurlteinRef+ '"-,*"' +CodeOwnerCurI teniRef +
end
else begin
// Нет владельца
Result:='(""1+idType+'"*. •♦'■“
+idRef+'--,"“•+codeCurItemRef+ '*•)';
end;
end
else begin
// Справочник иерархический
if length(CodeOwnerCurltemRef)>0 then begin
//Есть владелец
Results' {"* '+idType+""’, • + •“"■+idRef+'"",.'" +CodeParentCurItemRef+' / 14-CodeCurIternRef + --",""' +CodeOwnerCurI ternRef +1 * °}';
end
else begin
// Нет владельца Result: = '(““ +idType+’"",’ +'•"'+idRef+'"■,••• +CodeParentCurltemRef+'/'+CodeCurItemRef+'•"}'; end; end; H end;
end;
end-’
Текст функции sp_vaiueTostring_Ref прост и не требует дополнительных пояснений. Применить ее можно так, как показано в листинге 4.130.
// Вызываем диалог для выбора элемента справочника
if Olg_Saleot_ElemFr<xnRaf.Execute(ole_lC,
'ГородаСтраиМира1, ••) then begin
// Идентификатор реквизита справочника
idAttr:= 'ГородПрохивания1;
// Вариант с использованием метода EvalExpr
Н
// Формируем строковое представление выбранного
// элемента справочника (новое значение для реквизита)
!
Sx:=8p_ValueToString_Ref(ole_lC, Dlg_Salect_El*orrcxnRef .oleElemSal) ;
И
// Изменяем значение реквизита с помощью метода EvalExpr() ole_Ref.УстановитьАтрибут(1'+idAttr,
ole_lC.EvalExpr(1ЗначениеИэСтроки("'+Sx+'")1));
Е // Записываем изменения в справочнике в базу данных
ole_Ref.Записать;
Другой вариант применения метода УстановитьАтрибут для реквизитов типа Справочник (как и в случае с реквизитами типа перечисление):
Ble_Ref.УстановитьАтрибут(’*+idAttr, Dlg_Salect_ElemFrauRef.oleElemSel);
384'Часть I. 1С и механизм OLE Autornaf^ Использование метода Установить Атрибут для значений реквизитов типа Неопределенный, Справочник (неопределенного вида). Документ (неопредеден кого вида) ничем не отличается от уже рассмотренных примеров. Но перед ВЬ] зовом этого метода нужно назначить соответствующий тип (вид) значению та кого реквизита справочника (этот вопрос был подробно рассмотрен ранее).
Примечание
В папке \Part_1\Chapter_04\Topic_4_7\ltem_4_7_1\sp_EditAttrlnRef_2.PAS\04 На сопроводительном компакт-диске книги есть исходные тексты проекта sp_EditAttrlnRef_2.DPR, иллюстрирующие этот вопрос.
Теперь рассмотрим вопросы, связанные с редактированием значений периодических реквизитов. Откроем Конфигуратор 1С:Предприятие и создадим новый справочник, который содержит только периодические реквизиты разных типов (рис. 4.252).
®”^
: » Тил_Строкв
:-# Тип_Число
i ЗА Тип_Дата
* # Тк1_Справ_ФизЛица
• др Тип.Переч СемейноеПсложение
: » Т к1_Док_ИзмСостФизЛииа
<3 Тип_Неопределенный
; » Тип Справочник
* Т ил_Докцменг
Рис. 4.252. Новый справочник для иллюстрации вопросов,связанных с редактированием периодических реквизитов справочников
В табл. 4.16 приведена информация о типе периодических реквизитов справочника СправПериодРекв.
Таблица 4.16. Типы реквизитов справочника СправПериодРекв
Реквизит
Тип
Вид
Тип_Строка
Строка
—
Тип_Число
Число
—
Тип_Дата
Дата
Тип_Справ_ФизЛица
Справочник
ФизЛица
- -——
Тип_Переч_СемейноеПоложение
Перечисление
СемейноеПоложение
ТипЛок_ИзмСостФизЛица '
Документ
ИзменениеСостоянияФизЛиЦ,
Тип_Неопределенный
Неопределенный
Неопределенный
Тип_Справочник
Справочник
Неопределенный
Тип_Документ
Документ
Неопределенный
^ува 4. Доступ к информации 1С из внешних приложений Как было сказано в разд. 4.1.5, периодические реквизиты — это реквизиты, значения которых связаны с датой. При изменении значения периодического „еквизита старое значение сохраняется, при этом новое значение действует ^указанной даты, а старое — до указанной даты.
ПРИМЕЧАНИЕ
Более подробно о леридических реквизитах и методах работы с ними можно прочитать в специальной литературе по 1С.
Здесь мы рассмотрим вопросы, связанные с редактированием таких реквизитов, на конкретных примерах.
Внести новое значение периодического реквизита справочника можно с помощью метода УстановитьАтрибут справочника (см. ранее в этом разделе), но перед его вызовом нужно вызвать метод ИспользоватьДату справочника (см. разд. 4.1.5).
Для иллюстрации использования этих методов создадим новый Delphi-проект sp_EditAttrPeriodlnRef.DPR.
Примечание
Исходные тексты проекта находятся на сопроводительном компакт-диске книги в папке \Part_1 \Chapter_04\Topic_4_7\ltem_4_7_1 \sp_EditAttrPeriodlnRefPAS\01.
На рис. 4.253 представлена форма проекта sp_EditAttrPeriodInRef.DPR.
1 ££ Редок тирооание элементов справочника. Периодически...Н@В||
1 Соединить с 1С | ,V77 Applicationi
Строка инициализации ■ pDEA1C.example.DB|
Открыть елраео-м* | [СправПериоаРеке
Найти по коду I I1
1J
Наименование | |EA.Name_
Периодические реквизиты
—-—
Iип.Строка
; ]Edit_STR
Тип.Чнсло
1 |Edit_NUMj
Тип. Дата
| |Edil_DATE
Тип.Переч.СемейноеПолохение ] |Edit_Enun_SemPol
।Тип.Спрао.ФиаЛица
| |Edit_Rel.FaLica»
Тип.Док.ИзмСостФизЛица
J |E<tt_Doc_SoftFizlica
Т ип_Неопреде ленный
| Тит j|E<M_Neopc
Тип.Справочник
| ]Edit_Ref
Т ип_ Документ
| [Edit.Ooc
(Iwewiwew мот.ода.'Мдта*ЭИ№^ЕС.- -—;_--—.— —
Рис. 4.253. Форма проекта sp_EditAttrPeriodl nRef. DPR для иллюстрации процесса редактирования значений периодических реквизитов справочника
Как видите, для каждого периодического реквизита справочника СправПериодре создана отдельная кнопка. В листинге 4.131 приведен пример обработчиКв события: "нажатие кнопки Тип_Дата".а
procedure TForml.SpeedButtonAClick(Sender: TObject);
И Редактирование периодического реквизита "Тип Лата"
Var
Sx: string;
idAttr: string; // Идентификатор реквизита
begin
// Проверяем, существует ли ссылка на справочник
if not VarIsanpty(ole_Kef) then begin
// Перед вводом нового значения периодического реквизита
11с применением метода "УстановитьАтрибут" нужно вызвать
// метод "ИспользоватьДату" для установки даты значения // реквизита
ole_Ref.ИспользоватьДату(''+DateToStr(NOW), 1) ;
idAttr : = "ТипЛата';
Sx:=Edi t_DATE.Text;
H Вводим новое значение
if InputQuerytidAttr,'Новое значение на jiaTy=,+DateToStr(NOW),Sx) then begin
Sx:=Trim(Sx);
// Редактируем значение реквизита
ole_Ref.УстановитьАтрибут!''+idAttr,''+Sx);
// Записываем изменения в справочнике в базу данных
01e_Ref.Записать;
// Вновь читаем значения реквизитов из справочника SpeedButton9.Click;
end;
end
else begin
ShowMessage(1 Справочник не открыт');
end;
end;
рели сравнить листинги 4.131 (редактирование периодического реквизита тарождения) и 4.125 (редактирование не периодического реквизита ДатаРо- ^ения). то видно, что единственное существенное отличие — вызов метода справочника ИспользоватьДату перед ВЫЗОВОМ УстановитьАтрибут.
результат представлен на рис. 4.254.
' -Периодические реквизиты: - Тип_Строка Т ип Число Тип ДатаТ ип Переч СемейноеПо( Т ип Справ<РиэЛи| Т ил Док ИэмСостФи: Т ип Н еопраделенн!Тип Справочник' -Периодические реквизиты: - Тип_Строка Т ип Число Тип ДатаТ ип Переч СемейноеПо( Т ип Справ<РиэЛи| Т ил Док ИэмСостФи: Т ип Н еопраделенн!Тип Справочник|Строка-1 Г®|Строка-1 Г®1ип_Дата1ип_ДатаххНовое значение на датц-О8.10.2006 |24 08.2003Новое значение на датц-О8.10.2006 |24 08.2003OK I Cancel jOK I Cancel j
' -Периодические реквизиты: - Тип_Строка Т ип Число Тип Дата
Т ип Переч СемейноеПо( Т ип Справ<РиэЛи| Т ил Док ИэмСостФи: Т ип Н еопраделенн!
Тип Справочник
' -Периодические реквизиты: - Тип_Строка Т ип Число Тип Дата
Т ип Переч СемейноеПо( Т ип Справ<РиэЛи| Т ил Док ИэмСостФи: Т ип Н еопраделенн!
Тип Справочник
|Строка-1 Г®
|Строка-1 Г®
1ип_Дата
1ип_Дата
х
х
Новое значение на датц-О8.10.2006 |24 08.2003
Новое значение на датц-О8.10.2006 |24 08.2003
OK I Cancel j
OK I Cancel j
Рис. 4.254. Новое значение периодического реквизита Тип^Цатасправочника СправПериодРекв на 08.10.2006
Такой же подход (сочетание методов ИспользоватьДату и УстановитьАтрибут) можно применять для периодических реквизитов других типов. В случае, если периодический реквизит имеет ТИП Неопределенный, Справочник неопределенного вида ИЛИ Документ неопределенного вида, ТО дополнительно вызываются методы назначитьТип и НазначитьВид, как и для непериодических реквизитов (см. ранее).
Например, обращение к методу НазначитьВид может быть следующим: idAttr:= 'Тип_Справочник';// Идентификатор реквизита
SKind:= 'ГородаСтранМира';
°1е_1С.НазначитьВид(ole_Ref.ПолучитьАтрибут('’+idAttr),''+sKind);
Ничего особенного здесь нет, поэтому не будем заострять на этом внимание. Желающие могут посмотреть исходные тексты проекта sP_EditAttrPeriodInRef.DPR.
Единственное, что следует отметить, — для заданной даты может быть только одно значение периодического реквизита (созданное без участия докумен- ^в). А это значит, что если в базе данных уже существует значение периодического реквизита с заданной датой (не связанное с документом), то при вызове метода ИспользоватьДату (с ЭТОЙ же датой) метод УстановитьЗначение Модифицирует существующее значение периодического реквизита. Если же
в базе данных нет значения (не связанного с документом) с этой датой то будет добавлено новое значение с заданной датой.
На рис. 4.255 представлен результат ввода новых значений периодических реквизитов для элемента (с кодом 1) справочника СправпериодРекв.
Т ил ДетаТ ип Переч СвмейноеПоложениеТ ил ДетаТ ип Переч СвмейноеПоложениеV77.AppfcdlionV77.AppfcdlionСправПериодРеквСправПериодРеквНайти по кодуНайти по кодуЗлемемт-1Злемемт-1НаименованиеНаименованиеТип_ЧислоТип_Число•Г Редактирование элементов справочника. Периодически...ВВЕЗ•Г Редактирование элементов справочника. Периодически...ВВЕЗ-Периодические реквизиты: Тип_Строка-Периодические реквизиты: Тип_СтрокаСоединить с 1С |Строка инициализации = Открыть справочникСоединить с 1С |Строка инициализации = Открыть справочникТ ип Справ ФизЛицаТ ип Справ ФизЛицаТ ип Док ИзмСостФизЛицаТ ип Док ИзмСостФизЛицаТ ип НеогределенмыйТ ип НеогределенмыйТ ип СправочникТ ип Справочник(Строка-1 [^ (24.08.2003 |ГражданскийБрак (Федоров Федор Федорович |Ыдок=3 Дата=12.07.2006 Тип |Значение-Строка?Элемент-1(Строка-1 [^ (24.08.2003 |ГражданскийБрак (Федоров Федор Федорович |Ыдок=3 Дата=12.07.2006 Тип |Значение-Строка?Элемент-1
Т ил Дета
Т ип Переч СвмейноеПоложение
Т ил Дета
Т ип Переч СвмейноеПоложение
V77.Appfcdlion
V77.Appfcdlion
СправПериодРекв
СправПериодРекв
Найти по коду
Найти по коду
Злемемт-1
Злемемт-1
Наименование
Наименование
Тип_Число
Тип_Число
•Г Редактирование элементов справочника. Периодически...ВВЕЗ
•Г Редактирование элементов справочника. Периодически...ВВЕЗ
-Периодические реквизиты: Тип_Строка
-Периодические реквизиты: Тип_Строка
Соединить с 1С |
Строка инициализации = Открыть справочник
Соединить с 1С |
Строка инициализации = Открыть справочник
Т ип Справ ФизЛица
Т ип Справ ФизЛица
Т ип Док ИзмСостФизЛица
Т ип Док ИзмСостФизЛица
Т ип Неогределенмый
Т ип Неогределенмый
Т ип Справочник
Т ип Справочник
(Строка-1 [^ (24.08.2003 |ГражданскийБрак (Федоров Федор Федорович |Ыдок=3 Дата=12.07.2006 Тип |Значение-Строка?
Элемент-1
(Строка-1 [^ (24.08.2003 |ГражданскийБрак (Федоров Федор Федорович |Ыдок=3 Дата=12.07.2006 Тип |Значение-Строка?
Элемент-1
Т ип ДокументТ ип ДокументВ ыплагыФ из Л ицам 1В ыплагыФ из Л ицам 1
Т ип Документ
Т ип Документ
В ыплагыФ из Л ицам 1
В ыплагыФ из Л ицам 1
Применение .метода 'V сгю/ммягъДату"
Рис. 4.255. Результат ввода новых значений периодических реквизитов элемента(с кодом 1) справочника СправпериодРекв
Как отмечалось в разд. 4.1.5, для работы с периодическими реквизитами справочников и периодическими константами в системе используется специальный агрегатный тип данных— периодический. Объекты данного типа предоставляют возможность записи, редактирования и удаления значений периодических реквизитов справочников и периодических констант (т. е- позволяют работать с историей значений периодического реквизита) Модифицируем наш проект sp_EditAttrPeriod!nRef.DPR следующим образом (рис. 4.256).
Как видите, для каждого периодического реквизита добавлена новая кнопка История.
Рис. 4.256. Модифицированная форма проекта sp_EditAttrPeriodlnRef.DPR
Рис. 4.257. Модифицированная форма (Delphi) для визуализации и редактирования истории изменения значений периодического реквизита
Примечание
Исходные тексты этого примера находятся на сопроводительном компакт-диске книги в папке \Part_1\Chapter_04\Topic_4_7\ltem_4_7_1\sp_EcfitAttrPeriodlnRef.PAS\02.
Добавим к проекту форму, разработанную нами в разд. 4.1.5 (см. рис. 4.89), и модифицируем ее, добавив контекстное меню (рис. 4.257).
В листинге 4.132 представлен текст обработчика события "выбор пункта ме ню Новое значение".
procedure TDlg_AttrPeriod_History.NlClick(Sender: TObject);
II Новое значение периодического реквизита
Var
NrType: integer; II Тип реквизита по метаданным
Sx: string;
sDate,sValAttr: string;
ole_period: OleVariant; // Ссылка на объект "Периодический" begin
// Поскольку значения периодических реквизитов
// рассматриваются в контексте конкретного элемента
// справочника, ссыпка на текущий элемент справочника
// ole_TekEl должна быть корректной.
if not VarlsBnpty(ole_TekEl) then begin
ole_period:=UHAssigned;
sDate:=DateTostr(NOW);
II Вводим дату нового значения реквизита
if inputQueryl'Периодический реквизит',
Введите дату нового значения', sDate) then begin
sDate:=Trim(sDate);
if length(sDate)>0 then begin
// Создаем объект "Периодический" для того, // чтобы прочитать историю значений периодического // реквизита справочника
ole_period:=Forml.ole_lC.CT*ateObject('Периодический');
if not VarIsBnpty(ole_period) then begin
// Устанавливаем фильтр по текущему элементу справочника if ole_period.ИспольЗожатьОбъект(’'+id_AttrPeriod, ole_TakKl)*1>0 then begin
// Определяем тип реквизита по метаданным
NrType:=Q«tTypeAttrXeferencelC(Forml.ole_lC, Label_id_Ref.Caption, id AttrPeriod);
if (NrType in (1..3J) then begin // Реквизит имеет базовый тип // Вводим новое значение реквизита sValAttr:='‘;
if XnputQueryf'Периодический реквизит', 1 Введите новое значение', sValAttr) then begin sValAttr:=Trim(sValAttr);
И // Присваиваем новое значение и дату И периодическому реквизиту ole„period.ДатаЗнач:= sDate; ole_period.3качение:= sValAttr; // // // Записываем в базу данных (здесь следует помнить, // что все значения периодических реквизитов хранятся Н в отдельной таблице 1SCQNST.DBF.
// Очевидно, что поэтому у объекта "Периодический" // есть свой метод "Записать") ole_period.Записать; //
// Визуализируем историю значений реквизита View_Values;
end;
end;
end;
end;
end;
end;
ole_period:=UnAssigned;
end;
end;
Думаю, дополнительно пояснять текст этого обработчика не требуется. Единственное, что следует отметить, — метод записать объекта периодически выполняет запись значения периодического реквизита на заданную да- ty Как уже отмечалось, если для этой даты уже имеется запись (созданная без участия документов), то она модифицируется (если новое значение тоже
не связано с каким-то документом). А это значит, что этот же обработчик мо-^ но использовать и для редактирования значений периодического реквизита
Следует помнить, что при редактировании конкретного значения реквизит- объект периодический должен быть позиционирован на этом значении. д1я ЭТОГО можно использовать метод НайтиЗначение (или FindValue). позволяю щий найти значение на заданную дату. Его синтаксис:
НайтиЗначение(<Дата>, <Режим>}
Параметры: <дата> — выражение, задающее значение даты, на которую тре- буется найти периодический реквизит справочника или периодическую константу; <Режим> — числовое выражение, значение которого задает режим поиска, если на заданную дату не существует значения периодического реквизита (-1 — возвращается значение на предыдущую дату, 0— возвращается код завершения неуспешной операции, 1 — возвращается значение на следующую дату). Возвращаемое значение (число): 1 — если вызов метода закончился успешно, 0 — если нет.
Метод НайтиЗначение позволяет найти периодическое значение на заданную дату <дата>. Режим поиска в случае, если на заданную дату не существует значения периодического реквизита, задается параметром <Режим>. Само полученное значение следует считывать из атрибута Значение.
В нашем случае обращение к этому методу может быть таким:
if (ole_period.НайтиЗначение(‘'+sDate,0)*1) > 0 then begin
Мы рассмотрели возможность применения объекта периодический для редактирования значений периодических реквизитов на примере реквизита базового типа. С помощью наших предыдущих наработок можно по такому же принципу реализовать ввод новых и редактирование существующих значений реквизитов агрегатного типа (включая реквизиты неопределенного вида).
Для удаления конкретного значения периодического реквизита служит метод Удалить объекта периодический. При этом объект периодический должен быть позиционирован на удаляемом значении. Это можно сделать, используя (например) его метод НайтиЗначение, который позволяет позиционировать объект периодический на значении по заданной дате.
Желающие ознакомиться подробнее могут посмотреть исходные тексты проекта, а также почитать специальную литературу по этому вопросу.
Примечание
Напомню, что представленные выше примеры исходных текстов — это упрощенная иллюстрация к рассматриваемым вопросам. Назначение этих примеров — дать представление о возможном подходе при решении задач информационного обмена с системой 1С:Предприятие. При работе с реальными базами 1С может потребоваться их дальнейшая доработка.
Редактирование документов
Как отмечалось в разд. 4.1.5, реквизиты документов разделяются на:
у обшие реквизиты документов;
у реквизиты "шапки" документов конкретного вида;
у реквизиты "табличной части" документов конкретного вида.
Каждый реквизит документа заданного вида имеет уникальный идентификатор- Причем уникальность соблюдается среди всего множества реквизитов для документов конкретного вида и множества общих реквизитов документе. То есть если среди общих реквизитов документов есть реквизит с идентификатором комментарий, то никакие документы (в рамках данной конфигурации) любого вида не могут иметь реквизиты с таким же идентификатором Ни в "шапке" документов, ни в "табличной части" документов. Точно так же, если в "шапке" документа (конкретного вида) есть реквизит с каким-то идентификатором, то среди реквизитов "табличной части" документов этого же вида не может быть реквизита с таким же индетификатором. Это существенно упрощает как считывание информации из документов (см разд. 4.2), так и редактирование информации в документах.
Рассмотрим вопросы редактирования информации в документах с использованием механизма OLE Automation на примере документов вида выплатыФизЛицам (см. рис. 4.166). Для этого создадим новый проект sp_EditAttr!nDoc.DPR.
Примечание
■ Исходные тексты проекта есть на сопроводительном компакт-диске книга в папке \Part_1\Chapter_04\Topic_4_7\ltem_4_7_2\sp_EditAttrlnDoc.PAS.
На рис. 4.258 представлена форма проекта.
Форма проекта разделена на три части.
О Верхняя часть — соединение с 1С, с документами вида ВыплатыФизЛицам, навигация (позиционирование) по списку документов данного вида.
□ Средняя часть — общие реквизиты документов и реквизиты "шапки" документов данного вида.
О Нижняя часть — реквизиты "табличной части" документов данного вида. Вопросы, связанные с открытием документов и позиционированием на кон- •фетном документе заданного вида, были подробно рассмотрены в разд. 4.2, и здесь мы на этом останавливаться не будем.
|1£ Редактирование документов
-|D|x
Соединить с 1С ]
Строка инициализации = Открыть документ
]V77 Application |/DE:\1C_example.DB
[Выплат ыФиэЛицам
Найти по номеру Провести документ
Ji _ Д_. ^.1140720Ж Новый документ |
г-Шалка:
— ——-—-
Город
|Edl_Gofodi
Комментарий
|Edit_Comment1
Табличная часть:
Строка N [1 Новая строка |
41Всего = |Ed<_CountLine
Удакгь строку | Удалить все строки]
ФиэЛицо
|Edit_FizUco
СуммаНачислено
]Edit_SumPlus
СуммаУдержано
[Edit_SumMinus
СуммаВыплачено
|Edit_SumTake
ВидВыплат
|Edit_VidVyplat
Способаьплаты
|Edit_SposVyplat|
Рис. 4.258. Форма проекта sp_EditAttrlnDoc.DPR
Посмотрим, каким образом можно редактировать общие реквизиты документов и реквизиты "шапки" документов. В листинге 4.133 представлен обработ
чик события "нажатие кнопки Комментарий" (общий реквизит документов).
procedure TForml.SpeedButton3Click(Sender: TOb ject) ;
// Редактирование реквизита "Комментарий" Var
idAttr: string;// Идентификатор реквизита документа
NumLine: integer; // Номер текущей строки
Sx: string;// Вспомогательная переменная
begin
// Проверяем, существует ли ссыпка на документ
if not VarlsEmpty(ole_Doc) then begin
// Убеждаемся, что объект ole_poc позиционирован //на конкретном документе
//(т. е. ссылка на текущий документ корректна)
if not VarlsQnpty(ole_TekDoc) then begin
// Идентификатор реквизита
idAttr:=1Комментарий';
Sx:=Tr im(Edit_Comment.Text);
// Вызываем диалог для ввода строки
if InputQuery(idAttr, 'Введите новое значение1,Sx) then begin Sx:=Trim(Sx);
// Редактируем значение реквизита
ole_Doc.УстановитьАтрибут(''+idAttr,'’+Sx);
// Записываем изменения в документе в базу данных
ole_Doc.Записать;
// Это нужно, чтобы после повторного открытия документа
// вернуться на текущую строку
NumLine:=SE_NumLine.Value;
II Визуализируем документ
SpeedButton9.Click;
11 Возвращаемся на текущую строку документа SE_NumLine.Value:=NumLine;
end;
end
else begin
ShowMessage{1 Такой документ не существует в базе данных');
end;
end
else begin
ShowMessage('Документ не открыт');
end;
end;
Поясним текст обработчика.
Здесь проверяется корректность ссылки на текущий документ (это значит, что созданный объект oie_Doc позиционирован на конкретном документе):
^ not VarlsBnpty(ole_TekDoc) then begin
Далее следует запрос на ввод нового значения реквизита:
^ InputQuery(idAttr, 'Введите новое значение',Sx) then begin
Затем модифицируем значение реквизита:
°le_Doc.УстановитьАтрибут(''+idAttr,''+Sx);
И записываем изменения в базу данных:
ole_Doc.Записать;
Точно такой же подход можно использовать и при редактировании реквизитов "шапки" документов (листинг 4.134).
procedure TForml.SpeedButton2Click(Sender: TObject);
// Редактирование реквизита "Город"
Var
idAttr: string; И Идентификатор реквизита документа
NumLine: integer; // Номер текущей строки
begin
// Проверяем, существует ли ссылка на документ
if not VarIsEmpty(ole_Doc) then begin
// Убеждаемся, что объект ole_Doc позиционирован
// на конкретном документе
// (т.е. ссылка на текущий документ корректна)
if not VarIsEmpty(ole_TekDoc) then begin
// Идентфикатор реквизита
idAttr:=*Город';
// Вызываем диалог для выбора элемента справочника
II (новое значение реквизита документа)
if Dlg_8elect_ElemFromRaf.Execute(ole_lC, 'ГородаСтранМира1, then begin
// Редактируем значение реквизита
о1е_0ос.УстановитъАтрибут(1'+idAttr, Dlg_Select_ElemFrornRef .oleElemSel) ;
// Записываем изменения в документе в базу данных
ole_Doc.Записать;
// Это нужно, чтобы после повторного открытия документа
// вернуться на текущую строку NumLine:=SE_NumLine.Value;
// Визуализируем документч
SpeedButton9.Click;
// Возвращаемся на текущую строку документа
SB_J»umLine.Value:=NumLine;
end;
end
else begin
ShowMessage('Такой документ не существует в базе данных'); end;
end
- else begin
ShowMessage('Документ не открыт');
end;
end;
Как видите, листинг 4.133 отличается от листинга 4.134 только способом ввода нового значения реквизита документа. В первом случае реквизит Комментарий имеет тип Строка. Во втором случае реквизит город имеет тип справочник.городаСтранМира. Поэтому во втором случае для ввода нового значения мы используем разработанную нами ранее диалоговую форму для выбора элементов справочника заданного вида.
При редактировании реквизитов табличной части документа можно использовать точно такой же подход с учетом того, что данный документ (текущий документ) должен быть позиционирован на конкретной строке "табличной части". Для этого можно использовать метод получитьстрокупономеру (ил GetLineByNuin) объекта Документ, ПОЗВОЛЯЮЩИЙ получить строку документа по заданному номеру. Синтаксис:
ПолучитьСтрокуПоНомеру(<Номер>}
Параметр: <номер> — выражение, содержащее номер искомой строки. Возвращаемое значение (число): 1 — если действие выполнено; 0 — если действие не выполнено.
Метод получитьстрокупономеру устанавливает в качестве текущей строки спецификации документа строку с заданным номером (не порядковым, а тем, который записан в строке, т. к. могут быть пропуски).
В листинге 4.135 представлен исходный текст обработчика, где производится Редактирование реквизита "табличной части" документа (кнопка Способ Выплаты).
К;•"— ...^д..^; •••
ацетин г 4.135. Редактирование реквизитов "табличной части" Документов .
Procedure TForml.SpeedButEonlOClick(Sender: TObject);
/z Редактирование реквизита "СпособВыплаты"
Var
idAttr: string; // Идентификатор реквизита документа
NumLine: integer; // Номер текущей строки
Yes: integer; // Вспомогательная переменная begin
// Проверяем, существует ли ссылка на документ
if not VarlsQnpty(ole_Doc) then begin
// Убеждаемся, что объект oleJDoc позиционирован
// на конкретном документе
// (т.е. ссылка на текущий документ корректна)
if not VarlsEmpty(ola_TekDoc) then begin
// Убеждаемся, что номер строки - в допустимом интервале
if SE_NumLine.Value>0 then begin
if SE_NumLine.Value<=(о1е_Оос.Количест»оСтрок*1) then begin
// Позиционируемся на выбранной строке // табличной части документа
Yea: = (ole_Doc.ПолучитьСтрокуПоНомеру(SE_NumLine.Value*1) * 1);
if Yes>0 then begin
// Идентификатор реквизита idAttr:= 1СпособВыплата1;
// Вызываем диалог для выбора элемента справочника if Dlg_Select_ValueOfEnum.Execute(ole_lC,
'СпособВыплатыФизЛицам', Edit_SposVyplat.Text) then begin
// Редактируем значение реквизита
ole_Doc.УстановитьАтрибут(''+idAttr, Dlg_Select_ValueOfEnum.oleValueEnum);
// Записываем изменения в документе в базу данных ole_Doc.Записать;
// Это нужно, чтобы после повторного открытия документа // вернуться на текущую строку
NumLine:=SEJIumLine.Value;
// Визуализируем документ SpeedButton9.Click;
// Возвращаемся на текущую строку документа SE_NumLine.Value:=NumLine;
end;
end;
end;
end;
end; end else begin
ShowMessage("Такой документ не существует в базе данных'); end;
F end
! else begin
I showMessage("Документ не открыт'); end;
end;
I Как видите, единственное существенное отличие от предыдущих листингов — позиционирование строки документа по номеру:
Yes:=(ole_Doc.ПолучитьСтрокуПоНомеру(SE_NuniLine.Value*1) * 1); .It Yes>0 then begin
Для удаления строки из табличной части документа служит метод Удалить- Строку (при этом документ должен быть позиционирован на удаляемой строке):
it (о1е_Оос.ПолучитьСтрокуПоНомеру(5Е_МишЫпе.Value*1)*1)>0 then begin ole_Doc.УдалитьСтроку;
ole_Doc.Записать;
Для удаления всех строк из табличной части документа предназначен метод УдалитьСтроки:
61e_Doc.УдалитьСтроки;
01e_Doc. Записать ;
Внести новую строку в табличную часть документа можно с помощью метода НоваяСтрока:
°1е_Пос.НоваяСтрока;
°1е_Оос.Записать;
Внести новый документ в список документов заданного вида можно с помо-
*ДЫо метода Новый документа:
& not VarIsEmpty(ole_Doc) then begin °le_Doc.Новый;
ole_Doc .Записать;
340
Часть I. 1С и механизм OLE Automata
fpaea 4- Д°стУп к информации 1С из внешних приложений
341
Для проведения документов заданного вида служит метод Провести:
if not VarlsEmpty(ole_Doc) then begin
ole_Doc. Провести 10, 1 *) ;
end;
Скомпилируем наш проект sp_EdilAltrlnDoc.DPR, запустим его на выполне. ние и отредактируем реквизиты "шапки" и первой строки табличной части документа ВыплатыФизЛицам (с номером 1) ОТ 14.07.2006.
На рис. 4.258 и 4.259 показан этот документ до редактирования.
.«р- Редактирование документов
-|О|х
]f СоюинигьсТСJ)| (V77App6cation Строка инициализации = Г
Открыть документ(ВыплатыФизЛицам
Найти по номеру |l
Провести документ
-Шапка :
Город
Комментарий [
Табличнаячасть:
Строка N
р"
"^ Дата |14.07.2006
Новый документ [
Новая строка
Всего = р
] Удалить строку | Удалить все строки (
ФизЛицо
СуммаНачислено
СуммаУдержано
СуммаВыплачено
ВидВып лат
СпособВ уплаты
(1000
,990
(Аксакалов Аксакал Аксакалович
(ЗарПлата (ПоПочте
Рис. 4.259. Документ ВыплатыФизЛицам (с номером 1)от 14.07.2006 до редактирования
Л на рис. 4.260 и 4.261 — после редактирования.
Если посмотреть движения этого документа до редактирования (рис. 4..
.262)
и после редактирования, то видно, что ничего не изменилось.
То есть изменения в документе сделаны, но документ не проведен, и поэто движения по документу (а значит и по регистрам) остались старые.
р—
Номер Док
Рис. 4.260. Документ ВыплатыФизЛицам (с номером 1) от 14.07.2006 после редактирования
1
Дата Доюр 4.07 06[q]
В
ФизЛицо
СуммаНа..
СуммаУдер...
СуммаВы...
ВидВып...
СпособВыплаты
п
Федоров Федор Фер!
2000
50
1950
Аванс
ЧерезКассу
Аксакалов Аксакал
30
1
29
МатПомощь
ПоПочте
U
Сидоров Сидор Сидор|
300
3
297
Премия
ЧерезБанк
|„.| Комментарий: |б табличной части изменена стро
Город:(Москва
Рис. 4.261. Документ ВыплатыФизЛицам (с номером 1)
от 14.07.2006 после редактирования (просмотр в программе 1С:Предприятие)
и
Город
Физ лицо
ВидВып...
Сумма начис...
СуммаУд...
СуммаВы... ЦСпособВыпл<
Волгогр
Аксакалов Акс.
ЗарПлата
1000
10
990шоПочте
Волгогр
Аксакалов Акс.
МатПомощь
30
1
29 ПоПочте
Волгогр
Сидоров Сидор
Премия
300
3
297ЧерезБанк
рис. 4.262. Движения по документу ВыплатыФизЛицам (с номером 1) от 14.07.2006 доредактирования (просмотр в программе 1 С: Предприятие)
JIN..
Город
Физ лицо
ВидВып..
Сумма и...
СуммаУд...
СуммаВы... ЦСпособВып»
Москва
Федоров Феде
Аванс
2000
50
195оГчерезКассу
Москва
Аксакалов Акс
МатПомощь
30
1
29 ПоПочте
I 3
Москва
Сидоров Сидор
Премия
300
3
297ЙЧерезБанк
FРис. 4.263. Движения по документу ВыплатыФизЛицам (с номером 1)
От 14.07.2006 после редактирования и проведения (просмотр в программе 1С:Предприятие)
Вновь запустим программу sp_EditAttrlnDoc.EXE, проведем этот документ (кнопка Провести документ), закроем программу, запустим программу 1С:Предприятие и посмотрим движение по этому документу (рис. 4.263).
Теперь все так, как и должно быть. Движения по документу соответствуют информационному содержанию документа.
Примечание
Более подробные сведения о способах редактирования информации в доку, ментах можно найти в специальной литературе по программе 1С:Предприятие.
Примечание
Напомню, что представленные примеры исходных текстов — это упрощенная иллюстрация к рассматриваемым вопросам. Назначение этих примеров — дать представление о возможном подходе при решении задач информационного обмена с системой 1С:Предприятие. При работе с реальными базами 1С может потребоваться их дальнейшая доработка.
Синхронизация баз данных 1С
В процессе эксплуатации программных продуктов IC на предприятии может возникнуть необходимость частой и периодической (например, ежечасной) частичной синхронизации разных баз данных (возможно, разных конфигураций). Может оказаться, что использование механизма OLE Automation в этом случае будет наиболее оптимальным.
Один из возможных вариантов синхронизации (применительно к справочникам, например) может быть таким:
Заранее определяются справочники и их реквизиты, которые должны быть включены в процесс синхронизации.
В случае разных справочников — определяются соответствия реквизитов (по идентификаторам) и правила конвертации (если реквизиты имеют разные типы).
Открывается база данных № 1.
Считывается информация из метаданных о структуре синхронизируемо'0 справочника А базы данных № 1.-■
Проверяется соответствие списка реквизитов справочника А, заданий для синхронизации, и списка реквизитов, реально существующих в спр вочнике А (лишние из списка синхронизируемых удаляются).
Открывается справочник А базы данных № 1.
Открывается база данных № 2.
Считывается информация из метаданных о структуре синхронизируемого справочника Б базы данных № 2.
Проверяется соответствие списка реквизитов справочника Б, заданных для синхронизации, и списка реквизитов, реально существующих в справочнике Б (лишние из списка синхронизируемых удаляются).
: 10. Открывается справочник Б базы данных № 2.
Ц. Сканируется справочник А и поэлементно проверяется (по уникальным кодам или реквизитам) наличие элементов в справочнике Б.
Если такого элемента в справочнике Б нет, то добавляется новый элемент и копируются значения синхронизируемых реквизитов (по заранее установленным правилам, если типы реквизитов отличаются).
Если такой элемент в справочнике Б есть, то значения синхронизируемых реквизитов в справочнике Б заменяются на значения соответствующих реквизитов из справочника А (по заранее установленным правилам, если типы реквизитов отличаются).
В предыдущих разделах мы подробно рассмотрели все то, что потребуется для реализации этого алгоритма, а именно:
соединение с 1С как сервером OLE Automation;
О работа с метаданными;
выборка элементов справочников;
поиск элемента справочника;
О считывание информации из элемента справочника;
О редактирование информации в элементе справочника;
О вычисление значений в строковом представлении (методы EvaiExpr. ЗначениеВСтроку, ЗначениеИзСтроки).
Разработка универсальных программных средств, ориентированных на синхронизацию баз данных 1С (с использованием механизма OLE Automation), — существенно трудоемкое занятие. Поэтому мы рассмотрим этот процесс на простом примере синхронизации двух "родственных" справочников в разных Конфигурациях.
Для этого скопируем конфигурацию 1 C_exampIe.DB в каталог с именем c_example.DB_synhro и отредактируем новую конфигурацию таким обра- чтобы структуры справочника Физлица отличались (рис. 4.264 и 4.265).
Улем считать базу данных lC_example.DB эталонной, а базу данных '--.example.DB_synhro— синхронизируемой. Примем также, что элементы
справочников Физлица синхронизируются по всем свойствам (наименование Код, Родитель) и реквизитам, которые выбирает пользователь (типы реквизи тов одинаковы).
Фи-ПищФи-Пищо»
Фи-Пищ
Фи-Пищ
.■ ДатаРождения
<У СостояниеФизлица
# КолвоДегей
Город Проживания
ДомашнийАдрес
- ■ Пол
СемейноеП сложение
СсстоитВПроФсоюзе
Дооолнитвльнаойнформация
Рис. 4.264. Структура эталонного справочника ФизЛицабазы данных lC_example.DB
SEBEGHEГ
ДатаРождения
» С ост оямиеФ излица
» КолеоДетей
ГородПрожтеания
ДомашнийАдрес
Пол
СемейноеП сложение
ДооолнитвльнаяИнФормация
Рис. 4.265. Структура синхронизируемого справочника ФизЛицабазы данных 1C_example.DB_synhro
Как видите, в целом структура обоих справочников совпадает, за исключением реквизита СостоитВПрофсоюзе.
Теперь запустим программу 1С:Предприятие (конфигурация lC_example.DB_ synhro) и сделаем непроведенными все документы вида изменениеСосточния- ФизЛиц (рис. 4.266). Это нужно для того, чтобы удалить из справочника ФизЛица значения всех периодических реквизитов, созданные при проведении документов.
Откроем справочник ФизЛица и внесем следующие изменения.
Перенесем элемент С кодом 5 (Аксакалов Аксакал Аксакалович) ИЗ груП' пы с кодом 7 (группа-i) в группу с кодом 9 (группа з).
Очистим историю всех периодических реквизитов (состояниеФизлии3 и колвоДетей) для этого же элемента справочника.
Откроем этот же элемент справочника для редактирования и внесем еле дующие изменения (рис. 4.267).
2312231211.?706 S Новый 15.07.06 1„ - ® Открыть11.?706 S Новый 15.07.06 1„ - ® ОткрытьПросмотрПросмотр— L ^ Копировать— L ^ КопироватьНом... 1 ДатаНом... 1 Дата112а.,.ЗП 29 06.112а.,.ЗП 29 06.12.07—1207.0612.07—1207.06зменеме состояния физ лиц Iзменеме состояния физ лиц IИзменение состояния физ лщ быглатыТизЛицамвменение состояния физ лицИзменение состояния физ лщ быглатыТизЛицамвменение состояния физ лицц~ ^ Пометить на удаление Del Г % Ввести на основанииц~ ^ Пометить на удаление Del Г % Ввести на основанииСделать непроведеннымСделать непроведеннымРис. 4.266. Сделаем документ "непроведенным"Рис. 4.266. Сделаем документ "непроведенным"Рис. 4.267. Содержание элемента справочника с кодом 5 в базе данных 1C_example.DB_synhroРис. 4.267. Содержание элемента справочника с кодом 5 в базе данных 1C_example.DB_synhro
2
3
1
2
2
3
1
2
11.?706 S Новый 15.07.06 1„
- ® Открыть
11.?706 S Новый 15.07.06 1„
- ® Открыть
Просмотр
Просмотр
— L ^ Копировать
— L ^ Копировать
Ном... 1 Дата
Ном... 1 Дата
112а.,.
ЗП 29 06.
112а.,.
ЗП 29 06.
12.07—
1207.06
12.07—
1207.06
зменеме состояния физ лиц I
зменеме состояния физ лиц I
Изменение состояния физ лщ быглатыТизЛицам
вменение состояния физ лиц
Изменение состояния физ лщ быглатыТизЛицам
вменение состояния физ лиц
ц~ ^ Пометить на удаление Del Г % Ввести на основании
ц~ ^ Пометить на удаление Del Г % Ввести на основании
Сделать непроведенным
Сделать непроведенным
Рис. 4.266. Сделаем документ "непроведенным"
Рис. 4.266. Сделаем документ "непроведенным"
Рис. 4.267. Содержание элемента справочника с кодом 5 в базе данных 1C_example.DB_synhro
Рис. 4.267. Содержание элемента справочника с кодом 5 в базе данных 1C_example.DB_synhro
""кроем программу 1С:Предприятие.
^1я сравнения на рис. 4.268 представлено информационное содержание Бемента справочника с кодом 5 в эталонной базе данных lC_example.DB.
Рис. 4.268. Содержание элемента справочника с кодом 5 в базе данных 1C_example.DB
В предыдущих разделах мы начинали рассматривать какой-либо вопрос "с начала", т. е. с программирования. В данном случае поступим с точностью до наоборот. Запустим программу sp_SynhroRefs.EXE, которая находится на сопроводительном компакт-диске книги в папке \Part_l\Chapter_04\Topic_4_8\ sp_SynhroRefs.PAS\, и "пощупаем", как она работает. Поочередно нажимаем кнопки 1С на левой и правой панели (естественно, в строке инициализации должен быть указан реальный путь доступа к конфигурациям). Результат представлен на рис. 4.269.
Нажимаем кнопку Мета. Результат представлен на рис. 4.270.
Список, показанный на рис. 4.270, можно отредактировать так, как это нужно для текущей задачи (например, удалить "лишние" реквизиты). Если нажать кнопку Контроль, то список реквизитов автоматически "синхронизируется таким образом, что в списке останутся "общие" реквизиты (по их идентификаторам). В нашем случае так и нужно поступить. После этого закроем эту форму нажатием кнопки ОК.
Теперь отметим в списке элементов строку с кодом 5 и нажмем кнопку Спр Результат представлен на рис. 4.271. Как видите, информация совпадает с представленной на рис. 4.267 и 4.268.
Рис. 4.269. Список элементов справочников ФизЛица в обеих конфигурациях
Рис. 4.270. Список реквизитов для синхронизации
Рис. 4.271. Содержание элемента справочника с кодом 5 в обеих базах данных до синхронизации
Закроем это диалоговое окно и нажмем кнопку -> ("синхронизировать") По окончании синхронизации на экране появится сообщение (рис. 4.272).
Вновь нажмем кнопку Спр. Результат представлен на рис. 4.273.
Рис. 4.272. Сообщение об окончании синхронизации элемента справочников
,f Содержание элемент он справочников,f Содержание элемент он справочниковf 1C example.D8 -эталон-f 1C example.D8 -эталон-1C example.DB«irihro1C example.DB«irihroКод=5гНаименоваше-Аксакалсе Аксакал Аксакалович ।ДатаРождения-01.01.1970IСостояние^ излица»СагрданикО сноснойКолвоДетей»3Г ородПроживания-21 Киев Домашний4дрес=Россия, г.Б, ул Б, дОО Пол=Мужской;СемейноеПоложение-РазведенСостоите П роФсоюзе=1 ДополнительнаяИнформаиия=Код=5гНаименоваше-Аксакалсе Аксакал Аксакалович ।ДатаРождения-01.01.1970IСостояние^ излица»СагрданикО сноснойКолвоДетей»3Г ородПроживания-21 Киев Домашний4дрес=Россия, г.Б, ул Б, дОО Пол=Мужской;СемейноеПоложение-РазведенСостоите П роФсоюзе=1 ДополнительнаяИнформаиия=■ Код-5; Наименоеамче-Аксакалов Аксакал АксакалоаичИ ДатаРождения-01.01.1970,{ СостояниеФизлица-СотрудникОсновнойL КолвоДетей=3*1 ГородПроживания-21 Киевj ДомашнийАдрес-Россия. г.Б. ул Б. д.00 Пол-Мужскойi СемейноеПоложение-Разведенfl ДополнительнаяИнФормация-I_■ Код-5; Наименоеамче-Аксакалов Аксакал АксакалоаичИ ДатаРождения-01.01.1970,{ СостояниеФизлица-СотрудникОсновнойL КолвоДетей=3*1 ГородПроживания-21 Киевj ДомашнийАдрес-Россия. г.Б. ул Б. д.00 Пол-Мужскойi СемейноеПоложение-Разведенfl ДополнительнаяИнФормация-I_
,f Содержание элемент он справочников
,f Содержание элемент он справочников
f 1C example.D8 -эталон-
f 1C example.D8 -эталон-
1C example.DB«irihro
1C example.DB«irihro
Код=5г
Наименоваше-Аксакалсе Аксакал Аксакалович ।
ДатаРождения-01.01.1970I
Состояние^ излица»СагрданикО сносной
КолвоДетей»3
Г ородПроживания-21 Киев Домашний4дрес=Россия, г.Б, ул Б, дОО Пол=Мужской;
СемейноеПоложение-Разведен
Состоите П роФсоюзе=1 ДополнительнаяИнформаиия=
Код=5г
Наименоваше-Аксакалсе Аксакал Аксакалович ।
ДатаРождения-01.01.1970I
Состояние^ излица»СагрданикО сносной
КолвоДетей»3
Г ородПроживания-21 Киев Домашний4дрес=Россия, г.Б, ул Б, дОО Пол=Мужской;
СемейноеПоложение-Разведен
Состоите П роФсоюзе=1 ДополнительнаяИнформаиия=
■ Код-5
; Наименоеамче-Аксакалов Аксакал Аксакалоаич
И ДатаРождения-01.01.1970
,{ СостояниеФизлица-СотрудникОсновной
L КолвоДетей=3
*1 ГородПроживания-21 Киев
j ДомашнийАдрес-Россия. г.Б. ул Б. д.00 Пол-Мужской
i СемейноеПоложение-Разведен
fl ДополнительнаяИнФормация-
I_
■ Код-5
; Наименоеамче-Аксакалов Аксакал Аксакалоаич
И ДатаРождения-01.01.1970
,{ СостояниеФизлица-СотрудникОсновной
L КолвоДетей=3
*1 ГородПроживания-21 Киев
j ДомашнийАдрес-Россия. г.Б. ул Б. д.00 Пол-Мужской
i СемейноеПоложение-Разведен
fl ДополнительнаяИнФормация-
I_
Рис. 4.273. Содержание элемента справочника с кодом 5в обеих базах данных после синхронизации
Комментарии, думаю, здесь не требуются.
N С.N С.ДокДокBSBS28.06.0612 07.0628.06.0612 07.06Переменно кПеременно кОткроем программу 1 С:Предприятие (конфигурация lC_example.DB_synhro) и убедимся, что элемент справочника с кодом 5 из группы Труппа-3" "вернулся в свою alma mater ("Группа-1"). А также посмотрим, что произошло с периодическими реквизитами (для этого же элемен та справочника) на примере реквизита СостояниеФизлица (рис. 4.274).
N С.
N С.
Док
Док
BS
BS
28.06.06
12 07.06
28.06.06
12 07.06
Переменно к
Переменно к
Временно не работает
Сотрудник по неосновному месту рабо^
Сотрудник по основному месту
Сотрудтк по основному месту
Рис 4.274. Значения периодического реквизита СостояниеФизлица для 3”e“e^ справочника с кодом 5 в базе данных 1 C_example.DB_synhro после синхрон -
ддя сравнения на рис. 4.275 представлены значения этого же реквизита для элемента справочника с кодом 5 в эталонной базе данных IC.example.DB.
Дэта
Время
Документ
Номер
НС...
Временно не работает
24 СБ 06
Сотрудтк по неосновному месту работы
28.06.06
23:3842
Изменение сс
1
1
Сотрудник по основному месту работы
12 07 06
23 26 40
Изменение сс
2
2
Сотрудник по основному месту работы
Рис. 4.275. Значения периодического реквизита СостояниеФизлица для элемента справочника с кодом 5 в базе данных 1C_example.DB
Здесь нужны пояснения. Как видите, значения реквизитов и даты совпадают в обоих случая. Но в эталонной базе данных lC_example.DB (см. рис. 4.275) два последних значения "привязаны" к документам, а в базе данных |C_example.DB_synhro (см. рис. 4.274) — нет. Это было сделано преднамеренно, поскольку в данном случае мы синхронизировали только справочники и не касались документов. А это значит, что списки документов в обеих базах данных могут отличаться. Более того, в случае "разнородных" баз данных в синхронизируемой базе вообще может не быть документов соответствующего вида.
Теперь откроем исходные тексты проекта sp_SynhroRefs.DPR (папка \Part_l\Chapier_04\Topic_4_8\sp_SynhroRefs.PAS\ на сопроводительном компакт-диске книги) и попробуем разобраться, как все это работает.
Примечание
Вопросы, связанные с запуском 1С (как сервера автоматизации), а также с формированием списка элементов справочников и списка синхронизируемых реквизитов (из метаданных), подробнейшим образом рассмотрены ранее.
Сразу же перейдем к процессу синхронизации выбранного элемента справочника (по нажатию кнопки ->). Текст обработчика события: "нажатие этой кнопки" представлен в листинге 4.136.
•аботчик события "нажатия кнопки
Jl*^»AM.l^~^-^--^K*-L^^ill.JJ-w»^*-M^-aba^.*.-.i.-taa.a.7AKiu:
Procedure TForml.SpeedButtonlClick(Sender: TObject);
Синхронизация текущего элемента справочника Ver
Sx: string;
sCode: string; II Код синхронизируемого элемента справочника ■Ln
” i£ ListBoxl.ltemIndex>=0 then begin
^ 1064
Н Если какой-то элемент справочника в списке выбран, // считываем текущую строку в списке-эталоне //(см. рис. 4.271)
Sx:=Trim(ListBoxl.Items[ListBoxl.Itemindex]);
// Выделяем код элемента справочника
•Code:=Trim(sp_GetWordFronString('=', Sx, 1));
// Вызываем функцию, где реализован алгоритм
// синхронизации элемента справочника по его коду
if BynhroThi. eEi «п( sCode) then begin ShowMessage(1 Готово');
end
else begin ShowMessage('Неудачно ...');
end;
end;
end;
Здесь пояснения не требуются.
Более подробно мы рассмотрим реализацию функции synhroThisEiem.
Примечание
Полный исходный текст этой функции здесь не приводится (из-за экономии места, а также по той причине, что здесь это будет "нечитабельно").
Первое, что "делает" функция, — убирает "звездочку" из строковой переменной, где хранится код элемента (если элемент является группой, в начало строки добавлен символ "звездочка"):
// sCode - значение кода элемента, который синхронизируется
■Code:=sp_AllTrimUnChar('* ' , sCode);
Затем позиционируется справочник-эталон на выбранном элементе (код ко- | торого передан функции в качестве параметра в переменной scode): if (oleRef_FZ_l.НайтиПоКоду(StrToInt(aCode),0)*1) >0 then begin Поскольку справочник Физлица иерархический, определяется код родите.^ | выбранного элемента-эталона. Если у данного элемента есть родитель, то I синхронизируемый справочник позиционируется на этом родителе (по код)' I и в переменной oleParent2 сохраняется ссылка на текущий элемент (соот- । ветствующий найденному родителю):
SCodeParent:='';
// Проверяем, есть ли у этого элемента родитель
ififII(oleRef_FZ_l.Родитель.Выбрак*1)>0 then begin
if
if
I
I
//У данного элемента справочника есть родитель.
II Определяем код родителя.
eCode₽arent:=Trim(oleRef_FZ_l.Родитель.Код);,
// Ищем ЭТОГО родителя в синхронизимруемой базе данных
if (oleRef_FZ_2.НжйтиПоКоду(StrToInt(eCodeParent),0)*1) >0 then begin olePar«nt2:= oleRef_FZ_2.ТекущийЭлемент;
I
Примечание
Если в справочнике-эталоне родитель существует, а в синхронизируемом — нет, то сначала нужно завести этого родителя в синхронизируемом справочнике (как группу), а затем синхронизировать элемент слравочика. Отсюда следует, что если синхронизация справочников выполняется автоматически (сразу по всем элементам), то сначала (на первом проходе) нужно синхронизировать элементы-группы (чтобы создать "отсутствующих" родителей), а на втором проходе — остальные элементы.
После "выявления" родителя синхронизируемый справочник позиционируется на элементе с кодом scode (это тот элемент, который выбран для синхронизации). Если элемент не найден, создаем новый. Если это группа, вызываем метод Новаягруппа, для остальных элементов— метод новый. Затем присваиваем значения свойств код и Наименование элемента-эталона соответствующим свойствам созданного элемента (синхронизируемого справочника) и сохраняем созданный элемент справочника в синхронизируемой базе данных:
// В синхронизируемом справочнике ищем элемент с кодом sCode
If (oleRef_FZ_2.НайтиПоКоду(StrToIntleCoda),0)*1)<=0 then begin
И Если элемента в справочнике синхронизируемой базы данных
К // нет, то нужно внести новый элемент справочника
( ц
I if (oleRef_FZ_l.ЭтоГруппа*1)<=0 then begin
II Это НЕ группа - вызываем метод "Новый"
oleRef_FZ_2.Новый;
I end
■ else begin
// Это группа - вызываем метод "НоваяГруппа"
oleRef_FZ_2.Новаягруппа;
£ told;
Г //
[ //
I // Присваиваем такие же код и наименование, как
// в элементе справочника эталонной базы данных
oleRef_FZ_2.Код:=BCode;
oleRef_FZ_2.Наименование:=oleRef_FZ_l.Наименование;
//
// Записываем новый элемент справочника
//в базу данных
oleRef_FZ_2.Записать;
Далее вновь позиционируемся на элементе синхронизируемого справочника (следуя логике, это уже лишнее, но с 1С лучше перестраховаться) и редактируем свойства Наименование И Родитель элемента:
if (oleRef_FZ_2.Ha*™noKofly(StrToInt(sCode).0)*1) >0 Chen begin
oleRef_FZ_2.Наименование:=oleRef_FZ_l.Наименование;
//
// Привязываем этот элемент справочника
//к родителю
if not VarlsEmpty(oleParent2) then begin
// Родитель существует
oleRef_FZ_2.Родитель:=oleParent2;
end
else begin
// Родитель HE существует
oleRef_FZ_2.Родитель; = " ;
end;
И
Проверяем: если синхронизируемый элемент— это группа, то записываем изменения в синхронизируемую базу данных (для группы реквизиты не синхронизируем):
if (oleRef_FZ_l.ЭтоГруппа*1)>0 then begin
// Это группа - реквизиты синхронизировать не будем.
// Записываем изменения в элементе справочника
// в синхронизируемую базу данных
oleRe f_FZ_2.Записать;
end;
Проверяем: если синхронизируемый элемент — это не группа, то вызываем функцию synhroThisEiem_Attr для синхронизации реквизитов и, если уда4' но, сохраняем изменения в синхронизируемой базе данных:
if (oleRef_FZ_l.ЭтоГруппа*!)<=0 then begin
// Это НЕ группа.
// Вызываем функцию для редактирования реквизитов
if synhroThisElenLAttr then begin
// Все OK - записываем изменения в элементе справочника //в базу данных
oleRef_FZ_2.Записать;
end
Теперь посмотрим, каким образом можно синхронизировать элементы спра- дочников (функция SynhroThisElem_Attr). Сначала определяем — задан ли список реквизитов для синхронизации (была ли нажата кнопка Мета, СМ. рис. 4.270):
CountAttr:=Dlg._AttrStr.ListBoxl.Items.Count;
if countAttr>0 then begin
Если да, то сканируем список реквизитов (справочника-эталона) и выделяем из списка идентификаторы реквизитов:
iAttr:=-l;
while iAttr<(CountAttr-l) do
begin
I iAttr:=iAttr*l;
// Читаем идентификатор очередного реквизита
// справочника эталонной базы данных
"Sx:=Trim(Dly_AttrStr.ListBoxl.Items[iAttr ]);
idAttr:=Trim(sp_GetWordFromSbring( ' = ■ , Sx, 1)) ;
Затем (на всякий случай) определяем, существует ли реквизит с этим идентификатором в синхронизируемом справочнике:
// Получаем ссылку на синхронизируемый реквизит // как объект метаданных
01eMeba2:=olelC_2.Метаданные.Справочник(''+'Физлица');
pleMeta2:=oleMeba2.Реквизит(1'+idAttr);
it oleMeta2.Выбран*1>0 then begin
И Такой реквизит есть в синхронизируемой базе данных
Если такой реквизит имеется в синхронизируемом справочнике, определяем его тип:
И
** Читаем свойства синхронизируемого реквизита:
V/ "Периодичность0 реквизита
^■Serioda:=о1еМеСа2.Периодический*1;
Тип реквизита
«Туре2:= Trim(oleMeta2.Тип);
// Вид реквизита
■Klnd2:= Trim(oleMeta2.Вид);
Ц
Затем считываем тип реквизита в справочнике-эталоне:
// Получаем ссылку на реквизит-эталон как объект метаданных
oleMetal:=olelC_l.Метаданные.Справочник(' 1 *'ФизЛица');
oleMetal:=oleMetal.Реквизит(''+idAttr);
// Читаем свойства реквизита-эталона:
//"Периодичность" реквизита
ItePeriodl:=oleMetal.Периодический*1;
// Тип реквизита
■Typel:= Trim(oleMetal.Тип);
II Вид реквизита
■Kindi:= Trim (oleMetal.Вид);
Сравниваем типы реквизитов в обеих конфигурациях. Если типы несовместимы, то должны быть предварительно назначены правила конвертации. В противном случае данный реквизит пропускается (в нашем случае этого делать не надо):
if (sTypel = sType2) and
(sKindl = sKind2) and
(ItsPeriodl = ItsPeriod2) then begin
// Данный реквизит в обеих базах данных
// "одинаков" (для наших целей)
Теперь проверяем: если реквизит не периодический, то читаем значение реквизита с помощью метода ПолучитьАтрибут:
if XtsPeriodl<=0 then begin
// Это непериодический реквизит.
// Читаем значение реквизита-эталона
oleVal:=oleHef_FZ_l.ПолучитьАтрибут(1'+idAttr);
И синхронизируем с помощью метода Установитьдтрибут (как мы делали это в разд. 4.7./).
Для реквизитов базового типа:
if (AnsiUpperCase(■Typel)=AnsiUpperCase('Строка')) or
(AnsiUpperCase(elypel)=AnsiUpperCase('Число')) or
(AnsiUpperCase(sTypel)=AnsiUpperCase('Дата')) then begin
// Это базовый тип.
// Записываем эталонное значение реквизита
//в синхронизируемый реквизит
о1вВе£_ГЬ_2 .УстановитьАтрибут (1 1 +idAttr, Trim(oleVal)) ,-
end;
Для перечислений (используя методы ЗначениеВСтроку, ЗначениеИзСтроки I и EvalExpr):
if (AnsiUpperCase (sTypel)=AnsiUpperCase('Перечисление')) then begin
L // Это — перечисление.
С // Прочитаем идентификатор значения реквизита
idval:=Tr im(oleVal.Идентификатор);
II Формируем строку для выполнения с помощью метода EvalExpr()
Sx:='Перечисление.ПолучитьАтрибут(* 1+sKindl+1•)';
Sx:=Sx+'.ЗначениеПоИдентификатору("'+idVal+'•)';
Sx:='ЗначениеИзСтроки(ЗначениеВСтроку('+Sx+')) ';
// Получаем ссылку на значение перечисления
П в синхронизируемой базе данных
oleVal:=olelC_2.EvalExpr(Sx);
// Записываем новое значение
' // в синхронизируемый реквизит
oleRef_rz_2.УстановитьАтрибут(''+idAttr,oleVal);
end;
Для реквизитов типа Справочник (учитывая, что справочник, элементы которого являются множеством значений для данного реквизита, может иметь владельца):
if (AnsiUpperCase(sTypel)=AnsiUpperCase('Справочник')) then begin
| II Это — Справочник.
( 11 Прочитаем код элемента справочника (значение реквизита) ldVal:=Trim(oleVal.Kofl);
II Определим владельца элемента справочника (значение реквизита) idOwner:='1;
if (oleVal.Владелец.Выбран*1)>0 then begin
// Читаем код владельца
idOwner:=Trim(oleVal.Владелец.Код);
I end;
I И Если у этого реквизита есть владелец,
I * * позиционируемся на нем
oleOwner2:=UnAssigned; H Справочник-владелец
oleOwnarTekE12:=UnAssigned; II "ТекушийЭлемент" if length(idOwner)>0 then begin
// Владелец существует
владельца
oleOwnar2:=
olelC_2.GreateObject('Справочник.1+Trim(oleVal.Владелец.Вид));
if о1еОепег2.НайтиПоКоду( ‘ ,+idOwner,0) then begin
// Считываем ссылку на элемент-владелец
oleOwnezTekEl2:=oleOwner2.ТекушийЭлемант;
end;
end;
// Ищем текущий элемент справочника с кодом idVal
//в синхронизируемой базе данных
oleRef2:=olelC_2.CreateObject('Справочник.'+ТгЬп(о1еУа1.Вид));
if not VarlsEmpty(oleOwnerTekE12) then begin
// Если есть владелец — учитываем его
oleRef2.ИспользоватьВладвльца(oleO*nerTekK12,0);
end;
// Ищем новое значение реквизита
if (oleRef2.НайтиПоКоду(1,+ldVal,l)*l)>0 then begin
// Записываем эталонное значение реквизита
// в синхронизируемый реквизит
oleRef_FZ_2.УстановитьДтрибут!'1+idAttr,oleRef2.ТвкущийЭлемент);
end;
end;
Примечание
Естественно, что в случае реквизитов других типов (например, Документ) этот код должен быть функционально расширен.
Если синхронизируемый реквизит периодический — то используем объект Периодический (как мы делали это в разд. 4.7.1). Сначала в синхронизируй мом справочнике удаляем все значения реквизита (которые не связаны с Д0" кументами):
// Создаем объект "Периодический" в синхронизируемой базе данных olePerlod2:= olelC_2.CreateObject ('Периодический');
// Устанавливаем фильтр по синхронизируемому реквизиту
//и элементу справочника
^ (olePeriod2.ИспользоватьОбчект(1'+ldAttr, о1еЯв£_У2_2.ТекущийЭлемеит)*1) > 0 then begin
И
Удаляем ВСЕ значения данного реквизита,
и
кроме тех, что установлены документами
и
при проведении
if
(olePeriod2.ВыбраткЭначения*!) >0 then begin
<
while (olePeriod2.ПспучитьЗиачвкие*!) >0 do
L begin
// Пропускаем значения, созданные документами
if (olePeriod2.ТекущийДокумент.Выбран*1)<=0 then begin
if (olePeriod2.Удалить*!)>0 then begin It Удачно end;
I end;
end;
end;
end;
Затем копируем все значения из периодического реквизита элемента-эталона в синхронизируемый элемент без ссылки на документы;
и Создаем объект "Периодический" в эталонной базе данных
olePeriodl:= olelC_l.CreateObject {'Периодический•);
if (oleperiodl.ИспольЗоватьОбъект(''tidAttr, о1еНе1_Р2_1.Текущийалемент)*1) > 0 then begin
it Копируем все значения периодического реквизита-эталона
if (olePeriodl.B«6paTb3Ha4eHKH*l) >0 then begin
While (olePeriodl .ПолучитьЗначакиеЧ) >0 do begin
tl Проверяем корректность даты в значении реквизита-эталона if ep_leDate(Trim(olePeriodl.flaTaSHa4)) then begin // Сразу же устанавливаем дату значения
о1еРег1оа2.ДатаЗнач:=Тгмп(о1еРег1о<Ц.ДатаЗнач);
И иИ иДля упрощения - не будем отслеживать свойство "ТекущийДокумент".
И и
И и
// Читаем значение реквизита-эталона oleVal:=olePeriodl.Значение;
И Далее, почти так же, как и ранее (для непериодических реквизитов).
// В соответствии с типом значения...
// Присваиваем значение синхронизируемому реквизиту olePeriod2. Значением <3десь соответствующее значение»-, // Записываем изменение в синхронизируемую базу данных olePeriod2.Записать;
Вот, собственно, и все. В принципе — ничего "военного". Все это было рассмотрено в предыдущих разделах. Но потребуются существенные усилия и точность в программировании.
Примечание
Напомню, что представленные примеры исходных текстов — это упрощенная иллюстрация к рассматриваемым вопросам. Назначение этих примеров дать представление о возможном подходе при решении задач информационного обмена с системой 1С:Предприятие. При работе с реальными базами 1С может потребоваться их дальнейшая доработка.
Глава 5
Расширение функционала 1С
Как отмечалось выше, система 1 С:Предприятие обладает собственными (штатными) средствами, позволяющими произвести конфигурирование информационной структуры и настройку функционала для решения прикладных задач с учетом особенностей конкретной организации. Тем не менее, для решения специальных задач предусмотрена возможность расширения функциональности системы за счет использования технологии создания внешних компонент. Термин "внешняя компонента" адекватен, по сути, термину "сервер автоматизации" или "сервер OLE Automation" (см. главу 1).
Декларированные фирмой 1С возможности внешних компонент:
О расширение встроенного языка системы (новые объекты агрегатного типа);
□ добавление страницы свойств в параметры системы 1С:Предприятие;
О сохранение параметров внешней компоненты (с использованием механизмов системы 1С:Предприятие);
О создание дополнительных окон в окне системы 1С: Предприятие;
О доступ к функциям системы 1С:Предприятие (с помощью механизма OLE Automation);
О вызов процедур обработки событий (в контексте системы 1 С:Предприятие), генерируемых внешней компонентой;
О доступ к строке состояния программы 1С:Предприятие.
Основное назначение внешних компонент: сопряжение с различным торговым оборудованием, нестандартное отображение данных, дополнительные 'специфические) функции и т. д.
Есть две версии внешних компонент:
® версия 1.0 — совместима с системой 1С:Предприятие версий 7.5 и 7.7;
$ версия 2.0 — совместима с системой 1С:Предприятие версии 7.7.
Все создаваемые внешние компоненты должны следовать единому стандарт. Упростить процедуру создания стандартных внешних компонент позволяют специальные шаблоны, разработанные фирмой Ю для разных языков про граммирования (Borland Delphi, Microsoft Visual C++, Microsoft Visual Basic)
Примечание
Более подробную информацию о технологии создания внешних компонент можно найти в специальной литературе по системе 1 (^Предприятие.
В этой главе мы рассмотрим процесс создания внешних компонент (с ис пользованием шаблонов фирмы 1С) на конкретных примерах.
Общие сведения
Как отмечалось в главе 1. COM (Component Object Model — модель составных объектов) — одна из базовых технологий Windows. Основная цель СОМ — возможность экспорта объектов, создаваемых внутри приложения. То есть одно приложение создает объект, а другие приложения используют свойства и методы (сервисы) экспортируемого объекта. При этом не имеет принципиального значения, на каком именно языке программирования разрабатывались "взаимодействующие" приложения. Главное, чтобы был соблюден стандарт СОМ.
Приложение, поддерживающее технологию СОМ, должно иметь в своем составе хотя бы один СОМ-объект. Объект является экземляром какого-то класса (переменная объектного типа). Существенное отличие СОМ-объекта от "обычного" объекта в том, что СОМ-объект должен иметь хотя бы один интерфейс (их количество концептуально не органичено). У СОМ-объектов есть также отличия в объектном механизме наследования. СОМ-объекты поддерживают наследование интерфейсов.
Интерфейс (interface) — это средство согласованного взаимодействия экспортируемого СОМ-объекта и приложения-клиента, которое обращается к свойствам и методам экспортируемого СОМ-объекта. Интерфейс имеет два идентифицирующих его атрибута — имя интерфейса и его GUID (с.м. главу 1). Естественно, что GUID для каждого интерфейса должен быть уникальным. В среде Windows GUID формируется функцией coCreaceGuid. Среда Delphi позволяет формировать GUID прямо в тексте исходного кода модуля. Для этого достаточно нажать сочетание клавиш: <Ctrl>+<Shift>+<G>- Любой СОМ-объект должен иметь базовый интерфейс IUnknown. С помощью этого интерфейса можно получить список всех интерфейсов данного СОМ- объекта. Интерфейс IUnknown наследуется всеми остальными интерфейсами-
у интерфейса IUnknown есть 3 метода:
g Queryinterface — возвращает указатель на требуемый интерфейс;
AddRef — поддерживает механизм учета ссылок (увеличивает счетчик ссылок на единицу);
_Reiease — поддерживает механизм учета ссылок (уменьшает счетчик ссылок на единицу, как только счетчик ссылок обнуляется — СОМ-объект "самоуничтожается").
для создания и запуска COM-объекта (как экземпляра класса) используется фабрика класса. Для каждого класса должна быть своя фабрика класса.
СОМ-сервер — это исполняемый модуль (DLL-файл или приложение), имеющий в своем составе СОМ-объект(ы). СОМ-сервер должен быть зарегистрирован в операционной системе специальным образом (в системном реестре Windows). Есть разные способы регистрации COM-серверов. В частности, в состав Windows входит специальная утилита для регистрации СОМ- серверов — RegSvr32.EXE.
Как говорилось в главе I, есть 3 вида серверов:
внутрипроцессный (in-process) сервер — в виде DLL-библиотеки;
внепроцессный (out of process) сервер — в виде отдельного приложения;
удаленный (remote) сервер — запущен на другом (относительно клиента) компьютере (очевидно, что внутрипроцессный сервер не может служить удаленным сервером).
На СОМ-технологии базируется технология OLE Automation. При этом:
COM-серверы должны поддерживать интерфейс IDispatch — важнейший элемент технологии OLE Automation (поддержка механизма позднего связывания):
IDispatch = interface(IUnknown)
О COM-серверы должны поддерживать типы данных, используемые в технологии OLE Automation (например byte, variant, date, bstr, hresult, long и др.);
О все методы интерфейсов должны быть процедурами, поддерживающими соглашение о вызове safecall, или функциями, поддерживающими соглашение о вызове safecall и возвращающими значение типа HResult.
При управлении сервером автоматизации используются раннее связывание (все обращения к методам интерфейсов проверяются на корректность на этапе компиляции программы-клиента) и позднее связывание (все обращения к методам интерфейсов проверяются на корректность на этапе выполнения Программы-клиента).
Информация об интерфейсах, а также их свойствах и методах, содержите в библиотеке типов (файлы *.TLB). При создании библиотеки типов исполь зуется специальный язык IDL (Interface Definition Language).
Примечание
В общем случае наличие библиотеки типов не обязательно. Но для реализаци механизма раннего связывания она необходима.и
Примечание
СОМ-технология — очень объемная, важная и сложная тема, охватывающая различные аспекты создания и взаимодействия приложений в среде Windows и в рамках данной книги она детально не рассматривается. Подробную инфор^ мацию о технологии СОМ можно найти в специальной литературе.
Внутрипроцессный сервер автоматизации
Внутрипроцессный сервер автоматизации реализуется в виде специального DLL-модуля (библиотеки). В среде Delphi такой модуль создается следующим образом.
Нужно выбрать пункт File > New, в открывшемся диалоговом окне перейти на вкладку ActiveX и выбрать значок ActiveX Library (рис. 5.1).
После этого Delphi сгенерирует соответствующий код (листинг 5.1).
• ;: New Items
Forms | Dialogs I Projects ] Data Modules ] BusinessNew ActiveX | Multitiei | Addn_ExampleO1_01
R®®86
Active ServerActiveFormActiveXЦШЭОСЗЕИ
ObjectControl
? ШпйШ*
Automation COM Object Property Page Type Library Object
' ■ С Сод C Jnlrerit' Г Ure
Рис. 5.1. Выбор типа DLL-библиотеки для создания сервера автоматизации
piaea 5- Расширение функционала IC363
5^ЙЩ^^
library Project!;
uses
CaciSexv;
exports
DllGetClaseObject,
pllCanUnloadNow,
Dl IResi8terServer, DllUnregieterServer;
{$R *.RES}
begin end.
В табл. 5.1 представлена информация о назначении функций из листинга 5.1.
Реализация этих функций содержится в файле ComServ.PAS.
Таблица 5.1. Назначение функций из листинга 5.1
Функция
Назначение
DllGetClassObject
Создание фабрики классов и предоставление доступа к библиотеке классов
DllCanUnloadNow
Проверка возможности выгрузки DLL-библиотеки из памяти
DllRegisterServer
Регистрация сервера в системном реестре Windows
Dl lUnreg is terServer
Удаление информации о сервере из реестра Windows
Для создания объекта нужно вызвать диалоговое окно (см. рис. 5.1) и выбрать значок Automation Object. На экране появится диалоговое окно для ввода имени класса COM-объекта (рис. 5.2).
Поле CoClass Name содержит имя класса COM-объекта (это имя будет зарегистрировано в системном реестре Windows).
Раскрывающийся список Instancing позволяет выбрать одно из следующих значений:
О Internal — фабрика классов не будет регистрироваться в системном реестре, следовательно, этот класс не будет доступен для клиентских приложений;
Single Instance — для каждого клиента будет запускаться экзем пля СОМ-сервера;, р
Multiple Instance — запускается один экземпляр СОМ-сервера для всех клиентов.
ххAutomation Object Wizard
х
х
Cc£lass Mame: jPrimer
Indenting:Indenting:|Multiple Indance|Multiple IndanceJhr oadng Model; | ApartmentJhr oadng Model; | ApartmentHiHi- OptionsF Generate Event support code- OptionsF Generate Event support codeOK | Cancel ( В* |OK | Cancel ( В* |Рис. 5.2. Ввод имени класса COM-объектаРис. 5.2. Ввод имени класса COM-объектаIS’oProjectl.tlb* ❖ 3 it id ❖ ^[^ ФIS’oProjectl.tlb* ❖ 3 it id ❖ ^[^ ФAttributes | Use» | Flags [ Text |Attributes | Use» | Flags [ Text |Name:Name:)► IPnmer $ Primer)► IPnmer $ Primer|Proiecl1|(72S6F6C3-3AC6-48E7-B1E9-5810E1C11FAC)|Proiecl1|(72S6F6C3-3AC6-48E7-B1E9-5810E1C11FAC)QUID:QUID:Version:Version:LDD:LDD:-Help—Help String:Help ContextHelp Siring ContextIHelp String DLLHelp File:-Help—Help String:Help ContextHelp Siring ContextIHelp String DLLHelp File:(Projectl Lbrary(Projectl Lbrarytodfied | ■■todfied | ■■Рис. 5.3. Редактор библиотеки типовРис. 5.3. Редактор библиотеки типов
Indenting:
Indenting:
|Multiple Indance
|Multiple Indance
Jhr oadng Model; | Apartment
Jhr oadng Model; | Apartment
Hi
Hi
- Options
F Generate Event support code
- Options
F Generate Event support code
OK | Cancel ( В* |
OK | Cancel ( В* |
Рис. 5.2. Ввод имени класса COM-объекта
Рис. 5.2. Ввод имени класса COM-объекта
IS’oProjectl.tlb
* ❖ 3 it id ❖ ^[^ Ф
IS’oProjectl.tlb
* ❖ 3 it id ❖ ^[^ Ф
Attributes | Use» | Flags [ Text |
Attributes | Use» | Flags [ Text |
Name:
Name:
)► IPnmer $ Primer
)► IPnmer $ Primer
|Proiecl1
|(72S6F6C3-3AC6-48E7-B1E9-5810E1C11FAC)
|Proiecl1
|(72S6F6C3-3AC6-48E7-B1E9-5810E1C11FAC)
QUID:
QUID:
Version:
Version:
LDD:
LDD:
-Help—
Help String:
Help Context
Help Siring Context
I
Help String DLL
Help File:
-Help—
Help String:
Help Context
Help Siring Context
I
Help String DLL
Help File:
(Projectl Lbrary
(Projectl Lbrary
todfied | ■■
todfied | ■■
Рис. 5.3. Редактор библиотеки типов
Рис. 5.3. Редактор библиотеки типов
раскрывающийся список Threading Model позволяет выбрать одно из следующих значений:
Single — однопоточная модель;
Apartment — модель разделенных потоков;
Free — модель свободных потоков;
Both — модель смешанных потоков.
флажок Generate Event support code служит для поддержки механизма модификационных сообщений.
После нажатия кнопки ОК (см. рис. 5.2) на экране появится диалоговое окно редактирования библиотеки типов создаваемого сервера (рис. 5.3).
В диалоговом окне редактирования библиотеки типов создаются свойства и методы COM-объекта, которые будут доступны клиентским приложениям (контроллерам автоматизации) (рис. 5.4).
й Д Project 1
е ЯСИ
* Methodi
6£ PtopertylProperty!
:^ Prime,
Рис. 5.4. Новый метод и новое свойствоCOM-объекта сервера автоматизации
Среда Delphi автоматически сгенерирует соответствующий код (листинг 5.2).
У*”" 5 2 Код. =o,W„b.» .МрЫ пед^иО!*^ Automaton Obltot^^
unit: Unitl;
interface
uses
ComObj. ActiveX, Projectl_TLB, StdVcl;
type
TPr inter = class(TAutoObject, IPriroer)
protected
procedure Methodi; safecall;
I function Get_Propertyl: Integer; safecall;
Procedure Set_Propertyl(Value: Integer); safecall; Ь ( Protected declarations }
end;
implementation uses ComServ;
procedure TPrimer.Methodi;
begin
end;
function TPrimer.Get_Pxopertyl: Integer;
begin
end;
procedure TPrimer.Set_Propertyl(Value: Integer);
begin
end;
initialization
TAutoObjectFactory.Create(ComServer, TPrimer, Class_Primer, ciMultilnstance, tmApartment);
end.
Как видите, для написания кода реализации заданных свойств и методов COM-объекта оставлены соответствующие пустые "заглушки".
Здесь следует отметить одну существенную деталь. Свойство ProgiD СОМ- объекта в данном случае будет автоматически сформировано следующим образом:
Projectl.Primer
То есть в первой части (до точки) используется имя DLL-модуля (в данном случае), а во второй части — имя СОМ-объекта.
Примечание
Далее мы увидим, что при создании внешней компоненты для системы 1С:Предприятие в первой части свойства ProgiD всегда должна быть цепочка символов Addin. Но это не означает, что DLL-модуль обязательно должен называться Addln.DLL.
■ - • ■
Чтобы добавить страницу свойств сервера, нужно вызвать диалоговое окно I (см. рис. 5.1) и выбрать значок Property Page. Delphi создаст форму TProper- I tyPage:
jpropertyPage = class(TCustomForm)
Г я сгенерирует соответствующий код (листинг 5.3).
стинг 5.3^ Код, сгенвриро.
1анный D<
Яры при создании формы7
^2 _,. _ <.<^; я
«nit unitl;
interface
№es SysUtils, Windows, Messages, Classes, Graphics, Controls, StdCtrls, ExtCtrls, Forms, ComServ, ComObj, StdVcl, AxCtrls;
type
TPropertyPagel = class(TPropertyPagel private
( Private declarations } protected
{ Protected declarations } public
{ Public declarations }
procedure UpdatePropertyPage; override;
procedure Updateobject; override;
end;
■Const
| Class_PropertyPagel: TGUID = '(F8E326B1-5FB9-4973-B685-A5E084D530B7)';
.implementation
R$R *.dfm}
Procedure TPropertyPagel.UpdatePropertyPage; begin
( Update your controls from OleObject } «id;
«ocedure TPropertyPagel.UpdateObject;
begin
{ Update OleObject frcm your controls )
end;
initialization
TActiveXPropertyPageFactory.Create(
ComServer,
TPropertyPagel,
Class_PropertyPagel);
end.
Как видите, процесс создания внутрипроцессного сервера автоматизации в среде Delphi максимально упрощен и не представляет трудностей.
Примечание
Более подробную информацию о создании внутрипроцессных серверов автоматизации можно найти в специальной литературе,
В главе 1 говорилось, система 1С поддерживает механизм OLE Automation как сервер и как клиент. По отношению к внешней компоненте программа 1С выполняет роль клиента (контроллера автоматизации). Следовательно, здесь применимы все приемы и способы программирования серверов автоматизации, разработанные для использования этой технологии в других приложениях. Тем не менее, при создании внешних компонент для системы 1С:Предприятие есть некоторые нюансы.
Рассмотрим процесс создания внешних компонент для программы 1С: Предприятие на конкретных примерах, используя шаблоны, разработанные фирмой 1С для Delphi.
Прежде всего следует отметить, что все интерфейсы системы 1С:Предприятие определены в файле AddlnLib.PAS. То есть этот модуль должен присутствовать в директиве uses других модулей, использующих эти интерфейсы.
Создадим внешнюю компоненту версии 1.0 с использованием соответствующего шаблона (sample).
Примечание
Описание шаблона приведено в руководстве 1С по технологии создания внешних компонент.
Прежде чем приступить к созданию внешней компоненты, нужно придумать имя компоненты (вторая часть имени в свойстве ProgiD) и имя DLL-файла
компоненты (предполагается, что назначение компоненты, т. е. ее функциональность, уже определена). В нашем случае имя компоненты Addin_ExampleOi, а имя DLL-файла— AddIn_Example01_01.DLL.
Создадим новый каталог (например, AddIn_Example01_01) и скопируем туда gee файлы шаблона. Переименуем файл проекта шаблона Addln.DPR в AddIn_.Example01_01.DPR.
Примечание
Текст модуля Addln.DPR шаблона практически идентичен тексту, представленному в листинге 5.1.
Остальные файлы проекта (AddlnLib.PAS, AddlnObj.PAS, PropPage.*) можно оставить без изменения.
Примечание
Исходные тексты этого примера приведены на сопроводительном компакт- диске книги в папке \Part_1\Chapter_05\Topic_5_2\Addln_Example01_01.PAS.
Здесь файлы AddlnObj.PAS и PropPage.* переименованы в Addln0bj_01 .PAS и PropPage_01 .* соответственно.
Откроем файл AddInObj_01.PAS.
Как видите, OLE-объект (TAddinObject) здесь унаследован не от TAutoobject (листинг 5.2), а от icomobject. Мотивация разработчика шаблона (фирма 1С): если TAddinObject наследуется от TAutoobject, это приведет к созданию и использованию библиотеки типов, что усложнит шаблон.
В табл. 5.2 перечислены основные методы OLE-объекта TAddinObject.
Таблица 5.2. Назначение методов внешней компоненты (шаблон Sample)
Метод
Назначение
Init
Инициализирует объект компоненты. При успешном выполнении возвращает значение s_ok, в противном случае — значение e_fail
Done
Вызывается при завершении работы с объектом компоненты. При успешном выполнении возвращает значение s_ok
GetInfо
Вызывается программой 1 (^Предприятие для получения информации о компоненте (в частности, о версии компоненты). При успешном выполнении возвращает значение з_ок
RegisterExtensionAs
Определяет вторую часть свойства Progin (т. е. имя компоненты). При успешном выполнении возвращает значение s_ok
Таблица 5.2 (продолжение)
Метод
Назначение
GetNProps
Определяет количество свойств компоненты. При успешном выполнении возвращает значение s_ok
FindProp
Определяет порядковый номер свойства по его имени. При успешном выполнении возвращает значение s_ok, в противном случае — значение s_false
GetPropName
Определяет имя свойства по его номеру. При успешном выполнении возвращает значение s_OK, в противном случае — значение s_false
GetPropVal
Определяет значение свойства по его номеру. При успешном выполнении возвращает значение s_ok, в противном случае — значение s_false
SetPropVal
Присваивает свойству новое значение. При успешном выполнении возвращает значение s_OK, в противном случае — значение s_false
IsPropReadable
Определяет, доступно ли свойство для чтения. При успешном выполнении возвращает значение s_OK, в противном случае — значение s_false
IsPropWritable
Определяет, доступно ли свойство для записи. При успешном выполнении возвращает значение S_OK, в противном случае — значение s_false
GetNMethods
Определяет количество методов компоненты. При успешном выполнении возвращает значение S_OK, в противном случае — значение s_false
FindMethod
Определяет порядковый номер метода по его имени. При успешном выполнении возвращает значение s_ok, в противном случае — значение s_false
GetMethodName
Определяет имя метода по его номеру. При успешном выполнении возвращает значение s_ok, в противном случае — значение s_false
GetNParams
Определяет количество параметров заданного метода. При успешном выполнении возвращает значение 5_ок, в противном случае — значение s„false_
GetParamDefValue
Определяет значение по умолчанию для заданного параметра заданного метода. При успешном выполнении возвращает значение s_ok, в противном случае — значение S_FALSE
HasRetVal
Определяет, является пи заданный метод функцией (возвращает значение) или процедурой (не возвращает значения). При успешном выполнении возвращает значение s_ok, в противном случае — значение s_false
Таблица 5.2 (окончание)
Метод
Назначение
CallAsProc
Реализует вызов заданного метода как процедуры. При успешном выполнении возвращает значение 5_ок, в противном случае — значение s_false
CallAsFunc
Реализует вызов заданного метода как функции. При успешном выполнении возвращает значение з_ок, в противном случае — значение s_false
GetPages
Используется для привязки к странице свойств (TAddinPropPage). При успешном выполнении возвращает значение s_ok
GetIDsOfNames
Позволяет получить номер метода объекта (программы 1 С.-Предприятие как сервера OLE Automation) по имени метода (используется перед вызовом метода invoke интерфейса IDispatch). Если не реализовано, возвращает значение e_notimpl
Invoke
Осуществляет вызов метода объекта (программы 1С:Предприятие как сервера OLE Automation) по номеру. Если не реализовано, возвращает значение e_notimpl —
Примечание
Более подробную информацию о шаблонах (для разработки внешних компонент) фирмы 1С можно получить из специальной литературы по системе 1 С.-Предприятие.
Прежде всего, создадим новый GUID для новой компоненты и присвоим его значение переменной CLSiD_AddinObject (листинг 5.4).
const
CLSID_AddInObject : TGUID = '(AE5D9B58-F9E3-4A38-9262-621D1CEAAC97)';
Затем определим три константы (листинг 5.5), которые избавят нас от необходимости постоянно искать и менять определенные строки в тексте модуля при переходе от одной версии примера к другой.
Const
I // Имя компоненты (вторая часть свойства ProgID) ExtenoionNeuiW-Cccp = ' AddIn_Exairc:le01';
11 Суффикс для имени DLL-файла версии примера
ExcensionName_Comp_Vers = '_01‘;
// ИМЯ DLL-файла внешней компоненты
dllNameCont> = Excens ionName_Ccmp+ExtensionName_C<xnp_Vers;
В тексте модуля AddlnObj_OLPAS сделаем соотвтетствующие замены (листинг 5.6).
function TAddInObject.Hiit(pConnection: IDispatch): HResult; stdcall;
if (iRes = S_OK) then begin
Z/pProfile.RegisterProfileAs('Sample Addin Profile Name');
pProfile.RegisterProfileAs(ExtensionNama_Ccnv+' Profile Name');
end;
function TAddInObject.RegisterExtensionAs(var bstrExtensionName: WideString): HResult; stdcall;
begin
//bstrExtensionName := 'AddlnExtension';
bstrExtensionName : =" ExteneionName_Cccp;
RegisterExtensionAs := S_OK;
end;
initialization
ComServer. SetServerName (' Addin');
TComObjectFactory.Create(ConServer,TAddInObject,CLSID_AddInObject,
//'Addin','V7 Addin 2.0',ciMultilnstance);
dllNeme_Ccm>,'V7 Addin 2.0'.ciMultilnstance);
end.
Здесь следует отметить следующую важную деталь. Версия компоненты должна быть определена в методе Getinfo следующим образом (листинг 5.7).
ЯКЙйнг 5.7. Определение_еерсии внешней компоненты
■■к»еЮН«»-»час.2!^.^:Ьмжк™1<х^2К^.с^^^<к2^:^х;«и1иий.^:м*^.«м..я.^Хи«^^
function TAddlnObject.Qetlnfolvar plnfo: PSafeArrayt(OleVariant)}):
HResult; stdcall:
var
varlnfo : OleVariant;
begin
varlnfo := *2000';
PutNParam(plnfo,0,varlnfo);
GeClnfo := S_OK;
end;
Для внешней компоненты версии 1.00 в переменную varlnfo должна быть записана строка '1000', а версии 2.00 — '2000*. Поскольку все примеры данной книги ориентированы на 1С:Предприятие версии 7.7, которая поддерживает внешние компоненты обеих версий (1.00 и 2.00), то нет необходимости менять значение этой переменной.
В принципе, на этом подготовительные операции закончены, и можно перейти к программированию функциональности компоненты. Чтобы еще более упростить первый пример, пришлось удалить из данного модуля шаблона практически все, кроме реализации свойства Enabled (Включен) внешней компоненты. В дальнейшем мы будем постепенно наращивать функциональность.
Функциональность первой версии примера использования шаблона (sample) будет заключаться только в том, что внешняя компонента будет иметь свойство Включен и два метода — Включить И Выключить.
Свойство включен определено на странице свойств (форма TAddinPropPage) в виде Delphi-компонента Компонента включена (рис. 5.5) следующим образом (листинг 5.8).
type
- TAddinPropPage = class(TPropertyPage)
iMEnabled: TCheckBox; // "Компонента включена"
end;
Страница свойств компонентыВВЕЗ
■ । Страница свойств компоненты В odand Delphi 5~0
• • Г" Компонента включена - - - -
Рис. 5.5. Определение нового свойства компоненты на странице свойств
Следующий шаг — объявить имена свойств и методов внешней компоненты так, чтобы их можно было использовать в контексте встроенного языка системы 1С:Предприятие. В рамках рассматриваемого шаблона это делается следующим образом (листинг 5.9).
resourcestringstrlsEnabled = 1isEnabled,Включен'; // Свойство strEnable = 'Enable,Включить';// МетодstrDisable = 'Disable,Выключить 1; II МетодresourcestringstrlsEnabled = 1isEnabled,Включен'; // Свойство strEnable = 'Enable,Включить';// МетодstrDisable = 'Disable,Выключить 1; II Метод
resourcestring
strlsEnabled = 1isEnabled,Включен'; // Свойство strEnable = 'Enable,Включить';// Метод
strDisable = 'Disable,Выключить 1; II Метод
resourcestring
strlsEnabled = 1isEnabled,Включен'; // Свойство strEnable = 'Enable,Включить';// Метод
strDisable = 'Disable,Выключить 1; II Метод
Как видите, англоязычное и русскоязычное написания имен методов (свойств) разделены запятой.
«■6«■6// Свойства// СвойстваДалее нужно перечислить свойства и методы так, как это указано в листинге 5.10.
«■6
«■6
// Свойства
// Свойства
Type
TProperties = ( propIsEnabled, LastProp );
TMethods = ( methEnable, methDisable, LastMethod ); И Методы
Здесь важно отметить, что свойство LastProp и метод LastMethod должны быть всегда последними в списке перечислений (TProperties И TMethods). Это связано с тем. что они участвуют в определении количества свойств (GetNProps) и методов (cetNMethods) внешней компоненты следующим образом (листинг 5.11 и 5.12).
function TAddlnObject.GetNProps(var plProps: Integer): HResult; stdcall--function TAddlnObject.GetNProps(var plProps: Integer): HResult; stdcall--beginplProps := Integer(LastProp);GetNProps := S_OK;beginplProps := Integer(LastProp);GetNProps := S_OK;
function TAddlnObject.GetNProps(var plProps: Integer): HResult; stdcall--
function TAddlnObject.GetNProps(var plProps: Integer): HResult; stdcall--
begin
plProps := Integer(LastProp);
GetNProps := S_OK;
begin
plProps := Integer(LastProp);
GetNProps := S_OK;
end;
function TAddlnObject.GetM4ethods(var plMethods: Integer): HResult; stdcall; begin
plMethods := Integer(LaetMethod);
GetNMethods := S_OK;
end;
Реализация загрузки параметров OLE-объекта внешней компоненты приведена в листинге 5.13.
function TAddlnObject.LoadPropertie»: Boolean; var iRes : Integer;
varRead : OleVariant;
begin
VarClear(varRead);
( Simply cast OleVariant to Integer (VT_I4) } varRead := 0;
iRes := pProfile.Read('Enabiad:0'.varRead,nil);
if (iRes <> S_OK) then begin Loadproperties := False; Exit;
end;
boolisEnabled := varRead;
Loadproperties := True; end;
Реализация сохранения параметров OLE-объекта внешней компоненты приведена в листинге 5.14.
■Procedure TAddlnObject.SaveProperties; var
varSave : OleVariant;
varSave := booilsEnabled;
pProfile.Write!'Knabled:O'.varSave);
end;
Определение порядкового номера свойства по его имени приведено в листинге 5.15.
function TAddlnObject.FindProp(const bstrPropName: WideString; var plPropNum: Integer): HResult; stdcall;
begin
plPropNum := -1;
II
// Соответствие имени свойства и его порядкового номера
if (bstrPropName = Termstring(etrleKnebled,0)) then plPropNum := 0;
if (bstrPropName = Termstring (strlsEnabled,1)) then plPropNum := 0;
II
if (plPropNum = -1) then begin
FindProp := S_FALSE;
Exit;
end;
FindProp := S_OK;
end;
Здесь функция Termstring выделяет из первого параметра (типа string) англоязычное или русскоязычное написание свойства (см. листинг 5.9) в зависимости от значения второго параметра. В обоих случаях метод FindProp определяет одно и то же значение для переменной plPropNum. Это значение (в данном случае ноль) должно строго соответствовать порядку следования значений (в данном случае propisEnabled) перечисления TProperties (листинг 5.10). В данном случае свойство:
' IsEnabled, Включен' ;
установлено в соответствие значению перечисления propisEnabled:
( propl«Enabled, LastProp );
Такому же правилу нужно следовать при написании кода метода FindMethod (листинг 5.16).
function TAddlnObject.FindMethod!const bstrMethodName: WideString;
var plMethodNum: Integer): HResult; stdcall; begin
S
plMethodNum := -1;
H
II Соответствие имени метода и его порядкового номера
if (bstrMethodName = Termstring(etrKnable,0)) then plMethodNum := 0;
if (bstrMethodName = Termstring(strEnable,1)) then plMethodNum := 0;
if (bstrMethodName = Termstring(strDiaable,0)) then plMethodNum := 1;
if (bstrMethodName = TetmString(strDisable,1)) then plMethodNum := 1; i
if (plMethodNum = -1) then begin
FindMethod : = S_FALSE;
Exit;
end;
FindMethod := S_OK;
end;
Здесь имя метода внешней компоненты Включить (так, как оно будет использоваться в контексте встроенного языка программирования системы 1С:Предприятие) соответствует значению methEnable перечисления TMethods. А имя метода Выключить соответствует значению methDisable (см. листинг 5.9 и 5.10).
Определение имени свойства по его порядковому номеру приведено в листинге 5.17.
function TAddlnObject.GetPropName(IPropNum, IPropAlias: Integer; var pbstrPropName: WideString): HResult; stdcall;
, begin
PbstrPropName := ' ';
case TProperties(iPropNUm) of
propisEnabled: // Значение перечисления TProperties
Ibegin
&pbstrPropName := Termstring(strlsEnabled,IPropAlias);
end;
else
begin
GetPropName := S_FALSE;
Exit;
end;
enH;
GetPropName := S_OK;
end;
Здесь комментарии излишни.
По такому же принципу реализован метод GetMethodName (листинг 5.18).
function TAddlnObject. GetMethodName (IMethodNum, IMethodAlias: Integer; var pbstrMethodNanie: WideString): HResult; stdcall;
begin
pbstrMethodName := *';
case TMethods (IMethodNum) of
methEnable: II Значение перечисления TMethods
begin
pbstrMethodName := TermString(atrEnable,IMethodAlias);
end;
methDieable: // Значение перечисления TMethods
begin
pbstrMethodName := Termstring(itrDlMble,IMethodAlias);
end;
else
begin
GetMethodName := S_FALSE;
Exit;
end;
end;
GetMethodName := S_OK;•<
end;
Реализация определения значения свойства по его номеру представлена
в листинге 5.19.
■MiZI■MiZI19. On19. On■■
■MiZI
■MiZI
19. On
19. On
■
■
function TAddlnObject.GetPropVal(IPropNum: Integer; var pvarPropVal: OleVariant): HResult; stdcall;
begin
VarClear(pvarPropVal);
case TProperties(IPropMum) of
proplsEnabled: // Значение перечисления TProperties begin
pvarPropVal := boolIeBnabled;
end;
else
begin
GetPropVal := S_FALSE;
Exit;
end;
end;
GetPropVal := S_OK;
end;
Здесь следует сделать некоторые пояснения.
В нашем случае свойство включен (isEnabled) на странице свойств TAddinPropPage определено как тип Boolean (свойство Checked Delphi- компонента isEnabled : TCheckBox). Но в контексте встроенного языка системы 1 С: Предприятие нет такого типа данных (см. главу 4). Поэтому у объекта TAddinobject объявлено свойство типа Integer:
boolIeBnabled : Integer;
значение которого и считывается из программы 1С:Предприятие. То же самое относится к реализации метода SetPropVai (листинг 5.20).
function TAddlnObject.SetPropVai(IPropNum: Integer;function TAddlnObject.SetPropVai(IPropNum: Integer;
function TAddlnObject.SetPropVai(IPropNum: Integer;
function TAddlnObject.SetPropVai(IPropNum: Integer;
var varPropVal: OleVariant): HResult; stdcall; begin
case TProperties(IPropNum) of
propIsEnabled: // Значение перечисления TProperties begin
boolIeEnabled := varPropVal;
end;
else
begin
SetPropVal := S_FALSE;
Exit;
end;
end;
SetPropVal := S_OK;
end;
Здесь следует отметить, что для связи со страницей свойств и обмена данными используется интерфейс IPropertyLink (листинг 5.21).
IPropertyLink = interface(IUnknown)
['{B59789El-2E8B-lldl-A4E7-004095ElDAEA}'1
function get_Enabled(var boolIsEnabled : Integer): HResult; stdcall;
function put„Enabled(boolIsEnabled : Integer): HResult; stdcall; end;
Реализация его методов представлена в листинге 5.22.
function TAddlnObject.get_Enabled(var IsEnabled : Integer):
HResult; stdcall;
begin
IsEnabled := boolIsEnabled;
get_Enabled := S_OK;
end;
function TAddInObject.put„Enabled(IsEnabled : Integer): HResult; stdcall-' begin
boolIsEnabled := IsEnabled;
put_Enabled := S_OK;
end;
Реализация связи co страницей свойств представлена в листинге 5.23.
J
"^RRSIWWT
&«стинг553. Связь со стоаниией свойств- - ^^У * х*'6'-?^' '-'^^Tt^"’-^^--*^^
procedure TAddlnPropPage.UpdatePropertyPage; var
iCheck : Integer;
pLink : IPropertyLink;
• begin
pLink := IUnknown(OleObject) as IPropertyLink;
if (pLink <> nil) then begin
pLink.get_Enabled(iCheck);
if (iCheck <> 0) then IяEnabled.Checked := True
else
IeEnabled.Checked := False;
end;
end;
procedure TAddlnPropPage.UpdataChjact;
var pLink : IPropertyLink;
begin
pLink := IUnknown(OleObject) as IPropertyLink;
if (pLink <> nil) then begin
if (isKnabled.Checked = True) then
pLink.put_Enabled(1)
else
pLink.put_Enabled(0);
end;
Old;
Свойство может быть доступно (из программы 1С:Предприятие) только для Чтения, только для записи или как для чтения, так и для записи. Реализуются эти возможности в контексте методов isPropReadabie (листинг 5.24) и ^Propwritable (листинг 5.25).
^инг 5.24. Установка флага доступно !^ЖЙ!^8;й^:<
^ct ion TAddlnObj ect. lePropReadable (iPropNum: Integer ;
var pboolPropRead: Integer): HResult; stdcall;
^^ 1064
^Йк
case TProperties(IPropNum) of propisKnabled: // Значение перечисления TProperties begin pboolPropRead := 1; // Свойство доступно для чтения end; else begin IsPropReadable := S_FALSE; Exit; end;
end;
IsPropReadable := S_OK; end;
Примечание
В версии 1 С:Предприятие 7.7 объявленное свойство всегда доступно хотя бы для чтения.
запзап
зап
зап
function TAddlnObject.IsPropWritable(IPropNum: Integer; var pboolPropWrite: Integer): HResult; stdcall; begin case TProperties(IPropNum) of
propIsEnabled: // Значение перечисления TProperties begin
pboolPropWrite := 1; // Свойство доступно для записи end; else begin
IsPropWritable := S_FALSE;
Exit;4
end; end; IsPropWritable := S_OK; end;
g данной версии примера оба метода внешней компоненты включить и выключить вызываются из программы 1С: Предприятие как процедуры. Реализовано это в методе внешней компоненты CailAsProc (листинг 5.26).
function TAddlnObject.CailAsProc(IMethodNum: Integer;
var paParams: PSafeArrayI: HResult; stdcall;
■begin
case TMethods(IMethodNum) of
methEnable: II Значение перечисления TMethods begin
boolIeKnabled := 1; II Включить компоненту end;
methDieabla: // Значение перечисления TMethods begin
boolleEnabled := 0; // Выключить компоненту end;
else
begin
CailAsProc := S_FALSE;
Exit;
end;
end;
CailAsProc := S_OK; end;
Сохраним наш Delphi-проект и скомпилируем его. Перед компиляцией проекта нужно проследить, чтобы в свойствах проекта (команда Project > Options) на вкладке Linker была включена опция Generate С object files. Результат компиляции (файл AddIn_Example01_01.DLL) нужно скопировать 8 любой из каталогов:
О каталог пользователя;
О каталог информационной базы;
О каталог с исполняемым файлом системы 1С:Предприятие.
В данном случае лучше всего скопировать файл AddIn_Example01_01.DLL :е Каталог "нашей" конфгурации (lC_example.DB).
Теперь посмотрим, каким образом можно использовать свойства и методы внешней компоненты Addin_ExampieOi в среде программы 1С: Предприятие
Примечание
Сначала внешнюю компоненту нужно подключить к программе 1С:Предприятир Для этого есть два штатных метода встроенного языка программирования системы 1С:Предприятие — ЗагрузитьВнешнююКомпоненту и Подключись ВнешнвюКомпоненту. Подробную информацию об этих методах можно найти в специальной литературе по программе 1С:Предприятие.
Примечание
Внешняя компонента может быть подключена как в контексте глобального модуля, так и в любой обработке (включая и внешнюю обработку). Мы рассмотрим вариант подключения внешней компоненты в контексте внешней обработки.
Запустим Конфигуратор системы 1С:Предприятие, откроем "нашу" конфигурацию и создадим внешнюю обработку (рис. 5.6).
её Пример работы с смешней компонентпой HR В
Addln_ExampleO1
Файл : Addln_Example01_01.dll Включить Выключить | Состояние ???
Закрыть |
Рис. 5.6. Форма внешней обработки для тестирования внешней компоненты(файл Addln_Example01_01.DLL)
Чтобы проверить функциональность внешней компоненты Addin_ExanpleOi. реализованной в файле AddIn_Example01_01.DLL, достаточно трех кнопок (табл. 5.3).
Таблица 5.3. Назначение кнопок в форме внешней обработки
Кнопка
-——
Назначение
Включить
Тестирование метода Enable (Включить) внешней компоненты_
Выключить
Тестирование метода Disable (выключить) внешней компоненты^
Состояние
Тестирование свойства isEnabled (Включен) внешней компоненты^
пы с рйёшнеи иампилешмой »
Addln_ExampleO1
Файл : Addln_Example01_01.dll
Включить уСостояниеВключить уСостояниеВыключить???Выключить???
Включить у
Состояние
Включить у
Состояние
Выключить
???
Выключить
???
Свойства Кнопки
Закрыть | 06шие Доголнительм° | Команда | Картинка
Формула | Включить!)
Г" Пропускать при вводе
Рис. 5.7. Задание имени процедуры в качестве обработчика нажатия кнопки Включить
N'l ^'Mep работы с внеии*сйкомс>одент№ НВ И
Addln_ExampleO1
«Райл : Addln_Exaniple01_01.dll
СостояниеСостояние??????
Состояние
Состояние
???
???
Свойства Кнопки
Закрыть | °6шие Дополнигсльмо | Команда | Картинка • Формула: (Выключить!)
'• Г Пропускать при весте
Рис. 5.8. Задание имени процедуры в качестве обработчика нажатия кнопки Выключить
■ЙripM«4epp^fowС внешней комиоиентж^ ВИЕЗ
Addln_ExampleO1
Файл : Addln_Example01_01.dll
ВключитьВключитьСостояниеСостояниеВыключить???Выключить???
Включить
Включить
Состояние
Состояние
Выключить
???
Выключить
???
Свойства Кнопки
.( Общие Дополнительно I Команда I Картинка
Закрыть |
- Формула: (ПолучигьСостояние))
Г" Пропускать при вводе
Рис. 5.9. Задание имени процедуры в качестве обработчика нажатия кнопки Состояние
"Привяжем" к каждой кнопке (табл. 5.6) процедуру-обработчик события "нажатие этой кнопки". Для этого нужно вызвать диалоговое окно настройки для каждой кнопки и на вкладке Дополнительно в поле Формула ввести имя соответствующей процедуры (рис. 5.7—5.9).
Каждая из указанных процедур должна присутствовать в тексте модуля обработки (листинг 5.27).
Далее, для настройки элемента управления Текст (надпись ??? на рис. 5.6) нужно вызвать соответствующее диалоговое окно и на вкладке Общие в поле Идентификатор ввести идентификатор этого элемента управления (рис. 5.10).
(иоиства (екста (КакоеСостояние)
Общие | Дополнительно | Шрифт | Описание |
Заголовок р?’
Идентификатор. |КакоеСостояние
Г Сделать недоступным
Г Сделать невидимым
Г* Запретить релагтнобвониа
Рис. 5.10. Идентификатор элемента управления ‘Текст’
Для того чтобы можно было визуально отобразить состояние внешней компоненты (свойство Включен) В элементе управления КакоеСостояние, нужно на вкладке Дополнительно в поле Формула внести имя переменной (в данном случае состояниеОбъекта, рис. 5.11), объявленной в тексте модуля обработки (листинг 5.27).
Рис. 5.11. "Привязка" элемента управления КакоеСостояние к переменной модуля СостояниеОбъекта
Теперь значение переменной СостояниеОбъекта будет отображаться в эле-
уенте управления КакоеСостояние автоматически.
Исходный текст модуля внешней обработки представлен в листинге 5.27.
ЬиошняяФорма для Addln Example01_01 .ERT, '
И
// переменная, к которой "привязан" элемент управления "КакоеСостояние*
Перем СостояниеОбъекта;
И и
ц Ссылка на внешнюю компоненту
Перем ВК Экспорт;
Л
41
// Обработчик нажатия кнопки "Включить" Процедура Включить()
ВК.Включить () ;
КонецПроцедуры
^/
//
//Обработчик нажатия кнопки "Выключить*
Процедура Выключить()
ВК.Выключить();
КОнецЛроцедуры
//
//
//Обработчик нажатия кнопки "Состояние*
Процедура ПолучитьСостоккие()
г // Читаем значение свойства внешней компоненты
I Если (ВК.Включен > 0) Тогда
। i // Значение переменной ‘СостояниеОбъекта* в // автоматически отображается в элементе
I II управления "КакоеСостояние*
СостояниеОбъекта = ’Состояние: Включено";
к Иначе
I // Значение переменной "СостояниеОбъекта*
I И автоматически отображается в элементе
// управления "КакоеСостояние" СостоямиоОбчекта = "Состояние: Выключено";
КонецЕсли;
КонецПроцедуры // // Предопределенная процедура Процедура ПриОткрытам ()
// Подключаем внешнюю компоненту
ЗагрузитьВнешнпоКокпонанту (" AddIn_EtiHunile01_01.dll*);
II Получаем ссылку на OLE-объект внешней компоненты ВК = СоздатьОбмвкт( "Addin.AddIn_Kxen<)l«01') ;
// Сразу же считываем состояние внешней компоненты ПолучитьСостояние();
КонецПроцедуры
Теперь сохраним обработку в файле с именем ВнешняяФорма_для_АдЛп_ ExampleOIJM.ERT. запустим программу 1С:Предприятие и откроем сохраненную внешнюю обработку (рис. 5.12).
й Пример работы с внешней компонентной ВИВ
л a I? V
Addln_ExampleO1
•Райл: Add1n_Example01_01.dll
Включить Выключить I
L Состодаие' Состояние: Включено
Закрыть ;
Рис. 5.12. Внешняя обработка для тестированиявнешней компоненты Addln_Example01 (версия 1)
Чтобы проверить, как функционирует внешняя компонента, нужно поочередно нажимать кнопки Включить и Выключить, проверяя с помощью кнопки Состояние, изменилось ли состояние внешней компоненты.
Если есть необходимость отсылки в 1С:Предприятие сообщения о возникновении какого-либо внешнего события, то можно использовать для этого методы интерфейса lAsyncEvent (листинг 5.28).
Устинг 5.28. Интерфейс для отсылки сообщения в 1 С;Предприятие ^ком-либо событии ,_^
y^gyncEvent = interface(IUnknown)
[■{AB634004-F13D-11D0-A459-004095E1DAEA)']
procedure procedure procedureprocedure procedure procedureprocedure end;procedure end;SetEventBufferDepthdDepth: Integer); safecall;
procedure procedure procedure
procedure procedure procedure
procedure end;
procedure end;
GotEventBufferDopth (var plDepth: Integer); safecall; ExternalEvent(const bstrSource, bstrMessage, bstrData: WideString); safecall;
CloanBuffor; safecall;
В табл. 5.4 описано назначение методов интерфейса lAsyncEvent.
Таблица 5.4. Назначение методов интерфейса lAsyncEvent
Метод
Назначение
SetEventBufferDepth
Устанавливает размер очереди сообщений о внешних собьпиях
Ge tEventBufferDepth
Возвращает размер очереди сообщений о внешних событиях
ExternalEvent
Помещает в очередь сообщение о внешнем событии
CleanBuffer
Очищает очередь сообщений
Рассмотрим эту возможность на примере внешней компоненты Addin_Exampie01. Для этого модифицируем метод callAsProc следующим образом (листинг 5.29).
-^^^
изменении состояния
function TAddlnObject.CallAeProc(IMethodNum: Integer;
var paParams: PSafeArray{(OleVariant))): HResult; stdcall; begin
case TMethods(lMethodNum) of
MthEnable:
begin
boolIsEnabled := 1;
if (pEvent <> nil)then begin
pEvent.ExternalEvent('BK01','Ответ1, ' 1') ;
^-M^iT-
end;
end;
methDisable:
begin boolIsEnabled := 0; if (pEvent <> nil)Chen begin
pEvent.Kxternallventl'BK01','Ответ','O') ; end;
end;
else
begin
CallAsProc := S_FALSE;
Exit;
end;
end;
CallAsProc := S_OK;
end;
В данном случае в текст реализации метода CallAsProc добавлены строки, обеспечивающие отсылку в программу 1С:Предприятие сообщения об изменении состояния внешней компоненты (свойство Включен). Для этого вызывается метод ExternalEvent интерфейса lAsyncEvent (pEvent). Первый параметр, передаваемый методу ExternalEvent. это имя источника события (сообщения), второй параметр — имя сообщения, третий параметр — данные.
Сообщение помещается в очередь сообщений. В системе 1 С:Предприятие есть специальная предопределенная процедура, которая автоматически (если она реализована в программном модуле) вызывается для обработки очереди сообщений.
Теперь нужно сохранить проект, скомпилировать его и результат компиляции (DLL-файл) скопировать в каталог lC_example.DB.
Примечание
На сопроводительном компакт-диске книги исходные тексты этой версии примера находятся в папке \Part_1\Chapter_05\Topic_5_2\Addln_Example01_02.PAS.
Теперь модифицируем внешнюю обработку (программы 1С:Предприятие) следующим образом. Добавим в форму еще два элемента управления типа "Текст" (рис. 5.13).
391
ОтветВК:f???
Закрыть |
Свойства Текста
Общие Дополнительно | Шрифт ] Описани! Формула:|Состояние06ьекта_0твет
Положение; (прижать влево
tv Центр по вертикали Г* Прозрачный Фон
Рис. 5.13. Внешняя обработка для тестированиявнешней компоненты Addln_Example01 (версия 2)
Ж Здесь состояниеОбъекта_Ответ — переменная, объявленная в тексте модуля обработки (листинг 5.30). Ее значение меняется в предопределенной процедуре ОбработкаВнешнегоСобытия.
Перем ВК Экспорт;
Перем СостояниеОбъекта;
Перем СостояниеОбтехта_Ответ;
Процедура Включить()
ВК.Включить();
КонецПроцедуры
Процедура Выключить()
ВК.Выключить();
КонецПроцедуры
I Процедура ПолучитьСостояние()
Если (ВК.Включен > 0) Тогда
СостояниеОбъекта = "Состояние: Включено";
Иначе
СостояниеОбъекта = "Состояние: Выключено"; КонецЕсли;
Г КонецПроцедуры
17/
// Предопределенная обработка сообщений о внешних событиях
Процедура ОбработкаВкашнегоСобытия(Источник,Событие,Данные)
Если (Источник = "ВК01") И (Событие = ‘Огеот") Тогда
Если (Данные = "1") Тогда
СостояниеОбтьекта_Ответ = ‘Состояние: Включено";
Иначе
СостояниеОб'ьекта_Ответ = "Состояние: Выключено";
КонедЕсли
КонецЕсли;
КонецПроцедуры
И
Процедура ПриОткрытии()
СостояниеОбъекта_Ответ = "???";
ЗагрузитьВнешнкюКомпоненту("*ddIn_Exanple01_02.dll");
ВК = СоздатьОбъект("Addin.AddIn_Exarnple01");
ПолучитьСостояние();
КонецПроцедуры
Здесь видно, что сообщения, выбираемые из очереди сообщений (процедура ОбработкаВнешнегоСобытия), фильтруются по источнику и названию сообщения. В зависимости от значения параметра данные переменная состояниеОбъекта_ Ответ принимает соответствующее значение.
Сохраним обработку под именем ВнешняяФорма_для_Ад(11п_Ехатр1е01_ 02.ERT, запустим программу 1С:Предприятие и откроем сохраненную обработку (рис. 5.14).
Пример работы с внешней компонентной НВВ|
51 61 (?) у
Addln_ExampleO1
‘Райя : Addln_ExampleO1_O2.dll
[ Включить”) Выключить |
Состояние Состояние: Выключено
Ответ ВК:Состояние: Включено
Закрыть [
Рис. 5.14. Внешняя обработка для тестированиявнешней компоненты Addln_Example01 (версия 2). Доработка формы
Теперь, нажимая на кнопки Включить и Выключить, можно убедиться, что механизм сообщений о внешних событиях функционирует.
рассмотрим еще один пример, связанный с механизмом сообщений о внешних событиях. Еще раз модифицируем "нашу" внешнюю компоненту.
Примечание
На сопроводительном компакт-диске книги исходные тексты этой версии примера находятся в папке \Part_1\Chapter_05\Topic_5_2\Addln_Example01_03.PAS.
Добавим возможность генерировать сообщения для 1С:Предприятие, связанные с таймером. Для этого объявим еще одно свойство объекта TAddinObject — TimerAnswer Типа TTimer И метод OnMyTimerAnswer типа TNotifyEvent (ЛИСТИНГ 5.31).
TAddinObject = class ( ... ) boolIsEnabled : Integer; TimerAnswer ; TTimer;
procedure OnMyTimerAnswer(Sender: TObject) ;
end;
Внесем соответствующие изменения в методы mit и Done (листинг 5.32).Внесем соответствующие изменения в методы mit и Done (листинг 5.32).function TAddinObject.Init(pConnection: IDispatch): HResult; stdcall; varfunction TAddinObject.Init(pConnection: IDispatch): HResult; stdcall; var
Внесем соответствующие изменения в методы mit и Done (листинг 5.32).
Внесем соответствующие изменения в методы mit и Done (листинг 5.32).
function TAddinObject.Init(pConnection: IDispatch): HResult; stdcall; var
function TAddinObject.Init(pConnection: IDispatch): HResult; stdcall; var
begin
TimerAnswer : = TTimer.Create (NIL) ;
TimerAnswer.Interval: =55;
TimerAnswer.Enabled
TimerAnswer. OnTimer
:= False;
: = OnMyTimerAnswer;
function TAddlnObj ect. Done: HResult; stdcall;
begin
Timer Answer.Destroy() /
end;
В листинге 5.33 представлен текст метода OnMyTimerAnswer.
procedure TAddlnObject.OnMyTimerAnswer(Sender: TObject);
begin
TimerAnswer.Enabled:=FALSE;
if (pEvent <> nil)then begin
if boolIsEnabled=0 then begin
pEvent.ExternalEvent('BK01','ОтветПоТаймвру',' 0');
end
else begin
pEvent.ExternalEvent(1BK01','ОтветПоТаймеру‘,•1');
end;
end;
end;
Как видите, здесь проверяется свойство boolisEnabied и, в зависимости от значения свойства, генерируется соответствующее сообщение.
Внесем также измнения в текст метода caiiAsProc (листинг 5.34).
function TAddlnObject.CaiiAsProc (IMethodNum: Integer; var paParams: PSafeArray): HResult; stdcall;
begin
case TMethods (IMethodNum) of
sethKneble:
begin
boolisEnabied := 1;
if (pEvent <> nil)then begin
pEvent.ExternalEvent('BK01','Ответ', 11 •); end;
TimerAnswer. Enabled: =TRUE;
end;
BMthDi sable:
begin
boolisEnabied : = 0;
if (pEvent <> nil)then begin
pEvent.ExternalEvent('BK011,'Ответ',* 0') ;
end;
TimerAnswer.Enabled:-TRUE;
end;
Г „
else
begin
CaiiAsProc := S_FALSE;
Exit;
end;
end;
CaiiAsProc := S_OK;
end;
Идея заключается в том, что когда из программы 1С:Предприятие вызывается какой-либо из методов внешней компоненты включить или включить, то наряду с рассмотренным ранее вариантом генерации соответствующего сообщения запускается и таймер. Через 55 мс срабатывает таймер и, в зависимости от значения boolisEnabied, генерируется еще одно сообщение (листинг 5.33).
Сохраним наш Delphi-проект под именем AddIn_Example01_03.DPR, скомпилируем его и скопируем файл AddIn_Example01_03.DLL в папку iC_example.DB.
Теперь вновь запустим Конфигуратор 1С:Предприятие, откроем внешнюю обработку предыдущего примера и сделаем некоторые изменения.
Добавим в форму внешней обработки элемент управления "список" (рис. 5.15).
Изменим имя DLL-файла внешней компоненты, который нужно загрузить (листинг 5.35).
S3S3^Пример работы t, внешней «дмо'онентнрй Нф
S3
S3
Addin_ExampleO1
Файл : Addln_Example01_03.dll
Включить | Выключить |Состояние | ???
События: |СписокСобьтий ЛСписокСобытий Закрыть | |СписокСобытий
Рис. 5.15. Внешняя обработка для тестирования внешней компоненты AddIn_Example01 (версия 3)
Процедура ПриОткрытии()
СостояниеОбъекта_Ответ = "???";
ЭагруэитьВнешнкюКомпоненту ("AddIn_Exant>le01_03 .dll") ;
ВК = СоздатьОбъект("Addin.AddIn_ExampleO1*);
ПолучитьСостояние();
КонецПроцедуры
Изменим текст процедуры обработкаВнешнегоСобытия следующим образом (листинг 5.36).
Процедура ОбработкаВнешнегоСобытия(Источник,Событие,Данные)Процедура ОбработкаВнешнегоСобытия(Источник,Событие,Данные)
Процедура ОбработкаВнешнегоСобытия(Источник,Событие,Данные)
Процедура ОбработкаВнешнегоСобытия(Источник,Событие,Данные)
СписокСобытий.ДобавитьЗначение(СокрЛП(Источник) +"."+СокрЛП(Событие) +”:"+СокрЛП(Данные));
Если (Источник = *ВК01") И (Событие = "Ответ") Тогда
Если (Данные = *1") Тогда
СостояниеОбъекта_Ответ = "Состояние: Включено";
Иначе
СостояниеОбъекта_Ответ = "Состояние: Выключено";
КонецЕслиКонецЕсли;КонеиПроиедуры
То есть теперь все сообщения о внешних событиях будут отражены в элементе управления списокСобытий.
Сохраним обработку под именем ВнешняяФорма_лля_Аёд1п_Ехатр1е01_ 03.ERT, запустим программу 1С:Предприятие и откроем сохраненную обработку.
На рис. 5.16 представлен результат поочередного нажатия кнопок Включить и Выключить.
Й Пример работы с смешней компонентной НИ В
Л 51 2 ^
Addln_ExampleO1
«Рейл : Addln_Examp1e01_03.dll
Включить
Состояние
( Выключить]!
Состояние: Выключено
События;
Закрыть ]
ВК01 0твет;1
ВКО1 .ОтветПоТ аймеру. 1
ВКОЕОтвет.О
ВКО1 ОтветПоТ аймеру.О
Рис. 5.16. Внешняя обработка для тестированиявнешней компоненты AddIn_Example01 (версия 3). Доработка формы
Теперь расширим функционал внешней компоненты. За основу возьмем версию 2 "нашей" внешней компоненты.
Примечание
На сопроводительном компакт-диске книги исходные тексты новой (четвертой) версии примера находятся в папке \Part_1\Chapter_05\Topic_5_2\Addln_ Example01_04.PAS.
Добавим несколько новых процедур и функций для 1С:Предприятие (табл. 5.5 и листинг 5.37).
Таблица 5.5. Новые методы внешней компоненты
Метод
Назначение
ВывестиВСтрокуСтатуса (ИЛИ OutputToStatusLine)
Выводит сообщение в строку состояния (статуса) программы 1С:Предприятие. Аналог штатной процедуры Состояние (). Синтаксис: ВывестиВСтрокуСтатуса(Строка, Задержка);
Задержка — время, на которое выведенное в строку состояния сообщение "заморозится" (в секундах)
Сообщить
(или Message)
Выводит строку в окно сообщений программы 1С:Предприятие. Упрощенный аналог штатной процедуры Сообщить (). Синтаксис:
Сообщить(Строка);
ОчиститьОкноСообщений
(ИЛИ ClearMessageWindow)
Очищает окно сообщений программы
1 С:Предприятие. Аналог штатной процедуры
ОчиститьОкноСообщений (). Синтаксис: ОчиститьОкноСообщений ();
ПолучитьСписокФайлов (или GetListFiles)
Получить список файлов по маске. В качестве параметра принимает СписокЗначений, где размещает список найденных файлов. Синтаксис: ПолучитьСписокФайлов (СписЗнач,
МаскаФайлов);
Параметры: СписЗнач — СписокЗначений, должен быть создан в программном модуле 1С:Предприятие; МаскаФайлов — может включать путь к файлам, например, С: \MyDir\* . txC. Возвращаемое значение — количество найденных файлов
СоздатьСписокФайлов
(или CreateListFiles)
Создает список файлов по маске: создает СписокЗначений, размещает в нем список найденных файлов и возвращает его в вызвавший программный модуль 1С:Предприятие. Синтаксис: СоздатьСписокФайлов (МаскаФайлов);
МаскаФайлов может включать путь к файлам, например, С: \MyDir\* . txt
resourcestring
strlsEnabled = 'IsEnabled,Включен';
strEnable = 1 Enable,Включить';
scrDisable = 'Disable,Выключить';
etrOutputToStatusblne = 'ОиЕриЕТоЗЬаСизЬхпе.ВывестиВСтрокуСтатуса';
atxMessage = 'Message,Сообщить■;
atzClearMessageWindow = 'ClearMessageWindow,ОчиститьОкноСообщаний*;
strGetListFiles = 'СгеаСеЫзСРИез.СоздатьСписокФайлов*;
strGetLlBtFiles2 = 'GetListFiles,ПaлyчитьCпиcox♦aйлo■,;
Добавим новые значения перечисления TMethods (для реализации указанной выше функциональности).
type
TMethods = ( methEnable,
к
methDisable,
znethOutputToStatusLina, //
ВывестиВСтрокуСтатуса
methMessage,//
Сообщить
methClearMeesagewindow, //
ОчиститьОкноСообщений
methgetUstFlles,Ц
СоздатьСписокФайлов
methGetListFlles2,//
ПолучитьСписокФайлов
LastMethod );
Л?
Примечание
Обратите внимание: значение LastMethod всегда должно оставаться по-
следним!
Добавим строку pConn : IDispatch; в объявление объекта TAddlnObject (листинг 5.39).
®MdInObject = class ( . .. ) boolIsEnabled : Integer; PConn : IDispatch;
•nd;
В метод init объекта TAddlnObject добавим строку, где свойству pConn будет присвоен указатель на интерфейс IDispatch (листинг 5.40).
ЖЖЖЖжжметода init объекта TAddinObj eatметода init объекта TAddinObj eat
ЖЖ
ЖЖ
ж
ж
метода init объекта TAddinObj eat
метода init объекта TAddinObj eat
function TAddInObject.Init(pConnection: IDispatch): HResult; stdcall;
var
iRes : Integer;
begin
// Сохраним указатель на интерфейс IDispatch pConn :■ pConnection;
end;
Дополним текст метода FindMethod объекта TAddinobject следующим образом (листинг 5.41).
function TAddlnObject.FindMethod(const bstrMethodName: WideString;
var plMethodNum: Integer): HResult; stdcall;
begin
plMethodNum := -1;
//
if (bstrMethodName = TermString(strEnable,0)) then plMethodNum := 0;
if (bstrMethodName = TermString(strEnable,1)) then plMethodNum := 0;
if (bstrMethodName = TermString(strDisable,0)) then plMethodNum := 1;
if (bstrMethodName = Termstring(strDisable,1)) then plMethodNum := 1;
11 ВывестиВСтрокуСтатуса
if (bstrMethodName = TermString(strOutputToStatusLine,0))
then plMethodNum := 2;
if (bstrMethodName = Termstring(strOutputToStatusLine,1))
then plMethodNum := 2;
// Сообщить
if (bstrMethodName = TermString(strMessage,0)) then plMethodNum := 3;
if (bstrMethodName = TermString(strMessage,1)) then plMethodNum := 3;
// ОчиститьОкноСообщаиий,
if (bstrMethodName = TermString(strClearMessageWindow,0))
then plMethodNum := 4;
if (bstrMethodName = TermString (strClearMessageWindow, 1))
then plMethodNum := 4;
// СоэдатьСписокФайлов
if (bstrMethodName = Terms tring(strGetListFiles,0)) then plMethodNum := 5;
if (bstrMethodName = Termstring (strGetListFiles, 1)) then plMethodNum := 5;
// ПолучитьСписокФайпов
if (bstrMethodName = Termstring (strGetListFiles2,0)) then plMethodNum := 6;
if (bstrMethodName = Termstring(strGetListFiles2,1)) then plMethodNum := 6;
H
if (plMethodNum = -1) then begin
FindMethod := S_FALSE;
Exit;
end;
FindMethod : = S_OK;
end;
Дополним текст метода GetMethodName объекта TAddlnObject следующим образом (листинг 5.42).
function TAddlnObject.GetMethodName (IMethodNum, IMethodAlias: Integer; var pbstrMethodName: WideString) : HResult; stdcall;
begin
PbstrMethodName := "';
case TMethods (IMethodNum) of
methEnable:
begin
pbstrMethodName := Termstring(strEnable,IMethodAlias)• end;
methDisable:
begin
pbstrMethodName := Termstring(strDisable, IMethodAlias) ; end;
methOutputToStatusLine: // ВывестиВСтрокуСтатуса
begin
pbstrMethodName := TermString(strOutputToStatusLine,IMethodAlias);
end;
nethMeseage: fl Сооб<е«ть begin
pbstrMethodName := TermString(strMessage,IMethodAlias);
end;
methCleazMeeaageWindow: // ОчиститьОхиоСообщений
begin
pbstrMethodName := TermString(strClearMessageWindow,IMethodAlias);
end;
methGetLietFiles:// СоздатьСписок*айлов
begin
pbstrMethodName ;= TermString(strGetListFiles,lMethodAlias); end;
MthGetLi«tFila32: // Получить Слисок*айлов begin
pbstrMethodName := Termstring(strGetbistFiles2,IMethodAlias); end;
else
begin GetMethodName := S_FALSE;
Exit;
end;
end;
GetMethodName := S_OK;
end;
До этого момента ничего нового (относительно предыдущих версий примера) не было. Но теперь мы создаем процедуры и функции, которые имеют входные параметры. Это должно быть отражено в методе GetNParams объекта TAddinobject соответствующим образом (листинг 5.43).
function TAddlnObject.QetNParene(IMethodNum: Integer;function TAddlnObject.QetNParene(IMethodNum: Integer;var plParams: Integer): HResult; stdcall;var plParams: Integer): HResult; stdcall;
function TAddlnObject.QetNParene(IMethodNum: Integer;
function TAddlnObject.QetNParene(IMethodNum: Integer;
var plParams: Integer): HResult; stdcall;
var plParams: Integer): HResult; stdcall;
begin
plParams := 0; case TMethods(IMethodNum) of methEnable: begin plParams := 0; end; methDisable: begin plParams ;= 0;
end;
methOutputToStatuaLlne: // ВывестиВСтрокуСтатуса(Строка,Задержка) begin plParams := 2; end;
mathMeesage: // Сообщить(Строка) begin plParams : = 1;
S
end; methCleaxMeeaageWindow: // ОчиститьОкноСообшеиий() r' begin plParams := 0; end;
■ethOetMetFilee: // СоадатьСписохФайлов(МасхаФайлов) begin plParams := 1; end;
mathOetLietFilee2: //ПолучитьСписокФайлов(СлисокЗкачаний,MaскаФайлов) begin plParams := 2; end; else begin GetNParams := S_FALSE; Exit;
end;
I end;
GetNParams := S_OK;
В данном примере методы СоздатьСписокФайлов И ПолучитьСписокФайлов реализованы как функции (при их вызове из программных модулей 1С:Предприятие). Это должно быть отражено в методе HasRetVai объекта TAddinObject следующим образом (листинг 5.44).
function TAddinObject.HaeRatVal(IMethodNum: Integer;
var pboolRetValue: Integer): HResult; stdcall,- begin
pboolRetValue := 0;
case Methods(IMethodNum) of
Tn^th^trЛ etirl 1 ее;// СоздатьСписокФайлов (МаскаФайлож)
begin
pboolRetValue := -1;
end;
MtbGetLietFileB2:// ПолучитьСписокФайлов
begin
pboolRetValue := -1;
end;
else
begin
HasRetVai := S_FALSE;
Exit;
end;
end;
HasRetVai := S_OK;
end;
Примечание
В OLE Automation логическое значение true соответствует целочисленному значению -1, а значение false — целочисленному значению 0.
Теперь, собственно, нужно написать код реализации функционала внешней компоненты. При этом процедуры должны быть реализованы в методе CallAsProc, а функции — в методе CallAsFunc объекта TAddinObject (листинги 5.45 и 5.47).
function TAddInObject.CallMProa(lMethodNum: Integer;
var paParams: PSafeArray): HResult; stdcall;
Var
List : TStrings;
gMask : String;
VO : Variant;
V : Variant;
i,Res : Integer;
begin
case TMethods (IMethodNum) of /
methOutputToStatusLine: // ВывестиВСтрокуСтатуса(Строка,Задержка) begin
pStatuaLine.SetStatusLine(GetNParam (paParams, 0));
if GetNParam(paParams,1)*l>0 then begin
Sleep(GetNParam(paParams,1)*1000);
end;
end;
methMessage: II Сообщить(Строка)
begin
-.= pConn;
// Получаем указатель на интерфейс
// IDispatch программы IC:Предприятие
:= V.AppDiepatch;
// Увеличиваем счетчик ссылок на объект интерфейса
IDispatch(V)._AddRaf;
II Вызываем штатную процедуру Сообщить()
//с помощью метода ExecuteBatch
.ExecuteBat ch ('Сообщить(‘"+TrimRight(GetNParam(paParams, 0))
♦'");');
end;
tnethClearMessageWindow: II ОчиститьОкноСообщвний() begin
:= pConn;
II Получаем указатель на интерфейс
// IDispatch программа 1С:Предприятие
:= V.AppDispatch;
11 Увеличиваем счетчик ссылок на объект интерфейса
IDispatch(V)._AddRef;
// Вызываем штатную процедуру 'ОчиститьОкноСообщений()
//с помощью метода ExecuteBatch
V.ExecuteBatch{'ОчиститьОкноСообщений(>;");
end;
else
begin
CallAsProc := S_FALSE;
Exit;
end;
end;
CallAsProc := S_OK;
end;
Здесь требуются некоторые пояснения.
При реализации процедуры ВывестиВСтрокуСтатуса был использован метод SetStatusLine интерфейса IStatusLine (pStatusLine), ЛИСТИНГ 5.46.
мм
IStatusLine = interface(IUnknown)
['{AB634005-F13D-11D0-A459-004095E1DAEA}']
procedure SetStatusLine(const bstrSource: WideString); safecall;
procedure ResetStatusLine; safecall;
end;
Для реализации процедур Сообщить И ОчиститьОкноСообщений используется метод ExecuteBatch программы 1 С:Предприятие (который был подробно рассмотрен в разд. 4.6), с помощью которого вызываются соответствующие штатные процедуры программы 1С:Предприятие (более подробно об этих функциях можно прочитать в специальной литературе по этой системе).
Теперь нужно написать код, реализующий функции создатьСписокФайлов ИПолучитьСписокФайлов (ЛИСТИНГ 5.47).
function TAddInObject.CallAaFunc(lMethodNum: Integer;
var pvarRetValue: OleVariant;
var paParams: PSafeArray): HResult; stdcall;
Var
List : TStrings; sMask: string;
VOVibeginVOVibegin: OleVariant;
VO
V
i
begin
VO
V
i
begin
: Variant;
: Integer;
case TMethods(IMethodNum) of
//
mathSetLietPilee: // СовдатьСписокФайлов
begin
List := TStringList.Create;
TRY
V:=pConn;
II Получаем указатель на интерфейс
И IDispatch программы 1С:Предприятие
V := V.AppDispatch;
II Увеличиваем счетчик ссылок на объект интерфейса IDispatch(V)._AddRef;
И Возвращаемое функцией значение
И должно иметь агрегатный тип: "СписокЗначений".
// Поэтому создаем "СписокЗначений”
//с помощью метода EvalExpr.
PvarRetValua:=V.KvalExpr(•СоздатьОбъект(■СписокЗначений') 1);
// Получаем маску файлов из первого (и единственного)
II переданного параметра
•Mask: =Trim (GetNParamlpaParams, 0)) ;
II Если маска не задана, выбираем все файлы
if length(sMask)<=0 then sMask:=‘*.*1;
// Вызываем нашу функцию, которая отбирает
II файлы по маске и возвращает их в List:TStrings
■p_GetLiet FilesJHaek(sMask,List);
if List.Count>0 then begin
// Если список файлов не пуст,
// переписываем имена файлов построчно Н в созданный нами же "СписокЗначений" for i:=0 to (List.Count-1) do
begin
И С помощью метода "ДобавитьЗначение
И объекта "СписокЗначений"
pvarRatValue.ДобавитьЗначение(List[i],List[ i 1); end;
end;
FINALLY
// Очищаем "захваченные* нами ресурсы памяти
if ListoNIL then begin
List.Clear;
List.Free;
List:=NIL;
end;
END;
end;
methOetLl stFil—2: И ПолучитьСписокФайлов
begin
List := TStringList.Create;
TRY
// Возвращаемое функцией значение
// (количество файлов)
pvarRetValue: =0;
II Получаем значение первого переданного параметра.
// это должен быть объект типа: СписокЗначений
VO: =GetNParam(paParams, 0);
// Проверяем, относится ли это значение к агрегатному типу
if VarType(VO) = varDiepatch then begin
// Для простоты текста: не уточняем конкретный
// тип объекта и предполагаем,
// что это обязательно "СписокЗначений".
// Очищаем список значений
V0.УдалитьВсе;
И Получаем маску файлов из второго
II переданного параметра
«MaHk:^Trim(GetNParazn(paParams,D) ;
// Если маска не задана, выбираем все файлы
if length(sMask)<=0 then sMask:='*.*';/
I/ Вызываем нашу функцию, которая отбирает II файлы по маске и возвращает их в ListzTStrings ep_QetListFiles_Maek(sMask,List);
if List.Count>0 then begin
// Если список файлов не пуст,
II переписываем имена файлов построчно //в "СписокЗначений"
for i:=0 to (List.Count-1) do begin
II С помощью метода "ДобавитьЗначение"
// объекта "СписокЗначений"
У0.ДобаеитьЗначекие(Д1зС[1],List[i]);
// Счетчик файлов (возвращаемое значение) pvarRetValue:=pvarRetValue+l;
end;
end;
И Возвращаем "СписокЗначений" обратно
//в программный модуль 1С:Предприятие
PutNParemfpaParams, О, V0) ;
end;
FINALLY
11 Очищаем "захваченные" нами ресурсы памяти
if ListoNIL then begin
List.Clear;
List.Free;
List:=NIL;
end;
END;
end;
//
else
begin
CallAsFunc := S_FALSE;
Exit;
end;
end;
CallAsFunc := S_OK;
lend;
Листинг 5.47 содержит подробный комментарий. Текст функции 8p_GetListFiles_Mask здесь не приводится из-за ее тривиальности — доста- точно отметить, что там используются "стандартные" функции SysutiIs.FindFirst(), SysUtila.FindNext(), SysUtils.FindClose().
Сохраним наш Delphi-проект AddIn_Example01_04.DPR, скомпилируем его и скопируем файл AddIn_Example01_04.DLL в папку lC_example.DB.
Теперь запустим Конфигуратор 1С:Предприятие и создадим новую внешнюю обработку BнeшняяФopмaщля_AddIn_Example01_04.ERT (рис. 5.17).
Для начала протестируем созданные процедуры: вывестиВСтрокуСтатусао, Сообщить(), ОчиститьОкноСообшений().
Рис. 5.17. Внешняя обработка для тестирования внешней компоненты Addln_Example01 (версия 4)
Примечание
Реализация функциональности кнопок Включить и Выключить подробно рассмотрена в предыдущих примерах.
Реакция на событие "нажатие кнопки" для кнопок В строку статуса. Очистить окно сообщений и Сообщить организована с помощью процедур АЦЦ1п_ВывВСтрСтат(), AddIn_OчиcтитьПaнeльCooбщeний(), AddIn_Coo6mMTb () • В листинге 5.48 представлен текст модуля обработки ВнешняяФорма_ дл я „Add In_ExampleO 1 „04. ERT.
Перем ВК Экспорт;
Перем СостояниеОбъекта;
Процедура Включить!)
VГлава 5. Расширение функционала 1С
ВК.Включить();
КонеиПроцедуры
I Пр°ЦедуРа Выключить() j вк.Выключить();
1 КонеиПроцедуры
* процедура AddIn_Coo6eHTb() ВК.Сообщить(ТекстДляСообЩИТЬ);
I КонеиПроцедуры
У Процедура АйсНп_ОчиститьПан®льСообщаяий()
ВК.ОчиститьОкноСообшений();
КонеиПроцедуры
I Процедура Аоб1п_Вы»ВСтрСтат()
ВК.ВывестиВСтрокуСтатуса(ТекстДпяСтрокиСтатуса,Задержка_сек);
I КонеиПроцедуры
; Процедура ОбработхаВиешиегоСобытия(Источник,Событие,Данные)
Если (Источник = "ВК01") И (Событие = “Включен") Тогда
Если (Данные = "1") Тогда
СостояниеОбъекта = "Состояние: Включено";
Иначе
СостояниеОбъекта = "Состояние: Выключено";
КонецЕсли
КонецЕсли;
КонеиПроцедуры
Процедура ПриОтхрытии ()
СостояниеОбъекта = "???";
. ТекстДпяСтрокиСтатуса = "Привет, как дела ?•;
Задержка_сек = 7;
= "Привет, как дела-2 ???•;
ЗагрузитьВнешнсюКомпоненту("ЛхМ1п_Кхащ>1е01_04.dll");
ВК = СоздатьОбъект("Addin.AddIn_Example01"); «ецПроцедуры
"‘■"biMMUmifiKii
На рис. 5.18 представлен результат тестирования процедур внешней компо- ненты.
Для ТОГО чтобы Протестировать функции СоздатьСписокФайлов И Получить СписокФайлов, внесем изменения во внешнюю обработку (рис. 5.19).
ВВПример работы с внешней компонентнойПример работы с внешней компонентнойНВ вНВ в
В
В
Пример работы с внешней компонентной
Пример работы с внешней компонентной
НВ в
НВ в
Л Sk "t ^
Addln_ExampleO1
Файл : Addln_Example01_04.dll
Включить | Выключить [ Состояние: Включено
В строку статуса Цпривет. как дела ? Задер*ка(свк)- |7
Очистить окно сообщений |
Сообщить ((Пртеетг. как дела-2 ???
Привет, как дела-2 ???Привет, как дела-2 ???
Привет, как дела-2 ???
Привет, как дела-2 ???
I I !таЛ5.1I I !таЛ5.1[^ Пример...
I I !таЛ5.1
I I !таЛ5.1
Приест, как дела ?
Рис. 5.18. Результат тестирования процедурвнешней компоненты AddIn_Example01 (версия 4)
»Й Пример работы с внешней компонентной ■ ■ ,
Addln_ExampleO1
Файл: Addln_ExampleO1_O4.dll
Включить | Выключить | ???
В строку статуса ||т екстДляСтрокиСта Задержка(сек)- |3адер
Очистить окно сообщений
33Сообщить | |Т екстДляСообщитъСоздатьСтмсокФайлоо [ ПолучитьСписокФайлов [
3
3
Закрыть I СписокФайлов СписокФайлов
СписокФайлов
Рис. 5.19. Внешняя обработка Addln_Example01 (версия 4) для тестирования функцийСоздатьСписокФайловИПолучитьСписокФайлов
р листинге 5.49 представлен текст процедур-обработчиков событий нажатия кнопок СоздатьСписокФайлов и ПолучитьСписокФайлов (рис. 5.19).
WWистинг 5.49. Обработчики событий нажатия кнопок (модуль внешней бработки ВнешняяФорма_для_Абб1п_Ехатр1еО1 О4.
W
W
Процедура Ас1й1п_СоздатьСписокФайлов()
СписокФайлов.УдалитьВсе();
Список = ВК.СоздатьСписокФайлов(КаталогИБ () +
Список.ВыОратьЗначение(X); КонеиПроцедуры
Процедура АсМ1п_ПолучитьСписокФайлоз ()
ВК.ПолучитьСписокФайлов(СписокФайлов,КаталогИБ()+ : КонеиПроцедуры
QBxIQBxIНа рис. 5.20 и 5.21 представлены результаты тестирования функций внешней компоненты СоздатьСписокФайлов И ПолучитьСписокФайлов соответственно.
QBxI
QBxI
3»к 10643»к 1064I [j Пример работы с внешней котшонеигкои
3»к 1064
3»к 1064
£1 8k 0 У£1 8k 0 УAd d I n_Exam p I e01
£1 8k 0 У
£1 8k 0 У
Файл: Addin_ExeepleO1_O4.dll
Включить | Выключить] ???
В строку статуса ^Привет. как дела ? Задержка(сек)- |7
Очистить окно сообщСообщить | [Привет СоздатьСписокФайлов | Закрыть (Очистить окно сообщСообщить | [Привет СоздатьСписокФайлов | Закрыть (Выбор значенияВыбор значенияEA1C_exampleDBMSUSERS D8F
Очистить окно сообщ
Сообщить | [Привет СоздатьСписокФайлов | Закрыть (
Очистить окно сообщ
Сообщить | [Привет СоздатьСписокФайлов | Закрыть (
Выбор значения
Выбор значения
E:\1C example DBMSSYSTEM DBF
EA1C example.DBMSCONST DBF
EA1C_example.DBMSCONST COX
EA1C_example DBMSJOURN DBF
EA1C example.DBMSJOURNCDX
EA1C example.DBMSCRDOC.DBF
EA1C_example.DBMSCRD0C.CDX
Е МГ .,—ЬПРИСПМПГГ DDF
Рис. 5.20. Результат тестирования функции СоздатьСписокФайлов
33СозаатьСписокФайпоа | (Погвд^ьСлисок^^
3
3
3,KDbrrh I |EA1C_example.DB\lSUSERS.DBF.I E MC example.OBMSSYSTEM DBF
EA1C example. DBM SCONS I DBF
EA1C example DBMSCONST.CDX
Рис. 5.21. Результат тестирования функции ПолучитьСписокФайлов
Примечание
Рассмотренные примеры внешней компоненты AddIn_Example01 носили иллюстративный характер и вряд ли могут быть полезны для практических целей.
Чтобы как-то компенсировать этот момент, на сопроводительном компакт-диске книги в папке \Part_1\Chapter_05\Topic_5_2\Addln_Files.PAS приведены исходные тексты внешней компоненты Addln_Files, функциональность которой ориентирована на работу с файловой системой и включает процедуры и функции (табл. 5.6), из которых не все есть среди методов объекта ФС системы 1 (^Предприятие.
Таблица 5.6. Процедуры и функции внешней компоненты Addin_Fiies
Метод
Назначение
Функция
ПолучитьНовоеУникальноеИмяФайла (или GetNewFileName)
Получает на входе имя файла (включая полный путь) и проверяет, есть ли такой файл на диске. Если есть, то вычисляется новое имя файла (к нему добавляется единица; расширение остается неизменным). И так до тех лор, пока не будет вычислено уникальное имя файла
Функция
МожноСохранятьНаЭтотДиск (или ItsNotReadOnlyDisk)
Получает имя диска (полное имя файла или папки) и проверяет, можно ли сохранять файлы на указанном диске
Функция
ПолучитьСписокФайлов (или GetListFiles)
Получает на входе маску файлов, атрибуты файлов и СписокЗначений; возвращает вСписокЗначений список найденных файлов
Функция
ПолучитьРаэмерФайла | (или GetFileSize)
Получает на входе имя файла и определяет размер этого файла в байтах
Таблица 5.6 (продолжение)
Метод
Назначение
Функция
РазрезатьФайл (или CutFile)
Разделяет файл на части. Получает на входе имя файла, имя палки назначения, максимальный размер частей файла и префикс расширения частей файла. Заданный файл "нарезается" на части заданного размера, которые размещаются в заданной папке. Если задан последний входной параметр функции (СписокЗначений), то список полученных частей будет размещен в элементе СписокЗначений
Функция
СклеитьФайл (или StickFile)
Позволяет “склеить" файл из отдельных частей. Получает на входе маску частей файла и полное имя результирующего (склеенного) файла. Из найденных по маске частей “собирается" файл с заданным именем. Если задан последний входной параметр функции (СписокЗначений), то список имен найденных файлов-частей будет размещен в элементе СпискеЗначений
Функция
ПолучитьЛогическоеЗначениеИзППфайла (или GetBoolenFromlNl)
Считывает (и возвращает) из заданного INI-файла значение типа Boolean и конвертирует его в целое число (true — в 1, FALSE — В 0)
Процедура
ЗаписатьЛогическоеЗначениеВ1М1файл (или PutBoolenToINl)
Записывает в заданный INI-файл целочисленное значение как значение типа Boolean. Значения больше 0 трактуются как true, остальные — как false. Проверяется возможность записи на диск
Функция
ПолучитьЦелоеЧислоИзТШфайла (или GetlntegerFromlNl)
Считывает (и возвращает) из заданного INI-файла значение типа Integer
Таблица 5.6 (окончание)
Метод
Назначение
Процедура
ЗаписатьЦелоеЧислоВ1К1файл
(или PutlntegerToINI)
Записывает в заданный INI-файл целочисленное значение. Проверяется возможность записи на диск
Функция
Получить СтрокуИз1Ы1файла (ИЛИGetStringFromlNI)
Считывает (и возвращает) из заданного INI-файла значение типа string
Процедура
ЗаписатьСтрокуВ1К1файл (или PutStringToINl)
Записывает в заданный INI-файл строку. Проверяется возможность записи на диск
Функция
ПолучитьВещественноеЧислоИэЮТфайла (или GetRealFromlNl)
Считывает (и возвращает) из заданного INI-файпа значение типа Real
Процедура
ЗаписатьВешественноеЧислоВПИфайл (или PutRealToINl)
Записывает в заданный INI-файл вещественное число. Проверяется возможность записи на диск
Примечание
Более подробное описание этой внешней компоненты содержится на сопроводительном компакт-диске книги в файле ReadMe_Addln_Files.DOC из папки \Part_1 \Chapter_05\Topic_5_2\Addln_Files.PAS.
Здесь нужно отметить следующее. Процедуры и функции программного модуля встроенного языка системы ЮПредприятие могут иметь параметры, значения которых устанавливаются по умолчанию. Поддержка этой возможности во внешней компоненте реализована в методе GetParamDefValue следующим образом (листинг 5.50).
>е объекта TAddln>е объекта TAddln£72£72
>е объекта TAddln
>е объекта TAddln
£72
£72
function TAddlnObject .QetPareinDefV<lue(lMethodNuin, iParamNum: Integer; var pvarParamDefValue: OleVariant): HResult; stdcall;
begin
VarClear(pvarParamDefValue);
case methods(IMethodNum) of
//
// РазрезатьФайл(ИмяФайлa,ИмяПапкиКуда,РазмерЧастей,
//ПрефиксРасширения="а11",СписокЧастейФайла="")
methCutFile:
begin
// ПрефиксРасширения
if lParamNum=3 then pvarParamDefValue : = 'aif;
// СлисокЧастейФайла — может отсутствовать
if lParamNum=4 then pvarParamDefValue := ' ' ; end; // H
// СклеитьФайл(МаскаФайлов,ИмяСклеенногоФайла,
//СписокФайловИзКоторыхСобрали=*")
methStickFile:
begin
// СписокФайловИзКоторыхСобрали — может отсутствовать
if lParamNum=2 then pvarParamDefValue := '•; end; // H // ПолучитьСписокФайлов(СписокЗначений,Маска, //Скрытые=О,Системные=О,
//ТолькоЧтение=1,Архивные=1)
methGetListFiles_Mask: begin
// Скрытые файлы. По умолчанию = 0 (не учитывать)
if lParamNum=2 then pvarParamDefValue := 0;
// Системные файлы. По умолчанию =0 (не учитывать)
if lParamNum=3 then pvarParamDefValue := 0;
// ТолькоДляЧтения. По умолчанию = 1
if lParamNum=4 then pvarParamDefValue :=' 1;
// Архивные. По умолчанию = 1
if lParamNum=5 then pvarParamDefValue := 1;
end;
H
else
begin
GetParamDefValue := S_FALSE;
Exit;
end;
end;
GetParamDefValue := SOK;
ЕЕПример-2 работы с внешней компонентнойПример-2 работы с внешней компонентнойнванваД 51 ^ V
Е
Е
Пример-2 работы с внешней компонентной
Пример-2 работы с внешней компонентной
нва
нва
Addln_Files
Файл : Addln_Files.dllНарезка Файлз
Выбрать Файл ||САЕxportJrom_DВ.exe
Размер Файла (байт) 11663120
Выбрать папку | |Е А1 C_examp!e.DB\E xtForms\TMP\
Размер каждой части (байт) - |
Суффикс частей
100000 |sj100000 |sjI E MC_example DB\ExtForms\TMP^Expo(tJrom_DB.exe.abc_03Закрыть | EA1C example.DB\ExtForms\TMP\ExpoitJrom_DB.exe.abc_04I E MC_example DB\ExtForms\TMP^Expo(tJrom_DB.exe.abc_03Закрыть | EA1C example.DB\ExtForms\TMP\ExpoitJrom_DB.exe.abc_04Е А1 С_ example. О В \Е xlFormsXT М Р\Е xpoilJiom_ D В. exe. abc_05 . EA1C example.DB'£xtForms\TMP'£xporl Oom DB.exe.abc 06 JJЕ А1 С_ example. О В \Е xlFormsXT М Р\Е xpoilJiom_ D В. exe. abc_05 . EA1C example.DB'£xtForms\TMP'£xporl Oom DB.exe.abc 06 JJРис. 5.22. Результат тестирования функции РазрезатьФайлвнешней компоненты Addln_Files (BнeшняяФopмa-2_для_Addln_Frles.ERT)
100000 |sj
100000 |sj
I E MC_example DB\ExtForms\TMP^Expo(tJrom_DB.exe.abc_03
Закрыть | EA1C example.DB\ExtForms\TMP\ExpoitJrom_DB.exe.abc_04
I E MC_example DB\ExtForms\TMP^Expo(tJrom_DB.exe.abc_03
Закрыть | EA1C example.DB\ExtForms\TMP\ExpoitJrom_DB.exe.abc_04
Е А1 С_ example. О В \Е xlFormsXT М Р\Е xpoilJiom_ D В. exe. abc_05 . EA1C example.DB'£xtForms\TMP'£xporl Oom DB.exe.abc 06 JJ
Е А1 С_ example. О В \Е xlFormsXT М Р\Е xpoilJiom_ D В. exe. abc_05 . EA1C example.DB'£xtForms\TMP'£xporl Oom DB.exe.abc 06 JJ
ЕЕПример-2 работы с внешней компонентной
Е
Е
Addln_FilesФайл : Addln_Files.dllСклейка файлаAddln_FilesФайл : Addln_Files.dllСклейка файлаВыбрать папкуВыбрать папкуМаска частей ФайлаИь« реультир. файла»Маска частей ФайлаИь« реультир. файла»Размер Файла [байт)Склеить Файл | IЗакрыть |Размер Файла [байт)Склеить Файл | IЗакрыть ||EA1C_example.DB\ExlFocm$\TMP\I' abc_”]E xpotl_bom_DB_000. exe 11669120|EA1C_example.DB\ExlFocm$\TMP\I' abc_”]E xpotl_bom_DB_000. exe 11669120IFoimЛТМР\Ехг<и1 Oom DBIFoimЛТМР\Ехг<и1 Oom DBЗВЕ5ЯЦТЗВЕ5ЯЦТE A1 C_example О В \E xtForms\T M P\E xport Jiom_D 6. exe. abc_02 E A1 C_example. D B\E xlFormsXT M P\E xpoitJrom_D В .exe. abc_03 EA1C_example.DB\ExlFotms\TMP\Expoit_hom_DB.exe.abc_04 EA1C_example.DB\ExlFo(ms\TMP\ExpoitJ'om_DB.exe.abc_05 EA1C_example.DB\ExtFo<msMMPSExpoftJiom_DB.exe.abc_06 EA1C_example.DB\ExlFofms\TMP\ExpoitJiom_DB.exe.abc_07 EA1C_example.DB\ExtFo<ms\TMP\Expoft_from_DB.exe.abc_08 i F МГ »ултп1о nR^FvtFnfm^XTMPXFvfwl from ПЙ fvo аЬг- Лй —JE A1 C_example О В \E xtForms\T M P\E xport Jiom_D 6. exe. abc_02 E A1 C_example. D B\E xlFormsXT M P\E xpoitJrom_D В .exe. abc_03 EA1C_example.DB\ExlFotms\TMP\Expoit_hom_DB.exe.abc_04 EA1C_example.DB\ExlFo(ms\TMP\ExpoitJ'om_DB.exe.abc_05 EA1C_example.DB\ExtFo<msMMPSExpoftJiom_DB.exe.abc_06 EA1C_example.DB\ExlFofms\TMP\ExpoitJiom_DB.exe.abc_07 EA1C_example.DB\ExtFo<ms\TMP\Expoft_from_DB.exe.abc_08 i F МГ »ултп1о nR^FvtFnfm^XTMPXFvfwl from ПЙ fvo аЬг- Лй —Jл а й tv
Addln_Files
Файл : Addln_Files.dllСклейка файла
Addln_Files
Файл : Addln_Files.dllСклейка файла
Выбрать папку
Выбрать папку
Маска частей Файла
Иь« реультир. файла»
Маска частей Файла
Иь« реультир. файла»
Размер Файла [байт)
Склеить Файл | IЗакрыть |
Размер Файла [байт)
Склеить Файл | IЗакрыть |
|EA1C_example.DB\ExlFocm$\TMP\
I' abc_”
]E xpotl_bom_DB_000. exe 11669120
|EA1C_example.DB\ExlFocm$\TMP\
I' abc_”
]E xpotl_bom_DB_000. exe 11669120
IFoimЛТМР\Ехг<и1 Oom DB
IFoimЛТМР\Ехг<и1 Oom DB
ЗВЕ5ЯЦТ
ЗВЕ5ЯЦТ
E A1 C_example О В \E xtForms\T M P\E xport Jiom_D 6. exe. abc_02 E A1 C_example. D B\E xlFormsXT M P\E xpoitJrom_D В .exe. abc_03 EA1C_example.DB\ExlFotms\TMP\Expoit_hom_DB.exe.abc_04 EA1C_example.DB\ExlFo(ms\TMP\ExpoitJ'om_DB.exe.abc_05 EA1C_example.DB\ExtFo<msMMPSExpoftJiom_DB.exe.abc_06 EA1C_example.DB\ExlFofms\TMP\ExpoitJiom_DB.exe.abc_07 EA1C_example.DB\ExtFo<ms\TMP\Expoft_from_DB.exe.abc_08 i F МГ »ултп1о nR^FvtFnfm^XTMPXFvfwl from ПЙ fvo аЬг- Лй —J
E A1 C_example О В \E xtForms\T M P\E xport Jiom_D 6. exe. abc_02 E A1 C_example. D B\E xlFormsXT M P\E xpoitJrom_D В .exe. abc_03 EA1C_example.DB\ExlFotms\TMP\Expoit_hom_DB.exe.abc_04 EA1C_example.DB\ExlFo(ms\TMP\ExpoitJ'om_DB.exe.abc_05 EA1C_example.DB\ExtFo<msMMPSExpoftJiom_DB.exe.abc_06 EA1C_example.DB\ExlFofms\TMP\ExpoitJiom_DB.exe.abc_07 EA1C_example.DB\ExtFo<ms\TMP\Expoft_from_DB.exe.abc_08 i F МГ »ултп1о nR^FvtFnfm^XTMPXFvfwl from ПЙ fvo аЬг- Лй —J
Рис. 5.23. Результат тестирования функции СклеитьФайлвнешней компоненты AddIn_Fi les (ВнешняяФорма-3_для_А0б1п_ЕПе5.ЕЯТ)
pla рис. 5.22 представлен результат тестирования функции внешней компоненты разрезатьФайл (обработка ВнешняяФорма-2_juiB_AddIn_Files.ERT).
На рис. 5.23 представлен результат тестирования функции внешней компоненты склеитьФайл (обработка BнeшняяФopмa-3_лля_AddIn_Files.ERT).
Внешние компоненты (версии 2.0 и выше) могут создавать свои окна в среде Программы I С:Предприятие с помощью методов интерфейса lExtwndssupport (листинг 5.51).
.......v.:,,,,.,.:V,,,V.„V....;,,,™™.,r..,,..,.™,,V.„-,.p,^^
...
...
«стинг 5.51. Объявление интерфейса lExtwndssupport'..
jExtWndsSupport = interface(IUnknown)
[1(EFE19EA0-09E4-11D2-A601-008048DA00DE)']
function OetAppMainFrame(var hwnd: HWND): HResult; stdcall;
function GetAppMDlFraine (var hwnd: HWND): HResult; stdcall;
function CreateAddinWindow(const bstrProgID: WideString;
const bstrWindowName: WideString;
dwStyles: Integer; dwExStyles: Integer; var rctl: RECT;
Flags: Integer; var pHwnd: HWND; var pDisp: IDispatch): HResult;
stdcall;
I в”13-’
Поддерживаются три типа окон: диалоговые окна (модальные и немодальные) и формы.
Диалоговые окна создаются внешней компонентой. Формы создаются с по- . МОЩЬЮ метода CreateAddlnWindow интерфейса IBxtWndsSupport (листинг 5.52).
Примечание
Подробную информацию по этому вопросу можно найти в специальной литературе, посвященной вопросам создания внешних компонент для 1 (^Предприятие и технологии создания Active Documents.
В рамках этой главы рассмотрим процесс создания форм (из внешней компо- Л’.Ненты) на простом примере. Как и в предыдущем случае, за основу возьмем ■Шаблон (sample2), разработанный фирмой 1С.
Примечание
На сопроводительном компакт-диске книги исходные тексты этого примера находятся в папке \Part_1 \Chapter_05\Topic_5_2\Addln_Example02_01 PAS.
Новую компоненту назовем Addin_Example02_0i. Ее функциональность представлена в табл. 5.7.
Метод
—
Назначение
Показать
(или Show)
Создать форму и визуализировать ее
ПоказатьСписокСправочников (или ShowListRefs)
Создать форму и заполнить ее списком идентификаторов справочников
ПоказатьСписокДокументов (или ShowListDocs)
Создать форму и заполнить ее списком идентификаторов документов
ПоказатьСписокРегистров (или ShowListRegs)
Создать форму и заполнить ее списком идентификаторов регистров
Таблица 5.7. Процедуры и функции внешней компоненты Addin_Exampie02 oi
AddlnDoc
($E dll)
AddlnObj
AddlnLib
fpaea 5. Расширение функционала IC
library AddIn_Example02_01;
uses
ComServ,
Addln_TLB in 'Addln_TLB.pas',
in
in in
'AddlnDoc.pas' (AddlnDoc: TActiveFonn) (AddlnDoc: CoClass},
'AddlnObj.pas',
'AddlnLib.pas';
exports
DllGetClassObject, DllCanUnloadNow,
DIIRegisterServer, DllUnregisterServer;(SR *.TLB)(SR *.RES)($R AddlnStr.RES)DIIRegisterServer, DllUnregisterServer;(SR *.TLB)(SR *.RES)($R AddlnStr.RES)
DIIRegisterServer, DllUnregisterServer;
(SR *.TLB)
(SR *.RES)
($R AddlnStr.RES)
DIIRegisterServer, DllUnregisterServer;
(SR *.TLB)
(SR *.RES)
($R AddlnStr.RES)
Первоначально в рамках шаблона sample2 был реализован (как пример) про- смотрщик видеороликов с использованием Delphi-компонента TMediaPlayer. Поскольку внешняя компонента в нашем примере ориентирована на другие задачи, пришлось предварительно "вычистить" шаблон.
Прежде всего, нужно изменить содержание файла AddlnStr.RC следующим образом (листинг 5.52).
ЗвзивКб
Й^@л1
begin end.
100100AddInExample0201AddInExample0201Рис. 5.24. Форма окна внешней компонентыРис. 5.24. Форма окна внешней компоненты
100
100
AddInExample0201
AddInExample0201
Рис. 5.24. Форма окна внешней компоненты
Рис. 5.24. Форма окна внешней компоненты
STRINGTABLE DISCARDABLE
BEGIN
END
Здесь видно, что в строке с id = юо указана вторая часть свойства progic внешней компоненты.
Теперь нужно с помощью утилиты brc32.EXE, входящей в состав Delphi, скомпилировать файл AddlnStr.RC в файл ресурсов AddlnStr.RES:
brc32.exe AddlnStr.гс
Далее нужно подключить файл ресурсов к файлу проекта (AddIn_Example02„ 01.DPR) следующим образом (листинг 5.53).
Теперь в форме ActiveForm (TAddinDoc) шаблона нужно разместить еле дующие Delphi-компоненты: Panel 1 :TPanel, Panel2 :TPanel, ListBoxl: TListBox. SpeedButtonl:TSpeedButtor (рис. 5.24).
Создадим метод, который обеспечит дополнение строк в свойство items Delphi-компонента ListBoxl. Для этого нужно открыть диалоговое окно редактрования библиотеки типов и внести новый метод AddLine, как показано на рис. 5.25.
Рис. 5.25. Диалоговое окно библиотеки типов
У метода будет один входной параметр (строка, которую нужно добавить В СВОЙСТВО Items Delphi-КОМПОНеНТЗ ListBoxl), рис. 5.26.
Рис. 5.26. Входной параметр метода AddLine
Реализация этого метода проста (листинг 5.54).
procedure TAddlnDoc.AddLine(const sLine: WideString); begin
ListBoxl.Items.ADD(Trim(sLine)) ;
end;
Теперь напишем код, реализующий функциональность "нашей" внешней компоненты в методе caliAsProc объекта TAddinObj (листинг 5.55).
function TAddlnObj . CallAsProcdMethodNum: Integer;function TAddlnObj . CallAsProcdMethodNum: Integer;
function TAddlnObj . CallAsProcdMethodNum: Integer;
function TAddlnObj . CallAsProcdMethodNum: Integer;
var paParams: PSafeArray): HResult; stdcall; var wnd: HWND;
cntr: IDispatch;
ret: RECT;
form: TAddlnDoc;
obj.V: Variant;
Sx : string;
Count,i : integer;
id : string;
’begin
case TMethods(lMethodNum) of
И
II Показать!).
11 Здесь просто создается и визуализируется
// пустое окно ВК (внешней компоненты) methShow:
begin
form := TAddlnDoc.Create(nil);
ret.left := 10;
rct.top := 10;
ret.right := form.Width;
ret.bottom ;= form.Height;
pExtWndsSupport.CreateAddlnWindowt'Addin.AddlnDoc', 'Информационное окно ВК', 0, 0, ret, 0, wnd, Chtr);
obj := cntr;
cntr.„Release();
end;
// ПоказатьСписокСправочников().
// Здесь создается окно ВК, в котором
// отображены идентификаторы всех справочников
II данной конфигурации 1С:Предприятие
znethHhowld-BtRef ■:
begin form := TAddlnDoc.Create(nil); ret.left := 10; ret.top := 10; ret.right : = form.Width; ret.bottom := form.Height;
entr);entr);pExtWndsSupport.CreateAddlnWindow(1Addin.AddlnDoc', 'Список справочников', 0, 0, ret, 0, wnd, obj := entr; // // Считывание идентификаторов справочников /l из метаданных с помощью метода EvalExpr() // и их отображение в окне ВК с помощью метода AddLinef) V:=pConn; V := V.AppDispatch; IDispatch(V).„AddRef;
entr);
entr);
Count:=1*V.EvalExpr('Метаданные.Справочник()'); for i:=l to Count do begin
Sx:=1Метаданные.Справочник('+IntToStr(i) *1) 1; id:=Trim(V.EvalExpr(Sx) .Идентификатор) ; obj.AddLinefid); end; И• entr.„Release!); end; H // // ПоказатьСписокДокументов().
// Здесь создается окно ВК, в котором // отображены идентификаторы всех документов И данной конфигурации 1С:Предприятие methSbowLietDoce:ч
begin form := TAddlnDoc.Create(nil); ret.left := 10; ret.top := 10;
ret.right := form. Width;
ret.bottom := form.Height;
pExtWndsSupport.CreateAddInWindow('Addin.AddlnDoc',
'Список Документов', 0, 0, ret, 0, wnd, entr);
obj := entr;
//
// Считывание идентификаторов документов
//из метаданных с помощью метода EvalExprO
// и их отображение в окне ВК с помощью метода AddLineO V:=pConn;
V := V.AppDispatch;
IDispatch(V),_AddRef;
Count:=l*V.EvalKxpr( 'Метаданные.Документ() ’) ;
for i:=l to Count do
begin
Sx:='Метаданные.Документ(1+IntToStr(i)+')' ;
id:=Trim(V.EvalExpr(Sx).Идентификатор) ;
obj.AddLine(id);
end;
//
cntr._Release();
end;
//
//
И ПоказатьСписокРегистров().
И Здесь создается окно ВК, в котором
// отображены идентификаторы всех регистров
И данной конфигурации 1С: Предприятие
methShowLietRege:
begin
form := TAddlnDoc.Create(nil);
ret.left := 10;
ret.top := 10;
ret.right := form. Width;
rct.bottom := form.Height;
pExtWndsSupport.CreataAddlnWindow('Addin.AddlnDoc1,
'Список регистров1, 0, 0, ret, 0, wnd, entr);
obj := entr;
II
// Считывание идентификаторов регистров
//из метаданных с помощью метода EvalExprO
// и их отображение в окне ВК с помощью метода AddLinel) V:=pConn;
V := V.AppDispatch;
IDispatch(V).„AddRef;
Count:=1*V.EvalKxpr(1 Метаданные.Регистр() ‘); for i:=l to Count do
begin
Sx: = 'Метаданные.Регистр('+IntToStr(i) + ')'; id:=Trim(V.KvalExpr(Sx).Идентификатор);
obj.Mdliine(id);
end;
//
cntr.„Release();
end;
//
else
begin
CallAsProc := S_FALSE;
Exit;
end;
end;
CallAsProc := S_OK;
end;
В принципе, здесь используются приемы, рассмотренные ранее в этой и предыдущих главах. Единственное, что следует отметить: при создании нового окна (активного документа) метод CreateAddinWindow интерфейса lExtWndssupport возвращает указатель на интерфейс IDispatch (cntr) созданного активного документа, что позволяет управлять им из внешней компоненты, обращаясь к его методам и свойствам. Назначение параметров метода CreateAddinWindow:ч
function CreateAddinWindow
(const bstrProgID: WideString; // ProgID Активного Документа const bstrWindowName: WideString; // Заголовок окна
dwStyles: Integer; // Стиль окна (0 по умолчанию)
dwExStyles: Integer; var rctl: RECT; Flags: Integer;var pHwnd: HWND;var pDisp: IDispatch): HResult; stdcall;dwExStyles: Integer; var rctl: RECT; Flags: Integer;var pHwnd: HWND;var pDisp: IDispatch): HResult; stdcall;// Дополнительный стиль окна (0 по умолчанию)// Размеры и положение окна// Резерв (должен быть равен 0)И Указатель на дескриптор созданного окнаII Указатель на IDispatch// созданного "Активного Документа"// Дополнительный стиль окна (0 по умолчанию)// Размеры и положение окна// Резерв (должен быть равен 0)И Указатель на дескриптор созданного окнаII Указатель на IDispatch// созданного "Активного Документа"На рис. 5.27 представлена форма внешней обработки ВнешняяФорма_ jyifl_Add!n_Example02_01.ERT, предназначенная для тестирования внешней Компоненты Addln_Example02_01.На рис. 5.27 представлена форма внешней обработки ВнешняяФорма_ jyifl_Add!n_Example02_01.ERT, предназначенная для тестирования внешней Компоненты Addln_Example02_01.@№зи@№зиAddln_ExampleO2Файл : Addln_Example02_01.dll Открыть окно ВК | Список справочников) Список регистров | Список документов | Закрыть |Addln_ExampleO2Файл : Addln_Example02_01.dll Открыть окно ВК | Список справочников) Список регистров | Список документов | Закрыть |Рис. 5.27. Форма внешней обработки для тестированиявнешней компоненты AddIn_Example02_01Рис. 5.27. Форма внешней обработки для тестированиявнешней компоненты AddIn_Example02_01Текст программного модуля внешней обработки представлен в листинге 5.56.Текст программного модуля внешней обработки представлен в листинге 5.56.Перем ВК Экспорт;Перем ВК Экспорт;
dwExStyles: Integer; var rctl: RECT; Flags: Integer;
var pHwnd: HWND;
var pDisp: IDispatch
): HResult; stdcall;
dwExStyles: Integer; var rctl: RECT; Flags: Integer;
var pHwnd: HWND;
var pDisp: IDispatch
): HResult; stdcall;
// Дополнительный стиль окна (0 по умолчанию)
// Размеры и положение окна
// Резерв (должен быть равен 0)
И Указатель на дескриптор созданного окна
II Указатель на IDispatch
// созданного "Активного Документа"
// Дополнительный стиль окна (0 по умолчанию)
// Размеры и положение окна
// Резерв (должен быть равен 0)
И Указатель на дескриптор созданного окна
II Указатель на IDispatch
// созданного "Активного Документа"
На рис. 5.27 представлена форма внешней обработки ВнешняяФорма_ jyifl_Add!n_Example02_01.ERT, предназначенная для тестирования внешней Компоненты Addln_Example02_01.
На рис. 5.27 представлена форма внешней обработки ВнешняяФорма_ jyifl_Add!n_Example02_01.ERT, предназначенная для тестирования внешней Компоненты Addln_Example02_01.
@№зи
@№зи
Addln_ExampleO2
Файл : Addln_Example02_01.dll Открыть окно ВК | Список справочников) Список регистров | Список документов | Закрыть |
Addln_ExampleO2
Файл : Addln_Example02_01.dll Открыть окно ВК | Список справочников) Список регистров | Список документов | Закрыть |
Рис. 5.27. Форма внешней обработки для тестированиявнешней компоненты AddIn_Example02_01
Рис. 5.27. Форма внешней обработки для тестированиявнешней компоненты AddIn_Example02_01
Текст программного модуля внешней обработки представлен в листинге 5.56.
Текст программного модуля внешней обработки представлен в листинге 5.56.
Перем ВК Экспорт;
Перем ВК Экспорт;
Процедура ОткрытьИнформОкноВК()
• ВК.Показать();
КонецПроцедуры
Процедура ПокаэатьСписокСправочниковО ВК.ПоказатьСписохСправочнихов();
КонецПроцедуры
Процедура ПоказатьСписокДокументов()
ВК. ПогаватьСписокДокументов () ;
КонецПроцедуры
Процедура ПокаэатьСписокРегистровО
КонецПроцедуры
Процедура ПриОткрытии()
ЗагрузитьВнешнкюКомпоненту("AddIn_Kxanvle02_01.dll");
ВК = СоздатьОбъект("Addin.AddIn_ElcшwleO2,) ;
КонецПроцедуры
На рис. 5.28 представлен результат тестирования внешней компоненты
AddIn_Example02_01.
й ti\lCjw^npl«-UB\bdfom>s\#i№^й ti\lCjw^npl«-UB\bdfom>s\#i№^LOLOСписоксправочник он иСписоксправочник он иti 51 S 1Уti 51 S 1УAddln_ExampleO2Файл : Addln_Example02_01.dllОткрыть окно ВК | Список справочников! гСписок регистров | Список документов | |Addln_ExampleO2Файл : Addln_Example02_01.dllОткрыть окно ВК | Список справочников! гСписок регистров | Список документов | |ФизЛицаСтраныМираГ ородаСтранМираФизЛицаСтраныМираГ ородаСтранМираЯ Список Документов НВ вЯ Список Документов НВ вЗакрыть |Закрыть |[■ Список регк трое[■ Список регк троеI _ | ИзменениеСостоянияФизЛиц — В ВыплатыФиэЛицамI _ | ИзменениеСостоянияФизЛиц — В ВыплатыФиэЛицам11 УчетИзмененийСостоямияФи.УчетВыплатФизЛицам11 УчетИзмененийСостоямияФи.УчетВыплатФизЛицамРис. 5.28. Результат тестированиявнешней компоненты AddIn_Example02_01Рис. 5.28. Результат тестированиявнешней компоненты AddIn_Example02_01Для одной внешней компоненты можно создать несколько форм типа TActiveForm. Чтобы рассмотреть этот вопрос на конкретном примере, расширим функциональность компоненты Addin_ExampieO2_oi. Добавим в нее что-то вроде простой записной книжки. Записная книжка представляет собой набор пронумерованных текстовых файлов (на каждую букву алфавита —- отдельный текстовый файл). Вызов записной книжки из программыДля одной внешней компоненты можно создать несколько форм типа TActiveForm. Чтобы рассмотреть этот вопрос на конкретном примере, расширим функциональность компоненты Addin_ExampieO2_oi. Добавим в нее что-то вроде простой записной книжки. Записная книжка представляет собой набор пронумерованных текстовых файлов (на каждую букву алфавита —- отдельный текстовый файл). Вызов записной книжки из программы
й ti\lCjw^npl«-UB\bdfom>s\#i№^
й ti\lCjw^npl«-UB\bdfom>s\#i№^
LO
LO
Списоксправочник он и
Списоксправочник он и
ti 51 S 1У
ti 51 S 1У
Addln_ExampleO2
Файл : Addln_Example02_01.dll
Открыть окно ВК | Список справочников! г
Список регистров | Список документов | |
Addln_ExampleO2
Файл : Addln_Example02_01.dll
Открыть окно ВК | Список справочников! г
Список регистров | Список документов | |
ФизЛица
СтраныМира
Г ородаСтранМира
ФизЛица
СтраныМира
Г ородаСтранМира
Я Список Документов НВ в
Я Список Документов НВ в
Закрыть |
Закрыть |
[■ Список регк трое
[■ Список регк трое
I _ | ИзменениеСостоянияФизЛиц — В ВыплатыФиэЛицам
I _ | ИзменениеСостоянияФизЛиц — В ВыплатыФиэЛицам
11 УчетИзмененийСостоямияФи.
УчетВыплатФизЛицам
11 УчетИзмененийСостоямияФи.
УчетВыплатФизЛицам
Рис. 5.28. Результат тестированиявнешней компоненты AddIn_Example02_01
Рис. 5.28. Результат тестированиявнешней компоненты AddIn_Example02_01
Для одной внешней компоненты можно создать несколько форм типа TActiveForm. Чтобы рассмотреть этот вопрос на конкретном примере, расширим функциональность компоненты Addin_ExampieO2_oi. Добавим в нее что-то вроде простой записной книжки. Записная книжка представляет собой набор пронумерованных текстовых файлов (на каждую букву алфавита —- отдельный текстовый файл). Вызов записной книжки из программы
Для одной внешней компоненты можно создать несколько форм типа TActiveForm. Чтобы рассмотреть этот вопрос на конкретном примере, расширим функциональность компоненты Addin_ExampieO2_oi. Добавим в нее что-то вроде простой записной книжки. Записная книжка представляет собой набор пронумерованных текстовых файлов (на каждую букву алфавита —- отдельный текстовый файл). Вызов записной книжки из программы
1С:Предприятие будет производиться с помоЩью процедуры ПоказатьМоиЗаписи иЛи showMyNotes. В качестве входного параметра процедура принимает имя папки, где будут размещаться файлы записной книжки. Таким образом, задавая имя папки, мы, по сути, выбираем определенную записную книжку.
Новую компоненту назовем Addin_Exampie02_02.
Примечание
На сопроводительном компакт-диске книги исходные тексты этого примера ходится в папке \Part_1\Chapter_05\Topic_5_2\Addln_Example02_02.PAS.
Чтобы создать новую форму, нужно выбрать пункт меню File > New, в открывшемся диалоговом окне перейти на вкладку ActiveX и выбрать значок ActiveForm (см. рис. 5.1). На экране появится диалоговое окно настройки свойств формы (рис. 5.29).
Рис. 5.29. Новая форма типа AcCiveForm внешней компоненты Addln_Example02_02Рис. 5.29. Новая форма типа AcCiveForm внешней компоненты Addln_Example02_02Создав форму, нужно будет открыть файл проекта Add!n_Example02_02. и заменить строку ($е осх} строкой {$е dll).
Рис. 5.29. Новая форма типа AcCiveForm внешней компоненты Addln_Example02_02
Рис. 5.29. Новая форма типа AcCiveForm внешней компоненты Addln_Example02_02
На рис. 5.30 представлена форма записной книжки.
В листинге 5.57 представлена реализация функциональности проце; ПоказатьМоиЗаписи в методе SaveAsProc объекта TAddlnObj.
Рис. 5.30. Форма TMyNotes внешней компоненты AddIn_Example02_02
(Стинг 5.57. Реализация процедуры ПоказатьМоиЗаписи в методе , Мй^^^^^^-З^^
// ПоказатьМоиЗаписи(DirName_for_Notes)
methShowHyNotoe:
begin
//В первом входном параметре
II получаем имя папки, гае хранятся файлы
// записной книжки
Sx:=Trim( (Ge tNParam(pa Params, 0)}) ;
if length(Sx)>0 then begin
form! := ЩуКоЬеш.Create(nil);
ret.left := 10;
ret.top := 10;
ret.right := form2.Width;
ret.bottom := form2.Height;
pExtWndsSupport.CreateAddlnWindow('Addin.Myttotea•,
1 Моя записная книжка', 0, 0, ret, 0, wnd, entr);
obj := entr;4
11 Запоминаем имя папки
Obj.SatDirName(Sx);
// Загружаем текстовый файл для первой закладки
// (буква А)
r-r4Pr,7~ "T^WV^F7. '4
Глава 5. Расширение функционала IC 43
obj.LoadThisPage(0) ;
//
cntr.„Release();
end;
end;
На рис. 5.31 представлена форма внешней обработки ВнешняяФорма_лля AddIn„Example02_02.ERT системы 1С:Предприятие для тестирования внеш ней компоненты AddIn_Example02_02.
^1. нвв
Addln_ExampleO2
Файл: Addln_Example02_02.dll
Открыть окно ВК | Слисок справочников|
Слисок регистров | Слисок документов |Закрыть |Записная книжка |
Рис. 5.31. Форма внешней обработки
для тестирования внешней компоненты Addln_Example02_02
В листинге 5.58 представлен текст программного модуля обработки.
|IЖ';TW:г.','™;'TmЧ■г'VT.,^^
Юистйнг 5.58. Программный модуль обработки] 4 $$^ ^ешняяФормаи»пя Аас11п^Ехатр1е02 02.ЕЯТ ,.^
Перем ВК Экспорт;
Процедура ОткрытьИнформОкноВК() ВК.Показать();
КонецПроцедуры
Процедура ПоказатьСписокСправочников() ВК.ПоказатьСписокСправочников();
•КонецПроцедуры
Процедура ПоказатьСписокДокументов() ВК.ПоказатьСписокДокументов();
КонецПроцедуры
Процедура ПоказатьСписокРегистров() ВК.ПоказатьСписокРегистров();
КонецПроцедуры
Процедура ЗаписнаяКнижка()
ВК.ПоказатьМоиЗаписи(каталогИЕ()+•ExtFormsV + *ТМР\*);
КонецПроцедуры
Процедура ПриОткрытии()
ЗагрузитьВнешнкюКомпоненту("AddIn_ExanpleO2_Q2.dll");
ВК = СоздатьОбъект("Addin.AddIn_ExanpleO2”);
КонецПроцедуры
На рис. 5.32 представлен результат тестирования внешней компоненты
AddIn_Example02_02.
' л а В ^' л а В ^й E;iНЯЕ|■ Моя зинпм книжке
' л а В ^
' л а В ^
Add I n_Example02_02
Addln_ExampleO2Фай»: Ad<fln_E»a»>ple02_01.dUОткрыть окно ВК | Список справочников]Список регистров | Список документов ]Addln_ExampleO2Фай»: Ad<fln_E»a»>ple02_01.dUОткрыть окно ВК | Список справочников]Список регистров | Список документов ]ЗакрытьЗакрытьВторое окно внешней компоненты ...Второе окно внешней компоненты ...Г Форматировать по шцжне окнаГ Форматировать по шцжне окнаЗаписная книжка |Записная книжка |ФизЛица Стране^ ира ГорараСтранМираФизЛица Стране^ ира ГорараСтранМира[НЕЗ Я ■Список Документ» ИИ 13[НЕЗ Я ■Список Документ» ИИ 13И зменениеСсстоянияФ изЛиц ВьппатыФизЛицамИ зменениеСсстоянияФ изЛиц ВьппатыФизЛицам
Addln_ExampleO2
Фай»: Ad<fln_E»a»>ple02_01.dU
Открыть окно ВК | Список справочников]
Список регистров | Список документов ]
Addln_ExampleO2
Фай»: Ad<fln_E»a»>ple02_01.dU
Открыть окно ВК | Список справочников]
Список регистров | Список документов ]
Закрыть
Закрыть
Второе окно внешней компоненты ...
Второе окно внешней компоненты ...
Г Форматировать по шцжне окна
Г Форматировать по шцжне окна
Записная книжка |
Записная книжка |
ФизЛица Стране^ ира ГорараСтранМира
ФизЛица Стране^ ира ГорараСтранМира
[НЕЗ Я ■Список Документ» ИИ 13
[НЕЗ Я ■Список Документ» ИИ 13
И зменениеСсстоянияФ изЛиц ВьппатыФизЛицам
И зменениеСсстоянияФ изЛиц ВьппатыФизЛицам
Рис. 5.32. Результат тестирования внешней компоненты AddIn_Example02_02
Примечание
Напомню, что приведенные примеры исходных текстов — это упрощенная иллюстрация к рассматриваемым вопросам. Назначение этих примеров — ДаТЬ представление о возможном подходе при решении задач информационного обмена с системой 1С:Предприятие. При работе с реальными базами 1С может потребоваться их дальнейшая доработка.
Внепроцессный сервер автоматизации
Внепроцессный сервер автоматизации выполняется в собственном адресном пространстве (отличном от адресного пространства контроллера). Отсюда следует, что для управления сервером клиент должен обращаться к свойствам и методам объектов, находящихся в ином адресном простанстве. Для этого используется технология LRPC (Local Remote Procedure Calls). Как правило, большинство внепроцессных серверов автоматизации являются полноценными автономными приложениями. С другой стороны, приложение легко можно превратить во внепроцессный сервер автоматизации.
В этом разделе мы на конкретном примере рассмотрим, каким образом можно использовать внепроцессный сервер автоматизации для расширения функциональности системы 1С:Предприятие.
Создадим новый Delphi-проект (рис. 5.33).
Рис. 5.33. Пустая форма Delphi-проекта
Сохраним проект под именем oleSrvlC.DPR и, не внося больше изменений в проект, выберем пункт меню File > New. В открывшемся диалоговом окне на вкладке ActiveX нужно выделить значок (пиктограмму) Automation Object (рис. 5.34) и нажать кнопку ОК.
На экране появится диалоговое окно настройки свойств объекта Automation Object (рис. 5.35).
В разд. 5.2 это окно было рассмотрено достаточно подробно, поэтому здесь Углубляться не будем. Отметим только, что свойство ProgiD сервера автоматизации будет установлено так:
OleSrvlC.Toole
Закрыв окно нажатием кнопки ОК, нужно сохранить и скомпилировать проект OleSrvlC.DPR. Полученное приложение oleSrvlC.EXE и есть внепроцессный Сервер автоматизации.
МП чМП ч• K New Items• K New ItemsххActiveFcxmActiveFcxmAutomata".ObiectAutomata".ObiectActive Server ObiectActive Server ObiectActiveX ActiveX Library ControlActiveX ActiveX Library ControlDialogs I Projects | Data Modules | Business New ActiveX I Multitier | oleSrvIC | FormsDialogs I Projects | Data Modules | Business New ActiveX I Multitier | oleSrvIC | FormsV.V.Property PageProperty PageTypelibraryTypelibraryCOM ObjectCOM Object
МП ч
МП ч
• K New Items
• K New Items
х
х
ActiveFcxm
ActiveFcxm
Automata".
Obiect
Automata".
Obiect
Active Server Obiect
Active Server Obiect
ActiveX ActiveX Library Control
ActiveX ActiveX Library Control
Dialogs I Projects | Data Modules | Business New ActiveX I Multitier | oleSrvIC | Forms
Dialogs I Projects | Data Modules | Business New ActiveX I Multitier | oleSrvIC | Forms
V.
V.
Property Page
Property Page
Typelibrary
Typelibrary
COM Object
COM Object
C Copy <" Inherit С Ц$е
I OK | Cancel [ Help
Рис. 5.34. Выбор значка Automation Object
Рис. 5.35. Диалоговое окно настройки свойств Automation ObjectРис. 5.35. Диалоговое окно настройки свойств Automation Object
Рис. 5.35. Диалоговое окно настройки свойств Automation Object
Рис. 5.35. Диалоговое окно настройки свойств Automation Object
Примечание
На сопроводительном компакт-диске книги исходные тексты этого примера находятся в папке \Part_1\Chapter_05\Topic_5_3\oleSrv1C_01.PAS.
Для того чтобы зарегистрировать сервер в операционной системе (в реестре), нужно просто запустить приложение oIeSrvlC.EXE — и все. Очевидно, что создать внепроцессный сервер автоматизации существенно проще, чем внутрипроцессный (см. разд. 5.2).
Теперь наделим наш сервер автоматизации каким-нибудь свойством, например, позволяющим делать невидимой форму главного окна приложения (сервера)-
Для этого откроем диалоговое окно библиотеки типов и введем свойство Visible (рис. 5.36).
oooleSrvlC.tlb
jj ^ 3
Я A oleSrvIC
В > (Took
<V Visible
ф IToolsE vents
Name:
(Visible
ID:
b
Type:
(long
Invoke Kind.
| Property Put
AUibuies | Parameters | Flags [Text |
Рис. 5.36. Диалоговое окно библиотеки типов
В листинге 5.59 представлена реализация свойства visible сервера автоматизации.
function TTools.Gat_Vislble: Integer;
// Считывание свойства Visible begin
Result:=0;
if Fonnl.visible then Result:>1;
end;
procedure TTools.Set_Vleible(Value: Integer); // Запись свойства Visible
if Value>0 then begin
Fonnl .Vis ible: =TRUE ; end else begin
Fonnl.Visible:=FALSE; end;
end;
Здесь все очевидно.
•
Теперь нужно скомпилировать проект и запустить приложение oleSrvlC.EXE для того, чтобы оно само себя зарегистрировало как сервер OLE Automation Это достаточно сделать один раз. В дальнейшем, при обращении к серверу какого-либо другого приложения (контроллера автоматизации) операционная система сама найдет и запустит oleSrvlC.EXE.
№В|!|№В|!|Чтобы протестировать сервер автоматизации, откроем Конфигуратор 1С:Предприятие и создадим внешнюю обработку (рис. 5.37).
№В|!|
№В|!|
ifcsM
oleSn/1 С.ехе
ВнеПроцессный сервер автоматизации
Запустить
Видимость-да
Закрыть
Видим остынет
Закрыть I
Рис. 5.37. Внешняя обработка для тестирования oleSrv1C.EXE
Имя файла этой обработки — ВнешняяФорма-1^для_о1е5гу1С_ехе.ЕКТ.
Текст программного модуля обработки представлен в листинге 5.60.
Перем oleSrvlC;Перем oleSrvlC;
Перем oleSrvlC;
Перем oleSrvlC;
Процедура Запустить_о1е5гу1С() oleSrvlC = Со1дать0»ьект("oleSrvlC.Toole");
КонецПроцедуры
Процедура Закрыть_о1е5гу1С() oleSrvlC = ”";
КонецПроцедуры
Процедура ВидимостьДА() oleSrvlC.Vleible = 1;
КонецПроцедуры
Процедура ВидимостьНЕТ() - oleSrvlC.Visible = 0;
КоненПронедуры
Результат тестирования представлен на рис. 5.38.
й Е:\1С_енатр1е.РВ\Ек1Еогт$\ВнешняяФ... ВВЕЗ
Л 51 Й V
oleSrvI С.ехе
ВнеПроцессный сервер автоматизации
I ЗапуститьВидимость-даI ЗапуститьВидимость-даЗакрытьВидимость-нетЗакрытьВидимость-нет
I Запустить
Видимость-да
I Запустить
Видимость-да
Закрыть
Видимость-нет
Закрыть
Видимость-нет
Закрыть |Закрыть |
Закрыть |
Закрыть |
Внепроцессный сервер автоматиза...
Рис. 5.38. Результат тестирования сервера oleSrv1C.EXE
По нажатию кнопки Запустить на экране компьютера появится окно сервера автоматизации. По нажатию кнопки Видимость-нет окно сервера станет невидимым (при этом сам сервер остается в памяти). По нажатию кнопки Видимость-да окно сервера вновь появится на экране и т. д. Чтобы выгрузить сервер, нужно просто закрыть форму или "обнулить" переменную, где хранится ссылка на сервер (в данном случае переменная olesrvic (см. листинг 5.60)).
Расширим функциональность сервера. Для этого вновь откроем диалоговое окно библиотеки типов и введем новый метод isDate (рис. 5.39).
■Этот метод получает во входном параметре snate строку, которая представляет собой дату в допустимом формате (например, ДД.ММ.ГПТ или ММ/ГГГГ). Метод должен проанализировать строку и вернуть значение 1, *сли дата корректна, или 0 в противном случае. Реализация этого метода риведенав листинге 5.61.
Рис. 5.39. Расширение функциональности сервера автоматизации: новый метод IsDateРис. 5.39. Расширение функциональности сервера автоматизации: новый метод IsDate.51 v.51 vИЯ методИЯ методgategate* te сервер* te сервер
Рис. 5.39. Расширение функциональности сервера автоматизации: новый метод IsDate
Рис. 5.39. Расширение функциональности сервера автоматизации: новый метод IsDate
.51 v
.51 v
ИЯ метод
ИЯ метод
gate
gate
* te сервер
* te сервер
function TTools.lBDate(const sDate: WideString): Integer;
II Проверка строки sDate на корректность, если это дата begin
Result:=0;
if ep_IeDate(Trim(sDate)) then Result:=l; end;
Текст функции sp_isDate здесь не приводится из экономии места (полный текст функции можно посмотреть в файле oslc_(K).PAS данного примера).
Следует отметить, что проверка даты на корректность особенно актуальна, когда производится считывание информации из программы 1С:Предприятие через механизм OLE Automation. В случае "пустого" значения даты это становится существенной проблемой при "стандартном" подходе.
Проблему можно решить, обеспечив соединение одной программы 1С:Предприятие (как клиента автоматизации) с другой программой 1 С:Предприятие (как с сервером автоматизации) с помощью сервера oleSrvlC.EXE.
То есть сервер oleSrvlC.EXE будет выполнять роль посредника. В этом случае, как ни странно, метод isDate работает корректно (то есть воспринимает "пустую" дату как строку с ошибочной датой).
Попробуем применить это на практике. Создадим новый метод connectToic (рис. 5.40).
Рис. 5.40. Расширение функциональности сервера автоматизации: новый метод ConnectTolcРис. 5.40. Расширение функциональности сервера автоматизации: новый метод ConnectTolc
Рис. 5.40. Расширение функциональности сервера автоматизации: новый метод ConnectTolc
Рис. 5.40. Расширение функциональности сервера автоматизации: новый метод ConnectTolc
Его назначение — запуск программы I С: Предприятие как сервера OLE Automation и возврат ссылки на него в вызывающий программный модуль. Реализация этого метода приведена в листинге 5.62.
| function TTools.ConoectTolC(const slnitLine: WideString): OleVariant;
I . // Запуск программы IC:Предприятие в режиме сервера OLE Automation:
' // slnitLine — строка инициализации программа 1С:Предприятие begin
I Result:=CcnnectTolC_via(Trim(sInitLine));
I end;
В листинге 5.63 приведен текст функции connectToic_via.
function ConnectTolC_via(InitStr : string) : OleVariant;
। // Запуск программа IC:Предприятие в режиме сервера OLE Autonation:
|7/ InitLine - строка инициализации программы 1С:Предприятие
Var
ResOpen : integer;
begin-г
Result:=UnAssigned;
InitStr:=Trim(InitStr);
Result := CreateOleObject(‘V77.Application');
ResOpen:=Result.Initialize(Result.RMTrade, Initstr, 1');
if ResOpen>=0 then begin
Result:=ОпАя вigned;
end;
end;
Сохраним и скомпилируем наш Delphi-проект.
Чтобы протестировать функцию isDate, запустим программу 1С:Предприятие. откроем кофигурацию lC_example.DB2 и очистим значение реквизита датаРождения для одного из элементов справочника Физлица, например, для элемента справочника с кодом 5 (рис. 5.41).
Рис. 5.41. Содержание справочника ФизЛица в конфигурации lC_example.DB2
Закроем программу 1С:Предприятие.
Теперь запустим Конфигуратор 1С:Предприятие, откроем конфигурацию lC_example.DB и создадим внешнюю обработку ВнешняяФорма-2_лпя_ oleSrvlC_exe.ERT (рис. 5.42).
Рис. 5.42. Форма внешней обработки для тестирования функции IsDate сервера автоматизации
; Здесь требуются некоторые пояснения. Попробуем прочитать значение реквизита дата Рождения элемента справочника ФизЛица с кодом 5 двумя способами.
Способ I ("стандартный"): из программного модуля ЮПредприятие вызывается также программа 1С:Предприятие в качестве сервера OLE Automation следующим образом:
OlelC = СоэдатьОбъект("V77.Application");
OlelC.Initialize(OlelC.RMTrade, "", "•);
Способ 2: в программном модуле ЮПредприятие вызывается сначала сервер автоматизации oleSrvlC.EXE, а затем с помощью его метода connectToic вызывается программа ЮПредприятие в качестве сервера OLE Automation следующим образом:
oleSrvlC = СоэдатьОбъект("oleSrvlC.Tools");
oleSrvlC.Visible = 0;
OlelC = oleSrvlC.ConnectTolC("");
Для чистоты эксперимента попутно прочитаем значения реквизита датаРож- дения элемента справочника ФизЛица с кодом б обоими способами.
Назначение элементов управления в форме обработки приведено в табл. 5.8.
Таблица 5.8. Назначение элементов управления формы обработки ВнешняяФорма-2_для_о1е8л/1С_ехе.ЕРТ
Элемент управления
Тип
Назначение
ДатаОЬЕ1_5
Дата
Значение реквизита Дата Рождения элемента справочника ФизЛица с кодом 5 при считывании через механизм OLE (способ 1)
ДатаОЬЕ1_6
Дата
Значение реквизита ДатаРождения элемента справочника ФизЛица С кодом 6 при считывании через механизм OLE (способ 1)
ДатаОЬЕ2_5
Дата
Значение реквизита ДатаРождения элемента справочника ФизЛица С кодом 5 при считывании через механизм OLE (способ 2)
ДатаОЬЕ2_6
Дата
Значение реквизита ДатаРождения элемента справочника ФизЛица с кодом 6 при считывании через механизм OLE (способ 2)
Таблица 5.8 (окончание)
Элемент управления
Тип
—-—
Назначение
Прочитать Дату(OLE)
Кнопка
Соединение с 1С:Предприятие (способ 1). Считывание значений реквизита ДатаРождения элементов справочника Физлица с кодами 5 и 6 через механизм OLE
Прочитать Дату(OLE)- oleSrvlC.exe
Кнопка
Соединение с 1С:Предприятие (способ 2). Считывание значений реквизита ДатаРождения элементов справочника Физлица с кодами 5 и 6 через механизм OLE
В листинге 5.64 представлен текст программного модуля внешней обработки ВнешняяФорма-2 _juifl_oleSrvlC_exe.ERT.
Перем oleSrvlC;
//==================================
// Считывание информации из 1С_ехагпр1е.DB2 посредством механизма OLE.
// Способ 1: соединение "напрямую*
Процедура ПрочитатьДатуОЬЕ()
ДатаОЕЕ1_5 = *" ;
ДатаОЬЕ1_6 = *";
OlelC - СоздатьОбтлкт("V77.Application");
OlelC.Initialize(OlelC.RMTrade, ”", **);
СпрФизЛица = OlelC.CreateObject("Справочник.ФизЛица");
//
//Здесь дата рождения пустая
Если СпрФиаЛица.НайтиПоКоду(5,0)>0 Тогда
Sx = СпрФизЛица.ДатаРождения;
ДатаОЬЕ1_5 = ДАТА(5х);
КонецЕсли;
//
//
//Здесь дата рождения ж 15.03.65
Если СпрФиэЛица.НайтиПоКоду(6,0)>0 Тогда
Sx = СпрФизЛица.ДатаРождения;
ДатаОЬЕ1_6 = ДАТА(Зх);
КонецЕсли;
//
ецПроцедурыецПроцедуры// Считывание информации из lC_example.DB2 посредством механизма OLE.
ецПроцедуры
ецПроцедуры
// Способ 2: соединение через oleSrvlC.EXE
цедура ПрочитатьДатуОЬЕ_2()
ДатаОЬЕ2_5 = "";
ДатаОЬЕ2_6 = "";
oleStvlC ж Создать0бчект("о1е8гу1С.Toole*);
oleSrvlC.Visible = 0;
OlelC ж oleSrvlC.CormectTolC("*);
СпрФиэЛица = OlelC.CreateObject("Справочник.ФизЛица");
//
// Здесь дата рождения пустая
Если СпрФиэЛица.НайтиПоКоду(5,0)>0 Тогда
Sx = СпрФиэЛица.ДатаРождения;
Если oleSrvlC.IeDate(Sx)>0 Тогда
ДатаОЬЕ2_5 = ДАТА(Зх);
Иначе
Сообщить("Оливка в дате="+5х);
КонецЕсли;
КонецЕсли;
//
//Здесь дата рождения ж 15.03.65
Если СпрФиэЛица.НайтиПоКоду(6,0)>0 Тогда Sx = СпрФиэЛица.ДатаРождения; Если oleSrvlC.leOate(Sx}>0 Тогда
ДатаОЬЕ2_6 = ДАТА(Зх);
Иначе
Сообщить("Ошибка в дате="+5х);
КонецЕсли;
КонецЕсли;
//
КонецПроцедуры
//===================:
Теперь запустим программу Ю.Предприятие, откроем внешнюю обработку ВнешняяФорма-2_juifl_oleSrvlC_exe.ERT и протестируем оба способа (естественно, нужно выбрать одну и ту же конфигурацию lC_example.DB2). Результат тестирования представлен на рис. 5.43.
0 Е:\ 1С_еиатр1е.0В\Ек1Гогт5\Внешняя<Ро- ВЕР
Л Л 2 oleSn/1 С.ехеВнвПроцессный сервер автоматизацииПрочитать Дату(0 LE J|
[3012.99[15 03.65,
11
| "[15.03.65
Закрыть]
Ц|">;0шибкавдате=30.12 99
Рис. 5.43. Результат тестирования функции isDate сервера oleSrv1C.EXE
Здесь комментарии излишни.
У внешних компонент для системы 1С:Предприятие в виде внутрипроцессных серверов автоматизации (см. разд. 5.2) есть свои преимущества. Но один из их существенных недостатков — трудоемкость в разработке и отладке функционально сложных внутрипроцессных серверов OLE Automation для программы 1С:Предприятие. Тогда как использование внепроцессных серверов автоматизации существенно упрощает и ускоряет решение этой задачи- Рассмотрим этот момент на следующем примере.
Папка \lC_example.DB\ExtForms\ сопроводительного компакт-диска книги содержит демонстрационный ЕХЕ-модуль oleExecScript.EXE. представляющий собой внепроцессный сервер автоматизации, функциональность которого кратко описана в табл. 5.9.
Таблица 5.9. Методы и свойства сервера OLE Automation oleExecScript.EXE
Метод/Свойство
Назначение
Visible
(свойство)
Видимость главного окна приложения: если значение этого свойства больше 0, то окно сервера видимо, в противном случае — нет
StayOnTop
(свойство)
Режим визуализации главного окна приложения: если значение этого свойства больше 0, то окно приложения находится в режиме "всегда сверху", в противном случае — нет
BvalExpr (метод)
Вычисление выражения. Синтаксис:
EvalExpr(СтрокаВыражения.КодЯзыка);
КодЯзыка: 0 (по умолчанию) — Pascal. Возвращаемое значение: variant
ExecuteBatch (метод)
Выполнение скрипта (сценария). Синтаксис:
ExecuteBatch(ТекстСкрипта,КодЯзыка.Строка Сшибки);
ТекстСкрипта: строка, содержащая текст выполняемого скрипта; КодЯзыка'. 0 (по умолчанию) — Pascal. Возвращаемое значение: integer (больше 0 — успешное выполнение, в противном случае — нет)
I ExecuteBatchF
(метод)
Выполнение скрипта из файла. Синтаксис:
ExecuteBatchF1.ИмяФайлаСкрипта,КодЯзыка, Строка Ошибки);
КодЯзыка: 0 (по умолчанию) — Pascal. Возвращаемое значение: integer (больше 0 — успешное выполнение, в противном случае — нет)
I GetVarValue
* (метод)
Получение значения переменной выполненного скрипта. Синтаксис:
GetVarValue(ИмяПеременной);
Возвращаемое значение: variant
GetVarCount (метод)
Получение количества переменных выполненного скрипта. Синтаксис:
GetVarCount();
Зак. I064
Таблица 5.9 (окончание)
Метод/Свойство
Назначение
GetVarName
(метод)
Получение имени переменной по ее номеру (начиная с нуля). Синтаксис:
GetVarName(НомерПеременной);
Возвращаемое значение: string
GetVarNamesString (метод)
Получение имен всех переменных. Синтаксис:
GetVarNamesString();
Возвращаемое значение: string
Примечание
Указанная функциональность сервера была реализована с помощью пакета FastScript версии 1.4 (Copyright 1998—2004 by Fast Reports Inc., Author: Alexander Tzyganenko, http://www.fastreport.ru), который представляет собой прекрасную библиотеку для выполнения скриптов с поддержкой синтаксиса PascalScript, C++Script, BasicScript, JScript. Этот пакет имеет статус коммерческого программного продукта, поэтому исходные тексты программы oleExecScript.EXE здесь не приводятся.
ййЗапустим Конфигуратор 1С:Предприятие и создадим внешнюю обработку ВнешняяФорма-1 _для_о1еЕхес5спр1.ЕКТ (рис. 5.44).
й
й
oleExecScript.exe
ВнеПроцессный сервер автоматизации
Текст скрипта (pascal):
Текст Скрыта
Закрыть |Закрыть |Выполнить |
Закрыть |
Закрыть |
Рис. 5.44. Внешняя обработка для тестирования сервера oleExecScript.EXE
447
В листинге 5.65 приведен текст программного модуля внешней обработки ВнешняяФорма-1_для_о1еЕхес5спр1.ЕКТ.
Листинг 5.65. Программный модуль обработ^^ ^нешняяФррма^^^
Перем oleExecScript;
Процедура ВыполнитьСкрипт()
СтрокаОшибки="";
И
// Выполнение скрипта
Если oleExecScript.ExecuteBatch(ТекстСкрипта,0,СтрокаОшибки)<=0 Тогда Предупреждение(СтрокаОшиОки);
КонецЕсли;
//
КонецПроцедуры
Q Е:\ 1 С_ехатр1еД)В\Ехи-огт5\8нешняяФсрм_. В[ё| □
61 61 В у
oleExecScript.exe
ВнеПроцессный сервер автоматизации
T екст скрипта (pascal):
Va
О: TQuery;
begin
Q.-TQueiy.CieateM;
try
0. Databasename:-”;
Q.SQLAddl'select count[-n
Q.SQLAddCffom');
ExecScript
Кол-во строк=9
х
Q.SQLAdd(,"EA1C_example.D8\ExtFoпns\sc12.dЫ,*);
Q.Open;
ShowMessage(Xon-Bo crpoK-'*lntToSti(Q.Fields|01Adnteger)l; finals
Q.Close;
Q.Free;
end;
end.
Выполнить |
Закрыть |
Рис. 5.45. Результат тестирования метода ExecuteBatch сервера oleExecScript.EXE
Запустим программу IC:Предприятие, откроем файл созданной обработки введем текст скрипта и запустим его на выполнение (рис. 5.45).Запустим программу IC:Предприятие, откроем файл созданной обработки введем текст скрипта и запустим его на выполнение (рис. 5.45).
Запустим программу IC:Предприятие, откроем файл созданной обработки введем текст скрипта и запустим его на выполнение (рис. 5.45).
Запустим программу IC:Предприятие, откроем файл созданной обработки введем текст скрипта и запустим его на выполнение (рис. 5.45).
Примечание
Для выполнения указанного скрипта требуется, чтобы на компьютере был уста- новлен пакет BDE-5.
Программистам, использующим Delphi, этот скрипт понятен и не требует пояснений.
Теперь снова запустим Конфигуратор 1С:Предприятие. откроем обработку ВнешняяФорма-1 _juifl_oleExecScript.ERT и внесем в текст процедуру выполнитьСкрипт () программного модуля следующие изменения (листинг 5.66).
Процедура ВыполиитъСкрипт()
СтрокаОшибки="";
//
// Выполнение скрипта
Если oleKxecScript.ЕхваиРвВаЪсЫТекстСкрипта,0,СтрокаСшибки)>0 Тогда
// Считываем значение переменной Count после
// выполнения скрипта
V = oleExecScript.GetVarValue("Count");
Предупреждение("Значение переменной Count-"+СокрЛП(V));
Иначе
Предупреждение("Оливка I "+СтрокаОшибки);
КонецЕсли;
Н
КонецПроцедуры
После успешного выполнения скрипта (ExecuteBatch) вызывается метод Getvarvaiue, куда в качестве параметра передается имя переменной count.
Вновь запустим програму 1С:Предприятие, откроем обработку, введем скрипт и запустим его на выполнение (рис. 5.46).
11Как видите, текст скрипта изменился по сравнению с предыдущим (см. рис. 5.45)- А именно: объявлена еще одна переменная count: integer, и результат запроса не выводится на экран (showMessage), а присваивается переменной Count.
1
1
& £1 ^ ^
о I е ExecScri pt. ехе
ВнеПроцессный сервер автоматизации
1С:Предприятие
V»
Count: integei 1 J Значение переменной Count=9 Q TQuety;
begin
Q:=TQuery.Cres||
Q.Databasena
Q.SOLAddl'select cointf ■ ft
O.SQLAddTfromT
Q.SQLAddf'EAIC.example.DBSExtFormtXtcIZdbrft
Q Open;
Count: -Q. Fields[Q]. Asi nleger;
finals
Q.Close;
Q Free;
lend;
Выполнить |Закрыть
Рис. 5.46. Результат тестирования метода GetVarValue сервера oleExecScript.EXE
Сообщение "Значение переменной Count=9" (см. рис. 5.46) сгенерировано не скриптом, а программной строкой обработки (см. листинг 5.66):
Предупреждение("Значение переменной Count-"+СокрЛП(V));
То есть на экран было выведено то, что вернул метод GetVarValue сервера । автоматизации, после того как выполнился скрипт. С помощью методов сервера автоматизации oleExecScript.EXE можно не только выполнять скрипты различной сложности, но и считывать значения переменных скрипта после его выполнения, что очень существенно (особенно если учесть, что система 1С:Предприятие при использовании штатного метода ExecuteBatch не предоставляет такой возможности).
Примечание
Программа oleExecScript.EXE была разработана "на скорую руку" (в течение полутора часов) только для демонстрационных целей и не претендует на большее.
Часть II
Доступ к базе данных 1Сбез программы1С:Предприятие
В предыдущей части были рассмотрены вопросы обмена информаций (с программой 1:Предприятие) при помощи механизма OLE Automation. Как мы увидели, программа 1С:Предприятие обладает очень мощными и гибкими системными возможностями для доступа к информации в базе данных 1с (включая и метаданные) через механизм OLE Automation, позволяющими охватить весь спектр практических задач обмена информацией, стоящих перед разработчиками программного обеспечения. Но есть один существенный недостаток (относящийся, скорее, к механизму OLE Automation в целом) — довольно низкая скорость обмена информацией. В ряде случаев это может быть существенным ограничением для использования OLE Automation.
В настоящий момент для хранения базы данных в системе 1С:Предприятие предусмотрены два варианта: DBF-файлы и MS SQL Server (см. рис. 2.6). Это позволяет организовать доступ к информации в базах данных 1С (минуя программу 1 С:Предприятие) посредством механизма стандартных SQL-запросов к таблицам баз данных, что в ряде случаев значительно эффективнее по быстродействию, чем доступ через механизм OLE Automation.
SQL (Structured Query Language) — универсальный язык структурированных запросов, ориентированный на операции с данными, представленными в виде логически взаимосвязанных совокупностей таблиц. Прототип языка (SEQUEL— произносится "сиквел") был создан компанией IBM в начале 1970-х. Позже язык SEQUEL был переименован в SQL. В 1986 году первый стандарт языка SQL был принят ANSI (American National Standards Institute) и официальным произношением стало "эс-кью-эл" ([,es kju:' el]), или "эс-ку-эль". За все время существования (в процессе развития) у языка было несколько стандартов. В настоящее время действует стандарт, принятый в 2003 году (SQL-3).
Одним из главных достоинств языка SQL является независимость от конкретной СУБД. А это значит, что с помощью SQL-запросов можно получать доступ как к локальным базам данных (DBF-файлы, MS Access и т. д.). так и к "серверным" базам данных (Oracle, Interbase, MS SQL Server и т. д ). используя общий подход в решении задач.
Забегая вперед, отмечу, что в рамках этой части я намеренно не буду касаться вопросов редактирования информации в базе данных 1С (без использования программы I С: Предприятие). Это связано с тем, что модификация информации в рабочей (производственной) базе данных — дело весьма ответственное. Информации, представленной в этой части, достаточно для решения такой задачи. Но инструментарий, ориентированный на такую задачу, должен разработать программист под свою личную ответственность.
Глава 6
Файлы формата DBF
В 1980-е годы широкую популярность приобрела реляционная СУБД dBASE для персональных ЭВМ, созданная небольшой компанией Ashton Tate. Эта же компания предложила простой формат файлов для хранения реляционных таблиц, который получил название DBF. Как показало время, этот формат оказался очень "живучим" и ныне все еще не утратил своей актуальности как один из популярнейших форматов хранения информации при разработке локальных баз данных, а также как универсальный формат (по сути, принятый стандарт) обмена информацией между программными продуктами разных производителей.
Общая информация о DBF-формате
DBF-файл состоит из двух частей:
полный заголовок (описатель структуры таблицы базы данных);
блок информационных записей (собственно таблица базы данных).
Полный заголовок DBF-файла состоит из двух частей:
общий заголовок таблицы (32 байта);
блок описателей (дескрипторов) полей таблицы базы данных (размер каждого описателя — 32 байта).
Полный заголовок DBF-файла имеет размер 32 х (/V + 1) байт, где N — количество полей в таблице базы данных. Полный заголовок DBF-файла отделяется От блока информационных записей терминальным байтом (ASCII-код 13). Файл завершается байтом с ASCII-кодом 26. Таким образом, блок информационных записей в файле начинается с байта номер 32 х (/V + 1) + 1 при условии. что нумерация байтов начинается с нуля.
Примечание
Далеко не все разработчики программного обеспечения следуют тому правилу что терминальный байт должен иметь ASCII-код 13. Очень часто там просто пробел (ASCII-код 32).
Все информационные записи в DBF-файле (строки таблицы базы данных) имеют строго определенный размер. Значения полей таблицы хранятся в ASCII- кодах (по сути, если исключить полный заголовок, это текстовые файлы).
Информационная запись DBF-файла состоит из двух частей:
признак актуальности записи (помечена ли на удаление) — 1 байт;
информационное содержание всех полей (кроме немо и blob) строки таблицы (без каких-либо разделителей).
Как видим, файлы DBF-формата имеют единую (в целом) структуру. Тем не менее, в зависимости от версии заголовки файлов могут отличаться по содержанию.
Рассмотрим структуру DBF-файлов на примере версии dBASE Ш+. В табл. 6.1 приведена структура общего заголовка таблицы базы данных.
Таблица 6.1. Структура общего заголовка таблицы для файлов формата dBASE 111+
Номер байта
Число байт
Назначение
0
1
Признак наличия мемо-поля:
03h— мемо-лоля в таблице нет;
8 3h — в таблице есть мвмо-поле (DBT-файл)
1
3
Дата последнего обновления таблицы в формате YYMMDD:
1-й байт — две младшие цифры года;
2-й байт — месяц;
3-й байт — день
4
4
Количество записей в таблице
8
2
Размер (в байтах) полного заголовка, включая терминальный байт
10
2
Размер информационной записи (в байтах)
12
3
Зарезервированная область
15
13
Зарезервированная область
28
4
Зарезервированная область
Примечание
Далеко не все разработчики программного обеспечения следуют тому правилу, что байт номер 1 (общего заголовка таблицы) должен содержать две младшие цифры года даты последнего обновления файла.
В табл. 6.2 приведена структура описателя поля таблицы базы данных.
Таблица 6.2. Структура описателя поля таблицы базы данных в формате dBASE 111+
Номер байта
Количество байт
Назначение
0
10
Имя поля таблицы базы данных (в ASCII- кодах). Если имя поля короче 11 символов, то "лишние" байты (справа) заполняются нулями
11
1
Тип поля:
С — строка (до 254 символов);
N — число (до 18 символов);
о — дата (8 символов);
L — логическое (1);
и —- МЕМО-поле
12
4
Адрес поля в памяти (ОЗУ). Вероятно, для внутренних целей СУБД, поддерживающих этот формат
16
1
Размер поля (в байтах)
17
1
Количество знаков после запятой (актуально только для полей типа N)
18
14
Зарезервированная область
'-'-В табл. 6.3 приведена структура информационной записи DBF-файла или строки (возможно, только ее части) таблицы базы данных.
'-
'-
Таблица 6.3. Структура информационной записи таблицы базы данных в формате dBASE 111+
Номер байта
Число байт
Назначение
0
1
Признак актуальности записи:
если запись актуальна, то "пробел" (ASCll-код 32, или 20b);
если запись помечена на удаление, то "звездочка" (ASCll-код 42, или 2АЬ)
1
Сумма размеров полей таблицы
Значения полей таблицы (кроме мемо-поля)
Очевидно, что термины "файл в формате DBF" и "таблица в формате DBF" в общем случае обозначают принципиально разные понятия. Например строка таблицы базы данных может быть "распределена" больше, чем в од' ном файле. То есть значения всех полей (кроме мемо) размещены в DBF- файле. а значения МЕмо-полей — в DBT-файле. Ну и индексы, естественно.
Доступ к информации в DBF-файлах
В принципе, приложив определенные усилия, можно написать собственный инструментарий для доступа к информации, хранящейся в файлах формата DBF (без применения пакета BDE или других). Мы не будем здесь останавливаться на этом вопросе.
Примечание
Папка Part_2\Chapter_06\Topic_2\sp_ViewDBF.pas\ на сопроводительном компакт-диске содержит исходные тексты примера простого просмотрщика небольших DBF-файлов.
На рис. 6.1 представлен результат открытия файла SC12.DBF (справочник Физлица) в программе sp_ViewDBF.exe.
I «Г Простой просмотрщик DBF-файлов (dBASE Hit) без BDE-5
Файл
\1С с
‘Kdmple.DBSSCI2 DBF
Нзал
ID
|paren|cod
DESCR|lSFOL|
SMOVERS
SP15
|SP37
SP16
1
1
J7
1
Иванов Иван Иванович 2
18
19710101
2
Россия. Г НвИЗ I
2
2
8
2
Петров П етр Петрович 2
Н
19720101
9
Россия. г.Неиз
3
3
,8
3
Сиаоров Сивор Сборов 2
I
19730101
4
Россия, г Нвиз!
4
4
9
4
Феворов Фавор Фавор' 2
D
19740101
6
Россия. гИэве)
5
5
7
5
Аксакалов Аксакал Акс 2
L
19700101
6
Россия. г.Б.ул*
6
6
0
6
Криогеноаа Фекла Mapi 2
F
19650315
А
Россия. r.N.ye
7
7
0
7
Группа-11
io
Г "
0
8
8
0
8
Группа-2И
.0
0
9
9
■ 0
9
Группа-3П
0
■0
■
< ||
*1 vf-
21
Рис. 6.1. Простой просмотрщик DBF-файлов без использования BDE-5.Открыт файл SC12.DBF (справочник Физлица)
Г Структура DBF-файлаГ Структура DBF-файлаN122 22 еN122 22 еТип Размер ТочностьТип Размер ТочностьНВВ]НВВ]Имяю~ PARENTIDCODE DESCR ISFOLDER ISMARKИмяю~ PARENTIDCODE DESCR ISFOLDER ISMARKС С С с N СС С С с N СVERSTAMP СVERSTAMP С9956411699564116о о о о о о оо о о о о о о
Г Структура DBF-файла
Г Структура DBF-файла
N
1
2
2 2
2 е
N
1
2
2 2
2 е
Тип Размер Точность
Тип Размер Точность
НВВ]
НВВ]
Имя
ю~ PARENTID
CODE DESCR ISFOLDER ISMARK
Имя
ю~ PARENTID
CODE DESCR ISFOLDER ISMARK
С С С с N С
С С С с N С
VERSTAMP С
VERSTAMP С
9
9
5
64
1
1
6
9
9
5
64
1
1
6
о о о о о о о
о о о о о о о
Dale-15.10.2X6 23:3246
File-E :\1 C.exampte. D В \SC12 DBF
Размер полного заголовка-449
Кол-во гтолей=13
Рис. 6.2. Простой просмотрщик DBF-файлов без использования BDE-5. Структура открытого файлаРис. 6.2. Простой просмотрщик DBF-файлов без использования BDE-5. Структура открытого файлаКол-во записей-9
Рис. 6.2. Простой просмотрщик DBF-файлов без использования BDE-5. Структура открытого файла
Рис. 6.2. Простой просмотрщик DBF-файлов без использования BDE-5. Структура открытого файла
Размер записи-197
Номер 1 -го байта информ.блока-442
। На рис. 6.2 представлена структура открытого файла (информация прочитана из полного заголовка DBF-файла).
: В особых случаях такой инструментарий может быть крайне полезен и даже незаменим. Тем не менее, в "обычной" жизни существенно проще (да и на- ' дежнее. пожалуй) использовать уже готовый инструментарий (например, па
кет BDE-5). Хотя бы потому, что при решении главной задачи не придется ' отвлекаться на второстепенные вопросы. Поэтому в данной части мы (для । организации доступа к информации в DBF-файлах) будем опираться на возможности пакета BDE-5.
' Создадим новый Delphi-проект.
Примечание
Исходные тексты проекта sp_1Cv7_Viewer_Tables.DPR находятся на сопроводительном компакт-диске книги в папке \Part_2\sp_1Cv7_Viewer_Tables.PAS\001\.
f На рис. 6.3 представлена форма проекта.
В листинге 6.1 представлен текст обработчика события "нажатие кнопки [ Открыть таблицу".
^а^1^
Рис. 6.3. Форма проекта sp_1Cv7_Viewer_Tables.DPR
procedure TForml. SpeedButtcnlClick (Sender: TObj ect);
// Открытие DBF-файла для просмотра
begin
Query1.Close;
Query1.SQL.Clear;
Label_TableName.Caption:='...' ;
// Проверяем, выбран ли файл для просмотра
if FileListBoxl.ItemIndex>=0 then begin
И
// Формируем SQL-запрос для открытия DBF-фйла
Query1.SQL.ADD('SELECT * ');
Query 1.SQL.ADD('FROM ');
Query 1. SQL .ADD (#39+FileLietBcdtl. FileName+#39) ;
//
//Выполняем SQL-запрос
Query 1. Open;
Label_TableName.Caption: =ExtractFileName (FileListBoxl.FileName) ; end;
end;
Здесь все просто. Если в списке файлов (FileListBoxi) выбран какой-либо DBF-файл, формируется и выполняется стандартный SQL-запрос (команда select). После выполнения запроса на экране визуализируется информация из открытого набора данных.
Если сравнить тексты этого обработчика и программы sp_ViewDBF.EXE (для выполнения одного и того же действия), то видно, насколько проще организовать доступ к информации в формате DBF (и не только) при использовании пакета BDE-5 и соответствующих специальных компонентов из палитры компонентов Delphi.
Создадим еще одну диалоговую форму (рис. 6.4).
Рис. 8.4. Диалоговая форма TDlg_View_Rec для просмотра информационного содержания записи открытого набора данных
Ее назначение — просмотр информации из текущей записи открытого набора данных. Это полезно, если количество полей в открытом наборе данных может быть таким, что неудобно просматривать информационное содержание одной записи в табличной форме. В листинге 6.2 представлен текст метода Execute ЭТОЙ формы.
^®М
function TDlg_View_Rec.execute(Q : TQuery) : boolean; И Визуализация записи открытого набора данных
i : integer; Sx : string; Yes : byte; igin
Result:=FALSE;
ListBoxl.Items.Clear;
if Q.Active then begin // Набор данных открыт для доступа / / ===================================== II Считываем информацию из текущей записи II открытого набора данных for i:=0 to (Q.Field*.Count-1) do begin
И Имя поля
Sx:=Q.Fields[i).FieldName-t-1 =' ;
Yes :=1; // // Проверяем тип поля. // Пропускаем поля следующих типов: // МЕНО if Q.Fields[i].DataType=ftMamo then Yes:=0; // BLOB if Q.Fields[i]. DataType=ftBlob then Yes:=0; II Graphic if Q.Fields[i].DataType-ftQraphic then Yes:=0; И и т.д. // if Yes>0 then begin
II Если "допустимое" поле - считываем значение Sx:=Sx+Q.Fielded].AeString;
end else begin // Если HE "допустимое" поле - пропускаем Sx:=Sx+'3ro поле - не визуализируем';
end;
II Записываем сформированную строку //в свойство Items компонента ListBoxl ListBoxl.Items.Add(Sx);
end; //======================================= // Показываем прочитанную информацию if ShowModal = mrOk then begin
Result:=TRUE;>
end; ListBoxl.Items.Clear; end; end;
ii
i
i
--,'#-VT"";;"™ Л --™™' -y-yvi-) -- --чу-.™;^—~
Листинг 6.3. Вызов метода Execute формы TDlg view Rec
procedure TForml.DBGridlltolClicktSender: TObject);
begin
// Вызываем метод Execute форкы T Dlg_View_Rec
// для визуализации текущей записи открытого набора данных Dlg_View_Rec.Execute(Query1);
end;
Скомпилируем наш проект и запустим его на выполнение. Выберем файл SC12.DBF в каталоге базы данных lC_exarnple.DB, нажмем на кнопку Открыть таблицу и сделаем двойной щелчок левой кнопкой мышки на записи открытого набора данных, у которой значение поля id равно 5 (компонент DBGridi). Результат представлен на рис. 6.5.
Думаю, комментарий здесь не требуется.
Г'ДЙ5Й**ЯРШнх таблиц рВРя-айлоэГ'ДЙ5Й**ЯРШнх таблиц рВРя-айлоэвнивниПросмотр таблиц (dbl) I... * Список таблиц (файлов): “-Содержание таблицы: —' ISTiT Д|Найдите каталогПросмотр таблиц (dbl) I... * Список таблиц (файлов): “-Содержание таблицы: —' ISTiT Д|Найдите каталогSC12.DBF ;SC12.DBF ;w 1 C.example 06w 1 C.example 06f*3 ExlFoimsО NEW.STRUQ SYSLOGf*3 ExlFoimsО NEW.STRUQ SYSLOGP Открывать одним щеА jP Открывать одним щеА jRA52D8F RA78 DBF RG52.DBF RG78.DBFRA52D8F RA78 DBF RG52.DBF RG78.DBFSC137DBFSC144 DBFSC137DBFSC144 DBF.*■.*■iiS®^iiS®^М I 4 I ^ I н I Открыть таблицу [М I 4 I ^ I н I Открыть таблицу [DESCRИванов Иван ИвановичDESCRИванов Иван ИвановичПетров Пет Сидоров Си Федоров Ч Аксакалов Криогенов!Группа-1 Г руппа-2Группа-3Петров Пет Сидоров Си Федоров Ч Аксакалов Криогенов!Группа-1 Г руппа-2Группа-3Г Содержание записи DBF-Ф... ВВЕЗГ Содержание записи DBF-Ф... ВВЕЗID- 5PARENTID- 7CODE- 5DE SCR-Аксакалов Аксакал АксакаловичISFOLDER-2ISMARK-VERSTAMP- LSP15-01.01.1970SP37- 6SPIG-Россия. г.Б, ул.Б.д.00SP29- JSP3O- QSP113-1ID- 5PARENTID- 7CODE- 5DE SCR-Аксакалов Аксакал АксакаловичISFOLDER-2ISMARK-VERSTAMP- LSP15-01.01.1970SP37- 6SPIG-Россия. г.Б, ул.Б.д.00SP29- JSP3O- QSP113-1
Г'ДЙ5Й**ЯРШнх таблиц рВРя-айлоэ
Г'ДЙ5Й**ЯРШнх таблиц рВРя-айлоэ
вни
вни
Просмотр таблиц (dbl) I
... * Список таблиц (файлов): “-Содержание таблицы: —
' ISTiT Д|
Найдите каталог
Просмотр таблиц (dbl) I
... * Список таблиц (файлов): “-Содержание таблицы: —
' ISTiT Д|
Найдите каталог
SC12.DBF ;
SC12.DBF ;
w 1 C.example 06
w 1 C.example 06
f*3 ExlFoims
О NEW.STRU
Q SYSLOG
f*3 ExlFoims
О NEW.STRU
Q SYSLOG
P Открывать одним щеА j
P Открывать одним щеА j
RA52D8F RA78 DBF RG52.DBF RG78.DBF
RA52D8F RA78 DBF RG52.DBF RG78.DBF
SC137DBF
SC144 DBF
SC137DBF
SC144 DBF
.*■
.*■
iiS®^
iiS®^
М I 4 I ^ I н I Открыть таблицу [
М I 4 I ^ I н I Открыть таблицу [
DESCR
Иванов Иван Иванович
DESCR
Иванов Иван Иванович
Петров Пет Сидоров Си Федоров Ч Аксакалов Криогенов!
Группа-1 Г руппа-2
Группа-3
Петров Пет Сидоров Си Федоров Ч Аксакалов Криогенов!
Группа-1 Г руппа-2
Группа-3
Г Содержание записи DBF-Ф... ВВЕЗ
Г Содержание записи DBF-Ф... ВВЕЗ
ID- 5
PARENTID- 7
CODE- 5
DE SCR-Аксакалов Аксакал Аксакалович
ISFOLDER-2
ISMARK-
VERSTAMP- L
SP15-01.01.1970
SP37- 6
SPIG-Россия. г.Б, ул.Б.д.00
SP29- J
SP3O- Q
SP113-1
ID- 5
PARENTID- 7
CODE- 5
DE SCR-Аксакалов Аксакал Аксакалович
ISFOLDER-2
ISMARK-
VERSTAMP- L
SP15-01.01.1970
SP37- 6
SPIG-Россия. г.Б, ул.Б.д.00
SP29- J
SP3O- Q
SP113-1
S- .- i>\.S' pT'-ftrir^rtT-nS- .- i>\.S' pT'-ftrir^rtT-nГбкЦ Cancel |ГбкЦ Cancel |•kS•kS
S- .- i>\.S' p
T'-ftrir^rtT-n
S- .- i>\.S' p
T'-ftrir^rtT-n
ГбкЦ Cancel |
ГбкЦ Cancel |
•kS
•kS
Рис. 6.5. Содержание записи открытого набора данных с ID = 5Рис. 6.5. Содержание записи открытого набора данных с ID = 5
Рис. 6.5. Содержание записи открытого набора данных с ID = 5
Рис. 6.5. Содержание записи открытого набора данных с ID = 5
Глава 7
Обработка словаря базы данных 1С (файл 1Cv7.DD)
В предыдущей главе мы создали простой просмотрщик DBF-файлов, позволяющий визуализировать содержание таблиц баз данных, хранящихся в формате DBF. Но применительно к базам данных 1 С:Предприятие это малоэффективно.
Для того чтобы "расшифровать" информационное содержание таблиц, нужна дополнительная информация. В каждом каталоге базы данных 1С есть текстовый файл 1Cv7.DD (словарь данных), см. рис. 2.22. Посмотрим, каким образом можно использовать его для наших целей.
Откроем файл 1Cv7.DD в любом текстовом редакторе (например, в Notepad). Как видим, описание каждой таблицы представляет собой отдельный блок (см. рис. 2.29). Признаком начала блока может служить строка, начинающаяся с цепочки символов:
#==TABLE ПО
Признаком окончания блока может служить конец файла или строка с единственным символом:
#
Блоки, описывающие таблицы, разделены между собой строками:
#======================================================
Каждый блок можно условно разделить на 3 части (рис. 7.1—7.3).
W--T1BLE по 8: Справочник ФизЛица
«Name |DeacrIType[A/S/U]|DBTableNamelReUaabie
T“SC12 |Справочник ФизЛица|A|SC12|1
Рис. 7.1. Файл 1Cv7.DD. Блок описания таблицы. Описатель таблицы
$—Fields
# Name
|Descr
|Type|Length,Precision
F-ID
1 ID object
IC
19
Ю
F-PARENTID
|ID parent obj
IC
19
Ю
F-CODE
|object code
IC
15
Ю
F-DESCR
|object description
IC
|64
10
F-ISFOLDER
(Flag - Is Line - Fol|N
11
|0
F-ISHARK
(Flag Object is MarkelC
11
10
F-VERSTAMP
|Version stamp
IC
16
Ю
F-3P15
|(P)ДатаРождения
ID
18
10
F-SP37
|(P)ГородПроживания
IC
19
10
F-SP16
|(P)ДомашнийАлрес
|C
|64
|0
F-SP29
| (P) Пол
IC
19
|0
F-SP3O
I (P)СемейкоеПоложение, С
19
|0
F-SP113
|(Р)СостохтВПрофсоюзе|Ц
12
|0,
Рис. 7.2. Файл 1Cv7.DD. Блок описания таблицы. Описатель полей таблицы
# Name
IDescr
I Unique,Indexed fields
| DBName
I-IDD
lot ID
Ю
1 ID
I IDD
I-PCODE
I of PARENT and
,0
| PARENTID, ISFOLDER, CODE (UPPER)
|PCODE
I-PDE3CR
lot PARENT and
Ю
IPARENTID,ISFOLDER, DESCR(UPPER)
|PDE3CR
I-CODE
lot CODE
Ю
I CODE (UPPER)
(CODE
I-DE3CR
lot DESCR
,0
1DESCR(UPPER)
|DESCR
I-VI37
IVI37
,0
ISP37
IVI37
I-VIP37
IVIP37
,0
|PARENTID,ISFOLDER, SP37
IVIP37
Рис. 7.3. Файл 1Cv7.DD. Блок описания таблицы. Описатель индексов таблицы
Интерпретируя описатель таблицы (рис. 7.1), можно извлечь имя таблицы (DBF-файла) ИЗ столбца Name ИЛИ DBTableName, тип и вид (в контексте 1С:Предприятие) обязательно из первой строки описателя. В данном случае: □ имя таблицы (DBF-файла): sci2
О тип: Справочник
О вид (идентификатор): Физлица
Примечание
Столбцом Descr пользоваться ‘опасно* — по той причине, что информация в нем может быть усечена по ширине столбца.
Интерпретируя описатель полей таблицы (см. рис. 7.2), можно извлечь имя Поля таблицы (DBF-файла) из столбца Name и его идентификатор (в контексте 1С:Предприятие) из столбца Descr.
Может оказаться полезной информация о формате этих полей:
тип поля (столбец туре);
длина (столбец Length);
количество знаков после запятой (столбец Precision).
Примечание
Информация в столбце Descr может быть усечена по ширине столбца {рис. 7.4) В этом случае невозможно создать корректное соответствие между полем DBF-файла и его идентификатором в контексте 1С:Предприятие, пользуясь только файлом 1Cv7.DD.
F-VERSTXMP
|Version stampIС
16
Ю
F-SP139
|(P)Реквизит Неопреде|С
|23
10
F-TSP139
1ic
13
10
F-3P140
| (Р)Реквизит Справочн|С
ИЗ
Ю
F-SP141
|(Р)Реквизит Документ!С
ИЗ
Ю
F-SP142
|(Р)Примечание|С
1 64
Ю
Рис. 7.4. Файл 1Cv7.DD. Блок описания таблицы. Описатель полей таблицы. Усеченные идентификаторы
Тем не менее, попытаемся извлечь из файла 1Cv7.DD полезную информацию. Для начала попробуем выделить список таблиц (в данном случае DBF-файлов) базы данных 1 С:Предприятие и создать соответствие между этими таблицами и их идентификаторами в контексте базы данных системы 1С:Предприятие.
Создадим новый Delphi-проект.
Примечание
Исходные тексты этого проекта (sp_1Cv7_DD_01.DPR) находятся на сопроводительном компакт-диске книги в папке \Part_2\Chapter_07\sp_1Cv7_DD_01 .PASI
На рис. 7.5 представлена форма проекта.
Кнопка Открыть 1Cv7.DD предназначена для того, чтобы открыть файл 1Cv7.DD и загрузить его в свойство Lines компонента RichEditi. Кнопка Список таблиц предназначена для того, чтобы создать список таблиц из файла 1Cv7.DD.
Здесь мы не будем углубляться в детали этого процесса. Листинг 7.1 представляет результат интерпретации файла 1Cv7.DD.
Рис. 7.5. Форма проекта sp_1Cv7_DD_01.DPRРис. 7.5. Форма проекта sp_1Cv7_DD_01.DPR
Рис. 7.5. Форма проекта sp_1Cv7_DD_01.DPR
Рис. 7.5. Форма проекта sp_1Cv7_DD_01.DPR
листинг 7.1. Результат интерпретации файла 1Cv7.DD — список таблиц базы* £ №$15Ш®3^^^.
Мстр_в_файле | Мтабл | ИмяТабл | ДескрипторТабл
7 I
0
1SUSERS |
Соединений
16 |
1
1SSYSTEM |
Системная
31 1
2
1SCONST |
Константы1
52 |
3
1SJOURN |
Журналы
80 |
4
1SCRDOC |
Ссыпки документов
97 |
5
1SDNLOCK |
Номеров документов
109 |
6
1SUIDCTL |
Уникальности
121 |
7
1SBLOB |
Длинные строки
135 |
8
SC12 |
Справочник ФизЛица
164 |
9
SC33 |
Справочник СтраныМира
181 |
10 |
SC35 |
Справочник ГородаСтранМира
201 |
11
SC137 |
Справочник
СправочкикСНеопределеннымиРеквизитами
223 |
12 |
SC144 |
Справочник Новый1_Влад
240 |
13 1
SC146 |
Справочник Новый2_Подч
262 |
14 I
SC155 |
Справочник СправПериодРекв
279 |
15 I
DH46 |
Документ ИзменениеСостоянияФизЛиц
292 |
16 I
DT46 |
Документ (Мн.ч.) ИзменениеСостоянияФизЛиц
306 |
17 I
DH88 |
Документ ВыплатыФизЛицам
319 |
18 I
DT88 |
Документ (Мн.ч.) ВыплатыФизЛицам
337 |
19 I
RG52 |
Регистр УчетИэмененийСостоянияФизЛиц
352 |
20
1
RA52 |
| Регистр
(Дв. >
УчетИзмененийСостоянияФизЛиц
373 |
21
1
RG7B
| Регистр
УчетВыплатФизЛицам
390 |
22
1
RA78
| Регистр
(Дв.) УчетВыплатФизЛицам
Доработаем наш Delphi-проект.
Примечание
Исходные тексты этого примера (sp_1Cv7_DD_02.DPR) находятся на сопроводительном компакт-диске книги в папке \Part_2\Chapter_07\sp_1Cv7_DD_02.PASV
На рис. 7.6 представлена форма проекта.
Рис. 7.6. Форма проекта sp_1Cv7_DD_02.DPR
Здесь по нажатию кнопки Список таблиц из открытого файла !Cv7.DD выделяется список таблиц, который размещается следующим образом:
идентификаторы таблиц (в контексте 1С:Предприятие) — в список Список дескрипторов таблиц;
имена таблиц (DBF-файлов) — в список Список таблиц.
Оба списка синхронизированы в том смысле, что если выбирается строка в одном списке, то второй список автоматически позиционируется на соответствующей строке.
По нажатию кнопки Структура таблицы из открытого файла !Cv7.DD вы делается информационный блок, описывающий выбранную таблицу, и ре зультат помещается в свойство Lines компонента RichEdit2 (рис. 7.7).
Рис. 7.7. Информационный блок, описывающий таблицу SC12 (справочник ФизЛица)
1о нажатию кнопки Список таблиц и дескр. из открытого файла !Cv7.DD Создается список таблиц (почти так же, как в предыдущем примере).
Ды не будем разбирать здесь исходные тексты этого проекта по причине тривиальности решения этой задачи.
Глава 8
Доступ к таблицам базы данных с учетом информации в файле 1Cv7.DD
Вернемся к нашему проекту sp_lCv7_Viewer_Tables.DPR (ам. разд. 6.2) и модифицируем его (с учетом обработки файла lCv7.DD).
Примечание
Исходные тексты этого примера находятся на сопроводительном компакт-диске книги в папке \Part_2\sp_1Cv7_Viewer_Tables.PAS\003\.
На рис. 8.1 представлена модифицированная форма проекта.
Рис. 8.1. Форма проекта sp_lCv7_Viewer_Tables.DPR
Здесь, на вкладке Просмотр таблиц 1С, сохранены все возможности, имевшиеся в первоначальной версии проекта. Дополнительно:
на вкладке 1Cv7.DD — содержимое открытого файла !Cv7.DD;
на вкладке Просмотр таблиц 1С с использ. Icv7.dd — просмотр DBF-файлов с учетом информации из файла !Cv7.DD.
При выборе таблицы в списке, из файла 1Cv7.DD выделяется информационный блок (описатель выбранной таблицы), который (после некоторых несущественных преобразований) помещается в свойство Lines компонента RichEdit2. В дальнейшем при открытии таблицы эта информация используется для визуализации дескрипторов полей таблицы.
В листинге 8.1 представлен фрагмент обработчика события "нажатие кнопки Открыть таблицу".
procedure TForml.SpeedButtcn2Click(Sender: TObject); Varprocedure TForml.SpeedButtcn2Click(Sender: TObject); Var
procedure TForml.SpeedButtcn2Click(Sender: TObject); Var
procedure TForml.SpeedButtcn2Click(Sender: TObject); Var
if FileExists(fDBTableName_Full+',dbf') then begin
//
| // Формируем SQL-запрос
//и открываем набор данных
Queryl.SQL.ADD('SELECT • ');
Query1.SQL.ADD('FROM ');
Queryl.SQL.ADD(#39+fDBTableName_Full+#39);
Queryl.Open;
I //
// Создаем переменную, где будем формировать
// список полей DBF-файла и их дескрипторов
// для визуализации
LIstFN:=TStringList.Create;
TRY
// Выделяем дескрипторы (наименования) полей //из фрагмента файла ICvT.DD для данной таблицы if QetFleldNeme_frouulCv7DD(RichEdit2.Lines,
470470Часть II. Доступ к базе данных 1С без программы 1С:ПредприятМе
470
470
ListFN)>0 then begin
И
// Показываем дескрипторы полей
// (наименование в терминах 1С).
// Для этого сканируем список полей открытого
// набора данных Query1 и записываем в свойство
// DisplayLabel соответствующий дескриптор
for i:=0 to (Queryl.Fi aids.Count-1) do
begin
// Выбираем из ListFN дескриптор, соответствующий
// полю DBF-файла с именем FieldName
Sx:=LietFN.VALUES[Queryl.Fields[i].FieldName];
// Записываем дескриптор в свойство DisplayLabel
Query 1.Fields[ i ] .DisplayLabel:=Sx;
end;
//
end;
FINALLY
if ListFNoNIL then begin ,
// Освобождаем ресурсы,
II занятые переменной ListFN
ListFN.Clear;
ListFN.Free;
ListFN:=NIL;
end;
END;
end
else begin
ShowMessage('Файл не найден : '+fDBTableName_Full);
end;
end;
Если сравнить исходные тексты листингов 8.1 и 6.1, то видно: различаются они только тем. что после открытия набора данных (листинг 8.1) из файла 1Cv7.DD считываются дескрипторы полей таблицы (функция GetFieldName_from_lCv7DD* и присваиваются свойству DisplayLabel соответствующего поля.
Назначение функции GetFieidName_from_icv7DD: обработка информационного блока (описателя заданной таблицы) с целью создания списка соответствий между именами полей таблицы и их дескрипторами (в контексте про- граммы 1С:Предприятие). В листинге 8.2 приведен исходный текст этой функции.
function GetFieldName_frcet_lCv7DD(ListInfo, ListFN : TStrings) : integer;
// Выделение дескрипторов (наименований) полей из файла 1CV7.DD:
// Listinfo - описатель таблицы из файла 1CV7.DD (входной параметр),
// ListFN - дескрипторы полей (выходной параметр)
Var
fn,// Имя поля (DBF-файла)
descr : string; // Дескриптор поля (наименование в терминах 1С) i : integer;
Sx : string;
InBlock : byte;
begin
Result:=0;
if bietnioNIL then begin
ListFN.Clear;
। if ListlnfooNIL then begin
InBlock := 0;
i:=-l;
while i<(Listinfo.Count-1) do
begin
i:=i+l;
Sx:=Trim(Lietlnfо[ 1 ]);
if length(Sx)>0 then begin
if InBlock>0 then begin
//Мы внутри блока описателя полей таблицы.
// Теперь анализируем строку
if Sx[l]='Fl then begin
H Эта строка - описатель поля.
И Выделяем имя поля (DBF-файла)
fn := Trim(sp_GetWordFromString('|' , Sx,1));
fn ;= Trim(sp_GetWordFromString(' =1 , fn,2));
// Выделяем дескриптор поля
// (наименование в терминах 1С)
descr := Trim(sp_GetWordFromString(’|’ , Sx,2));
// Сохраняем в списке
List™.VALUES [fn] :=deecr;
end;
end;
if POST Поля таблицы :',Sx)>0 then begin
// Внутри блока (описание полей таблицы)
InBlock:=1;
end;
if POSCИндексы таблицы :',Sx)>0 then begin
H Конец блока (описание полей таблицы)
// Выходим из цикла
InBlock:=0;
i:=(Listinfo.Count+1);
end;
end;
end;
end;
Result:=ListFN.Count;
end;
end;
Здесь следует отметить, ЧТО на ВХОД функции GetFieldName_from_lCv7DD подается не вся информация из файла LCv7.DD, а уже выделенный блок (описатель таблицы) из свойства Lines компонента RichEdit2 (см. рис. 8.1):
if GetFieldName_from_lCv7DD(RichEdit2.Lines, ListFN)>0 then begin
Скомпилируем проект и запустим его на выполнение.
При выборе пункта меню Открыть ICvT.DD (рис. 8.2) нужно найти файл 1Cv7.DD в каталоге (например, lC_example.DB) какой-либо базы данных 1С:Предпритие и открыть его.
.^ Пример работы с т
) Файл
Открыть 1Cv7 DD
Рис. В.2. Пункт меню для выбора файла 1Cv7.DDв каталоге базы данных 1 С: Предприятие
Теперь откроем справочник Физлица и двойным щелчком мыши на строке таблицы с id 5 откроем запись в отдельном окне. Результат представлен на рис. 8.3.
SCI 2SCI 2Открыть таблицуОткрыть таблицуf Информация из Файла 1f Информация из Файла 1Структура таблицеСтруктура таблицеji Поля таблицыji Поля таблицыCancelCancel5033-164 SC35-18I SC137=201 SC144-2235033-164 SC35-18I SC137=201 SC144-22315UIDCTL-109 158108=12115UIDCTL-109 158108=121ЖурналыСсылки документовНомеров документовУникальностиДлинные строкиЖурналыСсылки документовНомеров документовУникальностиДлинные строкиСправочник СтраныМирг Справочник ГородаСтра! Справочник Справочник! Справочник Новый1_Вл!Справочник СтраныМирг Справочник ГородаСтра! Справочник Справочник! Справочник Новый1_Вл!ID ob|ect= 5ID patent ob|= 7object code= 5object description-Аксакапов Аксакал Аксакалович (РЩатаРождения»01.01.1970 (РЩомашнийАдрес=Россия. г.Б. улБ. дОО (Р)ГородПроживания* БFlag ■ Is Line • Fol»2Flag Object is Matke-Version stamp» L (РЩол. J (РРемейноеПоложение» Q (Р)СостоигВПроФсоюзе»1ID ob|ect= 5ID patent ob|= 7object code= 5object description-Аксакапов Аксакал Аксакалович (РЩатаРождения»01.01.1970 (РЩомашнийАдрес=Россия. г.Б. улБ. дОО (Р)ГородПроживания* БFlag ■ Is Line • Fol»2Flag Object is Matke-Version stamp» L (РЩол. J (РРемейноеПоложение» Q (Р)СостоигВПроФсоюзе»1Дескритптор таблищ Имя таблицы : SC1I Я строки в файле КДескритптор таблищ Имя таблицы : SC1I Я строки в файле К■Просмотртаблиц 1С Просмотртаблиц 1Ссиспольз. 1cv7.dd 11Cv7.DD |- Список дескриоторовтабли; Содержание таблицы: -■Просмотртаблиц 1С Просмотртаблиц 1Ссиспольз. 1cv7.dd 11Cv7.DD |- Список дескриоторовтабли; Содержание таблицы: -otjID р|objejobjectdascriptio|(РЩатаРо^(РЩомашнийА|(Р)ГородПрот) jb|494Федоров Феде 01 01.1974Россия, г.Изве6575Аксакалов Акс 01 01.1970Россия. г.Б. ул.6—I606Криогеноеа Фе 15.031965Россия, г.N. улА,|:otjID р|objejobjectdascriptio|(РЩатаРо^(РЩомашнийА|(Р)ГородПрот) jb|494Федоров Феде 01 01.1974Россия, г.Изве6575Аксакалов Акс 01 01.1970Россия. г.Б. ул.6—I606Криогеноеа Фе 15.031965Россия, г.N. улА,|:Найдите каталог |lC_example.DB на этом р Открывать одним щел^Найдите каталог |lC_example.DB на этом р Открывать одним щел^Г Содержание записи DBF-файлаГ Содержание записи DBF-файлаПример работы г? талидами ТС через 8DE-& Прясуотрщи^таблиц {ь данной при BREПример работы г? талидами ТС через 8DE-& Прясуотрщи^таблиц {ь данной при BREРис. 8.3. Содержание записи с значением 5 поля id открытого набора данных с учетом информации из файла 1Cv7.DDРис. 8.3. Содержание записи с значением 5 поля id открытого набора данных с учетом информации из файла 1Cv7.DD
SCI 2
SCI 2
Открыть таблицу
Открыть таблицу
f Информация из Файла 1
f Информация из Файла 1
Структура таблице
Структура таблице
ji Поля таблицы
ji Поля таблицы
Cancel
Cancel
5033-164 SC35-18I SC137=201 SC144-223
5033-164 SC35-18I SC137=201 SC144-223
15UIDCTL-109 158108=121
15UIDCTL-109 158108=121
Журналы
Ссылки документов
Номеров документов
Уникальности
Длинные строки
Журналы
Ссылки документов
Номеров документов
Уникальности
Длинные строки
Справочник СтраныМирг Справочник ГородаСтра! Справочник Справочник! Справочник Новый1_Вл!
Справочник СтраныМирг Справочник ГородаСтра! Справочник Справочник! Справочник Новый1_Вл!
ID ob|ect= 5
ID patent ob|= 7
object code= 5
object description-Аксакапов Аксакал Аксакалович (РЩатаРождения»01.01.1970 (РЩомашнийАдрес=Россия. г.Б. улБ. дОО (Р)ГородПроживания* Б
Flag ■ Is Line • Fol»2
Flag Object is Matke-
Version stamp» L (РЩол. J (РРемейноеПоложение» Q (Р)СостоигВПроФсоюзе»1
ID ob|ect= 5
ID patent ob|= 7
object code= 5
object description-Аксакапов Аксакал Аксакалович (РЩатаРождения»01.01.1970 (РЩомашнийАдрес=Россия. г.Б. улБ. дОО (Р)ГородПроживания* Б
Flag ■ Is Line • Fol»2
Flag Object is Matke-
Version stamp» L (РЩол. J (РРемейноеПоложение» Q (Р)СостоигВПроФсоюзе»1
Дескритптор таблищ Имя таблицы : SC1I Я строки в файле К
Дескритптор таблищ Имя таблицы : SC1I Я строки в файле К
■Просмотртаблиц 1С Просмотртаблиц 1Ссиспольз. 1cv7.dd 11Cv7.DD |
- Список дескриоторовтабли; Содержание таблицы: -
■Просмотртаблиц 1С Просмотртаблиц 1Ссиспольз. 1cv7.dd 11Cv7.DD |
- Список дескриоторовтабли; Содержание таблицы: -
otjID р|objejobjectdascriptio|(РЩатаРо^(РЩомашнийА|(Р)ГородПрот) jb|
494Федоров Феде 01 01.1974Россия, г.Изве6
575Аксакалов Акс 01 01.1970Россия. г.Б. ул.6—I
606Криогеноеа Фе 15.031965Россия, г.N. улА,|:
otjID р|objejobjectdascriptio|(РЩатаРо^(РЩомашнийА|(Р)ГородПрот) jb|
494Федоров Феде 01 01.1974Россия, г.Изве6
575Аксакалов Акс 01 01.1970Россия. г.Б. ул.6—I
606Криогеноеа Фе 15.031965Россия, г.N. улА,|:
Найдите каталог |lC_example.DB на этом р Открывать одним щел^
Найдите каталог |lC_example.DB на этом р Открывать одним щел^
Г Содержание записи DBF-файла
Г Содержание записи DBF-файла
Пример работы г? талидами ТС через 8DE-& Прясуотрщи^таблиц {ь данной при BRE
Пример работы г? талидами ТС через 8DE-& Прясуотрщи^таблиц {ь данной при BRE
Рис. 8.3. Содержание записи с значением 5 поля id открытого набора данных с учетом информации из файла 1Cv7.DD
Рис. 8.3. Содержание записи с значением 5 поля id открытого набора данных с учетом информации из файла 1Cv7.DD
Примечание
Забегая вперед, отметим, что значения поля id (так же, как и значения других полей таблиц базы данных, содержащих ссылки на объекты агрегатного типа, включая объекты метаданных), хранятся в 36-чной системе счисления. Исключение, пожалуй, составляют только ссылки на имена таблиц базы данных (например, поле dnprefix таблицы isjourn, см. далее.
Для сравнения на рис. 8.4 представлено информационное содержание элемента Справочника (открытого в программе 1С:Предприятие), соответствующего ^Данной записи таблицы.
В данном случае (см. рис. 8.3) мы открыли таблицу (DBF-файл), соответствую- (<Цую справочнику Физлица. Если не считать полей типа Строка неограниченной йлины и периодических реквизитов (которые хранятся в отдельных файлах).
474Часть II. Доступ к базе данных 1С без программы 1С:ПредприятПч вся информация из этого справочника содержится в одном DBF-файле Но ситуация существенно усложняется, если речь идет о документах.
Рис. 8.4. Содержание элемента (с кодом 5) справочника ФизЛица (программа 1 С:Предприятие)
Для примера рассмотрим один из документов вида выллатыФизЛииам (номер I. дата 14.07.2006. время 12:00:00).
Запустим программу 1С:Предлриятие и откроем журнал документов (рис. 8.5).
ina-EBai ВЯЗУ
Документ
'Ml
11128.06 06
23:38.42 I
Изменение состояния физ.лиц
tell
з|| 29.06 06
12:26:28
В ьллатыФ изЛ ицам
№1
212.07 06
23:26.40
Изменение состояния физ.лиц
Mi
ЗЙ12.07 06
23:29:02
Изменение состояния физ.лиц
;|eii
■grill 4.07.06
12:00:00
ВыплатыФизЛицам
№1
2gl5.07.06
11:53:53
В ыплагыФ изЛ ицам
Рис. 8.5. Журнал документов, открытый в программе 1С:Прадприятие
Если мы откроем файл 1SJOURN.DBF (соответствует журналу документов) в нашем "просмотрщике" (рис. 8.6), то увидим, что все далеко не так краси как на рис. 8.5.
Соединений
Системная
I Сонет акты
182 1А9 28.06.2006 E2SLKC 461
18 v 3 . 1А J 9 12.07.2006 DYHUK 462
Ссылки докуменп' Номеров докумен; Уникальности ■
Длинные строки
< 1JA; 9 12.07.2006 DZCA8t 463
►
18
5261 14.07.2008 7579С088
18
8 2G1 15.07.2006 730LIK 882
Справочник ФизГ|,
18_ .7 . 2G; 1 29 06.2006 7ENMF. 883
Рис. 8.6. Журнал документов, открытый в программе sp_1Cv7_Viewer_Tables.EXE
В табл. 8.1 приведено соответствие имен полей файла 1SJOURN.DBF (важных с точки зрения идентификации документов) и их дескрипторов из файла ПП
Дескриптор поляИмя поляID DocumentIDDOCdateDATEPrefix Document NoDNPREFIXDocument NoDOCNOДескриптор поляИмя поляID DocumentIDDOCdateDATEPrefix Document NoDNPREFIXDocument NoDOCNOЗначениеПримечание5Идентификатор документа14.07.2006Дата документа88Номер в имени DBF-файла (в нашем случае), соответствует свойству вид документов1Номер документаЗначениеПримечание5Идентификатор документа14.07.2006Дата документа88Номер в имени DBF-файла (в нашем случае), соответствует свойству вид документов1Номер документаТаблица 8.1. Соответствие имен полей файла 1SJOURN.DBF и их дескрипторов из файла 1Cv7.DDТаблица 8.1. Соответствие имен полей файла 1SJOURN.DBF и их дескрипторов из файла 1Cv7.DD
Дескриптор поля
Имя поля
ID Document
IDDOC
date
DATE
Prefix Document No
DNPREFIX
Document No
DOCNO
Дескриптор поля
Имя поля
ID Document
IDDOC
date
DATE
Prefix Document No
DNPREFIX
Document No
DOCNO
Значение
Примечание
5
Идентификатор документа
14.07.2006
Дата документа
88
Номер в имени DBF-файла (в нашем случае), соответствует свойству вид документов
1
Номер документа
Значение
Примечание
5
Идентификатор документа
14.07.2006
Дата документа
88
Номер в имени DBF-файла (в нашем случае), соответствует свойству вид документов
1
Номер документа
Таблица 8.1. Соответствие имен полей файла 1SJOURN.DBF и их дескрипторов из файла 1Cv7.DD
Таблица 8.1. Соответствие имен полей файла 1SJOURN.DBF и их дескрипторов из файла 1Cv7.DD
Теперь откроем документ в программе 1С:Предприятие (рис. 8.7).
Если мы попробуем открыть этот документ в нашем "просмотрщике", то окажется, что это, мягко говоря, сложно сделать, потому что этому виду до- кументов соответствуют две таблицы (т. е. два DBF-файла):
□ DH88.DBF — реквизиты шапки документа и общие реквизиты документов;
О DT88.DBF — реквизиты табличной части документа.
ИомерДок:1
Город:|Вотгоград
: Дат а Док:ll4.07.06
U Комментария !
ФизЛицо
СдммаНа.
СуммаВы...
Вид»ыллат |
СпособВыпяаты
Аксакалов Аксака
1000
10
99С
ЗарПлата
ПоПочте
1__2|АксакаловАксакг
30
1
29
МатПомощь
ПоПочте
1 зЦ Сидоров Сидор Си
300
3
297
Премия
ЧерезБанк
Рис. 8.7. Документ открыт в программе 1 С:Предприятие
Здесь номер 88 в имени DBF-файла соответствует значению поля dnprefIx файла 1SJOURN.DBF (в нашем случае). То есть открывать этот документ придется "по частям" — отдельно каждый файл (что не очень хорошо ддя
пользователя).
Тем не менее, откроем файл DH88.DBF (рис. 8.8).
44Справочник Новый2_Подч Справочник СправЛериоаРекв 1Документ ИзмвмеииеСостоянияФ Шок.Мнч1ИэмвмениеСостоСправочник Новый2_Подч Справочник СправЛериоаРекв 1Документ ИзмвмеииеСостоянияФ Шок.Мнч1ИэмвмениеСостоID Document's] (P)Topoe|(P)Ki»^
4
4
Справочник Новый2_Подч Справочник СправЛериоаРекв 1Документ ИзмвмеииеСостоянияФ Шок.Мнч1ИэмвмениеСосто
Справочник Новый2_Подч Справочник СправЛериоаРекв 1Документ ИзмвмеииеСостоянияФ Шок.Мнч1ИэмвмениеСосто
,р Содержание записи НИВ,р Содержание записи НИВ5
,р Содержание записи НИВ
,р Содержание записи НИВ
55ID Document's* 1
5
5
Документ (Мн ч) ВыплатьФизПии Гр^ороц.4
Регистр УчетИэменемийСостояни! ] 1р)Ког.»иеитарий-
Рис. 8.8. -Шапка- документа вида выплатыФизЛицам(открыта в программе sp_lCv7_Vtewer_Tables.EXE)
ри Id) Do] Linet (Р)Фиэ И 1 ~>р525р533р611626№712р72Бри Id) Do] Linet (Р)Фиэ И 1 ~>р525р533р611626№712р72Бр У чет Изменения вгистр(Дв)УчетИзмен егистр УчетВыплатФизр У чет Изменения вгистр(Дв)УчетИзмен егистр УчетВыплатФизX)1292L2D30032972К2Е1001992J2D2002:1982L20100010990У2В30032972К20X)1292L2D30032972К2Е1001992J2D2002:1982L20100010990У2В30032972К20,П|1Р)С1^маНа11Р)Су^х1|(РХ^^М1000 W 930 21 2D,П|1Р)С1^маНа11Р)Су^х1|(РХ^^М1000 W 930 21 2DСправочник Новый2_Под_ Справочник СпраеПерисб (Документ ИэменениеСос [Документ (Мн ч) Измене акименг ВыллатыФизГСправочник Новый2_Под_ Справочник СпраеПерисб (Документ ИэменениеСос [Документ (Мн ч) Измене акименг ВыллатыФизГКак видим, в этом файле не хранится ни номер документа, ни дата документа. Теперь откроем файл DT88.DBF (рис. 8.9).
ри Id
) Do] Linet (Р)Фиэ И 1 ~>
р
5
2
5
р
5
3
3
р
6
1
1
6
2
6
№
7
1
2
р
7
2
Б
ри Id
) Do] Linet (Р)Фиэ И 1 ~>
р
5
2
5
р
5
3
3
р
6
1
1
6
2
6
№
7
1
2
р
7
2
Б
р У чет Изменения вгистр(Дв)УчетИзмен егистр УчетВыплатФиз
р У чет Изменения вгистр(Дв)УчетИзмен егистр УчетВыплатФиз
X)
1
29
2L
2D
300
3
297
2К
2Е
100
1
99
2J
2D
200
2:
198
2L
20
1000
10
990
У
2В
300
3
297
2К
20
X)
1
29
2L
2D
300
3
297
2К
2Е
100
1
99
2J
2D
200
2:
198
2L
20
1000
10
990
У
2В
300
3
297
2К
20
,П|1Р)С1^маНа11Р)Су^х1|(РХ^^М
1000 W 930 21 2D
,П|1Р)С1^маНа11Р)Су^х1|(РХ^^М
1000 W 930 21 2D
Справочник Новый2_Под_ Справочник СпраеПерисб (Документ ИэменениеСос [Документ (Мн ч) Измене акименг ВыллатыФизГ
Справочник Новый2_Под_ Справочник СпраеПерисб (Документ ИэменениеСос [Документ (Мн ч) Измене акименг ВыллатыФизГ
Рис. 8.9. Табличная масть документов вида в^ы^Лииам(открыта в программе sp_1Cv7_Viewer_Tables.EXE)
Как видим, здесь собраны все строки табличной части всех документов данного вида. То есть нужно фильтровать эту таблицу по идентификатору документа (поле iddoc), чего наш просмотрщик делать еще не умеет.
Таким образом, можно сделать вывод: для того чтобы открыть документ как целостный объект (по аналогии с программой 1С:Предприятие), нужно прочитать информацию, как минимум, из трех DBF-файлов:
□□1SJOURN.DBF — журнал документов (чтобы получить номер и дату до
□
□
кумента);
□□□□DH*.DBF — "шапка" документов (чтобы получить значения реквизитов "шапки" документа и общих реквизитов документов);
□
□
□
□
DT*.DBF — табличная часть документов.
I При этом нужно выполнить следующие действия:
I 1. Открыть файл 1SJOURN.DBF, выбрать интерактивно (или найти по идентификатору) нужный документ и прочитать значения полей dnprefix. DOCNO, DATE И IDDOC.
| 2- Открыть файл DH*.DBF (вместо звездочки должны быть первые 10 символов значения поля dnprefix файла ISJOURN.DBF), найти по полю iddoc соответствующий документ и прочитать значения всех полей записи.
к 3. Открыть файл DT*.DBF (вместо звездочки должно быть значение поля dnprefix файла ISJOURN.DBF), отфильтровать по полю iddoc все записи (строки) соответствующего документа и прочитать значения всех полей из каждой записи (строки).
Г 4. "Расшифровать" значения реквизитов агрегатного типа (в рамках данной главы мы это не рассматриваем).
Внимание!
Поле dnprefix может содержать, например, и такие значения:
"303702002*
" 25943"
Примечание
В любом случае под системный идентификатор вида документа выделены первые 10 символов (включая пробелы).
"На сопроводительном компакт-диске книги в папке \Part_2\sp_lCv7_Viewer_ 1 Tables.PAS\004\ приведены исходные тексты примера, иллюстрирующего 'этот алгоритм открытия документа (в упрощенном виде, естественно). Здесь .мы не будем вдаваться в подробности реализации (кто желает — посмотрит сам) по той причине, что с точки зрения простого считывания информации Из таблиц базы данных с использованием BDE-5 там ничего сложного нет.
с точки зрения "расшифровки" значений реквизитов агрегатного типа (что было бы интересно), там тоже ничего нет.
На рис. 8.10 показан результат визуализации документа ВыплатыФизЛииам С Номером 1 от 14.07.2006.
Здесь следует отметить, что информации, содержащейся в файле 1Cv7.DD, »но не хватает, чтобы корректно выявить тип реквизитов и "расшифровать" Значения реквизитов агрегатного типа (а также получить значения периоди- | Рсских реквизитов). Например, если в справочник Физлица внести еще один
®31к. 1064
реквизит (идентификатор — строкаЭ, тип — строка, длина — 9), то в файле !Cv7.DD это отразится (для файла SC12.DBF) следующим образом:F=SP37реквизит (идентификатор — строкаЭ, тип — строка, длина — 9), то в файле !Cv7.DD это отразится (для файла SC12.DBF) следующим образом:F=SP37| (Р)ГородПроживания |С| (Р)ГородПроживания |СI»I»|0|0F=SP166То естьF=SP166То естьI»I»|0|0|(Р)строк»9|Сневозможно коррею-но различить реквизиты городПроживания (агре-|(Р)строк»9|Сневозможно коррею-но различить реквизиты городПроживания (агре-гатный тип) и строкаЭ (базовый тип) по типу.гатный тип) и строкаЭ (базовый тип) по типу.
реквизит (идентификатор — строкаЭ, тип — строка, длина — 9), то в файле !Cv7.DD это отразится (для файла SC12.DBF) следующим образом:
F=SP37
реквизит (идентификатор — строкаЭ, тип — строка, длина — 9), то в файле !Cv7.DD это отразится (для файла SC12.DBF) следующим образом:
F=SP37
| (Р)ГородПроживания |С
| (Р)ГородПроживания |С
I»
I»
|0
|0
F=SP166
То есть
F=SP166
То есть
I»
I»
|0
|0
|(Р)строк»9|С
невозможно коррею-но различить реквизиты городПроживания (агре-
|(Р)строк»9|С
невозможно коррею-но различить реквизиты городПроживания (агре-
гатный тип) и строкаЭ (базовый тип) по типу.
гатный тип) и строкаЭ (базовый тип) по типу.
НВ В
.Г Содержание документа„^—^^„^^^^„^„„^^^
DH88.DBF
dmdbL——^^
,-Заголовокдокумента: :.■—__———
,||Ойъект-Док^ент ВыплатыФиэПтам
I Номер-1 ; Дата-14 07.2006 I Время-7579СО ' ID Document's- 5 I (Р)Город- 4
I (РЖоммеитарий- ~„^=_— _~—
Рис. 8.10. Документ ВыплатыФизЛицам (с номером 1) от 14.07.2006 (открыт в программе sp_1Cv7_Viewer_Tables.EX )
Глава 9
Дополнительные данные об информационном содержании таблиц, полученные с помощью механизма OLE Automation
В разд. 4.4 мы получили соответствия между идентификаторами значений перечислений и их системными (внутренними) идентификаторами (см. рис. 4.183). Попробуем использовать эту информацию в нашем просмотрщике.
Вспомним, что в программе sp_LoadStructure_lC.exe есть специальная кнопка [^1. предназначенная для сохранения информационной структуры 1С: Предприятие в специальном текстовом INI-файле (описателе структуры). Здесь мы не будем вдаваться в подробности реализации этого алгоритма (желающие могут посмотреть исходные тексты программы). Если открыть результирующий файл lC_example_DB.TXT и найти раздел перечисления- СоответствияЗначений_2, то можно увидеть, что содержание этого раздела (листинг 9.1) может помочь нам при визуализации полей DBF-файлов, значения которых имеют ТИП Перечисление.
[Перечисления_СоответствияЗначений_2]
~Направленность=5уз1В->Ю
>Т=Мужской
^Женский
Н=НикогдаНеСостоялВБраке
К=СостоитВЗарегистрированномБраке
О=СостоитВНеЗарегистрированномБраке р=ГражданскийБрак
О=Разведен
К=Раэошелся
5=Вдовец
13=СотрудникОсновной
14=СотрудникНеосновной
15=ВременноНеРаботает
20=Высокий
21=СХ5ычный
22=Низкий
2В=ЧерезКассу
2Е=ЧерезБанк
2О=ПоПочте
21=ЗарПлата
2 J=Аванс
2К= Премия
2Ь=МатПомощь
Используя эту информацию, можно при визуализации значений полей открытого набора данных (в нашем случае — таблиц из DBF-файлов) "расшифровать" значения полей, соответствующих агрегатному типу Перечисление (в контексте 1С:Предприятие). Проблема в том, что невозможно идентифицировать такие поля, основываясь только на информации из файла !Cv7.DD.
Тем не менее (чисто для иллюстративных целей), попробуем реализовать эту возможность в нашем проекте. Прежде чем визуализировать значение любого поля, которое является реквизитом (справочника, документа или регистра), проверим, присутствует ли это значение среди параметров списка соответствий (листинг 9.1). И если присутствует — предполагаем (в общем случае, необоснованно), что это значение есть Перечисление.
Примечания
Подобный подход категорически недопустим при решении практических задач!
Проверяем, является ли поле таблицы реквизитом, по двум признакам:
если имя поля таблицы начинается с символов sp, это реквизит;
если имя поля таблицы равно value, это реквизит (значение периодического реквизита).ч
То есть так:
if (POSCSP', AnsiUpperCase(Q.Fields[i].FieldName)}=1) or ('VALUE' = AnsiUpperCase(Q.Fields(i).FieldName)) then begin
II Предполагаем, что это реквизит
// (или значение периодического реквизита)
end;
В листинге 9.2 приведен исходный текст функции, возвращающей идентификатор значения перечисления по его системному (внутреннему) значению.
•.---——-™~'—г."-'~-—^
«Листинг 9.2. Функция чтения идентификатора значения перечисления по его :q gmwHWW .идокуфи^РУ. ^ЙЙтНМИ11Ш|^М
function TDlg_View_Record.Decode®nuntValue(sVal : string) : string;
, // Поиск идентификатора значения перечисления
j // по его системному (внутреннему) идентификатору:
।// sVal - системный (внутренний) идентификатор
Const
TopicName = 'Перечислаиия_СоответствияЗначеиий_2';
Var
// fn - имя INI-файла, где находится раздел
И [Перечисления_СоответствияЗначений_2] fn : string;
begin
Result: = '';
sVal:=Trim(sVal);
if length(sVal)>0 then begin
// Имя INI-файла c OLE-структурой
fn:=Trim(Forml.FileName_oleStr) ;
if length(fn)>0 then begin
if FileExists(fn) then begin
II Считываем идентификатор перечисления:
Result:=Trim(sp_GetFrcmINI_StringParain(fn,TopicName,BVal,'')); end;
end;
end;
Id;
апомню, что назначение функции sp_GetFromiNi_stringParam (разрабо- 1нной нами ранее) — считывание информации из INI-файлов.
Примечание
На сопроводительном компакт-диске книги в папке \Par1_2\sp_1Cv7_Viewer_ Tables.PAS\005\ приведены исходные тексты новой версии проекта. Подробно рассматривать эти тексты здесь нет смысла.
482482Часть It. Доступ к базе данных 1С без программы ЮЛредприяпп^ На рис. 9.1 приведен пример визуализации записи из файла SC12.DBF (справочник ФизЛица).
482
482
.. 9.1. Визуализация записи из файла SC12.I.. 9.1. Визуализация записи из файла SC12.I
.. 9.1. Визуализация записи из файла SC12.I
.. 9.1. Визуализация записи из файла SC12.I
|* Содержание записи|* Содержание записиmrwimrwiРис. 9.3. Визуализация записи из файла RA78.DBFРис. 9.3. Визуализация записи из файла RA78.DBF
|* Содержание записи
|* Содержание записи
mrwi
mrwi
Рис. 9.3. Визуализация записи из файла RA78.DBF
Рис. 9.3. Визуализация записи из файла RA78.DBF
На рис. 9.2 приведен пример визуализации записи из файла DT88.DBF (табличная часть документов вида выплатыФиэЛицам).
На рис. 9.3 приведен пример визуализации записи из файла RA78.DBF (движение по регистрам вида УчетВыплатФизЛицам).
ID Document's” 5
LneNo=1
(Р)ФизЛицо» 5
(РРуммаНачислено»! ООО (Р)СуммаУдержано-10 [Р)СуммаВьплачено»990 (Р]ВидВыплат= 21 ■> Зарплата (Р)СпособВыплатЫ” 2D •> ПоПочге
Рис. 9.2. Визуализация записииз файла DT88.DBF
new
Глава 10Глава 10II
Глава 10
Глава 10
I
I
Дополнительные данные об информационном содержании таблиц, полученные из файла 1Cv7.MD
В предыдущих главах мы столкнулись с тем, что для доступа к базам данных 1С (вне контекста программы 1С:Предприятие) не хватает информации из файла 1Cv7.DD, позволяющей корректно вычислять значения реквизитов агрегатного типа. Этот факт делает невозможным создание универсального программного обеспечения, ориентированного на доступ к информационному содержанию баз данных 1С (вне контекста программы 1С:Предприятие).
В разд. 4.4 мы рассматривали возможность считывания информационной структуры базы данных 1С из конфигурационного файла !Cv7.MD.
Примечание
Напомню, что в папках Part_1\Chapter_04\Topic_4_4\ltem_1_4_4\ и \Part_2\sp_ 1Cv7_Viewer_Tables.PAS\006\ на сопроводительном компакт-диске книги находится файл 1Cv7_md_Main_MetaData_Stream.TXT с информацией о структуре, прочитанной из потока Main MetaData Stream файла 1Cv7.MD.
На рис. 10.1 представлен фрагмент информационного содержания файла lCv7_md_Main_MetaData_Stream.TXT.
После экспериментов (с использованием Конфигуратора 1С и программы Read_from_lCv7_MD.EXE), которые может провести любой желающий, и анализа информационного содержания потока Main MetaData stream было j Выявлено следующее: в строках, соответствующих справочникам, количество "членов" = 18 (каждый "член" заключен в двойные кавычки, разделитель — : запятая). Их назначение приведено в табл. 10.1.
("SbCnts",
(*12*,"билЛипа","Пример","Список фижических лиц","О","5","2","2","2","64","1",*1" • ("Регем",
("15","ДетеРомхемих","","Дата рождение","D","О",“0","О","О","0“,"0",“1","О",“0",-j. (■42","Состохние*ихлице","","Состожние фи хлица","X","О","О","38","О","О","1","1",.q ("43" , "КолжоДатей"," " , "Колкчесежо детей","К","10","О","О","0","0","1","1","О","О",. (" 37 "."ГорохПрожхжанил ","•’, "Горох проххжаю«","В","0","0“,“35","0“,"0","0","1","0" ( "16" , "ДомажиихЛхрес" , " " , "Домажний адрес","S","64","О","О","0“,"О","О"."1","О",-Q"' ("29","Пол","","Пол","В","О","О",*17","О","О","О",*1","О","О","1","О","0"), ("30", "СемейкееПоложеиие" , " " , "Семейное полоханхе","I","О","О",“21","О","О",“0","!• ("113","СосаохтВПрофсоюае",“","Состоит ж профсоюзе","К",“1","О","О","О","О","0“,"!• ("31", "ДополмителькедИмформацкд" ,"", “Дополю»альнал ихформепиж","8", "О" , "О","О",“о-
Рис. 10.1. Фрагмент информационного содержания файла1 Cv7_md_Main_MetaData_Stream.TXT
Таблица 10.1. "Расшифровка" строк потока Main MetaData Stream, соответствующих справочникам
Номер “члена” в строке
Назначение
1
Системный идентификатор. Остается постоянным даже при изменении идентификатора (вида) справочника в Конфигураторе 1С
2
Идентификатор (вид) справочника (как он задан в Конфигураторе)
3
Комментарий
4
Синоним
5
Системный идентификатор владельца
6
Длина кода элемента справочника
7
Серии кодов (2 — в пределах подчинения, 1 — во всем справочнике)
8
Тип кода (2 — числовой, 1 —- текстовый)
9
Автоматическая нумерация (2 — да, 1 — нет)
10
Длина наименования элемента справочника
11
Основное представление (1 — в виде наименования, 0 — в воде кода)
12
Редактировать (0 — в списке, 1 — в диалоге, 2 — обоими способами)
13
Количество уровней
14
Системный идентификатор формы списка
15
Системный идентификатор формы списка'
16
Одна форма для элемента и группы (1 — да, 0 — нет)
17
Контроль уникальности (1 — да, 0 — нет)
18
Размещать группы сверху (1 — да, 0 — нет)
В строках, соответствующих реквизитам справочников, количество "членов" — 17. Назначение некоторых из них приведено в табл. 10.2.
Таблица 10.2. "Расшифровка" строк потока Main MetaData stream, соответствующих реквизитам справочников
Номер "члена" в строке
Назначение
1
Системный идентификатор. Остается постоянным даже при изменении идентификатора (или типа) реквизита в Конфигураторе 1С
2
Идентификатор реквизита (как он задан в Конфигураторе)
3
Комментарий
4
Синоним
5
Тип: s — строка N — число в — дата и — неопределенный в — справочник о — документ Е — перечисление т — счет к — субконто р — план счетов с — календарь А — вид расчета
6
Длина (если тип = s, то длина = 0 означает, что это строка неограниченной длины)
7
Число знаков после запятой
8
Если тип агрегатный (и вид определенный), то системный идентификатор (ссылка на соответствующий справочник, документ, перечисление и т. д.)
9
Неотрицательный (1 — да, 0 — нет)
10
Разделять на триады (1 — да, 0 — нет)
11
Периодический (1 — да, 0 — нет)
12
Использовать для элемента (1 — да, 0 — нет)
13
Использовать для группы (1 — да, 0 — нет)
14
Сортировка (1 — да, 0 — нет)
15
Если периодический: ручное изменение (1 — да, 0 — нет)
_16
Если периодический: изменяется документами (1 — да, 0 —нет)
MF1 486MF1 486Часть Й. Доступ кбвэеЧасть Й. Доступ кбвэе■ IC без программы■ IC без программы
MF1 486
MF1 486
Часть Й. Доступ кбвэе
Часть Й. Доступ кбвэе
■ IC без программы
■ IC без программы
В строках, соответствующих документам, количество "членов" — 15. Назна чение некоторых из них приведено в табл. 10.3.
Таблица 10.3. "Расшифровка" строк потока Main MetaData stream соответствующих документам
Номер "члена** в строке
Назначение
1
Системный идентификатор. Остается постоянным даже при изменении идентификатора (вида) документа в Конфигураторе 1С
2
Идентификатор (вид) документа (как он задан в Конфигураторе)
3
Комментарий
4
Синоним
5
Длина номера
6
Периодичность:
0 — по всем документам данного вида
— в пределах года
— в пределах квартала
— в пределах месяца
— в пределах дня
7
Тип номера (2 — числовой, 1 —текстовый)
8
Автоматическая нумерация (2 — да, 1 — нет)
9
Системный идентификатор журнала
11
Контроль уникальности (1 — да, 0 — нет)
13
Оперативный учет (1 — да, 0 — нет)
14
Расчет (1 — да, 0 — нет)
В строках, соответствующих реквизитам "шапки" документов, количество "членов" — 10. В строках, соответствующих реквизитам табличной части документов, количество "членов" — 11. Их назначение приведено в табл. 10.4.
Глава 10. Дополнительные данные об информационном содержании таблиц...487
Таблица 10.4. "Расшифровка"строк потока Main MetaData Stream, соответствующих реквизитам документов
Номер "члена" в строке
Назначение
1
Системный идентификатор. Остается постоянным даже при изменении идентификатора (или типа) реквизита в Конфигураторе 1С
2
Идентификатор реквизита (как он задан в Конфигураторе)
3
Комментарий
4
Синоним
5
Тип: s — строка N — ЧИСЛО □ — дата и — неопределенный в — справочник о — документ Е — перечисление т — счет к — субконто р — план счетов с — календарь А — вид расчета
6
Длина
7
Число знаков после запятой
8
Если тип агрегатный (и вид определенный), то системный идентификатор (ссылка на соответствующий справочник, документ, перечисление и т. д.)
9
Неотрицательный (1 — да, 0 — нет)
10
Разделять на триады (1 — да, 0 — нет)
11
Если это реквизит табличной части, то итог по столбцу (1 — да, 0 —нет)
В строках, соответствующих регистрам, количество "членов" — 8. Назначение некоторых из них приведено в табл. 10.5.
Таблица 10.5. "Расшифровка"строк потока Main MetaData stream, соответствующих регистрам
Номер "члена" в строке
Назначение
1
Системный идентификатор. Остается постоянным даже при изменении идентификатора (вида) регистра в Конфигураторе 1С
2
Идентификатор (вид) регистра (как он задан в Конфигураторе)
3
Комментарий
4
Синоним
5
Тип (0 — остатки, 1 — обороты)
в
Периодичность (м — месяц, Q — квартал, Y — год)
7
Быстрая обработка движения (1 —да, 0 — нет)
В строках, соответствующих измерениям регистров, количество "членов" — 12.
В строках, соответствующих реквизитам регистров, количество "членов" — 11.
В строках, соответствующих ресурсам регистров, количество "членов" — 10. Их назначение приведено в табл. 10.6.
Таблица 10.6. "Расшифровка"строк потока Main MetaData Stream, соответствующих реквизитам (измерениям, ресурсам) регистров
Номер "члена" в строке
Назначение
1
Системный идентификатор. Остается постоянным даже при изменении идентификатора (или типа) реквизита, измерения или ресурса в Конфигураторе 1С
2
Идентификатор реквизита (как он задан в Конфигураторе)
3
Комментарий
4
Синоним
5
Тип:
s — строка
N — число
D — дата
и — неопределенный в — справочник
о — документ
Е — перечисление
т — счет к — субконто р — план счетов с — календарь
А — вид расчета -——^
Таблица 10.6 (окончание)
Номер "члена” в строке
Назначение
6
Длина
7
Число знаков после запятой
8
Если тип агрегатный (и вид" определенный), то системный идентификатор (ссылка на соответствующий справочник, документ, перечисление и т. д.)
9
Неотрицательный (1 — да, 0 — нет)
10
Разделять на триады (1 —да, 0 — нет)
11
Если измерения или ресурсы, то отбор движений (1 — да, 0 — нет)
12
Если измерения, то отбор итогов (1 — да, 0 — нет)
В строках, соответствующих перечислениям, количество "членов" — 4. Их назначение приведено в табл. 10.7.
Таблица 10.7. "Расшифровка* строк потока Main MetaData stream, соответствующих перечислениям
Номер “члена" в строке
Назначение
1
Системный идентификатор. Остается постоянным даже при изменении идентификатора (вида) перечисления в Конфигураторе 1С
2
Идентификатор (вид) перечисления (как он задан в Конфигураторе)
3
Комментарий
4
Синоним
В строках, соответствующих значениям перечислений, количество "членов" — 5. Их назначение приведено в табл. 10.8.
Таблица 10.8. “Расшифровка" Строк потока Main MetaData Stream соответствующих значениям перечислений
Номер "члена” в строке
Назначение
1
Системный идентификатор. Остается постоянным даже при изменении идентификатора значения перечисления в Конфигураторе 1С
2
Идентификатор значения перечисления (как он задан в Конфигураторе)
3
Комментарий
4
Представление
5
Представление
Теперь можно сделать некоторые выводы.
Просмотрев файл lCv7_md_Main_MetaData_Stream.TXT, можно сделать вывод, что все объекты конфигурации 1С:Предприятие имеют сквозную нумерацию системных идентификаторов, которая никак не зависит от типа объекта или его "принадлежности" к другим объектам конфигураци.
Просмотрев файлы !Cv7.DD и lCv7_md_Main_MetaData_Stream.TXT, можно сделать вывод, что все поля таблиц (DBF-файлов), которые являются реквизитами (непериодическими), ресурсами или измерениями (начинаются с символов sp). содержат в имени число, которое однозначно соотносится с системным идентификатором объекта конфигурации 1С (первый "член" в строках файла lCv7_md_Main_MetaData_Stream.TXT).
Если открыть файл 1SCONST.DBF, где хранятся значения периодических реквизитов справочников, и провести определенный анализ, то видно, что значения поля id — это те же системные идентификаторы объектов из файла lCv7_md_Main_MetaData_Stream.TXT, но представленные в 36- ричной системе счисления.
Если открыть файл 1SBLOB.DBF, где хранятся значения реквизитов типа Строка неограниченной длины, то точно такие же выводы (как и с периодическими реквизитами) можно сделать относительно значений поля FIELDID.
Все значения полей, имеющих тип перечисление, так же однозначно соотносятся с системными идентификаторами объектов конфигурации 1С и тоже представлены в 36-ричной системе счисления.
Примеры:
В табл. 10.9 представлены реквизиты справочника Физлица, созданные в разное время. Очевидно, что системные идентификаторы были присвоены им в порядке очередности, наряду с другими объектами конфигурации.
Таблица 10.9. Реквизиты справочника Физлица
Реквизит
Системный идентификатор
Представление в 36-ричной системе счисления
Имя поля в файле SC12.DBF
ДатаРождения
15
F
SP15
СостояниеФизлица
42
16
—
КолвоДетей
43
17
—
ГородПроживания
37
11
SP37
ДомашнийАдрес
16
G
SP16
Пол
29
Т
SP29
СемейноеПоложение
30
и
SP30
СостоитВПрофсоюзе
113
35
SP113
ДополнительнаяИнформация
31
V
—
В табл. 10.9 показано соответствие полей файла SC12.DBF (который соответствует справочнику Физлица) и системных идентификаторов реквизитов справочника Физлица.
В табл. 10.10 показано соответствие значений поля id файла 1SCONST.DBF (значения периодических реквизитов справочников) и системных идентификаторов реквизитов СостояниеФизлица и КолвоДетей (представленных в Зб-ричной системе счисления).
Таблица 10.10. Периодические реквизиты и реквизиты типа
Строка неограниченной длины справочника ФизЛица
Реквизит
Системный идентификатор
Представление в 36-ричной системе счисления
Значение поля то в файле 1SCONST. DBF
Значение поля
FIELDID в файле 1SBLOB.DBF
СоетояниеФизлица
42
16
16
—
КолвоДетей
43
17
17
—
ДополнительнаяИнформация
31
V
—
V
В табл. 10.10 показано соответствие значений поля fieldid файла 1SBLOB.DBF (значения реквизитов типа Строка неограниченной длины) и системного идентификатора реквизита ДополнительнаяИнформацИя
(представленного в Зб-ричной системе счисления).
В табл. 10.11 показано соответствие системных идентификаторов значений перечислений (представленных в Зб-ричной системе счисления) и значений полей DBF-файлов.
Таблица 10.11. Соответствие системных идентификаторов значений перечислений (представленных в 36-ричной системе счисления) и значений полей DBF-файлов
Значение перечисления
Системный идентификатор
Представление в 36- ричной системе счисления
Файл, поле, значение
Пол.Мужской
19
J
SC12,
SP29, J
Пол.Женский
20
к
SC12, SP29, К
СемейноеПоложение.Разведен
26
Q
SC12, SP3 0, Q
СостояниеФизлица’. СотрудникОсновной
39
13
DT46, SP51, 13
ВидВыплатФизЛицам.МатПомощь
93
2L
RA78, SP103, 2L
СостояниеФизлица.ВременноНеРаботает
41
15
1SCONST, VALUE, 15 (ДЛЯ
ID = 16)
Попробуем использовать полученную выше информацию для наших целей.
Рассмотрим процесс визуализации DBF-файлов (не путать с объектами базы данных 1С). Алгоритм визуализации значений полей открытых DBF-файлов может быть следующим (кроме файлов 1SBLOB.DBF и 1SCONST.DBF):
Считывается значение очередного поля, имя которого начинается с символов SP.
F.-«' Г
Глава 10. Дополнительные данные об информационном содержании таблиц... 493
Из имени поля выделяется его системный идентификатор (как объекта 1С).
Определяются Тип и вид объекта (информация из !Cv7.MD).
Если тип вазовый — значение визуализируется.
Если тип Агрегатный, то вычисляется значение (в зависимости от типа) и визуализируется.
Алгоритм визуализации значений поля value файла 1SCONST.DBF:
Считывается значение поля id (системный идентификатор в 36-ричной системе счисления).
Считывается значение поля value (значение реквизита).
Значение поля id конвертируется в десятичную систему счисления.
Определяется Тип и Вид объекта (информация из !Cv7.MD).
Если тип Базовый — визуализируется значение поля value.
Если тип Агрегатный, то вычисляется значение (в зависимости от типа) и визуализируется.
С визуализацией файла 1SBLOB.DBF (реквизиты типа Строка неограниченной длины) дело обстоит иначе. Сначала должен быть задан соответствующий реквизит справочника, значение которого визуализируется, и выбран элемент справочника, для которого визуализируется значение реквизита. Затем устанавливается соответствующий фильтр. Фильтр формируется с учетом того, что системный идентификатор реквизита должен быть преобразован из десятичной системы счисления в Зб-ричную. Набор данных сортируется по полю blockno, информация (значение поля block) выбирается поочередно, начиная с первой записи набора данных, и объединяется в одной переменной (соответствующего типа).
Удобства ради (и упрощения для) сведем информацию о структуре базы данных из файлов !Cv7.DD и lCv7_md_Main_MetaData_Stream.TXT в единый файл, по структуре подобный INI-файлу. Из файла !Cv7.DD будем использовать список таблиц (DBF-файлов) и список полей для каждой таблицы (листинг 10.1).
[ТАБЛИЦЫ)
18С0М5Т=Константы
15ВЬОВ=Длинные строки
.8С12=Справочник ФизЛица
ОН88=Документ ВыплатыФизЛицам
ОТ88=Документ (Мн.ч.) ВыплатыФизЛицам
КС78=Регистр УчетВыплатФизЛицам
RA78=Регистр (Дв.) УчетВыплатФизЛицам
[SC12]
ID=1
PARENTID=1
CODE=1
DESCR=1
ISFOLDER=1
ISMARK=1
VERSTAMP=1
SP15=1
SP37=1
SP16=1
SP29=1
SP30=l
SP113=1
Список таблиц нужен для того, чтобы уже не обращаться к файлу !Cv7.DD при визуализации списка таблиц в приложении.
Список полей по каждой таблице нужен для того, чтобы можно было достаточно быстро контролировать наличие некоторых полей, которые могут участвовать в вычислении значений объектов агрегатного типа, но иной раз отсутствуют. Например, поле descr (в файлах SC*.DBF) соответствует свойству Наименование элементов справочников. Иной раз (хоть и редко) оно может отсутствовать. Можно, конечно, в INI-файле проверять значение параметра длинаНаименования для объекта, соответствующего этому имени файла (таблице). Если значение равно нулю, то свойство Наименование у элементов справочника отсутствует. Но список полей таблиц может быть полезен (попутно) и для других целей. Например, для визуализации имен столбцов. В этом случае формат строки может быть таким:
8Р15=Дата рождения
Из файла !Cv7_md_Main_MetaData_Stream.TXT будем использовать все объекты (справочники, документы, регистры, реквизиты, ресурсы, измерения и т. д.), которые представляют интерес с точки зрения извлечения и визуализа-
Гпава 10. Дополнительные данные об информационном содержании таблиц... 495 иии информации из базы данных. Каждому объекту будет соответствовать отдельный раздел INI-файла (листинг 10.2):
[17]
Идентификатор=Пол ЧтоЭто=Перечисление ИдентификаторСистемный=17 ИдентификаторСистемныйЗб=Н Синоним=Пол
119]
Идентификатор=Мужской ЧтоЭто=ЗначениеПеречисления Родитель=17
ИдентификаторСистемный=19 ИдентификаторСистемныйЗ6=J Синоним=Мужской
[12]
Идентификатор=ФизЛица ЧтоЭто=Справочник(ТаблицаБД) ИдентификаторСистемный=12 ИдентификаторСистемныйЗб=С Синоним=Список физических лиц Тип=Справочник
Вид=ФизЛица
КоличествоУровней=2 ДлинаКода=5
СерииКодов=2
ТИпКода=2
ДлинаНаименования=64 0сновноеПредставление=1
[42]
Кдентификатор=СостояниеФизлица
ЧтоЭто=РеквизитСправочника(ПолеТаблицыВД)
Родитель=12
ИдентификаторСистемный=42
ИдентификаторСистемныйЗ6=16
Синоним=Состояние физлица
Периодический=1
Тип=Перечисление
Вид=38
Длина=0
Точность=0
Неотрицательный^
РазделятьНаТриалы=О
Сортировка=0
РучноеИзменение=1
ИзменяетсяДокументами=1
Теперь, наконец, приступим к программированию. За основу возьмем наш предыдущий проект (удалив из него все лишнее).
Примечание
Исходные тексты этого примера находятся на сопроводительном компакт-диске книги в папке \Part_2\sp_1Cv7_Viewer_Tables.PAS\006\.
Прежде чем программировать доступ к базе данных 1С, нужно сформировать INI-файл, где будет храниться объединенная структура базы данных (листинг 10.2).
Извлечение списка таблиц (DBF-файлов) и их полей из файла 1Cv7.DD мы подробно рассмотрели в главе 8 и здесь на этом останавливаться не будем. А вот выделение нужной информации из файла !Cv7_md_Main_MetaData_ Stream.TXT (рис. 10.1) полезно будет затронуть подробнее.
Строки такого формата проще всего, пожалуй, обрабатывать с помощью свойства commaText Delphi-объекта TStrings. В листинге 10.3 приведен исходный текст функции, реализующей этот способ.
function ep_Convert_SDF_to_List(Sx : string; List : TStrings) : integer;
// Разделение строки Sx (a SDF-формате) на составляющие:
// List — результат (в каждой строке списка — отдельный "член") begin
Result:=0;
end;end;;end;;end;Result:='';if ListoNIL thenResult:='';if ListoNIL thenif ListoNIL then begin
end;
end;
;end;
;end;
Result:='';
if ListoNIL then
Result:='';
if ListoNIL then
List.Clear;
Sx: =sp_AlITrimUnChar CO, ' , Sx) ;
if length(Sx)>0 then begin
List. ConenaText: =Sx;
end;
Result:=List.Count;
Назначение функции sp_AUTrimUnChar — удаление не-символов из строки слева и справа. Текст ее прост и здесь не приводится.
В дальнейшем удобно считывать значения "членов" (согласно их назначению, см. табл. 10.1—10.8) из списка TStrings с помощью простой функции (листинг 10.4).
function GetValueKronList (NuznParam: integer; List : TSTrings) : string; // Считывание иформации из списка (по номеру параметра):
4/ NumParam - номер // List — результат for
Index : integer; in
"члена" (начиная с 1), функции sp_Convert_SDF_to_List"члена" (начиная с 1), функции sp_Convert_SDF_to_ListbeginbeginIndex: =NumParem-l ;
"члена" (начиная с 1), функции sp_Convert_SDF_to_List
"члена" (начиная с 1), функции sp_Convert_SDF_to_List
begin
begin
if (lndex>=0) and (Index<List.Count) then begin Result:=Trim (List[Index]);
end;
end;
ример использования:
f sp_Canvert_SDF_to_List(Sx, List&i£)>0 then begin // Считываем значение свойства "Длина кода // элемента справочника" справочника
SI:=GetValueFronLiet(6, 1Л BtBuf);
VI:=sp_StrTo!nt(SI,0) ;
ListINI.ADD(' ДпинаКода='+IntToStr(VI));
Здесь после считывания строки, соответствующей справочнику, вызывается функция sp_convert_SDF_to_Lisc. Затем из списка ListBuf считывается (согласно табл. 10.1) значение свойства Длина кода элемента справочника (функция GetValueFromList).
Для удобства обработки (и большей наглядности) файлы такого формата (см. рис. 10.1) можно преобразовать в "дерево" с помощью символов табуляции (рис. 10.2).
{•SbCnt»“,
("12*,"ФихЛице*,"Пример*,“Списох фивичесжих лиц",*0*,"5*,*2","2*,"2*,*64* {•Per ем",
{"15","ДатяРождехих",■•,"Дате рождения”,*D*,"О",“0“,"0"," (“42" , "СостолкиеФизлиця" ,*", "Состояние фивлица" ,”1",*0*,* ("43","КолвоДетей","",*Количество детей","Я","10","0","0" ( *37",*ГорохПроживания",*","Горох проживания","В","0","0* ("16","ДомажнийАлрес","“,"Домажкий адрес","3","64","0","0 (*29*,*Пол*,* *,*Пол*,*1*,"0*,*0*,*17*,"0*,*0*,*0*,*1*,"0* (•30* , ‘СемейкоеПоложекие", *" , "Семейное положение”,"I”,"0" ("ИЗ", "СостоитВПрофсоюве* ,"*, "Состоит в профсоюзе","Я"," ("31*,"ДополнителвкаяИнфорхания",**,"Дополнительная инфор:
("Рога*,
(*13*,•♦ормаСписка",**,**))),
("33","СтряныНира","","Стряим мира",*0*,*S","2*,"2","2*.*64",*1*,*0",*1", ("Рагамв"), ("Роге",
(*34","ФормаСписха" ,"’,""))>,
Рис. 10.2. Фрагмент информационного содержания файла1Cv7_md_Main_MetaData_Stream.TXT в виде "дерева"
В листинге 10.5 приведен исходный текст функции, реализующей это преобразование.
function »p_Convert_Info_fr«n_lCv7MD_To_TreeText(
List_lCv7MD : TStrings) : integer;
// Преобразование информации из потока Main MetaData Stream
//в виде "дерева" (не нарушая структуры строк):
U List_lCv7MD - входной и выходной параметр
// (содержание файла !Cv7_pici_MairOIetaData_Stream.TXT)
Var
CountTab, // Номер уровня иерархии i : integer;
SI.
Sx : string;
List : TStrings;
>egin
Result:=0;
if List_lCv7MD<>NIL then begin
if List_lCv7MD.Count>0 then begin
// Создаем буферную переменную
Liat:=TStringList.Create;
TRY
CountTab:=-l;
for i:=0 to (List_lCv7MD.Count-1) do begin
Sx:=Trim(List_lCv7MD(i]);
Sl:=Sx;
И Определяем, сколько в строке слева символов "{", II и увеличиваем уровень иерархии для текущей строки CountTab:=CountTab * ap_GetCountCharInString(SI,ORD('{'));
// Смещаем вправо (согласно уровню иерархии)
Sx:=ap_Append_Tab_to_StrlngLeft(Sx,CountTab);
Liet.Md(Sx) ;
II Определяем, сколько в строке всего символов *}", // и уменьшаем уровень иерархии для следующей строки CountTab:=CountTab - ap_QetCountCharInString(SI,ORD(')')); Application.ProcessMessages;
end;
II Возвращаем результат преобразования
List_lCv7MD.Assign(List);
Result:=List.Count;
FINALLY
II Освобождаем ресурсы
if ListoNIL then begin
List.Clear;
List.Free;. ,ri,
List:=NIL;
end;
EMD;
end;
end;
end;
Идея проста. Если в строке встречается символ {, то нужно сдвинуть всю текущую строку вправо на один знак табуляции (следующий уровень иерархии). Если в строке встречается символ ), то нужно сдвинуть всю следующую строку влево на один знак табуляции (предыдущий уровень иерархии).
В листинге 10.6 приведены тексты функций sp_GetCountCharInString И sp_Append_Tab_to_StringLeft.
function ep_GetCountCharInString(Sx : string; CodeChar : byte) : integer; // Подсчет символов с ASCII-кодом CodeChar в строке
Var
i : integer;
begin
Result:=0;
if length(Sx)>0 then begin
i:=0;
while i<length(Sx) do
begin
i:=i+l;
if ORD(Sx[i])=CodeChar then begin
Result:=Result+l;
end;
end;
end;
end;
r
function »p_Append_Tab_to_StringLeft(Sx : string;
CountTab : integer) : string;
// Добавление в начало строки заданного числа символов табуляции
Var
i : integer;
begin
Result:=Sx;
if CountTab>0 then begin
for i:=l to CountTab do
begin
Result:=#9+Result;
end;
end;
end;
В результате преобразования информационного потока Main MetaData stream (файла 1Cv7.MD) на первом уровне иерархии (один знак табуляции в начале строки) оказываются такие узлы "дерева", как:
— константы
("SbCnts", (•Registers", ("Documents", ("EnumList*,("SbCnts", (•Registers", ("Documents", ("EnumList*,— справочники
("SbCnts", (•Registers", ("Documents", ("EnumList*,
("SbCnts", (•Registers", ("Documents", ("EnumList*,
— регистры
— документы
— перечисления
| и др. По сути, это агрегатные типы данных (в контексте 1С).
Дочерними узлами (относительно перечисленных выше узлов) на следующем уровне иерархии (два знака табуляции в начале строки) оказываются объек- ты, представляющие собой виды указанных выше агрегатных типов данных. То есть это списки справочников, регистров, документов, перечислений). :Каждый вид (объектов) тоже является узлом "дерева". Он включает в себя разделы информации (три знака табуляции в начале строки). И, наконец, ка- |Ждый раздел (как узел "дерева") включает в себя "листья дерева" (четыре |знака табуляции в начале строки).
"Листьями дерева" являются, например:
;О реквизиты справочников и документов;
р измерения, ресурсы и реквизиты регистров;
О значения перечислений.
Схематично это отражено на рис. 10.3—10.6.
Теперь для обработки "дерева" (после преобразования информационного потока Main MetaData stream из файла !Cv7.MD) легко можно разработать роотвстствующий алгоритм выделения нужной информации.
502
Часть II. Доступ к базе данных 1С без программы 1С:Предприятие
Уровень иерархии
1234
CSbCirts",:•
;Справочник-1 irPaiams".
;Реквизит-1 справочника-1
^Реквизит- 2 справочника-1
;Справочник-2
•{"Params",
;Реквизит-1 справочника-2
::-Реквизит-2 справочника-2
Уровень иерархии
1234
Рис. 10.3. Ветвь "дерева" от узла {"SbCnts", (справочники)
{"Documents". :
! Документ-1
'{"Head Fields",
:РеквизитШапки-1 документа-1
:РеквизитШапки-2 документа-1 iCTable Fields",
;РеквизитТабЧасти-1 документа-1
:РеквизитТабЧасти-2 документа-1
•Документ-2
({-Head Fields",
::РеквизитШапки-1 документа-2
:РеквизитШапки-2 документа-2 iCTable Fiekls",
'РеквизитТабЧасти-1 документа-2
•РеквизитТа6Части-2 документа-2
Уровень иерархии
1234
C’Reyisters",
: Регистр-1 ;
i {"Props",
'Измерение-1 регистра-1
:Измерение-2 регистра-1
:'{"Figures",
:Ресурс-1 регистра-1
'Ресурс-2 регистра-1
iCFkls",
• Реквизит-1 регистра-1
'Реквизит-2 регистра-1
Регистр-2 ;
if'Props",
; ;Измерение-1 регистра-2 :Измерение-2 регистра-2
iCHgures",
;Ресурс-1 регистра-2
■Ресурс-2 регистра-2
i{"Flds",
: Реквизит-1 регистра-2
'Реквизит-2 регистра-2
Рис. 10.4. Ветвь "дерева" от узла {"Registers ", (регистры)
ной
Рис. 10.5. Ветвь "дерева" от узла {"Documents ", (документы)
Уровень иерархии 1234
CEiHimLisf. :
'Перечисление-1 ifbiiimVaF,
'Значение-1 перечисления-1
'Значение-2 перечисления-1
'Перечисление-2
'{"EnumVal",
'Значение-1 перечисления-2
'Значение-2 перечисления-2
Рис. 10.6. Ветвь "дерева" от узла ("EnumList ", (перечисления)
преооразования значения системного идентификатора из десятич
системы счисления в 36-ричную можно использовать функцию 5P_Convert_IntlO_to_Another(листинг 10.7).
| Листинг 10.7. Перевод целого числа из десятичной системы счисления *вдругую с основанием [2 .36],
function sp_Convert_IntlO_to^Another(vlO : cardinal;
BaseAnother : integer) : string;
И Перевод десятичного целого числа vlO в систему счисления
//с основанием BaseAnother.
// Функция возвращает представление числа
//в заданной системе счисления
Var
vFrac : integer; М Остаток по модулю (основание)
vFracStr : string;// Строковое представление остатка
begin
Result: = ' ' ;
if (BaseAnother>l) and (BaseAnother<=36) then begin
repeat
vFrac:=vlO MOD BaseAnother; II vlO-(vlO div BaseAnother)‘BaseAnother vlO:=vlO DIV BaseAnother; // trunc(vlO/BaseAnother)
if vFrac>9 then begin
// Это буква латинского алфавита
vFracStr:=CHR(ORD('A')-10+vFrac)
end
else begin
// Переводим остаток в строковое представление
STR(vFrac,vFracStr);
end;
Result:=Result+vFracStr;
until vl0=0;
// Инвертируем результат
Result:=sp_Inversionstring(Result);
end;
end;
По сути, функция sp_Convert_intiO_to_Another — это аналог функции _idTostr программы 1С:Предприятие, которую мы использовали вразд. 4.4. Для обратной конвертации (из Зб-ричного представления в десятичное) можно использовать функцию sp_Convert_IntAnother_to_10 (ЛИСТИНГ 10.8).
Йистинг 10.8. Перевод целого числа из системы счисления [ с основанием [2 .. 36] в десятичную_
№J^pgJ^£C
function ep_Convert._Int*nothar_to_10(vhnother : string;
BaseAnother : integer) ; cardinal;
//
Перевод целого числа (vAnother) из системы счисления BaseAnother
//
в десятичную систему.
И
Функция возвращает представление числа
ь
в десятичной системе счисления.
var
i : integer;
Res, ValNum : integer;
begin
Result:=0;
if (BaseAnother>l) and (BaseAnother<=36) then begin vAnother:=Trim(vAnother);
if length(vAnother)>0 then begin
vAnother:=AnsiUpperCase(vAnother);
for i:=l to length(vAnother) do
begin
И Конвертируем текущий символ в число
VAL(vAnother[i],ValNum,Res);
if ResoO then begin
// Если это не число, считаем, что это буква латинского алфавита, // и вычисляем по позиции
ValNum:=10+ORD(vAnother[i])-ORD('А') ;
end;
// Вычисляем соответствующую степень и суммируем
Result:= Result+sp_XpowerN(BaseAnother,length(vAnother)-i)WalNum;
end;
end;
end;
в листинге 10.9 представлены тексты вспомогательных функций.
ir 10.9. Вспомогательные функции для перевода числа из одной
^ЖМ^.^Ь;.i^r^j;: ■1
Eunction sp_Invereionstring(Sx : string) : string;
// Функция инвертирует строку
Var
i : integer;
begin
Result:=Sx;
if Length(Sx)>0 then begin
Result:=*';
for i:=Length(Sx) downto 1 do begin
Result:=Result+Sx[ i);
end;
end;
end;
function ep_XpowerN(X, N :integer ):cardinal; // X в степени N
var
i : integer;
begin
Result:=1;
for i:=l to N do begin
Result:=Result*X; end;
end;
Примеры вызова:
перевести число 20 из десятичной системы счисления в 36-ричную: ShowMessage(ep_Convert_Intl0_to_*nother(20,36));
перевести число 21 из Зб-ричной системы счисления в десятичную:ShowMessage(IntToStr(ep_Convert_IntAnothar_to_10('211,36)));
В листинге 10.10 представлен исходный текст функции, реализующей обра ботку информационного потока Main MetaData Stream ИЗ файла 1Cv7.MD-
! Л И СТИН г 10.10. Обработка информации лотока Main к. t aD.
^*Й’Ж®ей:^^
f unccion ep Kxtract.Info_fcoclICvTMD(List_lCv7MD, ListINI : TStrings) : integer;
// Выделение нужной информации из файла lCv7jnd_Main_MetaData_Stream.TXT:
// List_lCv7MD - входной параметр
// (содержание файла lCv7_jnd_Main_MetaData_Stream.TXT).
// ListINI - результат (INI-структура)
begin
Result:=0;
if List_lCv7MD<>NIL then begin
if List_lCv7MD.Count>0 then begin
if ListINIoNIL then begin
// Преобразуем в "дерево*
sp Cccivert lnfo f rcm lCv71<D_To TreeText (List_lCv7MD) ;
II Выбираем константы
■p_>ctiane_for_Conets(List_lCv7MD, ListINI);
i
ll Обрабатываем раздел DocNumDef
■p^Actione_for_DocNumDef(List_lCv7MD, ListINI) ;
// Выбираем общие реквизиты документов
ep_Actiane_far_GenJrnlFldDef(List_lCv7MD, ListINI);
// Выбираем и обрабатываем перечисления
ep_Actione_far_Enwxie (List_lCv7MD, ListINI) ;
И Выбираем и обрабатываем справочники
■p^Actions_for_SbCnts(List_lCv7MD, ListINI);
// Выбираем и обрабатываем документы sp_*ctian«_for_Docun>ente(List_lCv7MD, ListINI);
11 Выбираем и обрабатываем регистры
■P_>ctions_for_R*Bist»re(List_lCv7MD, ListINI);
end;
end;
end;
end;
Назначение функций:
o sp_convert_lnfo_from_lCv7MD_To_TreeText — конвертация информационного потока Main MetaData Stream;
sp_Actions_for_Consts — обработка ветви дерева от узла {"Consts",;
sp_Actions_for_DocNumDef — обработка ветви дерева ОТ узла ("DocNumDef-,;
sp_Actions_for_GenJrnlFldDef — обработка ветви дерева от узла
("GenJrnlFldDef“,;
sp_Actions_for_Enums — обработка ветви дерева от узла {"EnumList•,;
sp_Actions_for_sbCnts — обработка ветви дерева от узла {"Sbcnts",;
sp_Actions_f or_Documents — обработка ветви дерева от узла {"Documents ”,;
sp_Actions_for_Registers — обработка ветви дерева от узла ("Registers",.
Примечание
Исходный текст функции sp_Convert_Info_from_lCv7MD_To_TreeText представлен в листинге 10.5. Исходные тексты других функций здесь не при- водтся по причине их "громоздкости", а также тривиальности в реализации вышеуказанных алгоритмов. Желающие могут посмотреть тексты этих функций в файлах исходных текстов Delphi-проекта в папке \Part_2\sp_1 Cv7_Viewer_ Tables.pas\006\ на сопроводительном компакт-диске книги.
В иллюстративных целях мы ограничились обработкой только некоторых узлов информационного потока Main MetaData stream. В реальных условиях может возникнуть необходимость использования дополнительной информации из потока.
Здесь следует коснуться некоторых вопросов вычисления значений полей таблиц (DBF-файлов) как значений объектов 1С (с точки зрения их визуализации). Как отмечалось в главе 9, поля таблиц, имена которых начинаются с символов SP, являются реквизитами (измерениями, ресурсами) справочников, документов, регистров. Точно так же интерпретируется поле value таблицы 1SCONST.DBF (значения констант и периодических реквизитов справочников). Кроме этого, в таблицах SC*.DBF (справочники) могут присутствовать поле parentid (соответствует "родителю" элемента справочника, если справочник иерархический) и поле parentext (соответствует владельцу элемента справочника, если у справочника есть владелец). Для всех этих полей при визуализации необходимо соответствующим образом вычислять значения.
Для вычисления значений полей таблиц (DBF-файлов), начинающихся с символов sp, может быть принят, например, такой алгоритм;
Из имени поля удаляются первые 2 символа. Оставшиеся символы — это системный идентификатор соответствующего объекта 1С.
2. По системному идентификатору из INI-файла (структура базы данных) считываются тип и вид объекта.
Г 3. Если тип объекта — Базовый, то значение поля просто визуализируется "как есть".
4. Если тип объекта — Агрегатный, то значение вычисляется с учетом вида объекта.
5. Если тип объекта — Неопределенный, то значение вычисляется по специальным правилам.
[ Для вычисления значений полей, соответствующих агрегатному типу Пере- F числение, можно воспользоваться прямым считыванием параметра Синоним К(из INI-файла) для заданного системного идентификатора (значения поля 1DBF-файла) с предварительной конвертацией значения поля из 36-ричной $ системы счисления в десятичную:
1.1.I idSys:=IntToStr(sp_Convert_IntAnother_Co_10(ЗначениеПоля,36)) ; tsValueEnum : = sp_GetFromINI_StringParam(fnINIstr,idSys,'Синоним',‘'); u Для вычисления значений полей, соответствующих агрегатному типу Спра- вочник, может быть принят такой алгоритм:
1.
1.
По системному идентификатору объекта (значение поля записи таблицы, преобразованное из Зб-ричной системы счисления в десятичную) из INI-файла считывается параметр вид (это системный идентификатор соответствующего справочника).
По значению параметра Вид вычисляется имя таблицы (DBF-файла):
TableName := 'SC + ЗначениеПараметраВид + '.dbf
3. Проверяется, имеется ли в таблице TableName поле descr (имя элемента справочника). Для этого используется список полей таблицы (см. листинг 10.1).
Если поле descr существует, то формруется SQL-запрос для таблицы TableName:
I SELECT
DESCR
FROM
1ИмяТаблицы или ПолноеИмяДВУФайла'
WHERE
П)='Значение поля’
В листинге 10.11 приведен текст функции GetsbcntName, возвращающей имя Элемента справочника по его системному идентификатору.
Р3«к 1064
ЕЛйстинг 10.11. Функция oetSbcutName, возвращающая имя элемента ^справочника ^^.....
function GetSbCntName(fnINI,idKindlO,idSbCnt36 : string) : string;
// Получение имени элемента справочника: // fnINI - имя файла с INI-структурой, Н idKindlO - системный идентификатор (вид) справочника II(десятичная система счисления),
И idSbCnt36 - системный идентификатор элемента справочника //(Зб-ричная сист.счисления)
Var sFilter, I! Фильтр fnTable, // Имя таблицы Sx : string; begin Result:='' ;
idKindlO:=Trim(idKindlO) ;
if (length(Trim(idKindlO))>0) and (length(Trim (idSbCnt36))>0) then begin
II Проверяем наличие поля DESCR в таблице 1SC'+idKindlO
Sx:= sp_GetFromINI_StringParam(fnINI,'SC1+idKindlO,'DESCR', * 0 ’ >;
if Trim(Sx) = '1' then begin
// В этом справочнике есть поле DESCR
И
// Вычисляем имя таблицы (DBF-файла) - справочника fnTable: ='SC1+idKindlO*1.dbf';
fnTable:=ExtractFilePath(fnINI)+fnTable;
fnTable:=#39+fnTable+#39;
// // // Формируем фильтр sFilter:=,ГО=';
sFilter:=sFilter+#39+idSbCnt36+#39;
// Выбираем наименование элемента справочника
I/ из таблицы(DBF-файла)
Sx:=ep_QetrieldValue_TableDB('',fnTable,'DESCR',sFilter, 1 *);
Result:=Trim(Sx);
end
else begin
//В этом справочнике НЕТ поля DESCR Result: ='DESCR not found1;
end;
end;
end;
В листинге 10.12 представлен исходный текст функции, возвращающей значение заданного поля заданной таблицы базы данных с помощью приведенного выше SQL-запроса.
И1ИСТИНГ 10,12. функция GetFleldValue_frc=LTableDB, возвращающаяi j
Значение заданного поля заданной таблицы базы данных:
function QetFioldValue_fratuTebleDB(AliasName,
TableName, FieldName, sFilter, sSort : string) : string;
■// Получение значения заданного поля из заданной таблицы
К/ для заданного фильтра sFilter:
V/ AliasName - Alias из BDE-5 (может быть пустым),
7/ TableName - имя таблицы (может быть именем DBF-файла,
«/в этом случае заключается в кавычки),
FieldName - имя поля, значение которого возвращается,
У/ sFilter - фильтр (если по фильтру будет найдено несколько записей, ^/то функция возвращает значение поля первой записи),
7/ sSort - список полей для сортировки (через запятую) Var
0 : TQuery;
Yes : byte;
begin
Result:='';
, Tabi eName: =Tr im (TableName) ;
FieldName: =Trim( FieldName) ;
SFilter:=Trim(sFilter) ;
SSort:=Trim(sSort);
AliasName:=Trim(AliasName);
if Length(TableName)>0 then begin
if Length(FieldName)>0 then begin
Yes := 0;
Q := TQuery.Create(Nil);
TRY
if QoNIL then begin
Q. Da tabaseName: =A1 iasNante ;
Q.SQL.ADDt'SELECT 1+WleldName);
Q.SQL.ADD('FROM ');
Q.SQL.ADD(TableName);
if length(sFilter)>0 then begin Q.SQL.ADDt'WHERE ');
Q. SQL. ADD (BWilter);
end;
if length(sSort)>0 then begin Q.SQL.ADDt'ORDER BY ') ;
Q.SQL.ADD(sSort) ;
end;
Q.Open;
Q.riret;
Remit: =Q. Wield* [ 0 ] . AsString ;
Yea := 1;
end;
FINALLY
if QoNIL then begin
Q.Close;
if Yes<=0 then begin
// Если попытка открыть набор данных завершилась ошибкой, //то выводим соответствующее сообщение ShowMessage('Err: SQL= '+Q.SQL.Text);
end;
Q.SQL.Clear;
Q.Free;
Q:=NIL;
end;^
END;
end;
end;
end;
Пример вызова:
idParent:='Т ;
' TableName:=#39+'E:\lC_exainple.DB\SC12.DBF1+#39;
sFilter:='ID='+#39+idParent+#39;
sValue:=Trim(GetFieldValue_fxxxn_TableDB('',
TableName,
'DESCR',
sFilter, "));
, Для вычисления значений полей, соответствующих агрегатному типу Доку- 1 мент, можно просто сформировать SQL-запрос к таблице 1SJOURN.DBF I (журнал документов), фильтруя по полю iddoc и прочитав значения полей | docno (номер документа) и date (дата документа). Вид документа (если нуж- i но) можно вычислить, используя следующий алгоритм:
L 1. Считывается значение поля dnprefix из таблицы 1SJOURN.DBF.
2. Из значения поля dnprefix выделяются первые 10 символов (включая пробелы). Затем начальные и конечные пробелы удаляются. Это будет системный идентификатор вида документа (как объекта метаданных).
3. Из INI-файла для этого системного идентификатора считывается параметр Синоним.
В листинге 10.13 приведен текст функции GetDocName, возвращающей имя документа по его системному идентификатору.
| function Extract_KindDoc_from_DNPREFIX(DNPREFIX : string) : string;■ // Выделение из префикса документа/ / системного идентификатора его вида:I// DNPREFIX - значение поля DNPREFIX из журнала документов сbeginResult:=DNPREFIX;System.Delete(Result, 11,255);| function Extract_KindDoc_from_DNPREFIX(DNPREFIX : string) : string;■ // Выделение из префикса документа/ / системного идентификатора его вида:I// DNPREFIX - значение поля DNPREFIX из журнала документов сbeginResult:=DNPREFIX;System.Delete(Result, 11,255);
| function Extract_KindDoc_from_DNPREFIX(DNPREFIX : string) : string;
■ // Выделение из префикса документа
/ / системного идентификатора его вида:
I// DNPREFIX - значение поля DNPREFIX из журнала документов сbegin
Result:=DNPREFIX;
System.Delete(Result, 11,255);
| function Extract_KindDoc_from_DNPREFIX(DNPREFIX : string) : string;
■ // Выделение из префикса документа
/ / системного идентификатора его вида:
I// DNPREFIX - значение поля DNPREFIX из журнала документов сbegin
Result:=DNPREFIX;
System.Delete(Result, 11,255);
I end;
»function GetDocName (fnDJI, idDoc36 : string) : string;
|// Получение имени документа из журнала документов:
|М|М1// fnINI - имя файла с INI-структурой,
|М
|М
II idDoc36 - системный идентификатор документа
II(36-ричная сист.счисления.)
Var
sFilter, idKind : string; fnTable : string; ListRes : TStrings;
begin
Result: = ' ' ;
if length(Trim(idDoc36))>0 then begin if Trim(idDoc36)<>'0' then begin ListRes := TSTringList.Create;
TRY
// I/ Название документа выбираем 11 из таблицы журнала документов fnTable:='1SJOURN'+'.dbf';
fnTable:=ExtractFilePath(fnINI)+fnTable; fnTable:=#39+fnTable+#39;
//
II // Формируем фильтр SFilter:='IDDOC=';
sFilter:=sFilter+#39+idDoc36+#39;
H
11 Читаем информацию из журнала документов ep_getRec_TableDB('',fnTable,' *',sFilter, 1'.ListRes); // Выделяем код вида документа из префикса документа idKind:=ListRes-VALUES('EKPREFIX'];
idKind: =Extract_KindDoc_fran_ENPREFlX(idKind) ;
// // Формируем имя документа Result: = 'N';
Result:=Result+' ' +Trim(ListRes.VALUES['DOCNO'));
Result:=Result+' ['+Trim(ListRes-VALUES!'DATE'])+']'; 11 Читаем из INI-файла ‘Синоним" вида документа Result := Result
+ Trim (ер_GetFronINI_StringParam( fnINI, Trim(idKind), 1 Синоним',''));
i "
FINALLY
if ListRes<>NIL then begin
ListRes.Clear;
ListRes.Free;
ListRes :=NIL,• end;
END;
end;
end;
’end;
Текст функции sp_GetRec_TableDB приведен в листинге 10.14.
(истине 10.14азы данных(истине 10.14азы данныхI. Функция, возвращающая значения заданных полей таблицы . J
(истине 10.14азы данных
(истине 10.14азы данных
■££l£^^~^^^-да; ’^.^ дЫ^^.^Жз
[function sp_GetRecTableDB(AliasName,TableName,FieldNames, sFilter, sSort : string; ListRes : TStrings) : integer;
Ц Получение списка значений заданных полей из заданной таблицы
/ для заданного фильтра sFilter:
!/ AliasName - Alias из BDE-5 (может быть пустым), // TableName - имя таблицы (может быть именем DBF-файла, У/в этом случае оно заключается в кавычки),
// FieldNames - имена полей,
Г/ sSortV ListResГ/ sSortV ListRes- фильтр (если в наборе данных больше, чем одна запись,то значения полей возвращаются из первой), - список полей для сортировки, - здесь возвращаются значения полей записи таблицы.
Г/ sSort
V ListRes
Г/ sSort
V ListRes
7 Функция возвращает размер списка ListRes 'аг
Q : TQuery;
Yes : byte;
i : integer;
egin
516Часть II. Доступ к базе данных 1С без программы 1С:Предприятие
Result:=0;
if ListResoNIL then begin
ListRes.Clear;
TableName: =Trim (TableName);
FieldNames:=Trim(FieldNames) ;
if length (FieldNames) <=0 then FieldNames : = '*'; sFilter:=Trim(sFilter);
sSort:=Trim(sSort);
AliasName: =Trim(AliasName) ;
if Length (TableName) >0 then begin
Yes := 0;
Q := TQuery. Create (Nil)*;
TRY
if QoNIL then begin
Q. Da tabaseName: =A1 iasNanie ;
Q.SQL.ADD('SELECT *+FieldNamee);
Q.SQL.ADD('FROM ');
Q. SQL. ADD (TableName) ;
if length(sFilter)>0 then begin
Q.SQL.ADD('WHERE ');
Q.SQL.ADD(eFllter);
end;
if length(sSort)>0 then begin
Q.SQL.ADD('ORDER BY ');
Q. SQL. ADD (eSort) ;
end;
Q.Open;
11 Позиционируемся на первой строке открытого Hat. :-а данных
Q. First;
//
Н Читаем значения полей записи открытого набора данных
for i:=0 to (Q.Fields.Count-1) do
begin.<
ListRes.ADD(Q.Fields [i].FieldName+ * = * +Q-Fields [i] .AsString); end; //
Result:=ListRes.Count;
Yes := 1;
Глава ю, Дополнительные данные об информационном содержании таблиц...Blf
end;
FINALLY
if QoNIL then begin
Q.Close;
if Yes<=0 then begin
// Если попытка открыть набор данных завершилась ошибкой, И то выводим соответствующее сообщение ShowMessage (* Err: SQL= ' +Q. SQL. Text) ;
end; •
Q.SQL.Clear;
Q.Free;
Q:=NIL;
end;
END;
end;
end;
end;
Для вычисления значений поля parentid таблиц (DBF-файлов), если справочник иерархический, может быть принят, например, такой алгоритм:
Проверяется, существует ли в этой же таблице (значение поля которой мы вычисляем) поле descr (наименование элементов справочника):
Sx: = sp_GetFromINI_StringParam (fnINIs tr, TableName, ’ DESCR', 101);
if Sx= '1' then begin
// Поле DESCR существует end;
Если поле descr существует, то формруется SQL-запрос для этой же таблицы:
SELECT
DESCR
FROM
* ИмяЭтойТаблицы или ПолноеИмяПВГФайла'
WHERE
TD='Значение поля PARENTID'
На рис. 10.7 представлен результат визуализации записи файла SC12.DBF (что соответствует элементу справочника Физлица).
На рис. 10.8 представлен результат визуализации записи файла RA78.DBF (регистр УчетВыплатФизЛицам).
Рис. 10.7. Визуализация записи файла SC12.DBF (справочник ФизЛица)
Рис. 10.8. Визуализация записи файла RA78.DBF (регистр УчетВыплатФизЛицам)
Для вычисления значений поля parentext таблиц (DBF-файлов), если у справочника есть владелец, может быть принят, например, такой алгоритм:
Из имени этой же таблицы (для которой вычисляется значение поля parentext) выделяется системный идентификатор соответствующего объекта (справочника).
По системному идентификатору справочника из INI-файла (структура базы данных) считывается значение параметра Владелец объекта (там хранится системный идентификатор владельца для данного справочника).
По системному идентификатору владельца вычисляется имя таблицы- владельца (DBF-файла):
tnOwner: = * SC1 + 1СистемныйИдентификаторВладельца’ +'.dbf1
Проверяется, существует ли в таблице (у владельца) поле descr (имя элемента справочника-владельца):
Sx:= sp_GetFrc«TiINI_StringParain(fnINIstr, tnOwner,'DESCR',10');
if Sx='1' then begin
// Поле DESCR существует end;
Если поле descr существует, то формруется SQL-запрос для таблицы tnOwner:
SELECT
'• DESCR
FROM
'ИмяТайлицыВладельца'
WHERE
ID='Значение поля PARENTEXT'
На рис. 10.9 представлен результат визуализации записи файла SC35.DBF (поле Владелец).
Ы Содержание записи DB F-... №13
Таблица: SC35
-Показать значения:
/* 06ьектов(1С) <• Полей и Объектов С Полей
Г Всеполятаблицы Г" Имена полейЮ= " 3 > 3'———•Код= 3Наименавание=УсинекВлаоелец= 1 -> РоссияГ Всеполятаблицы Г" Имена полейЮ= " 3 > 3'———•Код= 3Наименавание=УсинекВлаоелец= 1 -> Россия
Г Всеполятаблицы Г" Имена полей
Ю= " 3 > 3'———•
Код= 3
Наименавание=Усинек
Влаоелец= 1 -> Россия
Г Всеполятаблицы Г" Имена полей
Ю= " 3 > 3'———•
Код= 3
Наименавание=Усинек
Влаоелец= 1 -> Россия
Для периодических реквизитов можно использовать следующий алгоритм:
По системному идентификатору заданного периодического реквизита вычисляется его представление в Зб-ричной системе счисления:
idSye36:=ep_Convert_IntlO_to_Another(sp_SCrToInt(idSys,01,36);
Значение переменной idsysз6 дополняется слева нужным количеством пробелов (в нашем случае должно быть всего 4 символа).
Считывается значение поля id таблицы (справочника) из записи, соответствующей элементу idobj36 справочника, для которого фильтруются значения периодического реквизита.
Значения периодического реквизита idSys36 для значения поля id выбираются следующим образом:
SELECT
VALUE
FROM
'ПолныйПутьКФайлу\18СОЫЗТ.dbf'
WHERE
OBJID='iddbj36‘
AMD
ID='idSye361
На рис. 10.10 представлен результат визуализации записи файла 1SCONST.DBF (значение периодического реквизита справочника).
Для вычисления значений объектов неопределенного типа (а также значений типа Справочник неопределенного вида и документ неопределенного вида) придется применять дополнительные меры.
Рис. 10.10. Визуализация записи файла 1SCONST.DBF (значение периодического реквизита справочника)
В табл. 10.12 приведены примеры сравнения того, как значения заданы в контексте 1 С: Предприятие и как они отражены в DBF-файлах.
Таблица 10.12. Реквизиты неопределенного типа и/ипи вида
Тип реквизита
Тип (вид) значения
Значение в контексте 1С
Значение поля DBF-файла
Неопределенный
N 10.2
999.01
N 999.01
Неопределенный
S
Тип S длина=22 END
ЭТип S длина=22 END
Неопределенный
D
24.09.2006
D20060924
Неопределенный
Справочник. ФизЛица
Элемент справочника с кодом 6, системный идентификатор 6
Bl С6
Неопределенный
Неопределенное
Нет значения
и
Неопределенный
Документ.
ВыйлатыФизЛицам
Номер 3 от 29.06.2006, системный идентификатор 7
01 2G7
Неопределенный
Перечисление.
ВидВыплатФизЛицам
МатПомощь
El 2Н2L
Справочник неопределенного вида
ГородаСтранМира
Элемент справочника с кодом 3, системный идентификатор 3
23
Справочник неопределенного вида
Неопределенный
Нет значения
00
Документ неопределенного вида
ВыплатыФизЛицам
Номер 1 от 14.07.2006, системный идентификатор 5
2G5
Документ неопределенного вида
Неопределенный
Нет значения
00
Небольшой анализ позволяет сделать следующие выводы.
Для реквизитов неопределенного типа:
первый символ в значении поля обозначает тип объекта (к — число s — строка, в — справочник, о — документ, е — перечисление, d — дата и — неопределенный и т. д.);
если посмотреть формат поля (файл 1Cv7.DD), то видно, что его длина равна 23, тип — строка (независимо от хранящихся данных): это значит (как отмечалось в разд. 4.7.7), что максимальная длина значения реквизита, которое можно записать в это поле, 22 символа (независимо от типа данных);
значения всех объектов базового типа (кроме даты) можно визуализировать явно (то, что прочитали из поля), удалив первый символ; для объектов типа дата нужно дополнительно конвертировать дату из числового формата YYYYMMDD в ее строковый эквивалент ДД.ММ.ГПТ;
символ и в начале строки — это отсутствие значения.
Для всех объектов агрегатного типа:
второе слово в значении (разделитель слов — символ пробела) — это системный идентификатор вида объекта в Зб-ричной системе счисления;
третье слово в значении — это системный идентификатор соответствующей ссылки в Зб-ричной системе счисления (для справочника — это значение поля id соответствующей таблицы; для документа — значение поля iddoc соответствующей таблицы; для перечисления — системный идентификатор соответствующего значения).
Для реквизитов типа справочник или документ неопределенного вида:
если посмотреть формат поля (файл !Cv7.DD). то видно, что его длина равна 13, тип — строка (независимо от хранящихся данных);
первое слово в значении поля (разделитель слов — символ пробела) — это системный идентификатор вида объекта в Зб-ричной системе счисления;
второе слово в значении — это системный идентификатор соответствующей ссылки в Зб-ричной системе счисления (для справочника — это значение поля id соответствующей таблицы; для документа — значение поля iddoc соответствующей таблицы);
если оба слова = ■ о*, то это отсутствие значения (строка символов * о о-)- Все это справедливо и для периодических реквизитов (таблица isconst).
В приницпе, с учетом вышеизложенного алгоритм вычисления значений для реквизитов неопределенного типа (вида) напрашивается сам собой и весьма
навязчиво. Думаю, что не следует останавливаться здесь на этом подробнее (кто желает может посмотреть исходные тексты на сопроводительном компакт-диске книги).
В таблице isconst есть поле tvalue (рис. 10.11).
OBJID|lD (DATE
(RARTNO (VALUE '
[DOCID ITIME lATTNIl iucun-|n>«<
2TZ 4KB 31 122002
0 1B
—i^^^'^p^c |ными I UNt NO | TVALUE °000
2 2TZ 4КС 31 122002
0 E1 518 LT9
000n 1
2TZ 4KD 31.122002
0 B1 408 32
иUI
000n 1
н 2TZ 4КЕ 31.122002
0 В14KT AS
VиU I
0QПn 1
_ 2TZ 4KI 30121833
0 6.70
000о
2TZ 4KI 31.08.2000
0 6.70
0 : оо о
_ 2TZ 4KI 01.05.2001
0 6 70
0 оо0
|J 2TZ 4KN 01,01,2002
0 1.0
000o’
Рис. 10.11. Поле tvalue таблицы isconst
Это поле принимает значение *1" в тех случаях, когда периодический реквизит неопределенного типа (по метаданным) принимает определенное значение агрегатного типа (поле value). Если реквизиту назначен агрегатный тип, но не назначен вид, то значение поля tvalue = "О". В остальных случаях (из наблюдений) поле содержит три пробела.
ввначале имени поля.начале имени поля.Аналогично, для каждого реквизита (поля, начинающиеся с символов -sp") неопределенного типа (в справочниках, документах) в таблице присутствует поле, имеющее такое же имя, но с символом "Т"
в
в
начале имени поля.
начале имени поля.
Пример 1:
|о(о|о(оF-SP139|(Р)Реквиэит_Неопреде|с 123
|о
(о
|о
(о
F=TSP139 ||С |3
Пример 2 (рис. 10.12):
F=SP2857|(Р)ВидСтатус|с|23|0
F=TSP2857||С|3|0
__ /
На рис. 10.13 представлен результат визуализации записи файла SC2543
(справочник ДвиженияРегистров).
На рис. 10.14 представлен результат визуализации значения периодического
реквизита неопределенного типа (файл 1SCONST.DBF).
часть и. ^иишуи л иемы ионные -с ^ ир^рьммы 1Q.< vwiipuHmue
Рис. 10.12. Реквизит неопределенного типа видСтатус справочника ДвиженияРегистровРис. 10.12. Реквизит неопределенного типа видСтатус справочника ДвиженияРегистров
Рис. 10.12. Реквизит неопределенного типа видСтатус справочника ДвиженияРегистров
Рис. 10.12. Реквизит неопределенного типа видСтатус справочника ДвиженияРегистров
SP2538
|8Р253Э|5Р2857
|TSP2857|SP2541
ПартииОтданные
Е1 98
2ТА 11AU
ПартииНаличие
♦Е1 98
2TD 11AU
ПартииОтданные
Е1 98 и
2TD 11AU
0
ПартииНаличие
♦Е1 98
2ТВ 1.150
ПартииНаличие
♦Е1 98
2TD 1150
Покупатели
Е1 ВО
81 1150
Рис 10.13. Визуализация записи файла SC2543.DBF(справочник ДвиженияРегистров). Реквизит неопределенного типа
И Содержание записи DB . HIED
Таблица: 1SC0NST.
Показать значения;"~ —
С 06ьектоо(1С) <• Полей и Объектов;
Полей .3
•Г Е'-.е ।►.wте(:ЙА» . Г" Имена поле
ID объекта- 3UC ■> Принтер HP U 1100
Ю= 4KD •> Субконго 2
Значение-81 4КТ 87 ■> Руководство
Дата-31 12.2002->31.12.2002
Рис. 10.14. Визуализация значения периодического реквизитанеопределенного типа
Как мы увидели в части 11, при разработке универсального программного обеспечения (для доступа к базам данных 1С без программы 1 С:Предприятие) существенно возрастают "накладные расходы" по созданию инструментария (библиотек), ориентированных на "расшифровку" информационной структуры базы данных, с целью поддержки объектной модели хранения информации. принятой в системе 1С:Предприятие. В общем случае это может стать существенным ограничением для использования механизма SQL-запросов к базам данных 1С. То есть при выборе способа обмена информацией с 1С (OLE Automation или SQL-запросы) нужно следовать здравому смыслу в каждом конкретном случае и выбирать механизм доступа, наиболее эффективный для решения прикладной задачи.
Совсем другое дело, если нужно разработать программное обеспечение, ориентированное на узкую задачу и конкретную информационную структуру базы данных 1С. В этом случае можно создать эффективный инструментарий достаточно быстро и просто. В следующей главе мы рассмотрим именно такой случай на конкретном примере.
Примечание
Напомню, что представленные примеры исходных текстов — это упрощенная иллюстрация к рассматриваемым вопросам. Назначение этих примеров — дать представление о возможном подходе при решении задач информационного обмена с системой 1С:Предприятие. При работе с реальными базами 1С может потребоваться их дальнейшая доработка.
113». 1064
Глава 11
Остатки ТМЦ на складах.
Пример
Товарно-материальные ценности (ТМЦ) — это часть большой группы активов (материально-производственных запасов или МПЗ) предприятия. В процессе хозяйственной деятельности предприятия его работники используют предметы труда и средства труда. Предметы труда (материалы) — это сырье, топливо, материалы, тара, запасные части, инвентарь, материальные ценности, полученные от выбытия основных средств, и т. д. ТМЦ на предприятии группируются в систематизированный номенклатурный справочник, где каждому виду материалов соответствует отдельный номенклатурный номер. Номенклатурный номер используется в дальнейшем для отражения наличия конкретного материала и его движения на предприятии. Поступление ТМЦ на предприятие может происходить разными способами (приобретение, безвозмездное получение, изготовление, разборка ликвидированных основных средств и т. д.). Для хранения ТМЦ на предприятии создаются должным образом оборудованные склады, кладовые или специально приспособленные площадки. Хранение ТМЦ на складах организуется таким образом, чтобы была обеспечена возможность их быстрой приемки, отпуска и проверки наличия. В целом, учет ТМЦ на предприятии (в частности, хранение) — это очень сложный и трудоемкий процесс, реализованный в комплексной конфигурации 1С:Предприятие определенным образом. В этой главе мы на конкретном примере рассмотрим вопросы получения информации о движении и остатках ТМЦ на складах с использованием SQL-запросов к базе данных 1С в простейшей реализации.
В контексте комплексной конфигурации 1С:Предприятие учет остатков ТМЦ на складах предприятия организован с использованием регистра Остаткитми. На рис. 11.1 представлена структура этого регистра.
Попробуем создать простой инструментарий, который позволил бы получить остаток (а также движение за период) ТМЦ на заданную дату в разрезе склада, с применением механизма SQL-запросов к базе данных 1С.
@ Щ) ОстаткиТМЦEi У Измерения
—I Фирма
-л Номенклатура
—1 Склепj : м ЦенаЛрой£ й Ресурсы
I ы Ко/ычество
В •- Реквизиты
■'■ ■ Внутрететее
Рис. 11.1. Структура регистра ОстаткиТМЦ
Примечание
Не думаю, что в данном случае нужно оговаривать такие нюансы, как "получить ли остаток на дату или по дату", поскольку это важно с точки зрения бухучета, но не программной реализации инструментария.
Физически регистр ОстаткиТМЦ организован в виде двух таблиц (листинг 11.1):
RG405 — движение по регистру ОстаткиТМЦ;
RA405 — остатки на регистре ОстаткиТМЦ на конец каждого периода.
#-=TABLE по 473: Регистр (Дв.) ОстаткиТМЦ
# Name
|Descr
|Type[A/S/U]|DBTableName|Reusable
Т=ВА405
|Регистр (Дв.) ОстаткиТМЦ
|A
|RA405
|1
# Name
|Descr
|Type|Length|Precision
F=IDDOC
| ID Document1 s
IC
|9
|o
F=LINENO
[LineNo
IN
I»
|0
F=ACTNO
|Action No
|N
|6
|0
F=DEBKRED
I Flag Debet/Kredit
|N
|1
|0
F=SP4062
|(Р)Фирма
|c
|9
|0
F=SP408
|(P)Номенклатура
|c
|9
|0
F=SP418
|(P)Склад
|c
|9
|0
F=SP3117
|(Р)ЦенаПрод
|N
|16
12
F=SP411
|(P)Количество
|N
|16
|5
528
F=SP420|(Р)Внутреннее(N (2 (О
#==TABLE по 472: Регистр ОстатхиТМЦ
# Name
T=RO405
(Descr|Type(А/S/U)|DBTableName|Reusable
(Регистр ОстаткиТМЦ|A(RG405(1
*Fields
# Name
F=PERIOD F=SP4062 F=SP408 F=SP418
F=SP3117
F=SP411
(Descr(Type(Length(Precision
(Period Registr|D(8(0
|(P)Фирма|C(9(0
|(P)Номенклатура|C(9(0
|(P)Склад|C(9(0
|(Р)ЦенаПрод|N(16(2
|(P)Количество|N(16(5
Здесь значение поля period в таблице RG405 соответствует дате (остатки расчитываются на конец месяца), на которую рассчитаны остатки ТМЦ по данному регистру (в разрезе всех измерений). Поскольку среди измерений регистра (СМ. рис. И.!) есть объекты Номенклатура (поле SP408) И Склад (поле SP418), это гарантирует наличие уже рассчитанных остатков на дату (заданную в поле period) в разрезе номенклатуры (ТМЦ) и склада. Величина остатка хранится в объекте количество (поле SP411).
Казалось бы, можно создать простейший SQL-запрос к таблице RG405, где в качестве фильтра указать дату, системные идентификаторы соответствующей номенклатуры, склада — и задача решена. Если дата, на которую мы желаем получить остаток ТМЦ по складу, совпадает с одной из дат, на которую уже рассчитаны остатки, то это так и есть. Задачу позволит решить SQL-запрос, представленный в листинге 11.2.
SELECT
SP411
FROM
"ПолныйПуть_к_рвР-файлу\КЯ405.dbf"
WHERE
PERIOD = "ЗаданнаяДата"
AND
SP408 = "ТМЦ (СистемныйИдентификатор)"
AND
SP418 = "Склад (СистемныйИдентификатор)"
Но если дата, на которую нужно получить остаток ТМЦ на складе, не совпадает с какой-либо расчетной датой (на которую остатки уже рассчитайы), то такой простой подход, естественно, не применим. В этом случае нужно получить остаток на "ближайшую" расчетную дату, которая меньше заданной (листинг 11.2), а затем проанализировать движение по регистру (таблица КА405) и вычислить суммарный приход и Расход ТМЦ (в разрезе номенклатуры и склада) за период от "ближайшей" расчетной даты (конец месяца) до заданной даты. Очевидно, что остаток на заданную дату будет равен: ОстатокНаЗаданДату = ОстатокНаРасчДату * Приход - Расход
Здесь следует отметить важный нюанс. Дело в том, что в таблице RG405 все даты (поле period) имеют формат 01.ММГПТ <pwc. 11.2).
PERIOD#
]SP4O62. [SP4O6 |SP418 |SP31l7lSP<ie
01.01.2004
1
38SH
5Н
0.
1
2?
01.02.2004
1
38SH
5Н
0.
f
01.03 2004
1
3BSH
5Н
0
1
01.04.2004
1
3BSH
5Н
о:
V
01.05.2004
1
■ 38SH
5Н
" о:
1
01.06.2004
1
38SH
5Н
0
1
01.07 2004
1
, 38SH
5Н
0.
1
01.08.2004
1
3BSH
5Н
oi
г
01.09.2004
1
; 38SH
5Н .
о:
1
01.10.2004
1
3BSH .
5Н I
о,'
1.
01.11.2004
1
; 38sh
5Н !
0!
-1"
=
01.122004
1
38SH
5Н
о;
1
Рис. 11.2. Содержание таблицы RG405 (ОстаткиТМЦ)
Казалось бы, можно предположить, что все остатки рассчитаны на начало месяца. Но это не так — с точностью до наоборот. Все остатки рассчитаны на конец месяца, а значения поля period соответствуют дате конца месяца. А это значит, что при расчете остатков (в таблице RG405) нужно следовать Двум правилам:
Если дата (например, 31.05.2004), на которую мы желаем получить остаток ТМЦ, соответствует дате конца месяца, то в SQL-запросе нужно ее модифицировать таким образом, чтобы значение дня даты было равно 01 (в данном случае 01.05.2004).
Если дата (например, 12.05.2004), на которую мы желаем получить остаток ТМЦ, не соответствует дате конца месяца, то в SQL-запросе нужно ее модифицировать таким образом, чтобы значение дня даты было равно 01. а значение месяца — предыдущему месяцу (в данном случае 01.04.2004).
В общем случае для получения остатка ТМЦ на заданном складе и на заданную дату можно применить следующий алгоритм:
Пользователь выбирает:
дату, на которую нужно получить остаток (DateRest);
ТМЦ (номенклатуру), остаток ПО которой нужно получить (idMatSys);
склад, по которому нужно получить остаток (idstoresys).
Программа анализирует дату (DateRest), введенную пользователем, и определяет ее новое значение (DateRestx) по следующим правилам:
если дата (например, 31.05.2004), на которую пользователь желает получить остаток ТМЦ, соответствует дате конца месяца, то в SQL-запросе ее значение модифицируется таким образом, чтобы значение дня даты было равно 01 (в данном случае 01.05.2004);
если дата (например, 12.05.2004), на которую пользователь желает получить остаток ТМЦ, не соответствует дате конца месяца, то в SQL-запросе ее значение модифицируется таким образом, чтобы значение дня даты было равно 01, а значение месяца — предыдущему месяцу (в данном случае 01.04.2004).
Примечание
. Можно, конечно, модифицировать только значение месяца, но тогда придется учитывать переход с марта на февраль. Например, 30 марта — это не конец месяца, но 30 февраля в природе не бывает (во всяком случае в настоящее время).
Программа ищет "ближайшую" расчетную дату (DateRestcalc), которая меньше или равна DateRestx:
SELECT
MAX(PERIOD)
FROM
"ПолныйПуть_к_ДВГ-файлу\RG405.db£"
WHERE
SP408 = 'IdMatSys'
AND
SP418 = 'idStoreSys'
AND■<
PERIOD-- -'DateRestx1
Если дата DateRestcalc существует, выбирается остаток на эту дату:
SELECT
8Р411
- i—,>—■ ' if v.!"twe41ViPV
Глава 11, Остатки ТМЦ на складах. Пример531
FROM
"ПолныйПуть_к_ОВР-файлу\RG405.dbf"
WHERE
SP408 = 'idMatSys'
AND
SP418 = 'idStoreSys'
AND
PERTOD•DateReitCalo1
Если дата DateRestCalc не существует, то принимаем, что остаток RestOnDateCalc на дату DateRestCalc = 0.
Если DateRestx = DateRestCalc, то задача считается решенной и остаток на дату DateRest составляет: RestOnDate = RestOnDateCalc.
ЕСЛИ DateRestx > DateRestCalc, ТО нужно:
найденную дату DateRestCalc (например, 01.04.2004) конвертировать в соответствующую дату конца месяца DateRestCalcX (в данном случае 30.04.2004);
отобрать движение ТМЦ по складу за период [DateRestCalcX ... DateRest) (.исключая дату DateRestCalcX) и рассчитать суммарные приход (Valplus) И Расход (Valminus) За ЭТОТ период;
вычислить остаток ТМЦ по складу на дату DateRest:
"RestOnDate" = "RestOnDateCalc* + "Valplus" - "Valminus"
На этом будем считать задачу решенной. В принципе, ничего сложного в реализации этого алгоритма нет. Но есть существенный нюанс. Если посмотреть на структуру таблицы RA405, то видно, что в ее составе нет поля, которое бы содержало дату движения по регистру, но есть поле iddoc (системный идентификатор документа, к которому "привязано" это движение). Отсюда следует, что значения даты и времени, к которым приурочена любая строка таблицы RA405, можно получить из журнала документов isjourn (с.м. предыдущие главы).
В листинге 11.3 представлен текст SQL-запроса на получение списка документов, формирующих движение по регистру Остаткитмц за период.
SELECTIDDOCSELECTIDDOC
SELECT
IDDOC
SELECT
IDDOC
FROM
"ПолныйПуть_к_рВЕ-файлу\1SJOURN.dbf" J
WHERE
RF405>0
AND
J."DATE" > 'DateRestCalcX'
AND
J."DATE" <= 'DateRest';
ORDER BY
IDDOC
Таким образом, для решения нашей задачи нужно "задействовать" 5 таблиц из базы данных 1С:
□ RG405 — остатки на регистре остаткитмц на конец каждого периода. Поля:
period — дата, на которую рассчитаны остатки;
SP408 — номенклатура (системный идентификатор);
SP418 — склад (системный идентификатор);
SP411 — количество (остаток ТМЦ);
RA405 —движение по регистру Остаткитмц. Поля:
iddoc — документ (системный идентификатор);
DEBKRED — признак Приход/ Расход;
SP408 — номенклатура (системный идентификатор);
SP418 — склад (системный идентификатор);
SP411 — количество (остаток ТМЦ);
1SJOURN — журналы документов. Поля:
iddoc — системный идентификатор документа;
date — дата документа;
RF405 — признак того, что этот документ может принимать участие в формировании записей таблицы RG405;
SC55 — справочник Склады. Поля:
id — системный идентификатор элемента справочника;
code — значение свойства Код элемента справочника;
descr — значение свойства наименование элемента справочника;
SC84 — справочник Номенклатура. Поля:
id — системный идентификатор элемента справочника;
code — значение свойства код элемента справочника;
descr — значение свойства Наименование элемента справочника.
На рис. 11.3 представлена схема, иллюстрирующая связи между указанными таблицами.
Рис. 11.3. Схема, иллюстрирующая связи между таблицами, участвующими в формировании движения по регистру ОстаткиТМЦ
В конечном итоге для решения этой узкой задачи нам не потребутся проводить анализ информационной структуры базы данных, что существенно ускорит и упростит программирование.
Примечание
Здесь следует отметить, что все примеры данной главы будут тестироваться (по ходу изложения) на базе данных комлексной конфигурации. Из этого следует, что:
те, кто желает самостоятельно поэкспериментировать, должны иметь доступ к комплексной конфигурации;
естественно, что результат у каждого экспериментатора будет свой.
Создадим новый Delphi-проект. На рис. 11.4 представлена форма проекта.
Примечание
Исходные тексты находятся на сопроводительном компакт-диске книги в папке \Part_2\Chapter_11 \sp_1 Cv7_GetRest.PAS\01\.
Рис. 11.4. Форма проекта sp_1Cv7_GetRest.DPR
Элементы управления формы:
□ Склад:
кнопка ? — выбор склада;
текстовое поле (Edit_idSklad) — системный идентификатор выбранного склада;
□ группа Номенклатура:
кнопка ? — выбор ТМЦ;
текстовое поле (Edit_idNomenkl) — системный идентификатор номенклатуры;
□ группа Получить остаток на:
текстовое поле (Edit_oate2) — дата, на которую желаем получить остаток;
текстовое поле (Edit_Date2x) — модифицированное значение из поля 1 Edit_Date2 (ДЛЯ выборки ПО Таблице RG405);
О текстовое поле Остаток (Edit_Rest) — величина остатка на желаемую дату;
кнопка "бегущие человечки" — запуск алгоритма получения остатка на желаемую дату;
текстовое поле Есть остатки на дату (Edit_RestDateEnd) — "ближайшая" расчетная дата (на которую рассчитаны остатки), значение которой меньше или равно желаемой дате;
текстовое поле Всего (Edit_Rest_Last) — остаток ТМЦ на "ближайшую" расчетную дату.
Для выбора склада из таблицы scss и номенклатуры из таблицы SC84 создадим диалоговую форму (рис. 11.5)
Рис. 11.5. Форма для выбора склада и номенклатуры для фильтрации по таблицам RA405 и RG405
Не вдаваясь в детали исходного кода формы (см. рис. 11.5), отметим только, что список складов для выбора в интерактивном режиме можно получить, сформировав SQL-запрос (листинг 11.4).
SELECT
CODE,
DESCR,
ID
FROM
"ПолныйПуть_к_ОВР-файлу\ВС55.dbf*
WHERE
ISFOLDEROl
ORDER BY
DESCR
Номенклатурный список (ТМЦ) для выбора в интерактивном режиме можно получить, сформировав SQL-запрос (листинг 11.5).
[Листинг 11.5. SQL-запрос к таблице SC55 на получение номенклатурного
: :У
SELECT
CODE,
DESCR,
ID
FROM
"ПолныйПуть_к_ОВР-файлу\SC84.dbf*
WHERE
ISFOLDERol
ORDER BY
DESCR
В листинге 11.6 представлен фрагмент обработчика события "нажатие кнопки "бегущие человечки"" (запуск алгоритма вычисления остатка).
-«^--IW-eTV^-^r^^
работника нажатия кнопки "бегущие человечки*
procedure TForml.SpeedButt«i6Click(Sender: TObject);
Var
Sx,
sFilter,
fn,И Имя поля таблицы
tn : string; // Имя таблицы begin
// Модифицируем дату (на которую желаем получить остаток)
// для использования ее в SQL-запросе к таблице RG405
Edit_Date2X.Text:=ReCalcDate_for_SelectRest(Edit_Date2.Text);
//
// Определим "ближайшую" расчетную дату остатка sFilter:='1;
// Склад
sFilter:=sFilter+'SP418=1+#39+Edlt_ldSklad.Text+#39;
sFilter:=sFilter+' and ';
II Номенклатура
sFilter:=sFilter+'8P408='+«39*Edlt_idNamenkl.Text+#39; sFilter:=sFilter+' and ';
// Ограничение по дате
sFilter:=sFilter+'PERIOD <= '+#39+Trim(E<M.t_Date2X.Text)+#39;
tn:='"1+DirDB*'RQ4051+*.dbf'+'"';
// Выбираем максимальное значение поля для заданного фильтра fn:='HMt(PERIOD)1;
И Формируем и выполняем SQL-запрос
Sx:=ep_GetFioldValue_TableDB( " ,tn,fn,sFilter,'');
Edit_RestDateEnd.Text:=Trim(Sx);
//
if length (Edit_RestDateEnd.Text)>0 then begin
// Такая дата существует
//
// Читаем остаток за найденную "ближайшую" дату sFilter:=‘';
// Склад
sFilter:=sFilter+'SP418='+#39+Edit_ldSklad.Text+#39; sFilter:=sFilter+' and ' ;
// Номенклатура
sFilter:=sFilter+'SP408='+»39+Edit_idMcD*nkl.Text4-#39;
sFilter:=sFilter+' and ';
// "Ближайшая* дата остатка
sFilter:=sFilter+' PERIOD = '+#39+Trim(Edlt_RestDateEnd.Text)+#39;
// Выбираем количество (остаток ТМЦ) для заданного фильтра fп:='SP411•;
И Формируем и выполняем SQL-запрос
Sx:=ep_GetFleldValue_TableDe(' ',tn,fn,sFilter,•');
Edit_Rest_Last.Text:=Trim(Sx);
// end
else begin
ShowMessage(1 Остатков на эту дату не обнаружено'); end;
end;
Думаю, что здесь комментарии излишни. Функция sp_GetFieldvaiue_TabieDB была подробно рассмотрена в предыдущей главе, а функция ReCalcDate_ for_selectRest никакого интереса с технической точки зрения не представляет (реализацию этих функций можно увидеть в исходных текстах проекта).
и запустим его на выполнение. Выбереми запустим его на выполнение. ВыберемСкомпилируем наш Delphi-проскт склад и ТМЦ (рис. 11.6).
и запустим его на выполнение. Выберем
и запустим его на выполнение. Выберем
На рис. 11.7 представлен результат выполнения обработчика (листинг 11.6)
регис тр.Ог татки! ЧЦрегис тр.Ог татки! ЧЦQ ВыберитеQ ВыберитеО| Е:\1С_Комплексная\Условия отбора:О| Е:\1С_Комплексная\Условия отбора:Номенклатура 7 fl 202LНоменклатура 7 fl 202L_Склад-177?_Склад-177?Получить остаток на |31 05.2003101 05 2003Получить остаток на |31 05.2003101 05 2003Искать:строку • (чайник эмалир<7 Совладение С Вхождение по полю- (OESCRИскать:строку • (чайник эмалир<7 Совладение С Вхождение по полю- (OESCRНВ 13НВ 13CODE |0Е5СЯ00051015 Чайник фаянсовый заварной00010794 Майи* змалироеатвеяй 2 л ,00006057 Частотный регулятор ЧАСТЕР-200CODE |0Е5СЯ00051015 Чайник фаянсовый заварной00010794 Майи* змалироеатвеяй 2 л ,00006057 Частотный регулятор ЧАСТЕР-200
регис тр.Ог татки! ЧЦ
регис тр.Ог татки! ЧЦ
Q Выберите
Q Выберите
О| Е:\1С_Комплексная\
Условия отбора:
О| Е:\1С_Комплексная\
Условия отбора:
Номенклатура 7 fl 202L
Номенклатура 7 fl 202L
_Склад-1
77?
_Склад-1
77?
Получить остаток на |31 05.2003101 05 2003
Получить остаток на |31 05.2003101 05 2003
Искать:
строку • (чайник эмалир
<7 Совладение С Вхождение по полю- (OESCR
Искать:
строку • (чайник эмалир
<7 Совладение С Вхождение по полю- (OESCR
НВ 13
НВ 13
CODE |0Е5СЯ
00051015 Чайник фаянсовый заварной
00010794 Майи* змалироеатвеяй 2 л ,00006057 Частотный регулятор ЧАСТЕР-200
CODE |0Е5СЯ
00051015 Чайник фаянсовый заварной
00010794 Майи* змалироеатвеяй 2 л ,00006057 Частотный регулятор ЧАСТЕР-200
OK | Cancel |OK | Cancel |Рис. 11.7. Остаток ТМЦ по заданному складу (SQL-запрос)Рис. 11.7. Остаток ТМЦ по заданному складу (SQL-запрос)
OK | Cancel |
OK | Cancel |
Рис. 11.7. Остаток ТМЦ по заданному складу (SQL-запрос)
Рис. 11.7. Остаток ТМЦ по заданному складу (SQL-запрос)
Рис. 11.6. Выбор ТМЦ в справочнике Номенклатура
Теперь запустим программу 1С:Предприятие, откроем эту же конфигурацию, выберем стандартный отчет "Остатки ТМЦ" и "запустим" отчет для этого же склада, номенклатуры и на эту же дату. Результат представлен на рис. 11.8. Как видим, результаты одинаковы (по величине остатка). Но по времени выполнения наша программа (SQL-запросы) существенно быстрее (ради чего мы все это и затеяли). Для сравнения: у меня (на локальной базе данных) остаток был получен:
в программе sp_lCv7_GetRest.EXE — 3-4 с
в программе 1С:Предприятие — 50 с.
Остатки ТМЦ на складах
и* дату. 31 05 03
По всем фермам. По всем юр. лицам. По всем упр. аналит*ом По номоелатуре "Чайних эмалированный 2 л" Посжпажу" С«ла1-1’
ТМЦ
Ед.
Усред себест-тъ с НДС (РУб.)
_Свпад-1
Кол-во |
Материалы и оборудование вспомогательные
Посуда
Посуй.! стальная
Рис. 11.8. Остаток ТМЦ по заданному складу (стандартный отчет 1С:Предприятие "Остатки ТМЦ")
Модернизируем наш Delphi-проект. Посмотрим, каким образом можно получить выборку документов, участвующих в формировании движения по регистру Остаткитмц за период дат от "ближайшей" расчетной даты до даты, на которую мы желаем получить остаток ТМЦ. На рис. 11.9 представлена форма проекта.
Примечание
Исходные тексты этого примера находятся на сопроводительном компакт-диске книги в папке \Part_2\Chapter_11\sp_lCv7_GetRest.PAS\02\.
Рис. 11.9. Форма проекта sp_1Cv7_GetRest.DPR
В листинге 11.7 представлен текст функции, формирующей список документов.
isis
is
is
function TForml.OpenLietDoc : integer; begin
Result:=0;
QueryDoc.Close;
QueryDoc.SQL.Clear;
QueryDoc.SQL.ADD('SELECT ');
QueryDoc.SQL.ADD('IDDOC, ');
QueryDoc.SQL.ADD('J."DATE", ');
QueryDoc.SQL.ADD('DOCNO, ');
QueryDoc.SQL.ADD("DNPREFIX ');
QueryDoc.SQL.ADD('FROM ');
QueryDoc.SQL.ADD(‘"'+DirDB+'1SJOQRN'+'.dbf•♦•• J');
QueryDoc.SQL.ADD('WHERE ');
// Отбираем только те документы, которые могут формировать
// движение по регистру “ОстаткиТМЦ" QueryDoc.SQL.ADD('RF405>0 ');
QueryDoc.SQL.ADD('AND ');
// Дата начала периода - начало следующего месяца // (после даты остатков)
QueryDoc.SQL.ADD('J.“DATE" > '+#39+EditJRestDateEndX.Text+#39); QueryDoc.SQL.ADD('AND ');
// Дата конца периода - заданная дата
QueryDoc.SQL.ADD('J."ПАТ*" <= '+#39+Edit_Date2.Text+#39); QueryDoc.SQL.ADD('ORDER BY ');
// Сортируем по дате и системному идентификатору документов QueryDoc.SQL.ADD('J."DATE”,IDDOC ');
QueryDoc.Open;
Result:=QueryDoc.Recordcount;
end;
Текст функции прост и не нуждается в пояснениях.
В листинге 11.8 представлен фрагмент обработчика (см. листинг 11.6) с учетом открытия списка документов.
ttZ.v::y;мчйджадЮТС^ге^’Ч^^УТ-гестго!?.*^^
ГЛ иотинг 11В.Доработанный обработчик нажатия кнопки “бегущие человечки* ^
procedure TForml.SpeedButton6Click(Sender: TObject);
Var
begin
fn: = 'SP411';
Sx:=sp_GetFieldValue_TableDB(‘',tn,fn,sFilter,* *);
Edit_Rest_Last.Text:=Trim(Sx);
// Вычисляем дату конца месяца, который соответствует
// найденной дате расчета остатков
Edit_RestDateEndX.Text:=
sp_ConvertThisDateToEndMonth(Edit_RestDateEnd.Text);
H Если даты не совпадают, формируем список документов
if Trim(Edit_ReatDateEndX.Text)<>Trim(Edit_J)ate2.Text) then begin
// Формируем список документов за период от даты последнего
// расчета остатков (конец месяца) до заданной даты
OpenLietDoc;
end;
end;
Скомпилируем проект, запустим его на выполнение и протестируем соответствующим образом. На рис. 11.10 представлен результат формирования списка документов.
Поле Имя документа в таблице (рис. 11.10) — вычисляемое. Его значение определяется в обработчике события OnCalcFields компонента QueryDoc нашего проекта. Для того чтобы визуализировать наименование документов (вернее, вид документов), в каталоге базы данных должен присутствовать файл lCv7_str.INI (мы подробно рассматривали это в предыдущих главах).
Здесь следует отметить, что в списке присутствуют только те документы, которые участвовали в формировании движения по регистру Остаткитмц за заданный период времени. Но далеко не все они участвовали в формировании движения именно этого ТМЦ по заданному складу.
Продолжим модернизацию нашего Delphi-проекта. Откроем таблицу ra405 (движение по регистру Остаткитмц) и отфильтруем записи по заданному складу и номенклатуре (листинг 11.9).
Рис. 11.10. Результат формирования списка документов
function TForml. OpenLietReg(NrWhat : integer) : integer;
И Открытие движения по регистру "ОстаткиТМЦ"
begin
Result:=0;
QueryReg.Close ;
QueryReg.SQL.Clear;
QueryReg.SQL.ADD("SELECT ") ;
QueryReg.SQL.ADD("IDDOC, ’);
QueryReg.SQL.ADD("LINENO, ');
QueryReg.SQL.ADD('DEBKRED, ');
QueryReg.SQL.ADD("SP411, ');
QueryReg.SQL.ADD('SP420 ");
QueryReg.SQL.ADD("FROM 1);
QueryReg.SQL.ADD(' " 1+DirDB+'RM05'*' .dbf" + "" ) ;
QueryReg.SQL.ADD("WHERE ");
QueryReg.SQL.ADD("89418=1+#39+Edit_idSklad.Text+#39);
QueryReg.SQL.ADD("AND ");
OueryReg.SQL.ADD(187408='+#39+Edit_idNcmenkl.Text*#39);
if NrWhat>=0 then begin
QueryReg.SQL.ADD('AND ');
if NrWhat=0 then begin
QueryReg.SQL.ADD(’DEBKRED<=0 ');
end
else begin
QueryReg.SQL.ADD('DEBKRED>0 *);
end;
end;
QueryReg.Open;
Result:=QueryReg.Recordcount;
end;
Здесь, как видим, присутствует все движение по заданным номенклатуре и складу, независимо от даты. А это нам не подходит. Как видно из схемы на рис. 11.3, обе таблицы — isjourn (журнал документов) и RA405 (движение по регистру Остаткитмц) — имеют общее поле iddoc. Следовательно, мы можем сделать дополнительную фильтрацию по набору данных (таблица RA405) с учетом списка документов (таблица isjourn) за заданный период. Для этого есть, как минимум, два способа.
Первый способ заключается в том, что можно использовать вложенный SQL-подзапрос (листинг 11.10).
SELECT
IDDOC,
LINENO,
DEBKRED,
SP411,
SP420
FROM
*ПолныйПуть_к_ОВЕ-файлу\RA405.dbf"
WHERE
SP418='Edit_idSklad.Text1
AND
87408=' Edi t_idNanenkl .Text1
AND
плюс ты (
SELECT
ПЛЮС
FROM
"ПолныйПуть_к_ПВЕ-файлу\18ООивм.дЬ£" J
WHERE
RF*05>0
AND j.nDATE" > 'Edit_RestDateEndX.Text'
AND
J."DATE" <= 1 Edit_Date2.Text'
Второй способ — использовать обработчик OnFilterRecord Delphi-компонента TQuery (ЛИСТИНГ 11.11).
procedure TFonnl.QueryRegFiltexRecord(DataSet: TDataSet;
var Accept: Boolean);
Var
idDoc : string;
begin
Accept:=FALSE;
if QueryDoc.Active then begin
idDoc:=QueryReg.FieldByName(1IDDOC').AsString;
if QueryDoc.Locate('IDDOC’,idDoc,[]) then Accept:=TRUE;
end;
end;
Первый способ должен обеспечить (в случае хранения базы данных на сервере MS SQL Server) более быстрое выполнение, поскольку все операции по фильтрации данных выполняются на сервере.
Примечаниеч
На сопроводительном компакт-диске книги в папке \Part_2\Chapter_1 sp_1Cv7_GetRest.PAS\03\ приведен пример, где реализован первый способ фильтрации.
На рис. 11.11 представлена форма проекта.
Рис. 11.11. Форма проекта sp_1 Cv7_GetRest.dpr
На рис. 11.12 представлен результат фильтрации записей по таблице RA405 (первый способ).
Рис. 11.12. Результат фильтрации записей о движении по регистру ОстаткиТМЦ
Для того чтобы визуализировать наименование документов (вернее вид документов), в каталоге базы данных должен присутствовать файл lCv7_str.INI
546
(см. предыдущий раздел). В случае отсутствия этого файла в имени документа будет отсутствовать вид документов (рис. 11.13).
ID Док.) Негр) Дебит/Кредит |
чол-во | Внутр) Документ|
У
5DD01
5CQО'1
2001N 0000000716(31.01 2003] :
55.80 N 0000000002 [31.01.20031:
Рис. 11.13. Результат фильтрации записей о движении по регистру ОстаткиТМЦ.Визуализация наименований документов без файла 1 Cv7_str.INI
После того как отфильтрованы записи движения по регистру, можно рассчитать остаток ТМЦ на заданную дату (листинг 11.12).
// Остаток на "ближайшую" расчетную дату
RestO:=StrToFloat(Edit_Rest_Last.Text);
Rplus := 0;
Rminus := 0;
// Сканируем записи движения по регистру
QueryReg.First;
while not QueryReg.EOF do
begin
if QueryReg.FieldByName{'DKBKRED'),AsInteger<=0 then begin // Это приход ТМЦ
Rplus := Rplus + QueryReg8P411.AsFloat;
end
else begin
// Это расход ТМЦ
Rminus : = Rminus + QueryRegSPill.AsFloat;
end;
Application.ProcessMessages;
QueryReg.Next;
end;
// Вычисляем остаток на заданную дату
RestX := RestO + Rplus - Rminus;
ПРИМЕЧАНИЕ
В папке \Part_2\Chapter_11\sp_1Cv7_GetRest.PAS\04\ на сопроводительном компакт-диске книги приведен пример, в котором реализован второй способ фильтрации записей по таблице RA405 (с использованием обработчика OnFilterRecord компонента TQuery). Здесь мы этот пример рассматривать не будем.
В приведенных примерах кроме остатка ТМЦ на складе мы получили "расшифровку" его движения. Если в этом нет необходимости, то программу можно еще упростить. Вместо одного SQL-запроса (см. листинг 11.10) можно выполнить два запроса — получить приход и расход ТМЦ по складу за период (листинги 11.13 и 11.14), и затем рассчитать остаток на дату (листинг 11.15).
SELECT
SDM(SP411}
FROM
"ПолныйПуть_к^ОВР-файлу\RA405.dbf•
WHERE
SP418='Edit_idsklad.Text'
AND
SP408='Edit_idN«nenkl.Text1
AND
UtaKiUED <■ 0
AND
IDDOC IN (
SELECT
IDDOC
FROM
■ПoлныйПyть_к_DBF-фaйлy\lSJOURN.dЬf• J WHERE
RF405>0
AND
J."DATE" > 1 Edit_RestDateEndX.Text1 AND
J."DATE" <= 'Edit_Date2.Text'
Листинг 11.14. Получение расхода ТМЦ по складу за период
SELECT
80М(8Р411)
FROM "ПолныМуть_к_ОВЕ-файлу\КА405 .dbf"
WHERE SP418='Edit_idSklad.Text'
AND SP408=' Edi t_idNotnenkl .Text ’
AND HKRKRKD > 0
AND IDDOC IN ( SELECT IDDOC FROM -ПолныйПуть_к_ОВР-файлу\1&7ОикН.<ЗЬ£“ J WHERE RF405>0
AND J."DATE” >'Edit_RestDateEndX.Text'
AND J."DATE" <= 1Edit_Date2.Text'
))
)
)
RrestO:=StrToFloat(Edit_Rest_Last.Text);
H Приход ТМЦ на склад
OpenListReg(O);
QueryReg-First;
Rplua ;= QueryReg.Fields[0].AsFloat;
4л4л// Расход ТМЦ на складе
4л
4л
OpenLiatReg(l)i
QueryReg.First;
Rminus := QueryReg.Fields[0]-AsFloat;
// Расчет остатка на дату
RreetX :■ RrestO * Rplua - Rminua;
ПРИМЕЧАНИЕ
В папке \Part_2\Chapter_11\sp_1Cv7_GetRest.PAS\05\ на сопроводительном компакт-диске книги приведен пример, реализующий этот способ вычисления остатка ТМЦ.
На рис. 11.14 представлен результат вычисления остатка ТМЦ по заданному складу.
Рис. 11.14. Результат расчета остатка ТМЦ на складе
В этой главе мы рассмотрели расчет остатков заданного ТМЦ на заданном складе. Если требуется найти, например, остаток заданного ТМЦ в целом по предприятию, то (при формировании SQL-запросов) из фильтра исключается условие органичения выборки по складу (поле SP418), например, так:
QueryReg.SQL.ADD(’WHERE ');
If length(Trim(Edit_idSklad.Text))>0 then begin
QueryReg.SQL.ADD('S₽418='+#39+Edit_idSklad.Text+#39);
QueryReg.SQL.ADD('AND ');
end;
QueryReg.SQL.ADD('SP408='+#39+Edit_idNomenkl.Text+#39);
QueryReg.SQL.ADD('AND ');
QueryReg.SQL.ADD('IDDOC IN (...)');
Примечание
Напомню, что приведенные примеры исходных текстов — это упрощенная иллюстрация к рассматриваемым вопросам. Назначение этих примеров — дать представление о возможном подходе при решении задач информационного обмена с системой 1С:Предприятие. При работе с реальными базами 1С может потребоваться их дальнейшая доработка.
Часть III
Программа1С:Предприятиев среде Windows
Программа 1С:Предприятие, будучи "обычным" приложением, функционирующим в среде Windows, использует системное окружение, включая соответствующие ресурсы (в частности, системный реестр Windows), которые предоставляет операционная система. В части / мы уже рассматривали вопрос визуализации окна программы 1С:Предприятие с применением стандартных средств управления процессами в среде операционной системы Windows. Посмотрим, что еще можно "выжать" полезного из программы 1С:Предприятие как приложения в среде Windows, используя возможности операционной системы.
rW -ЧЬ. . А
Глава 12
Список зарегистрированных баз даннных системы 1С:Предприятие
Рис. 12.1. Список конфигураций (баз данных) 1С, открытый в программе 1С:ПредприятиеРис. 12.1. Список конфигураций (баз данных) 1С, открытый в программе 1С:ПредприятиеВ предыдущих главах мы (когда нужно было найти каталог базы данных 1С) "напрягали" потенциального пользователя, вынуждая его вручную отыскивать расположение базы данных 1С. Но если запустить программу 1 С:Предприятие (или Конфигуратор 1 С), то на экране появляется диалоговое окно выбора нужной базы данных 1С из списка зарегистрированных (рис. 12.1).
Рис. 12.1. Список конфигураций (баз данных) 1С, открытый в программе 1С:Предприятие
Рис. 12.1. Список конфигураций (баз данных) 1С, открытый в программе 1С:Предприятие
Следовательно, программа 1С:Предприятие где-то хранит список своих баз данных (конфигураций). Если запустить редактор системного реестра Windows (программа RegEdil.EXE) и найти раздел (для Windows 2000/ХР):
HKEY_CURRENT_USER\Software\lC\10V7\7.7\Titles
то видно (рис. 12.2), что в этом разделе системного реестра программа 1С:Предприятие формирует список своих баз данных.
Jlts.^81(Поуюлчанио)|REG...(значение не npucet® DAICjMample DBSREG...Учебная база-1^]DA1C_exarrple.DB_synhio\ REG...Учебная синхроннаHgOA1C_example.DB2\REG...Учебная база-2Jlts.^81(Поуюлчанио)|REG...(значение не npucet® DAICjMample DBSREG...Учебная база-1^]DA1C_exarrple.DB_synhio\ REG...Учебная синхроннаHgOA1C_example.DB2\REG...Учебная база-2Q Soilwaie5Г
Jlts.^
81(Поуюлчанио)|REG...(значение не npucet
® DAICjMample DBSREG...Учебная база-1
^]DA1C_exarrple.DB_synhio\ REG...Учебная синхронна
HgOA1C_example.DB2\REG...Учебная база-2
Jlts.^
81(Поуюлчанио)|REG...(значение не npucet
® DAICjMample DBSREG...Учебная база-1
^]DA1C_exarrple.DB_synhio\ REG...Учебная синхронна
HgOA1C_example.DB2\REG...Учебная база-2
50 1С ; а Сз icv?
B-Q 7.7
Def ads
®СЗ Options
! <S Tiles^);
® C3 Учебная база-1
В Р1 Учебная база-2 1Учебная синхронист
Рис. 12.2. Список конфигураций (баз данных) 1С в системном реестре Windows
В листинге 12.1 представлен исходный текст функции, считывающей список баз данных 1С из системного реестра Windows.
function Load_LietDB_f rcBiJlegletxy (Keyname : string;
List : TStrings;
YesDetect_lCv7md : boolean) : integer;
// Чтение списка баз данных 1С из системного реестра:
// Keyname - полное имя раздела системного реестра,
// откуда читаем информацию. Значения для Windows-2000/ХР:
//KeyName= Softwar«\lC\lCV7\7.7\Titlee
//RootKey= HKey_Current_Ueer
// List - здесь возвращаем список баз данных 1С,
// YesDetect_lCv7md - если TRUE, то учитываем наличие файла lCv7.md.
var
snameDB,// Имя конфигурации (базы данных) 1С
fnMD : string; // Полное имя файла 1CV7.MD
Reg : TRegistry;
i : integer;
Yes : byte;
begin^
Result:=0;
if ListoNIL then begin
List.Clear;
Keyname:=Trim(Keyname) ;
if length(KeyName)>0 then begin
Reg:=TRegistry.Create;
try
Reg.RootKey: = HKey_Current_Uaer;
if Reg.OpenKey(KeyName,False) then begin
// Читаем полный путь к конфигурациям
U (базам данных) 1С
Reg.GetValueNamee(List);
if List.Count>0 then begin
H
//Формируем список баз данных IC i:=-l;
while i<(List.Count-1) do
begin i:=i+l; Yes := 0;
if YeeDetect_lCv7md then begin
И Проверка существования файла lCv7.n*j
// для данной конфигурации.
II Вычисляем полное имя MD-файла конфигурации fnMD := List[I]+'lcv7.md';
// Проверяем, существует ли MD-файл
if not FileExiets(fnMD) then begin
// MD-файл HE существует, удаляем из списка List.Delete(i);
i:=i-l;
end
else begin
// MD-файл существует Yes:=l;
end;
end
else begin
U Без проверки существования файла lCv7.md Yes:=l;
end;
if Yes>0 then begin
II Читаем имя базы данных
■Нешепв:=Trim(Reg.Readstring(List[i]));
List[i]:=sNameDB+'='+List[i];
end;
Application.ProcessMessages;
end;
//_
end;
end;
Result:=List.Count;
finally
II Освобождаем ресурсы
Reg.Free;
end;
end;
end;
end;
Поясним листинг 12.1.
Здесь после открытия соответствующего раздела системного реестра:
if Reg.OpenKeytKeyname,False) then begin
сначала считывается список каталогов (папок), где размещаются зарегистрированные базы данных 1С:
Reg.GetValueNemee(List);
Затем, в зависимости от значения параметра YesDetect_lcv7md, либо сразу формируется список баз данных:
■NaroeDB:=Trim (Reg.Readstring(List[ i ]));
Listti]:=sNameDB+'='+List[i];
либо сначала проверяется наличие файла конфигурации lCv7.md в каталоге базы данных. И если такого файла нет, предполагается, что тестируемая база данных некорректна и удаляется из списка:
// Проверяем, существует ли MD-файл
if not FileExiBta(fnMD) then begin
// MD-файл HE существует, удаляем базу данных из списка ч
List.Delete(i);
i:=i-l;
end
else begin
rnaea t2. список зарегистрированных баз даннных системы ^Предприятие 557
// MD-файл существует
Yes:=1;
end;
Примечание
Исходный текст примера, реализующего данный алгоритм, приведен на сопроводительном компакт-диске книги в папке \Part_3\Chapter 12\LoadUslDB 1С (файл LoadListDB_1C.DPR).
На рис. 12.3 показан результат считывания из реестра Windows списка баз данных системы 1С:Предприятие.
• Г Прочитать список баз данных 1С из реестра НЕ И
»У HKep_Cutienl_UteA |$oftware\1C\1CVA7.7\Titie$
Р Проверяем наличие Файла 10v7.md■ ■ . -
Учебная база-1 =D.\lC_example DB\""
Учебная 6asa-2-D:\lC_example.DB2\
Учебная сюоротпируемал-т1С_ехапф!е.ОВ_$упИго\
Рис. 12.3. Список конфигураций (баз данных) 1С,прочитанных из системного реестра Windows
19 Зак. 1064
Глава 13
Список активных пользователей базы данных 1С:Предприятие
В процессе эксплуатации системы 1С:Предприятие может возникнуть необходимость контроля пользователей, которые в текущий момент времени работают с определенной базой данных 1С (активные пользователи). Это может быть важно в тех случаях, например, когда требуются какие-либо регламентные процедуры по обслуживанию базы данных, возможные только при отсутствии активных пользователей. Можно, конечно, воспользоваться Монитором 1С (рис. 13.1).
1 [Имя пользователя
1П ользователь_1
Начало работы [Компьютер
11 11 2006.14:08:17 СОМР
11 11.2006.14:08:07 ||СОМР
Пользе взтель_2
11 11.2006.14:07:56 СОМР
[<£?[ Пользователь^
11 11.2006.14:07:49 ЦсОМР
Рис. 13.1. Список активных пользователей базы данных (Монитор 1С:Предприятие)
Но иной раз (для автоматизации этого процесса) предпочтительнее разработать собственные программные средства (например, для рассылки соответствующих оповещений о выходе из 1С всем активным пользователям базы данных). Естественно, лучше всего это делать вне контекста программы 1С:Предприятие— хотя бы затем, чтобы лишний раз не занимать ресурсы самой 1С для такой чисто системной задачи.
В каталоге каждой базы данных 1С есть подкаталог SYSLOG, где (в случае, если в данной конфигурации используется система разграничения прав доступа к информационной базе) присутствует файл links.tmp. Именно в этом файле и хранится информация об активных пользователях конкретной базы данных. Этот файл появляется в момент загрузки конфигурации 1С после авторизации пользователя и может быть автоматически удален программой 1С:Предприятие после ее закрытия, если больше нет активных пользователей.
Если загрузить этот файл в любой визуальный Delphi-компонент (имеющий свойство TStrings), то видно (рис. 13.2), что информация в файле хранится в SDF-формате (см. главу 10). Каждому пользователю отведено четко определенное количество строк файла (размер области файла, выделяемой для каждого пользователя, — 1024 байта).
•Г Прочитать список активных Пользователей 1С №□
"Список активных Пользователей:
{'Т1ате".''Польэователь_3‘‘), ("Run mode",'E"), (‘IsMono'VN").
("Date&Iime"."09.11.2006.07:56:58").
("ComputerName'VCOMP"))
("N ате".'Пользователь_2").
("Run mode",'E").
(‘IsMono'VN").)
("OetebTime"."0311 2006,07:57:10"),i
('CompuleiName’VCOMP"))
("Name'VAdmin").i
("Run mode'VE"),
{‘IsMono'VN").
("Datetime'V09.11.2006,07:57:13").
("ComputerName'VCOMP"))
{'Name" ."Пользователь..)").
("Run mode'VC").
{'IsMono'VN"),
("DaletTime"."09.11.2006.07:57:45").
{' ComputerM ame".' "CO MP"})
Рис. 13.2. Содержание файла links.TMP
Как видим, выделить из этого файла нужную информацию и конвертировать ее в любой другой формат (для целей визуализации) не составит труда. Но есть один существенный нюанс...
Если провести простой эксперимент (любой желающий может сделать это на локальной базе данных 1С). то видно, что с каждым новым подключением пользователя к конкретной базе данных 1С файл links.TMP растет (по 1024 байта на одно подключение, даже если один и тот же пользователь подключился несколько раз), но по мере отключения пользователей размер файла не меняется и пользователи из списка (см. рис. 13.2) не исчезают. То есть для получения списка активных пользователей одной этой информации недостаточно.
Программа 1С:Предприятие (и Конфигуратор 1С) "помечает" каждого активного пользователя следующим образом. В файле links.TMP блокируется байт
со смещением lE8481h * НомерПользователяВСписке. При этом нумерация пользователей начинается с нуля. Поэтому чтобы определить, является ли пользователь в списке (см. рис. 13.2) активным, достаточно сделать попытку блокировки соответствующего байта в файле links.TMP. Если удачно — этот Пользователь не активен.
В листинге 13.1 приведен текст функции, которая возвращает список активных пользователей, применяя этот способ.
ет^™^-^--'^^т^Г»- ,...?-...,„^-.^^^,....,..,...,,...,„,
Функция чтения списка активных пользователей базы данных 1С ।
function Get_Liat_ActiveUeers_fram_lC(DirTMP,
fn_Links_TMP : string;
Listusers : TStrings) : integer;
// Получение списка активных Пользователей IC:
// DirTMP- имя каталога для временных файлов
//(должен существовать),
// fn_Links_TMP - полное имя файла Links.TMP
//(в тестируемой конфигурации 1С),
// Listusers - список активных пользователей
//(каждая строка списка в SDF-формате).
Var
fn_Links_TMP_local :string;
fHandle:THandle;
i:integer;
Sx:string;
YesNext:byte;
List:TStrings;
begin
Result:=0;
YesNext := 0;
if ListUsersoNIL then begin
Listusers.Clear;
// Создаем временный список пользователей List := TStringList.Create;
TRY
DirTMP:=Trim(DirTMP);
if length(DirTMP)>0 then begin
if Dirrap[length(DirTMP)]о'\' then begin DirTMP:=DirTMP+' V ;
end;
И Проверяем наличие папки <DirraP>
if DirectoryExists(DirTMP) then begin
И Проверяем наличие файла «Links. txnp>, //в каталоге тестируемой конфигурации if FileExists(fn_Links_TMP) then begin H Вычисляем новое (полное) имя файла Links.trip, // куда скопируем тестируемой файл fn_Links_TMP_local: =DirTMP+ExtractFileName (fn_Links_raP) ; Н Копируем тестируемый файл Links.tup Н в папку DirTMP
if Windows.CopyFile(PCHAR(fn_Links_TMP), PCHAR(fn_Links_TMP_local). FALSE) then begin
Il Загружаем файл «Links.tmp> из // папки DirTMP в List
List.LoadFromPila(fn_Links_TMP_local);
if List.Count>0 then begin
// Формируем список всех пользователей // из файла links.tup И // Удаляем все "лишние" строки, // кроме имени пользователя i:=-l;
while i<(List.Count-1) do begin i:=i+l;
if POS(1{"Nana*',List[i])<>1 then begin List.Delete(i);
i:=i-l;
end;
end;
//
if List.Count>0 then begin
// Продолжаем, если список HE пуст
YesNext := 1;
end;
end;
end;
end;
end;
end;
if YesNext>0 then begin
// Открываем файл Links.tmp
fHendle:=Windows.CreateFile(PCHAR(fn_Links_TMP), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ OR FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0) ;
TRY
//
// Проверяем блокировку пользователей i:=-l;
while i<(List.Count-1) do
begin i:=i+l;
// Пытаемся блокировать область в файле Linke.tap, // соответствующую данному пользователю if not (LockFile(fHandle,
$lB8481+i, 0, 1, 0)) then begin
H Неудачная блокировка - значит, этот пользователь // активен, добавляем его в наш список
Listusere.Add(List[1]);
end
else begin
// Удачная блокировка - значит, этот пользователь // НЕ активен. Освобождаем блокировку UnLockFile(fHandle, $lK8481+i. 0, 1, 0);
end;
Application.ProcessMessages;
end;
П
// Вычисляем возвращаемое значение функции Result:=ListUsers.Count;
FINALLY
// Освобождаем ресурсы
Windows.CloseHandle(fHandle);
END;
end;
FINALLY
// Освобождаем ресурсы
if ListoNIL then begin
List.Clear;
List.Free;
List:=NIL;
end;
END;
end;
end;
Поясним листинг 13.1. Здесь сначала формируется временный список всех пользователей (List), указанных в файле links.tmp. Затем для каждого пользователя делается попытка блокировки соответствующего байта. Если блокировка не была успешной, считается, что этот пользователь подключен к базе данных, и информация о нем копируется в список активных пользователей (ListUsers).
На рис. 13.3) представлен результат, возвращаемый функцией Get_List_ ActiveUsers_f rom_lC.
Естественно, в таком виде список не очень-то легко читается.
Рис. 13.3. Список активных пользователей базы данных 1С
В листинге 13.2 представлена функция, конвертирующая список (см. рис. 13.3) в такой же формат, как на рис. 13.4.
Листинг 13.2. Функция, извлекающая из списка активных пользователей ^“.“^ - ::-: • ■-:...:... .:;.-.r^.v. <- .'л..:.'1.1 >й^. .1'. /: I^lv^-IL^
function Kxctr*ct_UeerNamB_fran_ListActiveUeers (
Listusers:TStrings):integer;
// Извлечение имен пользователей из списка активных пользователей 1С, // полученного с помощью функции Get_List_JActiveUsers_from_lC,
Var
List : TStrings;
i : integer;
begin
Result:=0;
if ListUsersoNIL then begin
if ListUsers.Count>0 then begin List := TStringList.Create;
TRY
И Сканируем список пользователей
for i:=0 to (Listusers.Count-1) do begin
// Разбиваем строку списка на части ep_Convert_SDF_to_Llet(Listusers(i).List,'О 1); // Выбираем вторую часть - имя пользователя Listusers[i]:=GetValueFranList(2,List);
end;
Result:=ListUsers.Count;
FINALLY
II Освобождаем ресурсы
if ListoNIL then begin
List.Clear;
List.Free;
List:=NIL;
end;
END;
end;
end;
end;
Глава 13. Слисок активных пользователей базы данных 1 ^Предприятие
Рис. 13.4. Список активных пользователей базы данных 1С после конвертации
Текст функции Exctract_UserName_from_ListActiveUsers достаточно прост И Вряд ЛИ требует пояснений. Функции sp_Convert_SDF_to_List И GetValueFranList были подробно рассмотрены в главе 10 и здесь их тексты не приводятся.
Примечание
Текст этого примера приведен на сопроводительном компакт-диске книги в папке \Part_3\Chapter_13\LoadListActiveUsers_1 C.PAS\LoadListActiveUsers_1 C.DPR.
В папке \Part_3\Chapter_13\GetUserslC.PAS\ сопроводительного компакт- диска книги приведены исходные тексты программы GetUserslC.EXE, назначение которой:
считывание списка зарегистрированных баз данных 1С из системного реестра (с возможностью считывания списка баз данных из текстового файла);
периодическое (по таймеру) считывание списка активных пользователей для заданной конфигурации (базы данных) 1С;
отсылка оповещения по сети на компьютер активного пользователя;
отсылка оповещения по сети на заданный компьютер, если список активных пользователей уже пуст.
В программе GetUserslC.EXE применены все способы обработки информации, рассмотренные нами ранее. На рис. 13.5 приведен результат визуализации списка активных пользователей.
N
User
(Dale [Time (Computer (isMono(RunModel
1
Попьзобыель_3
06.11.2006 14:56:25 COMP
N
E
2
Польз ователь_2
06.11.2006 14-56:44 COMP
N
•e
3
Admin
06.11.20® 14 56:51 COMP
N
'e
4
По/ьзоеатель_1
06.11.20® 14:57:03 COMP
N
■E
Рис. 13.5. Список активных пользователей базы данных 1С (программа GetUserslC.EXE)
Глава 14Глава 14
Глава 14
Глава 14
Отслеживание регламента системного обслуживания баз данных 1С:Предприятие
Как было отмечено в части!, в процессе производственной эксплуатации системы 1С:Предприятие может потребоваться периодическое и оперативное системное обслуживание баз данных 1С (например, изменение информационной структуры конфигурации). А это возможно лишь в том случае, если в контексте данной конфигурации нет активных пользователей. Следовательно, возникает необходимость в создании некоего регламента, который должен обеспечить освобождение баз данных 1С (т. е. выход пользователей из 1С) в строго заданные отрезки времени суток (часто— на время обеденного перерыва).
Создать-то регламент можно, и даже утвердить его в самых высоких инстанциях (на предприятии) с указанием мыслимых и немыслимых карающих мер по отношению к "тем, кто" — тоже несложная задача. Но, как показывает опыт, отслеживать этот регламент при большом количестве пользователей очень и очень проблематично.
Пользователь — он и в Африке пользователь. У пользователей своих проблем (в предметной области) по горло. И, по сути являясь существами в целом сознательными и доброжелательными, часто хотя бы один-другой пользователь (срочно убегая в столовую на обед), но забудет закрыть программу 1С перед уходом, со всеми вытекающими... Думаю, вряд ли кто-то сможет предложить одну "универсальную таблетку" для решения этой проблемы. Скорее всего здесь нужен ряд эффективных мер, специфичных для каждого предприятия. Но в любом случае необходим соответствующий программный инструментарий, помогающий отслеживать утвержденный регламент. В предыдущей главе мы рассмотрели способ выявления списка активных пользователей в заданной конфигурации, что может быть полезно при решении этой задачи.
Посмотрим, что можно еще предпринять для этих целей. Ранее (в части I) мы рассматривали способ визуализации окна программы 1С:Предприятие (как процесса в среде Windows). Мы создали функции, определявшие наличие программы I С: Предприятие в памяти компьютера. В принципе, нетрудно написать программу, которая будет автоматически запускаться при запуске Windows и периодически (например, раз в минуту) проверять наличие программы 1С:Предприятие. Если атакой программе предусмотреть возможность навязчивого напоминания пользователю (минут за 5—10 до начала регламентного перерыва) о том, что он должен выйти из 1С, то это снизит процент "забывчивых".
Примечание
На сопроводительном компакт-диске книги в папке \Part_3\Chapter_14\wSpy1C.PAS\ приведены исходные тексты программы wSpy1C.EXE, ориентированной как раз на такую ситуацию.
Здесь мы не будем подробно рассматривать тексты программы wSpylC.EXE (кто желает— посмотрит самостоятельно). Отметим только, что для сканирования по таймеру списка окон приложений, открытых в среде Windows, используются стандартные функции API Windows (листинг 4.98) — GecTopwindow и GetNextwindow. Текст заголовка окна считывается (чтобы идентифицировать окно 1С:Предприятие) с помощью функции GetwindowText. В остальном — что подскажет программисту его фантазия. Программа wSpylC.exe, например, очень навязчиво выдает соответствующее предупреждение на экран монитора пользователя (рис. 14.1) до тех пор, пока он не закроет программу 1С:Предприятие.
Рис. 14.1. Предупреждение о наступлении времени регламентного перерыва (программа wSpyIC.exd)
*..
Возможны ситуации, когда (при запуске программы IC) на экран выводится диалоговое окно, и программа ожидает идентификации пользователя. В этот момент пользователь уже "вошел" в систему, но в Мониторе (IC) его не видно (справедливости ради следует отметить, что и способ контроля активных пользователей, рассмотренный в главе 13, также не эффективен). То есть пользователь отправился по своим делам, диалоговое окно авторизации (идентификации) "висит" на экране. Монитор 1С ничего не видит, но база данных 1С занята. Сохранить изменения, сделанные в конфигурации, невозможно...
Вычислить такую ситуацию бывает проблематично. Программа wSpylC.EXE "борется" с этой ситуацией следующим образом:
Наряду с процессом поиска окна программы 1С:Предприятие (в заголовке окна присутствует строка символов "1С:Предприятие") производится поиск окна идентификации пользователя с заголовком (листинг 14.1):
"1Cv7 — Загрузка конфигурационной информации..."
В случае, если такое окно найдено, программа wSpylC.EXE пытается его закрыть, эмулируя соответствующие действия пользователя (листинг 14.2).
function GetHandleForDialogFaaswordlC : hWND;
// Функция проверяет :
// "висит” ли в памяти диалоговое окно ввода пароля для входа в 1С.
// Если ДА, то возвращает дескриптор окна
Var
Refl,Ref2 : hWND;
begin
Result:=0;
Refl:= Findwindow (nil,'1Cv7 - Загрузка конфигурационной информации...1);
if Refl>=32 then begin
Ref2:=FindWindoer(nil,'Авторизация доступа');
if Ref2>=32 then begin4
Result:=Ref2;
end;
end;
end;
function CloeeDialogPasswordlC : boolean;
II Закрыть диалог ввода пароля для входа в 1С
Var
Ref : hWND;
begin
Result:=FALSE;
Ref: =GetHandleForDialoa₽MBWordlC;
if Ref>=32 then begin
SendDlgltenMeseage(Ref,2, VM_KEYDOWN,32,0);
SendDlgltenHesaage(Ref,2, V®LKEYUP,32,0);
Result:=TRUE;
end;
end;
Тексты обеих функций "прозрачны" и не требуют пояснений.
Глава 15
Программа 1С:Предприятие в качестве DDE-сервера
DDE (Dynamic Data Exchange — динамический обмен данными)— это протокол, поддерживающий передачу данных между приложениями, функционирующими в среде Windows. При динамическом обмене данными одна программа (которая запрашивает данные) становится DDE-клиентом, а другая (которая поставляет данные) — DDE-сервером. DDE-протокол основан на использовании девяти сообщений (табл. 15.1).
Таблица 15.1. Сообщения DDE-протокола обмена данными
Сообщение
Назначение
wm_DDE_Initiate
Начать сеанс обмена данными
wm_DDE_Teminate
Завершить сеанс обмена данными
wm_DDE_Execute
Выполнить команду на сервере
wm_DDE_Ack
Получить статус операции
wm_DDE_Poke
Послать данные серверу
wm_DDE_Reqtest
Запросить данные с сервера
wm_DDE_Advis e
Установить связь с сервером
wm_DDE_UnAcvise
Завершить связь с сервером
wm_DDE_Data
Передать данные клиенту
Обмен данными (по DDE-протоколу) состоит из посылки ряда сообщений, общая форма которых имеет вид:
Poet№ee*ge(hWndH, wm_DDE_XXX, hWndS, Data);
Параметры: HWndR— дескриптор (ссылка) окна программы-клиента; vm_DDE_xxx— сообщение DDE; hwnds — дескриптор (ссылка) окна программы-сервера; Data — данные (атомы, ссылки на глобальные данные и т. д.).
DDE-сеанс начинается с того, что программа-клиент (инициатор сеанса) определяет название приложения (сервера) и темы "разговора". На основе DDE-протокола построен протокол OLE.
Программа 1 С:Предприятие может выполнять роль DDE-сервера, предоставляя свой сервис в получении данных (в частности, функции глобального модуля, объявленные с ключевым словом Экспорт). Программа MS Excel может выполнять роль как DDE-сервера, так и DDE-клиента. Поэтому попробуем использовать Excel (в качестве DDE-клиента) для иллюстрации возможностей 1С:Предприятие (в качестве DDE-сервера).
Запустим программу 1 С:Предприятие и откроем "нашу" конфигурацию lC_examp!e.DB. Затем запустим Excel.
Примечание
Роль DDE-клиента может выполнять любая ячейка Excel.
В документации к программе 1С:Предприятие приводится пример считывания рабочей даты в системе:
=11CV7'|DDE I1РабочаяДата()'
Попробуем таким же образом прочитать текущую дату:
=11CV7'|DDE I'ТекущаяДата()1
Результат представлен на рис. 15.1.
DDE-запрос к программе 1С предприятие из Excel:
='1СУ7'|ООЕ!,ТекущаяДатаО’
Формат ячейкиобщий|ДД.ММ.ПТГ
3903211.11.2006
Рис. 15.1. Результат считывания системной даты с использованием DDE-протокола
Теперь попробуем вызвать на выполнение функции, объявленные в глобальном модуле "нашей" конфигурации с ключевым словом экспорт.
Запрос:
='1CV7'|DDE!'гл9_Д_плюс_Б(5,7)'
Ответ: 12.
Запрос:
='1CV7' |DDE I 'гл9_ЗяачениеВСтрокуВнутр_для_Перечисления("Пол“, 1) '
Ответ: ("Е", "О", "О", "17*. "О", ”0", ”19").
Запрос:
=*1CV71|DDE!'гл9Получип»ЗначРеквизитаСправочника("ФизЛица","ГородПрожива НИЯ",1,”■,0)'
Ответ: Усинск.
Примечание
На сопроводительном компакт-диске книги в папке \Part_3\Chapter_l5\DDE\ есть файл 1C_DDE.XLS (Excel), где приведены все эти примеры.
В свое время я был заинтересован возможностью использовать механизм DDE-сообщений для того, чтобы можно было в реальном времени отслеживать начало каких-то процессов в системе 1 С:Предприятие (например, проведение документов) и их окончание. И, таким образом, построить некую "событийную" систему извещений пользователей о начале и окончании определенных процессов в системе. Но, к сожалению, не нашел в документации к IC никакой информации о механизме уведомления (со стороны 1С как DDE-сервера) DDE-клиента об изменении состояния системы 1С:Предприятие.
Естественно, рассмотренные в этой части примеры обмена информацией с системой 1С:Предприятие, реализованные как приложения в среде Windows, — лишь малая часть того, что можно использовать для решения прикладных задач системного сопрождения программы 1 С: Предприятие. Но мы на этом остановимся.
Примечание
Напомню, что представленные примеры исходных текстов — это упрощенная иллюстрация к рассматриваемым вопросам. Назначение этих примеров — дать представление о возможном подходе при решении задач информационного обмена с системой Ю.Предприятие. При работе с реальными базами 1С может потребоваться их доработка.
Приложение
Описание компакт-диска
Структура папок на сопроводительном компакт-диске книги соответствует ссылкам на примеры, приведенные в тексте книги. Каждый пример находится в отдельной папке. Каждая папка с примером расположена в папке, соответствующей номеру части, главы, раздела и подраздела. Если пример имеет несколько версий, то в папке примера находятся подпапки, имена которых соответствуют номеру версии. Каждая папка примера (или версии примера) содержит файлы, список которых определяется тематикой и контекстом изложения в книге.
Например, в разд. 4.7.1 части / приведен пример редактирования реквизитов справочника с использованием механизма OLE Automation. Файлы версии 1 этого примера расположены, соответственно, в папке \Part_l\Chapter_04\ Topic_4_7\Item_4_7_l\sp_EditAttrInRef.PAS\O 1.
Структура содержимого компакт-диска
Сопроводительный компакт-диск книги содержит папки:
lC_example.DB — учебная конфигурация 1С; основная тренировочная;
!C_example.DB_synhro— учебная конфигурация 1С; иллюстрация процесса синхронизации конфигураций;
lC_example.DB2 — учебная конфигурация 1С; иллюстрации использования возможностей внепроцессного сервера автоматизации (oleSrvlC.EXE) для проверки дат на корректность;
spJJb — исходные тексты библиотечных функций, используемых в программных примерах, приведенных на сопроводительном компакт-диске;
574 Приложение. Описание компакт-диска
Рап_1 — примеры по теме чисти / "1С и механизм OLE Automation":
Chapier_()3 — примеры по теме главы 3 "Подключение к 1С";
Chapter_04— примеры по теме главы 4 "Доступ к информации 1С из внешних приложений";
Chapter_()5 — примеры по теме главы 5 "Расширение функционала 1С";
Part_2— примеры по теме части II "Доступ к базе данных 1С без программы 1С:Предприятие":
Chapter_06 — примеры по теме главы б "Файлы формата DBF";
Chapter_07 — примеры по теме главы 7 "Обработка словаря базы данных 1С (файл lCv7.DD)";
Chapter.. 11 — пример по теме главы 11 "Остатки ТМЦ на складах";
Part_3— пример по теме части 111 "Программа 1С: Предприятие в среде Windows":
Chapter_12 — примеры по теме главы 12 "Список зарегистрированных баз данных 1С:Предприятие";
Chapter_13— примеры по теме главы 13 "Список активных пользователей базы данных I С: Предприятие";
Chapter_14— примеры по теме главы 14 "Отслеживание регламента системного обслуживания баз данных 1 С:Предприятие";
Chapter_15— примеры по теме главы 15 "Программа 1С:Предприятие в качестве DDE-сервера".
Предметный указатель
1
ICv7.MD. файл 227
А
ActiveForm, значок 429
ActiveX Library 362
ActiveX Library, значок 363
Addln_Example02_01, внешняя компонента 420
Addln_Example02_02, внешняя
компонента 429
AddIn_Files, внешняя компонента 414, 415.416
ANSI (American National Standards Institute) 452
Automation Object 363,434
В
BasicScript 446
BDE-5, пакет 448.457
C
C++Script 446
CallAsProc, метол 389
COM (Component Object Model 360
СОМ-объект 360
СОМ-сервер 361
D
dBASE 453
dBASE 111+ 454
DBF. формат 13,453
DBF-файл 262,479
структура 462
DBT-файл 456
DDE (Dynamic Data Exchange) 570
DDE-клиент 570
DDE-сервер 570
Detail table 51
DLL 371
E
EvalExpr, метод 234. 243
Excel 262
ExecuteBatch. метод 234,262
F
FALSE 404,415
FastScript, пакет 446
FindByCode, метод 49
G
Generate C object files, опция 383 GetFieldName_from_ !Cv7DD.
функция 470