Миникласс ТПерехватчик — методология работы с несколькими перехватчиками формы

Небольшое пособие "Как правильно накладывать несколько перехватчиков на одну форму" + мини-класс, реализующий описанную технологию.

Данный мини-класс, по сути, описывает технологию относительно удобной работы с множественными перехватчиками формы.

 

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

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

 Теперь возникает проблема — каждый из двух классов перехватывает события формы, и их действия необходимо согласовывать. Ибо каждый последующий навешаный перехватчик забирает все на себя («кто последний — тот и папа»).

 Собственно, в согласовании работы нет ничего сложного — достаточно запоминать предыдущий перехватчик в момент вызова ПерехватитьСобытияГК(), а потом, в обработчике перехваченного события, не забыть сделать ВыполнитьСобытиеГК.

 Правда, есть еще один маленький нюанс — если во втором навешенном перехватчике нет какого-то обработчика события, то до первого событие просто не дойдет.

 А значит в каждом классе необходимо описывать полный набор методов.

 

 Но мы же с вами люди ленивые! Зачем делать ручками то, что можно успешно автоматизировать?

 Мы возьмем, и унаследуем оба наших класса (привязок и табличного поля на запросе) от приложенного класса ТПерехватчик.

При инициализации класса-наследника делаем

Сам.ПолучитьБазовыйКласс(«ТПерехватчик»).Инит(_Контекст);   //_Контекст — контекст перехватываемой формы

 И дальше, единственное, что требуется от нас — после своих телодвижений не забывать в классе-наследнике вызывать событие базового класса.

Например, так:

 Процедура Событие_ПриОтжатииЛевойКнопки(Сост, Гор, Верт, ФСО) Экспорт
_ПриОтжатииЛевойКнопки(Сост, Гор, Верт);

Сам(Контекст).ПолучитьБазовыйКласс("ТПерехватчик").Событие_ПриОтжатииЛевойКнопки(Сост, Гор, Верт, ФСО);
КонецПроцедуры // Событие_ПриОтжатииЛевойКнопки

Если же нам обработчик события не нужен — то вообще ничего не нужно делать: в качестве обработчика выступит метод базового класса, который перенаправит событие туда, куда нужно.

 

http://www.1cpp.ru/forum/YaBB.pl?num=1340972871 

