Доброго дня! Мы собрались, чтобы разобраться с задачей, которая часто возникает у разработчиков на платформе 1С 7.7: создание интерактивного мини-журнала с возможностью отбора данных, используя табличное поле. Это может быть весьма непростой задачей, особенно когда требуется гибкое управление и визуальное оформление. Мы рассмотрим различные подходы к ее решению, начиная от базовых методов платформы и заканчивая использованием расширенных возможностей через внешние компоненты 1С++.
Наша цель — не изобретать велосипед, а использовать уже проверенные решения и подходы, чтобы вы могли создать функциональный и удобный инструмент. Давайте пошагово проанализируем, как можно добиться желаемого результата, основываясь на опыте сообщества и технических возможностях платформы.
Прежде чем углубляться в детали, давайте определимся, что такое табличное поле в контексте 1С 7.7. Это элемент управления на форме, предназначенный для отображения и, опционально, ввода табличных данных. Чаще всего оно работает с объектами типа ТаблицаЗначений или напрямую с записями базы данных, если используются расширенные компоненты. В модуле формы доступ к нему обычно осуществляется через имя элемента управления, которое вы присвоили ему на этапе конфигурирования, или через ключевое слово Таблица, если это единственный табличный документ на форме или он настроен как основной.
Основное назначение такого поля – это визуализация структурированных данных. Но функционал можно существенно расширить, добавив интерактивность, динамическую фильтрацию и форматирование.
Для создания мини-журнала нам потребуется не только отобразить данные, но и дать пользователю возможность взаимодействовать с ними: выбирать строки, применять фильтры. Рассмотрим, как это можно сделать.
Одним из ключевых аспектов интерактивности является реакция на действия пользователя. Табличное поле в 1С 7.7 имеет ряд событий, которые мы можем перехватывать для реализации нужного поведения.
Выбор: Это событие срабатывает при двойном клике мышью по ячейке или при нажатии клавиши Enter. Мы можем использовать его, чтобы, например, открыть документ, на который указывает выбранная строка, или выполнить какое-либо действие с данными этой строки.ПриНажатииКлавиши: Позволяет перехватывать нажатия клавиш, что дает более тонкий контроль над поведением.Предположим, мы хотим реализовать фильтрацию по определенной колонке при клике. Например, если пользователь кликает по колонке "Вид документа", мы можем предложить ему список доступных видов документов для отбора. Давайте посмотрим, как это можно сделать концептуально:
// В модуле формы, где размещено ТабличноеПоле
Перем ТабПоле; // Объект ТабличноеПоле на форме
Процедура ПриОткрытии()
// Предположим, что ТабПоле уже связано с ТаблицейЗначений или другим источником
ЗаполнитьТабличноеПоле();
КонецПроцедуры
Процедура ТабПоле_Выбор(НомерСтроки, Колонка)
// Обработка двойного клика или Enter
Сообщить("Выбрана строка № " + НомерСтроки + ", Колонка: " + Колонка);
// Здесь можно открыть документ или выполнить другое действие
// Например, получить данные из выбранной строки:
// ЗначениеЯчейки = ТабПоле.ПолучитьЗначение(НомерСтроки, Колонка);
// Док = СоздатьОбъект("Документ.МойДокумент");
// Если Док.НайтиПоНомеру(ЗначениеЯчейки) = 1 Тогда
// Док.Показать();
// КонецЕсли;
КонецПроцедуры
Процедура ТабПоле_ПриНажатииКлавиши(СтандартнаяОбработка, КодКлавиши, Состояние)
// Пример: Отключение стандартной обработки для некоторых клавиш
// Если КодКлавиши = 46 Тогда // Клавиша Delete
// СтандартнаяОбработка = 0; // Отключаем стандартное удаление
// Сообщить("Попытка удалить строку!");
// КонецЕсли;
КонецПроцедуры
// Пример обработчика клика, который не является стандартным событием, но может быть реализован
// если у вас есть возможность отслеживать клики через другие механизмы или внешние компоненты.
// Для "чистого" ТабличногоПоля 7.7 такое событие отсутствует,
// но его можно эмулировать, например, через внешний компонент.
// Однако, для реализации фильтрации через список значений, мы можем использовать событие
// "Выбор" или отдельную кнопку "Фильтр".
Процедура ПрименитьФильтрПоКолонке(ИмяКолонки)
Если ИмяКолонки = "ВидДокумента" Тогда
СписокВидов = СоздатьОбъект("СписокЗначений");
СписокВидов.Добавить("РасходнаяНакладная");
СписокВидов.Добавить("ПриходнаяНакладная");
СписокВидов.Добавить("СчетНаОплату");
// Открываем список для выбора
ВыбранныйВид = СписокВидов.ВыбратьЭлемент("Выберите вид документа для фильтрации");
Если ТипЗначения(ВыбранныйВид) = 1 Тогда // Проверяем, что что-то выбрано
// Здесь мы применим фильтр к нашему источнику данных.
// Если источник - ТаблицаЗначений, то нужно ее пересортировать/отфильтровать.
Сообщить("Применяем фильтр по виду документа: " + ВыбранныйВид);
// Пример: пересоздание или фильтрация ТаблицыЗначений
// ОтфильтроватьТаблицуПоВиду(ВыбранныйВид);
// ТабПоле.Обновить();
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Для реализации фильтрации по автору или проекту, мы будем использовать аналогичный подход, формируя СписокЗначений с уникальными авторами или проектами, присутствующими в данных.
Когда речь идет о фильтрации в табличном поле 1С 7.7, мы чаще всего подразумеваем фильтрацию данных в источнике, который отображает табличное поле, например, в ТаблицеЗначений. Если вы используете ТаблицуЗначений, то вам придется программно отфильтровывать ее содержимое и затем заново загружать или обновлять отображение табличного поля.
ТаблицыЗначений: При изменении фильтра мы можем пройтись по исходной ТаблицеЗначений, выбрать подходящие строки и поместить их в новую, отфильтрованную ТаблицуЗначений, которую затем присвоим табличному полю.Сортировать() и НайтиСтроки() для ТаблицыЗначений могут быть полезны, но для динамической фильтрации чаще всего применяется итерационный подход.Важный момент: Фильтры очень удобно делать программно, что позволяет гибко управлять отображением данных. Это особенно актуально при ограничении прав пользователя, когда необходимо показывать ему только разрешенные для просмотра документы или записи.
Для более сложных сценариев, работы с большими объемами данных или необходимости выполнения сложных запросов, стандартные возможности 1С 7.7 могут оказаться недостаточными. В таких случаях на помощь приходят внешние компоненты, такие как 1С++. В частности, классы ПоставщикДанных (DataProvider) и ПрямойЗапрос (DirectQuery) значительно расширяют функционал табличного поля.
Класс ПоставщикДанных является своего рода "прослойкой" между табличным полем и источником данных. Само табличное поле не взаимодействует напрямую с базой данных или файлами; оно обращается к ПоставщикуДанных за информацией. Это обеспечивает несколько ключевых преимуществ:
ТаблицейЗначений, файлом или прямым запросом к СУБД) без существенных изменений в коде, управляющем табличным полем.ПоставщикДанных может агрегировать данные из различных источников, преобразовывать их и представлять в удобном для табличного поля виде.Для работы с ПоставщикомДанных необходимо создать его объект и связать с ним источник данных. Затем этот поставщик связывается с табличным полем.
Класс ПрямойЗапрос — это мощный инструмент, который позволяет выполнять прямые SQL-запросы к базе данных (например, Microsoft SQL Server), на которой работает 1С 7.7. Это критически важно для производительности и гибкости при работе с:
Чтобы использовать ПрямойЗапрос, мы создаем его объект, задаем текст SQL-запроса, можем установить параметры (чтобы избежать SQL-инъекций и повысить гибкость), а затем передаем этот объект в качестве источника данных для ПоставщикаДанных.
Конфигурация 1С++: Для использования этих классов, вам потребуется установить компоненты 1С++. Это обычно включает размещение файлов .ert (с описанием классов) и .dll (с реализацией) в соответствующих папках вашей 1С или в системных директориях.
Давайте рассмотрим концептуальный пример связки ТабличноеПоле, ПоставщикДанных и ПрямойЗапрос:
// В модуле формы
Перем ТабПоле; // Объект ТабличноеПоле на форме
Процедура ПриОткрытии()
// Инициализируем компоненты 1С++
// Убедитесь, что 1С++ загружен и доступен
Попытка
Поставщик = СоздатьОбъект("ПоставщикДанных");
Запрос = СоздатьОбъект("ПрямойЗапрос");
Исключение
Сообщить("Ошибка инициализации компонентов 1С++: " + ОписаниеОшибки(), "!");
Возврат;
КонецПопытки;
// Задаем уникальное имя поставщика данных
Поставщик.Имя = "ДокументыЖурнала";
// Формируем текст SQL-запроса
// Пример: выборка данных из журнала документов "РасходнаяНакладная"
// с использованием параметров для отбора по дате
Запрос.ТекстЗапроса = "SELECT
Doc.ID,
Doc.Date AS ДатаДок,
Doc.Number AS НомерДок,
Val.Value AS СуммаДок,
Proj.ID AS Проект,
Auth.ID AS Автор
FROM
_1SDoc_РасходнаяНакладная AS Doc (NOLOCK)
LEFT JOIN
_1SConst AS Val (NOLOCK) ON Val.ObjID = Doc.ID AND Val.ID = '<ID_Реквизита_Сумма>' -- Пример связи с реквизитом
LEFT JOIN
_1SProject AS Proj (NOLOCK) ON Proj.ID = Doc.ProjectID -- Пример связи с проектом
LEFT JOIN
_1SUser AS Auth (NOLOCK) ON Auth.ID = Doc.AuthorID -- Пример связи с автором
WHERE
Doc.Date >= @ДатаНачала
AND Doc.Date <= @ДатаОкончания
AND Doc.ProjectID = @ТекущийПроект
AND Doc.AuthorID = @ТекущийАвтор
ORDER BY
Doc.Date DESC";
// Устанавливаем параметры запроса. Это важно для безопасности и гибкости.
Запрос.УстановитьПараметр("ДатаНачала", Дата(Год(ТекущаяДата()), 1, 1)); // Например, с начала года
Запрос.УстановитьПараметр("ДатаОкончания", ТекущаяДата());
Запрос.УстановитьПараметр("ТекущийПроект", ""); // Пустая строка - нет отбора или конкретный ID
Запрос.УстановитьПараметр("ТекущийАвтор", ""); // Пустая строка - нет отбора или конкретный ID
// Указываем ПоставщикуДанных, откуда брать данные
Поставщик.ИсточникДанных = Запрос;
// Привязываем ПоставщикаДанных к ТабличномуПолю на форме
ТабПоле.УстановитьПоставщикаДанных(Поставщик);
// Автоматически создаем колонки на основе полей запроса
ТабПоле.СоздатьКолонки();
// Загружаем данные в табличное поле
ТабПоле.Обновить();
КонецПроцедуры
// Пример реализации функции для обновления данных с новыми фильтрами
Процедура ОбновитьДанныеЖурнала(НоваяДатаНачала, НоваяДатаОкончания, НовыйПроект, НовыйАвтор)
Если ТипЗначения(Поставщик) = 1 Тогда // Проверяем, что поставщик инициализирован
Запрос = Поставщик.ИсточникДанных;
Если ТипЗначения(Запрос) = 1 Тогда
Запрос.УстановитьПараметр("ДатаНачала", НоваяДатаНачала);
Запрос.УстановитьПараметр("ДатаОкончания", НоваяДатаОкончания);
Запрос.УстановитьПараметр("ТекущийПроект", НовыйПроект);
Запрос.УстановитьПараметр("ТекущийАвтор", НовыйАвтор);
ТабПоле.Обновить(); // Перезагружаем данные с новыми параметрами
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Этот подход дает нам огромную гибкость: мы можем динамически менять параметры SQL-запроса, не переписывая его полностью, и моментально обновлять данные в табличном поле.
Для создания полноценного журнала с удобным интерфейсом нам нужно уметь не только выводить данные, но и форматировать их: менять цвета, добавлять флажки, скрывать или показывать колонки. Табличное поле в 1С 7.7 предоставляет для этого широкие возможности.
Вы можете как автоматически создавать колонки на основе источника данных (как в примере выше с СоздатьКолонки()), так и полностью управлять ими программно.
СоздатьКолонки() удобен, когда структура данных меняется. Он адаптирует колонки табличного поля под новый набор полей.Колонки объекта табличного поля позволяет нам добавлять, удалять, изменять свойства каждой колонки.Рассмотрим пример программного изменения колонок:
// В модуле формы
Процедура НастроитьКолонки()
// Удаляем все существующие колонки
ТабПоле.Колонки.УдалитьВсе();
// Добавляем новые колонки вручную
КолонкаДата = ТабПоле.Колонки.Добавить("ДатаДок");
КолонкаДата.Заголовок = "Дата документа";
КолонкаДата.Ширина = 100;
КолонкаДата.Тип = "Дата"; // Указываем тип данных для корректного отображения и сортировки
КолонкаНомер = ТабПоле.Колонки.Добавить("НомерДок");
КолонкаНомер.Заголовок = "Номер";
КолонкаНомер.Ширина = 80;
КолонкаСумма = ТабПоле.Колонки.Добавить("СуммаДок");
КолонкаСумма.Заголовок = "Сумма";
КолонкаСумма.Ширина = 120;
КолонкаСумма.Тип = "Число";
КолонкаСумма.Выравнивание = "Право";
КолонкаПроект = ТабПоле.Колонки.Добавить("Проект");
КолонкаПроект.Заголовок = "Проект";
КолонкаПроект.Ширина = 150;
КолонкаПроект.Видимость = 0; // Скрываем колонку по умолчанию, но она есть
// После настройки колонок обновляем данные
ТабПоле.Обновить();
КонецПроцедуры
Мы можем также комбинировать автоматическое создание с последующей доработкой, например, скрывая ненужные колонки или меняя их заголовки.
Одним из самых мощных инструментов для улучшения пользовательского опыта является условное форматирование. Мы можем менять цвет фона, цвет текста, отображать флажки или картинки в ячейках в зависимости от их содержимого. Для этого используется событие ПриПолученииДанных табличного поля.
Событие ПриПолученииДанных(ИдентификаторКолонки, НомерСтроки, Значение): Это событие срабатывает для каждой ячейки табличного поля перед ее отображением. В нем мы получаем доступ к идентификатору колонки, номеру строки и значению ячейки, что позволяет нам принять решение о ее форматировании.
Давайте рассмотрим, как мы можем сделать "галочки" и "разноцветные поля", о которых упоминал один из участников обсуждения:
// В модуле формы
Процедура ТабПоле_ПриПолученииДанных(ИдентификаторКолонки, НомерСтроки, Значение)
// Пример: условное форматирование для колонки "Сумма"
Если ИдентификаторКолонки = "СуммаДок" Тогда
Если Значение < 0 Тогда
ТабПоле.ЦветТекстаЯчейки(ИдентификаторКолонки, НомерСтроки, "Красный");
ТабПоле.ЦветФонаЯчейки(ИдентификаторКолонки, НомерСтроки, "Желтый");
ИначеЕсли Значение > 10000 Тогда
ТабПоле.ЦветТекстаЯчейки(ИдентификаторКолонки, НомерСтроки, "Синий");
ТабПоле.ШрифтЯчейки(ИдентификаторКолонки, НомерСтроки, "Полужирный");
КонецЕсли;
КонецЕсли;
// Пример: отображение флажка для колонки "Проведен"
Если ИдентификаторКолонки = "Проведен" Тогда // Предположим, у нас есть такая колонка
ТабПоле.ОтображатьФлажокЯчейки(ИдентификаторКолонки, НомерСтроки, Истина);
ТабПоле.УстановитьФлажокЯчейки(ИдентификаторКолонки, НомерСтроки, Значение); // Значение должно быть 0 или 1
КонецЕсли;
// Пример: отображение картинки для колонки "Статус"
Если ИдентификаторКолонки = "Статус" Тогда // Предположим, у нас есть колонка "Статус" с числовым значением
// Индексы картинок из списка картинок формы.
// Допустим, 0 - "Новый", 1 - "В работе", 2 - "Завершен"
Если Значение = 0 Тогда
ТабПоле.ИндексКартинкиЯчейки(ИдентификаторКолонки, НомерСтроки, 0);
ИначеЕсли Значение = 1 Тогда
ТабПоле.ИндексКартинкиЯчейки(ИдентификаторКолонки, НомерСтроки, 1);
ИначеЕсли Значение = 2 Тогда
ТабПоле.ИндексКартинкиЯчейки(ИдентификаторКолонки, НомерСтроки, 2);
КонецЕсли;
КонецЕсли;
// Пример: выделение всей строки цветом, если дата документа просрочена
Если ИдентификаторКолонки = "ДатаДок" Тогда
Если Значение < ТекущаяДата() ИЛИ Значение = "" Тогда // Просрочен или не указан
ТабПоле.ЦветФонаСтроки(НомерСтроки, "СветлоРозовый");
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Используя эти методы, мы можем создать очень наглядный и информативный журнал, где важные записи будут выделены цветом, а состояния будут отображаться флажками или иконками.
Табличное поле позволяет настроить, как пользователь может выделять элементы. Это может быть:
ВыделятьВсюСтроку = 1 у табличного поля.Выбор режима зависит от функциональности, которую вы хотите предоставить пользователю. Например, если основное действие – это просмотр и выбор целых записей, выделение всей строки будет удобнее.
Помимо событий, связанных с данными, существуют события, реагирующие на изменения самой структуры табличного поля:
ПриИзмененииШириныКолонки: Позволяет нам реагировать на изменение пользователем ширины колонки, например, чтобы сохранять эти настройки.ПриИзмененииПорядкаКолонок: Срабатывает при перетаскивании колонок.Использование этих событий дает нам возможность сделать интерфейс более "умным" и адаптируемым, сохраняя пользовательские предпочтения.
Мы рассмотрели различные подходы к работе с табличным полем в 1С 7.7 для создания интерактивного мини-журнала с отбором. Нам удалось выяснить, что есть два основных пути:
ТаблицуЗначений как источник данных, программно фильтруем ее, и используем события табличного поля (Выбор, ПриПолученииДанных) для интерактивности и форматирования. Это подходит для средних объемов данных и не требует установки дополнительных компонентов.ПоставщикДанных и ПрямойЗапрос): Этот подход открывает двери к высокопроизводительным решениям, позволяя работать напрямую с SQL-сервером. Он незаменим для больших объемов данных и сложных аналитических выборок, предоставляя при этом те же возможности по интерактивности и форматированию.Выбирая подходящий метод, мы должны учитывать объем данных, требования к производительности и сложность логики отбора. В любом случае, благодаря гибкости 1С 7.7 и расширениям 1С++, мы имеем все необходимые инструменты для создания мощных и удобных пользовательских интерфейсов. Мы надеемся, что этот подробный разбор поможет вам в вашей работе и позволит избежать "изобретения велосипеда".