gifts2017

Программное добавление кнопок копирования табличных частей во все документы с минимальными изменениями конфигурации (или вообще без изменения)

Опубликовал Дмитрий Семенов (Sam13) в раздел Обработки - Обработка документов

Работает на УТ 10.3, УПП
Механизм добавления кнопок копирование/вставки табличных частей во все документы без тотального изменения конфигурации.

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

Предлагается механизм добавления кнопок копирования/вставки без тотального изменения конфигурации. Документы можно даже не снимать с поддержки. Кнопки добавляются к каждой табличной части документа (их может быть несколько, например, "товары" и "услуги").

Upd: Сокращен состав изменений в конфигурации. Добавлена возможность сохранения буфера обмена в файл/ восстановления из файла.

Задача: в командную панель табличной части добавить кнопки копирования и вставки табличной части. Кнопка «Копировать» доступна всегда. Кнопка «Вставить» доступна если есть значения для копирования и если документ доступен для редактирования.

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

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

Upd: Изменены обработки альтернативного решения. Добавлена авторегистрация обработок в справочнике "Внешние обработки"

Изменения конфигурации:

  • новая обработка «БуферОбменаТаблицаЗначений»
  • изменения роли «Пользователь» для настройки доступа к обработке
  • изменения в процедуре «МеханизмНумерацииОбъектов.УстановитьДоступностьПоляВводаНомера»
  • изменения в процедуре «УниверсальныеМеханизмы.СформироватьПодменюЗаполненияТЧ»
  • изменения в процедуре «УниверсальныеМеханизмы.ОбработатьНажатиеНаДополнительнуюКнопкуЗаполненияТЧ»
Как видно из списка измененных объектов здесь отсутствуют изменения в документах, что и было главной целью.
 
Процесс:

1. Добавляем новую обработку «БуферОбменаТаблицаЗначений». Обработка используется для "предпросмотра" вставляемого значения, возможности отказа от вставки, варианта вставки, настройки состава строк и колонок. Картинки кнопок содержатся в обработке как макеты двоичных данных. Кроме того в модуле обработки содержатся экспортные процедуры, которые управляют вставкой кнопок в форму документа и обрабатывают нажатия на кнопки. Не забудьте дать права роли «Пользователь» для доступа к этому параметру всем пользователям.  

2. Программно добавляем кнопки в командные панели формы документа. Кнопки добавляются при открытии формы документа.

Для добавления кнопок в командные панели используем процедуру, которая вызывается в каждом стандартном документе при открытии:

МеханизмНумерацииОбъектов.УстановитьДоступностьПоляВводаНомера();

В этой процедуре доступны все контексты, которые нам нужны: контекст метаданных объекта и контекст формы объекта. 

Процедура УстановитьДоступностьПоляВводаНомера(МетаданныеОбъекта, ФормаОбъекта, ПодменюДействия, ПолеВводаНомера) Экспорт

    Обр = Обработки.БуферОбменаТаблицаЗначений.Создать();
   
Обр.БуферОбмена_ДобавитьКнопкиВКомандныеПанелиФормы(МетаданныеОбъекта,ФормаОбъекта);

    Если
ФормаОбъекта.Автонумерация = АвтонумерацияВФорме.Авто Тогда
        Возврат;
    КонецЕсли;

   
СтратегияРедактирования = ПолучитьСтратегиюРедактированияНомераОбъекта(МетаданныеОбъекта);

    Если
СтратегияРедактирования = Перечисления.СтратегияРедактированияНомеровОбъектов.Доступно Тогда
        Если
ПодменюДействия.Кнопки.Найти("РедактироватьКодНомер") <> Неопределено Тогда
           
ПодменюДействия.Кнопки.Удалить(ПодменюДействия.Кнопки.РедактироватьКодНомер);
        КонецЕсли;
       
ПолеВводаНомера.ТолькоПросмотр = Ложь;
    КонецЕсли;

   
ПолеВводаНомера.ПропускатьПриВводе = ПолеВводаНомера.ТолькоПросмотр;
   
УстановитьПодсказкуПоляВводаКодаНомера(ПолеВводаНомера, ПодменюДействия, СтратегияРедактирования);

КонецПроцедуры
// УстановитьДоступностьПоляВводаНомера()

Текст процедуры «БуферОбмена_ДобавитьКнопкиВКомандныеПанелиФормы» приведен ниже. 

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

Имя кнопки состоит из секций:

  • Кнопка копирования: «КопироватьТЧВБуферОбмена_"+ИмяТабличнойЧасти
  • Кнопка вставки: «ВставитьТЧИзБуфераОбмена_"+ИмяТабличнойЧасти

Если буфер обмена не содержит «правильного» значения, то кнопка вставки видна как неактивная.

Тонкий момент: если одной табличной части соответствует несколько командных панелей, то кнопки добавятся в первую из встреченных командных панелей.

ПримечаниеПроцедура находится в модуле обработки "БуферОбменаТаблицаЗначений", копировать ее из статьи нет необходимости. Текст процедуры приведен для наглядности.

// Параметры
//_Метаданные   - метаданные объекта
//_Форма        - форма объекта
//Процедура добавляет в командные панели формы кнопки работы с буфером обмена (копирования/вставки табличных частей)
Процедура БуферОбмена_ДобавитьКнопкиВКомандныеПанелиФормы(_Метаданные,_Форма) Экспорт
    Если
_Метаданные.ТабличныеЧасти.Количество() <> 0 Тогда
       
соотвТабЧасть_КоманднаяПанель = Новый Соответствие;

        Для Каждого
ЭФ Из _Форма.ЭлементыФормы Цикл
            Если
ТипЗнч(ЭФ) = Тип("КоманднаяПанель") Тогда
                Если
ТипЗнч(ЭФ.ИсточникДействий) = Тип("ТабличноеПоле") Тогда
                   
ИмяТЧ = ЭФ.ИсточникДействий.Данные;

                   
ТабЧасть = _Метаданные.ТабличныеЧасти.Найти(ИмяТЧ);
                    Если
ТабЧасть = Неопределено Тогда
                        Продолжить;
                    КонецЕсли;

                   
//Если одной табличной части соответствует несколько панелей, то добавляем кнопки в первую, а не в последнюю
                   
Если соотвТабЧасть_КоманднаяПанель.Получить(ТабЧасть) = Неопределено Тогда
                       
соотвТабЧасть_КоманднаяПанель.Вставить(ТабЧасть,ЭФ);
                    КонецЕсли;
                КонецЕсли;
            КонецЕсли;
        КонецЦикла;

       
ВставкаВозможна = Истина;
        Если
соотвТабЧасть_КоманднаяПанель.Количество() <> 0 Тогда
            Попытка
               
ХЗ = ПараметрыСеанса.ОбщиеЗначения;
               
ЗначениеХЗ = ХЗ.Получить();
                Если
ТипЗнч(ЗначениеХЗ) <> Тип("Структура") Тогда
                   
ВставкаВозможна = ЛОЖЬ;
                Иначе
                   
ОписаниеИсточника   = ЗначениеХЗ.ОписаниеИсточника;
                   
ЗначениеТЧ          = ЗначениеХЗ.ТабличнаяЧасть;
                    Если
ТипЗнч(ЗначениеТЧ) <> Тип("ТаблицаЗначений") Тогда
                       
ставкаВозможна = ЛОЖЬ;
                    КонецЕсли;
                КонецЕсли;
            Исключение
               
ВставкаВозможна = ЛОЖЬ;
            КонецПопытки;
        Иначе
           
ВставкаВозможна = ЛОЖЬ;
        КонецЕсли;

        Для Каждого
Элем Из соотвТабЧасть_КоманднаяПанель Цикл
           
КП = Элем.Значение;
           
ТабЧасть = Элем.Ключ;
           
КнопкаКопировать = КП.Кнопки.Добавить("КопироватьТЧВБуферОбмена_"+ТабЧасть.Имя,ТипКнопкиКоманднойПанели.Действие,,Новый Действие("НажатиеНаДополнительнуюКнопкуЗаполненияТЧ"));
           
КнопкаКопировать.Картинка = ПолучитьКартинкуКопировать();

            Если
ВставкаВозможна Тогда
               
КнопкаВставить = КП.Кнопки.Добавить("ВставитьТЧИзБуфераОбмена_"+ТабЧасть.Имя,ТипКнопкиКоманднойПанели.Действие,,Новый Действие("НажатиеНаДополнительнуюКнопкуЗаполненияТЧ"));
               
КнопкаВставить.Картинка = ПолучитьКартинкуВставитьАктивная();
            Иначе
               
КнопкаВставить = КП.Кнопки.Добавить("ВставитьТЧИзБуфераОбмена_"+ТабЧасть.Имя,ТипКнопкиКоманднойПанели.Действие,,Новый Действие("ПроизвольныйТекстЧтобыКнопкаБылаНедоступна"));
               
КнопкаВставить.Картинка = ПолучитьКартинкуВставитьПассивная();
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;
КонецПроцедуры


3. Добавление обработчика нажатия на кнопку.

Итак, кнопки в форму добавлены. Но как обработать их нажатие в форме?

Для обработки нажатия используем стандартный механизм работы с обработчиками табличных частей через внешние обработки. Стандартный механизм встроен во все документы, где есть табличные части. По вышеприведенному коду видно, что кнопкам назначен обработчик «НажатиеНаДополнительнуюКнопкуЗаполненияТЧ». Процедура этого обработчика есть во всех стандартных документах.

В стандартной УТ перед открытием любого документа вызывается процедура:

УниверсальныеМеханизмы.СформироватьПодменюЗаполненияТЧ(мКнопкиЗаполненияТЧ,СоответствиеТЧ);

Процедура устанавливает подменю "Заполнить" в командных панелях ТЧ документа при необходимости, где 

  • мКнопкиЗаполненияТЧ – дерево кнопок «пользовательской» обработки табличных частей
  • СоответствиеТЧ – соответствие табличной части и ее кнопки(подменю) заполнения

К сожалению, в процедуру передаются не сами командные панели, а только кнопки подменю «Заполнить», поэтому мы не можем ее использовать для добавления наших кнопок копирования/вставки. Именно по этой причине для добавления кнопок мы использовали другую процедуру, описанную выше.

Поэтому используем данную процедуру только для подготовки обработки нажатия на «наши» кнопки.

В контексте данной процедуры доступна переменная формы «мКнопкиЗаполненияТЧ», которая содержит дерево «пользовательских» кнопок обработки табличных частей. В конец этой процедуры добавим вызов «своей» процедуры.

Процедура СформироватьПодменюЗаполненияТЧ(ДеревоКнопок,СоответствиеТЧ) Экспорт

    Для Каждого
КлючИЗначение Из СоответствиеТЧ Цикл

       
ИмяТабличнойЧасти = КлючИЗначение.Ключ.Данные;

       
СтрокаПодменю = ДеревоКнопок.Строки.Найти(ИмяТабличнойЧасти, "Имя");

        Если
СтрокаПодменю <> Неопределено Тогда

           
// Табличное поле
           
СтрокаПодменю.Расшифровка = КлючИЗначение.Ключ;

           
ПодменюИлиКоманднаяПанель = КлючИЗначение.Значение;

            Если
ТипЗНЧ(ПодменюИлиКоманднаяПанель) = Тип("КоманднаяПанель") Тогда

               
ПодменюИлиКоманднаяПанель = ПодменюИлиКоманднаяПанель.Кнопки.Добавить(,ТипКнопкиКоманднойПанели.Подменю,"Заполнить");

            КонецЕсли;
           
СформироватьПодменю(СтрокаПодменю, ПодменюИлиКоманднаяПанель,Ложь,Истина);

        КонецЕсли;

    КонецЦикла;

   
Обр = Обработки.БуферОбменаТаблицаЗначений.Создать();
   
Обр.БуферОбмена_ДополнитьПодменюЗаполненияТЧ(ДеревоКнопок,СоответствиеТЧ);

КонецПроцедуры

Текст процедуры «БуферОбмена_ДополнитьПодменюЗаполненияТЧ» приведен ниже.

ПримечаниеПроцедура находится в модуле обработки "БуферОбменаТаблицаЗначений", копировать ее из статьи нет необходимости. Текст процедуры приведен для наглядности.

//Добавляем в дерево кнопок информацию о «своих» кнопках. Это дерево используется для определения обработчика при нажатии кнопки в форме.
//Отличать кнопки и из назначение будем по значению колонки «расшифровка».
//В стандартном решении поле расшифровка имеет тип "ВнешняяОбработка", а у нас тип "строка"
Процедура БуферОбмена_ДополнитьПодменюЗаполненияТЧ(_ДеревоКнопок,_СоответствиеТЧ) Экспорт
    Для Каждого
Элем Из _СоответствиеТЧ Цикл
       
НовСтрока = _ДеревоКнопок.Строки.Добавить();
       
НовСтрока.Расшифровка = "Полимагнит.БуферОбмена.Копировать";
       
НовСтрока.Имя = "КопироватьТЧВБуферОбмена_"+Элем.Ключ.Имя;

       
НовСтрока = _ДеревоКнопок.Строки.Добавить();
       
НовСтрока.Расшифровка = "Полимагнит.БуферОбмена.Вставить";
       
НовСтрока.Имя = "ВставитьТЧИзБуфераОбмена_"+Элем.Ключ.Имя;
    КонецЦикла;
КонецПроцедуры

Теперь, на момент открытия формы документа у нас добавлены кнопки в форму и подготовлена база для их обработки.

Как уже было сказано выше, для обработки нажатия доп.кнопок в стандартных документах используется общий обработчик «НажатиеНаДополнительнуюКнопкуЗаполненияТЧ». Используем его. В форме обработчик вызывает процедуру:

УниверсальныеМеханизмы.ОбработатьНажатиеНаДополнительнуюКнопкуЗаполненияТЧ()

В процедуре доступна строка дерева кнопок «мКнопкиЗаполненияТЧ» и контекст объекта документа. Строка дерева – это фактически инструкция к тому, как обрабатывать кнопку. В стандартном решении колонка «Расшифровка» содержит тип «СправочникСсылка.ВнешниеОбработки». У нас же это строка. Воспользуемся этим для определения того, что нажата именно "наша" кнопка. Добавим через «Иначе» вызов своей процедуры:

// Процедура - обработчик нажатия любой из дополнительных кнопок заполнения табличных частей
// Параметры:
//    СтрокаКнопки     : строка дерева значений, содержащая "инструкцию" к обработке кнопки
//    ЭтотОбъект       : контекст объекта документа
Процедура ОбработатьНажатиеНаДополнительнуюКнопкуЗаполненияТЧ(СтрокаКнопки,ЭтотОбъект) Экспорт

   
Расшифровка = СтрокаКнопки.Расшифровка;

    Если
ТипЗНЧ(Расшифровка) = Тип("СправочникСсылка.ВнешниеОбработки") Тогда
       
ИмяФайла = КаталогВременныхФайлов()+"PrnForm.tmp";
       
ОбъектВнешнейФормы = Расшифровка.ПолучитьОбъект();

        Если
ОбъектВнешнейФормы = Неопределено Тогда
           
Сообщить("Ошибка получения внешней обработки заполнения табличной части документа. Возможно обработка была удалена", СтатусСообщения.Важное);
            Возврат;
        КонецЕсли;

       
ДополнительныеПараметры = Неопределено;
       
МетаданныеОбъекта = ЭтотОбъект.Метаданные();
       
СсылкаОбъекта = Неопределено;
        Если
Метаданные.Документы.Содержит(МетаданныеОбъекта) Тогда
           
СсылкаОбъекта = Документы[МетаданныеОбъекта.Имя].ПустаяСсылка();
        ИначеЕсли
Метаданные.Справочники.Содержит(МетаданныеОбъекта) Тогда
           