17 Comments

  1. zk96

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

    Например вот так:

    Процедура Инит(Конт)

    КонтекстФормы = Конт;

    Перехватчик = СоздатьОбъект(«Перехватчик»);

    ПерехватчикСобытийГК = Перехватчик.ПолучитьПерехватчикСобытийГК(КонтекстФормы);

    МойКласс = СоздатьОбъект(«МойКласс»);

    МойКласс.Инит(КонтекстФормы);

    ПерехватчикСобытийГК.ДобавитьПодписчикаСобытия(МойКласс,ТипЗначенияСтр(«МойКласс),»ПриИзмененииРазмераОкна»);

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

    Ну а дальше создаю нужные процедуры.

    Ну а в классе-перехватчике при событии вызываю его у всех подписчиков.

    Лично мне такой метод больше нравится.

    Reply
  2. SatanClaws

    (1) Похоже, не совсем понял.

    Давай, на примере Привязок и ТТабличноеПоле.

    Если я правильно понял тебя, то в форме (на которую ты хочешь прицепить привязки и ТП), ты создаешь 3 объекта:

    ТТвойПерехватчик (обязательно первым)

    ТПривязки

    ТТабличноеПоле

    так?

    Дальше, как у тебя идет взаимодействие между ТПривязки и ТТабличноеПоле? Скажем, в ПриЗакрытии один из них вернул статус возврата 0 — второй в состоянии это увидеть?

    Ну или на примере события ПриОтжатииКнопкиКлавиатуры — можно ли передать будет ли передан ФСО из одного обработчика в другой?

    Reply
  3. SatanClaws

    (1) Более внимательно прочитал твой комментарий и еще меньше понял тебя:

    Я предположил, что ты используешь такую методологию:

    1. на форму вешаешь перехватчиком класс ТТвойПерехватчик

    2. в форме создаешь класс (оПривязки = СоздатьОбъект(«ТПривязки»);) и говоришь оПривзяи.Инит(…)

    3. в методе ТПривязки:Инит делаешь следующее: получаешь текущий перехватчик формы (подразумевается, что это объект класса ТТвойПерехватчик) и вызываешь у него метод ДобавитьПодписчикаСобытия(…) (передавая туда объект привязок и события, которые необходимы привязкам).

    Так, нет?

    Reply
  4. zk96

    У меня есть класс-перехватчик «ФабрикаСобытий», который инициализируется ПриНачалеРаботыСистемы. При открытии ЛЮБОЙ формы, а точнее в событии СобытиеГМ_СозданиеКонтекста, создаю новый объект класса «ФабрикаСобытий» и вешаю на эту форму.

    Любой класс, обработка и т.п. который хочет обрабатывать события этой формы, подписывается на них. Например при инициализации класс привязок делаю так:

    Перехватчик = СоздатьОбъект(«Перехватчик»);

    ПерехватчикСобытийГК = Перехватчик.ПолучитьПерехватчикСобытийГК(КонтекстФормы);

    ТПривязки = вирт();

    ПерехватчикСобытийГК.ДобавитьПодписчикаСобытия(ТПривязки,ТипЗначенияСтр(ТПривязки),»ПриИзмененииРазмераОкна»);

    В классе «ФабрикаСобытий» :

    //==========================================================­====================

    Функция СообщитьПодписчикам(ИДСобытия,Параметры = «») Экспорт

    ВозвратноеЗначение=1;

    Если ПодписчикиСобытий.НайтиКлюч(ИДСобытия,0) = -1 Тогда

    Возврат ВозвратноеЗначение;

    КонецЕсли;

    Если ПустоеЗначение(Параметры) = 1 Тогда

    Параметры = СоздатьОбъект(«СписокЗначений»);

    КонецЕсли;

    __ПодписчикиСобытия = ПодписчикиСобытий.Получить(ИДСобытия);

    КвоПодписчиков=ПодписчикиСобытия.Количество();

    Для НомерКонтекста = 0 По КвоПодписчиков-1 Цикл

    КонтекстПодписчика = ПодписчикиСобытия.Получить(НомерКонтекста);

    Если Информатор.МетодСуществует(КонтекстПодписчика,ИДСобытия)=1 Тогда

    Если Информатор.ЯвляетсяФункцией(КонтекстПодписчика,ИДСобытия)=1 Тогда

    РезультатРаботыФункции=0;

    ВыполняемыйМодуль.ВыполнитьФункциюКонтекста(КонтекстПодписчика,ИДСобытия,Параметры,РезультатРаботыФункции);

    Если РезультатРаботыФункции=0 Тогда

    ВозвратноеЗначение=0;

    Прервать;

    КонецЕсли;

    Иначе

    ВыполняемыйМодуль.ВыполнитьПроцедуруКонтекста(КонтекстПодписчика,ИДСобытия,Параметры);

    КонецЕсли;

    КонецЕсли;

    КонецЦикла;

    Возврат ВозвратноеЗначение;

    КонецФункции

    //==========================================================­============

    Процедура Событие_ПриИзмененииРазмераОкна(ТипСобытия,Ширина,Высота) Экспорт

    СЗПараметры = СоздатьОбъект(«СписокЗначений»);

    СЗПараметры.Установить(«ТипСобытия»,ТипСобытия);

    СЗПараметры.Установить(«Ширина»,Ширина);

    СЗПараметры.Установить(«Высота»,Высота);

    Рез=СообщитьПодписчикам(«ПриИзмененииРазмераОкна»,СЗПараметры);

    Перехватчик.ВыполнитьОригинальноеСобытиеГК(КонтекстФормы,»ПриИзмененииРазмераОкна»,ТипСобытия,Ширина,Высота);

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

    Эти куски кода я вырезал с рабочей конфигурации. Может чего-то не так подправил. Если нужно могу поделится классами.

    Reply
  5. SatanClaws

    (4) Примерно понятно.

    Немного более сложно технологически (Перехватчик сам по себе моск неплохо выносит, а тут еще и Фабрика событий), но тоже неплохо.

    Reply
  6. zk96

    (5) Почему сложнее? Ничего сложного нет. ФабрикаСобытий — это просто имя класса, не более. Я у кого-то увидел и мне понравилось слово 🙂

    И перехватчик не сложнее любого другого 1С++-объекта. Да, есть несколько фич, но это мелочи.

    Хотя это мое личное мнение.

    Reply
  7. zk96

    Как по мне подписка на события удобней.

    Reply
  8. SatanClaws

    (6)перехватчик сложнее тем, что за потоком исполнения следить сложнее

    Reply
  9. zk96

    (8)

    Я не понял. Объясни, пожалуста.

    Reply
  10. SatanClaws

    (9) Скажем, есть баг — при отжатии кнопки клавиатуры 1Ска падает

    без перехватчика:

    открываешь модуль формы, находишь обработчик события, ставишь брейкпоинт, топаешь отладчиком сначала «шагом через» — определяешь, какой используемый объект валит 1Ску, во второй раз — уже конкретно внутри класса.

    Все легко и прозрачно.

    С перехватчиком — сначала рыщешь по модулю, определяешь, какие объекты создаются, какие из них используют перехватчик.

    Потом разбираешься, какие имеют обработчик этого события. Потом ставишь брейкпоинты в этих классах (а отладка, начавшаяся с брейкпоинта внутри класса — то еще развлечение, ибо не безглючно там все).

    А в конце концов выясняется, что объект класса А, не использующего перехватчик, создает для своих нужд объект класса Б, уже использующего перехватчик — и валит 1Ску именно он.

    В этом плане твой подход немного лучше — ибо можно поставить брейкпоинт в классе ФабрикаСобытий и уже там топать по явному потоку исполнения.

    Хотя в моей схеме тоже есть «помошники» (втыкание сообщить() непосредственно в ТПерехватчик — будет видно, какие объекты отработали нормально, остается лишь определить порядок подключения перехватчиков).

    Reply
  11. zk96

    Для отладки я иногда использую команды препроцессора 1С++ #curmeth и #exinfo.

    Очень удобно их устанавливать в тех местах, где проблематично остановится.

    Reply
  12. Dolly_EV

    (4) zk96, Поделись классом. Нужно!

    Reply
  13. zk96

    (12) Dolly_EV,

    У меня не один класс, а несколько. В прилагаемом архиве на всякий случай есть кусок глобального модуля.

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

    Reply
  14. zk96

    О, нашел. У меня есть старый вариант моей «ФабрикиСобытий». Раньше это был один класс. Если надо, то тоже дам.

    Reply
  15. Dolly_EV

    (13) Ок, спасиб, завтра будем посмотреть!

    (14) Я так думаю, «текущий вариант» всяко лучше, чем «старый вариант»?))

    Reply
  16. zk96

    Если что, пиши в личку.

    Reply
  17. begemot

    (16) Пытаюсь подключить Ваш «новый» вариант Фабрики событий:

    Неудачная попытка создания объекта

    СервисныеМетоды = СоздатьОбъект(«СервисныеМетоды»);

    Подскажите, где искать данный класс?

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *