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

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

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

 

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

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

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

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

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

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

 

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

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

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

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

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

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

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

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

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

 

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 не будет опубликован. Обязательные поля помечены *