СсылкаОбъекта = Справочники[МетаданныеОбъекта.Имя].ПустаяСсылка();
        КонецЕсли;

        Если
СсылкаОбъекта <> Неопределено Тогда
            Для Каждого
Стр Из Расшифровка.Принадлежность Цикл
                Если (
Стр.СсылкаОбъекта = СсылкаОбъекта) И (СокрЛП(Стр.ТабличнаяЧастьИмя) = СтрокаКнопки.Родитель.Имя) Тогда
                   
ДополнительныеПараметры = Стр.ДополнительныеПараметрыОбработки.Получить();
                    Прервать;
                КонецЕсли;
            КонецЦикла;
        КонецЕсли;

       
ДвоичныеДанные = ОбъектВнешнейФормы.ХранилищеВнешнейОбработки.Получить();
       
ДвоичныеДанные.Записать(ИмяФайла);
        Попытка
           
Обработка = ВнешниеОбработки.Создать(ИмяФайла);
        Исключение
           
Сообщить("Ошибка исполнения внешней обработки табличной части документа."+Символы.ПС+ОписаниеОшибки(), СтатусСообщения.Важное);
            Возврат;
        КонецПопытки;

       
// Передать внешней обработке дополнительные параметры
       
Если ДополнительныеПараметры <> Неопределено Тогда
           
// Если у внешней обработки есть реквизит для дополнительных параметров, присвоить ему значение
           
Если НЕ Обработка.Метаданные().Реквизиты.Найти("ДополнительныеПараметры") = Неопределено Тогда
               
Обработка.ДополнительныеПараметры = ДополнительныеПараметры;
            КонецЕсли;
        КонецЕсли;

        Попытка
           
Обработка.Инициализировать(ЭтотОбъект, СтрокаКнопки.Родитель.Имя, СтрокаКнопки.Родитель.Расшифровка);
        Исключение
           
ОбщегоНазначения.СообщитьОбОшибке(ОписаниеОшибки(),, "Заполнение ТЧ не произведено!");
        КонецПопытки;
    Иначе
//доработки
       
Обр = Обработки.БуферОбменаТаблицаЗначений.Создать();
        Обр.БуферОбмена_ОбработатьНажатиеНаКнопку(СтрокаКнопки,ЭтотОбъект);
    КонецЕсли;

КонецПроцедуры

Текст процедуры «БуферОбмена_ОбработатьНажатиеНаКнопку» приведен ниже. 

Описание процедуры:

  • Через значение расшифровки определяем какая кнопка нажата – копирования или вставки.
  • Имя табличной части получаем через имя кнопки. Помним, что
    • Кнопка копирования: «КопироватьТЧВБуферОбмена_"+ИмяТабличнойЧасти
    • Кнопка вставки: «ВставитьТЧИзБуфераОбмена_"+ИмяТабличнойЧасти
  • Отсекая известные символы получаем имя табличной части.
  • Через контекст объекта и имя табличной части получаем значение табличной части.

При копировании в буфер обмена, и при вставки из буфера обмена добавлены вызовы дополнительных процедур. Это пригодится, если табличная часть содержит специфические реквизиты, которые нежелательно копировать (Например, уникальный идентификатор)

При вставке из буфера обмена вызывается обработка «БуферОбменаТаблицаЗначений». Не буду приводить листинг обработки. Кратко: перед вставкой обработка показывает вставляемое значение (таблицу), в заголовке видно строковое представление источника таблицы (документа). Существует возможность вставить строки с удалением существующих, добавить строчки ниже или отказаться от действия. Кроме того можно изменять состав добавляемых колонок через настройку их видимости в форме обработки. В объект-приемник вставляются только видимые колонки.

ПримечаниеПроцедура находится в модуле обработки "БуферОбменаТаблицаЗначений", копировать ее из статьи нет необходимости. Текст процедуры приведен для наглядности.

// Процедура - обработчик нажатия кнопку работы с буфером обмена (копировать/вставить)
// Параметры:
//    _СтрокаКнопки     : строка дерева значений, содержащая "инструкцию" к обработке кнопки
//    _ЭтотОбъект       : контекст объекта документа
Процедура БуферОбмена_ОбработатьНажатиеНаКнопку(_СтрокаКнопки,_ЭтотОбъект) Экспорт
   
Расшифровка = _СтрокаКнопки.Расшифровка;

   
ИмяКнопки = _СтрокаКнопки.Имя;

    Если
Расшифровка = "Полимагнит.БуферОбмена.Копировать" Тогда
       
ИмяТЧ = СокрЛП(СтрЗаменить(ИмяКнопки,"КопироватьТЧВБуферОбмена_",""));
       
ТабЧасть = _ЭтотОбъект[ИмяТЧ];
       
ЗначениеТабличнойЧасти = ТабЧасть.Выгрузить();

       
//предварительно обработаем таблицу значениий. Есть значения, которые нельзя копировать
       
ОбработатьТЗПриПомещенииВБуферОбмена(ЗначениеТабличнойЧасти,_ЭтотОбъект,ИмяТЧ);

       
стХЗ = Новый Структура();
       
стХЗ.Вставить("ОписаниеИсточника",Строка(_ЭтотОбъект));
       
стХЗ.Вставить("ТабличнаяЧасть",ЗначениеТабличнойЧасти);

       
ХЗ = Новый ХранилищеЗначения(стХЗ);
       
ПараметрыСеанса.ОбщиеЗначения = ХЗ;

    ИначеЕсли
Расшифровка = "Полимагнит.БуферОбмена.Вставить" Тогда

       
ИмяТЧ = СокрЛП(СтрЗаменить(ИмяКнопки,"ВставитьТЧИзБуфераОбмена_",""));
       
Приемник = _ЭтотОбъект[ИмяТЧ];

        Попытка
           
ХЗ = ПараметрыСеанса.ОбщиеЗначения;
           
ЗначениеХЗ = ХЗ.Получить();
            Если
ТипЗнч(ЗначениеХЗ) <> Тип("Структура") Тогда
               
Сообщить("Буфер обмена не содержит значений нужного типа!");
                Возврат;
            Иначе
               
ОписаниеИсточника   = ЗначениеХЗ.ОписаниеИсточника;
               
ЗначениеТЧ          = ЗначениеХЗ.ТабличнаяЧасть;
                Если
ТипЗнч(ЗначениеТЧ) <> Тип("ТаблицаЗначений") Тогда
                   
Сообщить("Буфер обмена не содержит значений нужного типа!");
                    Возврат;
                КонецЕсли;
            КонецЕсли;
        Исключение
           
Сообщить("Буфер обмена не содержит значений нужного типа!");
            Возврат;
        КонецПопытки;

       
ОбработатьТЗПриИзвлеченииИзБуфераОбмена(ЗначениеТЧ,_ЭтотОбъект);

       
Обр = ЭтотОбъект;
       
Обр.ОписаниеИсточника = ОписаниеИсточника;
       
ФормаТаб = Обр.ПолучитьФорму();
       
ФормаТаб.ТЧ = ЗначениеТЧ;
       
ОтветФормы = ФормаТаб.ОткрытьМодально();

        Если
ОтветФормы = Неопределено Тогда
           
//Это отмена
       
Иначе
           
Источник = ФормаТаб.ТЧ;

            Если
ОтветФормы = "ОчиститьВставить" Тогда
               
Приемник.Очистить();
            КонецЕсли;

            Для Каждого
Стр Из Источник Цикл
               
НовСтр = Приемник.Добавить();
               
ЗаполнитьЗначенияСвойств(НовСтр,Стр);
               
ОбработатьИсключительныеСлучаиИзмененияСтроки(НовСтр,_ЭтотОбъект)
            КонецЦикла;

        КонецЕсли;
    КонецЕсли;

КонецПроцедуры

Обработчик при помещении в буфер обмена может использоваться для настройки состава копируемых данных в зависимости от вида документа. В обработчике оставлен закомментированный код, который может быть использован для примера.

ПримечаниеПроцедура находится в модуле обработки "БуферОбменаТаблицаЗначений", копировать ее из статьи нет необходимости. Текст процедуры приведен для наглядности.

Процедура ОбработатьТЗПриПомещенииВБуферОбмена(_ТЗ,_ЭтотОбъект,_ИмяТЧ)
   
//Если ТипЗнч(_ЭтотОбъект) = Тип("ДокументОбъект.Заявка") Тогда
    //  Если _ИмяТЧ <> "Товары" Тогда
    //      _ТЗ.Очистить();
    //  Иначе //Товары
    //      стКолонкиДляУдаления = Новый Структура("Идентификатор");
    //      Для Каждого Элем Из стКолонкиДляУдаления Цикл
    //          _ТЗ.Колонки.Удалить(Элем.Ключ);
    //      КонецЦикла;
    //  КонецЕсли;
    //
    //  КолонкаНоменклатура = _ТЗ.Колонки.Найти("Наименование");
    //  Если КолонкаНоменклатура <> Неопределено Тогда
    //      КолонкаНоменклатура.Имя = "Номенклатура";
    //  КонецЕсли;
    //КонецЕсли;
КонецПроцедуры

Аналогично можно использовать обработчик при извлечении из буфера обмена. В обработчике оставлен закомментированный код, который может быть использован для примера.

ПримечаниеПроцедура находится в модуле обработки "БуферОбменаТаблицаЗначений", копировать ее из статьи нет необходимости. Текст процедуры приведен для наглядности.

Процедура ОбработатьТЗПриИзвлеченииИзБуфераОбмена(_ТЗ,_ЭтотОбъект)

   
//Если ТипЗнч(_ЭтотОбъект) = Тип("ДокументОбъект.Заявка") Тогда
    //  КолонкаНоменклатура = _ТЗ.Колонки.Найти("Номенклатура");
    //  Если КолонкаНоменклатура <> Неопределено Тогда
    //      КолонкаНоменклатура.Имя = "Наименование";
    //  КонецЕсли;
    //КонецЕсли;

КонецПроцедуры

Обработчик «ОбработатьИсключительныеСлучаиИзмененияСтроки» будет полезен, когда при добавлении строки нужны какие-либо обязательные действия. Например, у меня в одном из документов строка содержит уникальных идентификатор строки. Поэтому при добавлении строки обязательно его заполнение. В обработчике оставлен закомментированный код, который может быть использован для примера.

ПримечаниеПроцедура находится в модуле обработки "БуферОбменаТаблицаЗначений", копировать ее из статьи нет необходимости. Текст процедуры приведен для наглядности.

Процедура ОбработатьИсключительныеСлучаиИзмененияСтроки(_Строка,_ЭтотОбъект)
   
//Если ТипЗнч(_ЭтотОбъект) = Тип("ДокументОбъект.Заявка") Тогда
    //  _Строка.Идентификатор = Новый УникальныйИдентификатор();
    //КонецЕсли;
КонецПроцедуры

Подведем итог.

Для решения задачи нам пришлось внести следующие изменения в конфигурацию:

  • Добавить обработку «БуферОбменаТаблицаЗначений»
  • Настроить доступ роли «Пользователь» к обработке
  • Внести изменения в процедуру «МеханизмНумерацииОбъектов.УстановитьДоступностьПоляВводаНомера»
  • Внести изменения в процедуру «УниверсальныеМеханизмы.СформироватьПодменюЗаполненияТЧ»
  • Внести изменения в процедуру «УниверсальныеМеханизмы.ОбработатьНажатиеНаДополнительнуюКнопкуЗаполненияТЧ»


Скачать файлы

Наименование Файл Версия Размер
Обработка "БуферОбменаТаблицаЗначений" (8.2) 161
.epf 16,50Kb
21.01.12
161
.epf 16,50Kb Скачать
ВнешнийОбработчикБуфераОбмена_Вставить.epf 62
.epf 20,95Kb
21.01.12
62
.epf 20,95Kb Скачать
Альтернативное решение Обработка Копировать (8.2) 67
.epf 14,83Kb
21.01.12
67
.epf 14,83Kb Скачать

См. также

Подписаться Добавить вознаграждение
Комментарии
1. Андрей Краснокутский (Andry.Boris) 10.01.12 01:54
2. Ю М (mtv:)) 10.01.12 09:01
(0) Спасибо за хорошую идею и за качественное оформление публикации.
Однозначно плюс.
3. Сергей Ожерельев (Поручик) 10.01.12 10:00
Эээ, извините. А внешнюю обработку ТЧ никак не замутить, а вместо параметра сеанса БуферОбменаТаблицаЗначений приспособить ОбщиеЗначения? Или я чего-то не понял в этой жизни?
4. Дмитрий Семенов (Sam13) 10.01.12 10:26
(3) Поручик, действительно, в статье не написано, что можно использовать стандартный механизм регистрации обработчиков табличных частей. Создать обработку заполнения табличных частей, зарегистрировать ее для всех документов и использовать. Огромный плюс метода - вообще нет изменения конфигурации. Минус - кнопки будут "скрыты" в подменю "Заполнить".
Данная статья писалась не только как руководство к конкретному действию, но и как образец того, как можно программно изменять формы большого количества документов не изменяя конфигурацию тотально.
По поводу параметра сеанса "Общие значения". Наверняка можно использовать и его, спасибо за идею. Если использовать стандартный механизм изменения таб.частей - самое оно
5. Ю М (mtv:)) 10.01.12 10:34
(3) Поручик, если сделать через "Внешнюю обработку заполнения табличных частей", то у документов в закрытом периоде становятся недоступны пункты меню "Заполнить". Правда я сильно не копал в этом направлении, может и можно поправить этот "косяк"/фичу. Если найти, как обойти это, то действительно, через "Внешнюю обработку заполнения табличных частей" будет менее затратно реализовать предложенный функционал. Я уже подумал об этом - надо покопать...
6. Андрей 1 (andrej260276) 10.01.12 10:44
Молодец автор! Идея очень хорошая. Очень часто возникает необходимость в таком инструменте. Очень многим поможет с экономить массу времени. Однозначно плюсую!
7. Дмитрий Семенов (Sam13) 10.01.12 12:19
В описание добавлено альтернативное решение, использующее только стандартный функционал. В файлы добавлены 2 обработки (одна для Копирования, другая для Вставки), реализующие это решение.
8. Ю М (mtv:)) 10.01.12 12:59
(7) Sam13, Вопрос: А в альтернативном варианте решен ли вопрос с документами в закрытом периоде? Смотри замечание в (5).
У меня в документах, которые находятся в закрытом периоде, пункты меню "Копировать" и "Вставить" неактивны, на них невозможно нажать.
9. Дмитрий Семенов (Sam13) 10.01.12 14:16
Нет, Вопрос не решен. Если документ в закрытом периоде - форма открывается только на просмотр. Не вижу вариантов, как это можно обойти.
10. Ranika (Ranika) 11.01.12 04:44
Автор проделал огромную работу, особенно в написании документации, спасибо!!!
11. Евгений worker (worker1c) 11.01.12 06:05
Хорошая идея, подробное описание, многим будет полезным как в реальной работе, так и как пример интеграции. Не хватает только функции сохранения/восстановления буфера обмена. :)
12. Roman Biblbox (mr zafod) 11.01.12 07:27
(9) Задача была решена очень-очень давно.

У меня под рукой очень старая версия УТ, но обратите внимание:
1. При открытии любой формы только на просмотр блокируются только элементы с установленным свойством ИзменяетДанные
2. В универсальных механизмах есть такая функция ПолучитьДеревоКнопокЗаполненияТабличныхЧастей и кусок кода заполнения "дерева кнопок":

ДобавитьСтрокуВДеревоКнопок(СтрокаПодменю, "ЗаполнениеТЧ"+НомерКнопки, ТипКнопкиКоманднойПанели.Действие, ВыборкаДействий.Наименование, Действие , ВыборкаДействий.Ссылка, , , , , Истина)

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

ДобавитьСтрокуВДеревоКнопок(СтрокаПодменю, "ЗаполнениеТЧ"+НомерКнопки, ТипКнопкиКоманднойПанели.Действие, ВыборкаДействий.Наименование, Действие , ВыборкаДействий.Ссылка, , , , , (ВыборкаДействий.Ссылка.Комментарий = "НеИзменяетДанные"))

- Не самый лучший вариант. Для примера. Это позволит просто вписать в комментарий обработки НеИзменяетДанные и кнопка будет доступна 24/7 и при любой погоде.

Надеюсь комментарий окажется Вам полезным.
wolfsoft; mtv:); +2 Ответить
13. Roman Biblbox (mr zafod) 11.01.12 07:31
(11) По поводу копирования/вставки/сохранения/восстановления.

Посмотрите немного в сторону - есть же старые добрые "встроенные" возможности:
СохранитьЗначение и ВосстановитьЗначение которые работают как в текущем сеансе пользователя, так и во всех последующих.
wolfsoft; kereo; +2 Ответить
15. Артем Сотников (rago) 11.01.12 15:35
Спасибо автору. Очень пригодилась - как раз искал что-то подобное. Немного доделал - и теперь доволен :)
16. Александр Журавлев (apostal86) 11.01.12 15:37
Соглашусь с Поручиком, что подобный функционал можно было бы развернуть на внешних обработках табличных частей. Причем, даже если добавлять кнопочки в формы документов, то рано или поздно после какого-нибудь обновления они могут слететь, если разработчик форму поправит. Ну если кого-то не смущает потом кнопку снова вставлять и к процедурам привязывать, то я не спорю. Но все равно +, за старание
17. Юрий Иванов (itek.09) 11.01.12 17:31
оТЛИЧНО ВСЕ РАБОТАЕТ.. большое спасибо автору. очень пригодилась. подошло даже на управление производственным предприятием. и управление торговлей
18. Тарас Лохтин (Одинец) 11.01.12 21:54
В некоторых случаях (когда пользователь первый раз открывает документ) нажатие на кнопку вызывает:
{ОбщийМодуль.УниверсальныеМеханизмы.Модуль(342)}: Значение не является значением объектного типа (Расшифровка)
Расшифровка = СтрокаКнопки.Расшифровка;
Как поправить?
19. Дмитрий Семенов (Sam13) 12.01.12 00:19
(18) Одинец, Какая конфигурация? Какой документ. Очень любопытно.
Одинец; +1 Ответить 1
20. Дмитрий Семенов (Sam13) 12.01.12 00:20
(16) apostal86, Если разработчик хоть вообще удалит форму и добавить новую - функционал будет работать. Суть методики в том, что форма документа НЕ МОДИФИЦИРУЕТСЯ. Добавление кнопок происходит программно в общих модулях.
21. Дмитрий Семенов (Sam13) 12.01.12 00:26
Готовлю обновление. Количество изменений в конфигурацию сократится до:
-добавить обработку «БуферОбменаТаблицаЗначений»
-внести изменения в модуль "УниверсальныеМеханизмы"
-внести изменения в модуль "МеханизмНумерацииОбъектов"
-изменить роль "Пользователь" для доступа к обработке

Расширение функционала:
-буфер обмена можно сохранить в файл/восстановить из файла

Оптимизировано:
-"свои" процедуры перенесены в обработку.
-картинки кнопок перенесены в обработку
-используется существующий параметр сеанса "ОбщиеЗначения" - не нужно добавлять новый

Код обработчиков теперь не нужно копировать из описания методики - все уже будет в одной обработке. Картинки и прочую шелуху вставлять тоже не нужно.
22. Alexandr Zaslavskiy (Imm) 12.01.12 04:07
23. Александр Журавлев (apostal86) 12.01.12 07:57
(20) Sam13, тогда ясно)) плюсик
24. Тарас Лохтин (Одинец) 12.01.12 09:28
(19) Sam13, вписал настройку в конфигурацию "Управление торговлей", в документе "Поступление товаров и Услуг", закладка Товары.
В конфигурации "Бухгалтерия Предприятия" нет процедуры "СформироватьПодменюЗаполненияТЧ" : это функция, поэтому надо изменить поведение "БуферОбмена_ДополнитьПодменюЗаполненияТЧ(ДеревоКнопок,СоответствиеТЧ)"
а в целом конфертировал Вашу настройку в Бухгалтерию предприятия". Спасибо!
25. zavedeev (zavedeev) 12.01.12 12:25
Автор молодец, я думаю программно создавать кнопку в форме объекта делали все только автор пошел дальше. Молодец
26. Александр (Sanek_159) 12.01.12 16:30
Интересная статья, спасибо. Очень полезно. Будем ждать обновления, для еще меньшего изменения конфигураций =)
27. Сергей Ожерельев (Поручик) 12.01.12 16:51
(21) Лучше создать отдельную роль для доступа к обработке, чтобы не курочить штатную. Я всегда так делаю.
28. Дмитрий Семенов (Sam13) 12.01.12 17:26
(3) Поручик, Вы знаете точно как используют штатные механизмы ПараметрСеанса "ОбщиеЗначения"? Если его использовать не случиться ли так, что система "затрет" наш буфер своим значением. Или наоборот, мы какое-нибудь важное значение "убьем" своим буфером. насколько я понял стандартно система использует ПараметрСеанса "ОбщиеЗначения" для кеширования данных.
29. Дмитрий Семенов (Sam13) 12.01.12 17:28
(27) Поручик, Зачем плодить сущности? Чтобы не было геммороя при обновлении?
30. Олег Коваленко (OleGazz) 14.01.12 09:40
31. Nicenick Arena (Nicenick) 15.01.12 15:21
Интересная статья, спасибо. Очень полезно. Будем ждать обновления, для еще меньшего изменения конфигураций =)
32. 1CProfessional (Paul_Nevada) 16.01.12 09:51
Спасибо большое за такую разработку!
Очень нужный функционал, обязан сказать! Вообще, в конфигурациях "Восемь" нет некоторых очень привычных (полезных - самое главное) возможностей, которые имеются в "Семь"... И это - надо править!
33. 1CProfessional (Paul_Nevada) 16.01.12 09:52
34. msx max (tehas99) 16.01.12 14:16
интересно, нужно попробывать
35. Андрей Андрей (diarki) 16.01.12 23:17
Полезная информация Автору плюс однозначно.
36. Игорь (Signal) 17.01.12 13:27
37. Николай Харин (Shrike) 17.01.12 16:23
Спасибо большое! Попробую
40. Осипов Сергей (fixin) 17.01.12 18:58
41. Владимир Каракозов (karakozov) 18.01.12 11:12
Идея актуальна там, где например обновления выходят три раза в неделю (ЗУП) а вам нужно вести свои механизмы, прикрученные к ней 20 конфигураций назад.
43. Сергей Писларь (serpisal) 21.01.12 14:46
Отличная идея и её воплащение. Обожаю механизмы, которые не требуют внесения изминений в
конфигурацию.
44. Игорь Фелькер (Brawler) 21.01.12 15:48
Недавно скачал альтернативное решение и сразу вылезла ошибка при повторной попытке авторегистрации при нажатии кнопки регистрации. Ошибка наблюдается в обработке "Копирования" и "Вставки".

Ошибка вылезла в строке
СпрВнешОбработка.Комментарий = ЭтотОбъект.Метаданные().Имя;


Исправил ошибку в участке кода

Было:
	//регистрируем
	Если Выборка.Следующий() Тогда
		СпрВнешОбработка = Выборка.Ссылка;


Стало:
	//регистрируем
	Если Выборка.Следующий() Тогда
		СпрВнешОбработка = Выборка.Ссылка.ПолучитьОбъект();
45. Дмитрий Семенов (Sam13) 21.01.12 17:36
Согласен. Есть ошибка. Исправил.
46. 1CProfessional (Paul_Nevada) 23.01.12 14:59
(38) serovmsk, спасибо за информацию-идею! Надо по-скорее проверить в работе.
47. inf0start inf0start (inf0start) 24.01.12 15:02
Спасибо за идею! Порадую своих пользователей )
48. heseh (heseh) 27.01.12 10:10
49. Елена (elena_77) 31.01.12 10:49
Авторй плюс. Идея интересная и нужная. Пользователям очень пригодится. Спасибо.
50. Инга Поташова (inga75) 03.02.12 13:25
Интересная идея, Спасибо
51. AND AND (AAndryA) 07.02.12 12:00
Интересная идея и заманчивое описание реализации. Надо внедрить и протестировать в работе. Автору респект и плюс.
52. Филипп (Филипп) 27.03.12 11:25
Очень изящное решение вариант "Альтернативная обработка" для ЗУП,
т.к ЗУП - та конфигурация, которую никак нельзя снимать с поддержки из-за ПОСТОЯННОГО внесения изменений в законодательство! Большое спасибо!
И еще как просьба-пожелание:
- возможность выгрузить буфер в Excel, для правки сумм (или еще каких-нибудь примитивных типов), а потом опять загрузить в буфер для дальнейшей вставки. Вот это был бы класс! Например, постоянно изменяемые оклады или надбавки, которые проще и лучше рассчитать в Excel для ежемесячного документа "Ввод плановых начислений".
Это точка зрения пользователя-главбуха.
53. Карина -- (ponaroshku) 10.07.12 13:43
в упп у меня возникла проблема - документ поступление товаров и услуг, тч товары


{ОбщийМодуль.УниверсальныеМеханизмы.Модуль(587)}: Значение не является значением объектного типа (Расшифровка)
Расшифровка = СтрокаКнопки.Расшифровка;



Хотя все сделала по инструкции и на три раза

Подскажите, куда копнуть?:(
54. Карина -- (ponaroshku) 10.07.12 13:51
(53) разобралась
незнаю, что это было - запустила в новой чистой конфе, все встало
55. flaks Данилова (flaks) 18.09.12 12:14
Большое спасибо!!! Очень пригодилось.
56. Ivan Veres (MrFlanker) 20.12.13 16:44
Отличная... идея как раз собирался писать нечто похожее в обозримом будущем... хорошо что не придется изобретать велосипед.
57. Юрий Лу (yura1960) 07.01.15 15:08
На БП 8.3 кто нибудь юзал? Выглядит заманчиво. Но не придется ли допиливать? Просто времени разбираться нет, т.к. свою юзаю. Но эта смотрится симпатичнее, хочу её )))
58. Дмитрий Семенов (Sam13) 31.03.15 11:08
На БСП не полетит, конечно же. Там все механизмы переколбашены
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа