Оптимизированный подсчет суммы выделенных ячеек табличного документа (как в Excel)

Опубликовал Евгений Люлюк (Evg-Lylyk) в раздел Программирование - Практика программирования

Оптимизированный расчет данных выделенных ячеек

В Excel есть удобный механизм подсчет суммы выделенных ячеек в 1С к сожалению такого нет. 1С предлагает нам пользоваться кнопками калькулятора "М" что не так удобно как вариант предлагаемый ниже.

Простой вариант подсчета суммы выделенной области реализуется очень легко.
Добавляем процедуру обработки события ПриАктивизацииОбласти (Событие, возникающее при активизации области табличного документа) где обходим в выделенные области и суммируем.

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

Оптимизированный вариант расчета

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

В примере всю обработку по запоминанию суммы предыдущих выделенных областей и суммированию берет на себя функция ПолучитьИнформациюПоВыделеннымОбластям(ТабличныйДокумент) , которая возвращает массив структур содержащихся информацию по области.

Оптимизированный вариант более сложный, но более эффективный в плане скорости.
Особый случай с выделением через Crtl + A т.к. в этом случае в процедуру передается Область (0,0,0,0) подсчет не производится и это разумно в этом случае пользователь выделяет не для подсчета суммы.

p.s.
За любые идеи по улучшению производительности буду очень признателен
Если функции ВычислитьСуммуОбласти, ПолучитьЧислоИзСтроки  реализовать через ВК думаю производительность возрастет. Может кто поможет ;)

Функция ВычислитьСуммуОбласти (ТабличныйДокумент, Верх, Лево, Низ, Право)

   
Сумма = 0;

    Для
ЯчВерт = Верх По Низ Цикл
        Для
ЯчГориз = Лево По Право Цикл
           
ОдиночнаяОбласть = ТабличныйДокумент.Область(ЯчВерт,ЯчГориз);

            Сумма = Сумма + ПолучитьЧислоИзСтроки(ОдиночнаяОбласть.Текст);
        КонецЦикла;
    КонецЦикла;

    Возврат
Сумма;

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

Функция
ПолучитьЧислоИзСтроки(Текст)

    Попытка
       
Результат = Число(Текст);
    Исключение
       
Результат = 0;
    КонецПопытки;

    Возврат
Результат;

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

 Внимание!!! Код выше не является основой обработки. Вынесены процедуры которые желательно реализовать через ВК для повышения скорости

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

Наименование Файл Версия Размер
Пример 8.1
.epf 9,34Kb
01.10.09
271
.epf 9,34Kb 271 Скачать

См. также

Комментарии
1. highlander highlander (highlander) 28.09.09 15:51 Сейчас в теме
А я вот интересуюсь... а возможно такое на 7-ке?
2. Евгений Люлюк (Evg-Lylyk) 1994 28.09.09 15:59 Сейчас в теме
(2) посмотрел вроде нет предопределенной процедуры аналогичной 8.1 аналогично наверно не сделать

Надеюсь ветка не превратится в ветку, а как сделать тоже самое на 7.7 :)
3. Александр Рытов (Арчибальд) 2652 28.09.09 16:03 Сейчас в теме
4. highlander highlander (highlander) 28.09.09 16:12 Сейчас в теме
Нет не превратиться... не волнуйтесь :D Но за идею плюс однозначно
5. Евгений Люлюк (Evg-Lylyk) 1994 28.09.09 16:31 Сейчас в теме
(4) самая идея подсчета суммы работает через 5 минут, а вот над оптимизацией пришлось поломать голову
6. Антон Степанов (Stepa86) 608 28.09.09 17:13 Сейчас в теме
(5) какое самое узкое место? наверно получение одиночной области и вынимание из нее текста...
7. Алексей Башта (bashta.aleksey) 28.09.09 17:45 Сейчас в теме
Evg-Lylyk в конфе "Бухгалтерия предприятия КОРП" рел 2.0.6.3 этот механизм уже есть в стандартных отчетах.
Думаю это тебе поможет:
Функция ВычислитьСуммуВыделенныхЯчеекТабличногоДокумента(ПолеТабличногоДокумента) Экспорт
Сумма = 0;
Для Каждого Область Из ПолеТабличногоДокумента.ВыделенныеОбласти Цикл
Если ТипЗнч(Область) = Тип("ОбластьЯчеекТабличногоДокумента") Тогда
Для ИндексСтрока = Область.Верх По Область.Низ Цикл
Для ИндексКолонка = Область.Лево По Область.Право Цикл
Попытка
Сумма = Сумма + Число(СтрЗаменить(ПолеТабличногоДокумента.Область("R" + Формат(ИндексСтрока, "ЧГ=0") + "C" + Формат(ИндексКолонка, "ЧГ=0")) .Текст, " ", ""));
Исключение
КонецПопытки;
КонецЦикла;
КонецЦикла;
КонецЕсли;
КонецЦикла;
Возврат Сумма;
КонецФункции
...Показать Скрыть
8. Алексей Башта (bashta.aleksey) 28.09.09 17:46 Сейчас в теме
Извините.
Функция ВычислитьСуммуВыделенныхЯчеекТабличногоДокумента(ПолеТабличногоДокумента) Экспорт
Сумма = 0;
Для Каждого Область Из ПолеТабличногоДокумента.ВыделенныеОбласти Цикл
Если ТипЗнч(Область) = Тип("ОбластьЯчеекТабличногоДокумента") Тогда
Для ИндексСтрока = Область.Верх По Область.Низ Цикл
Для ИндексКолонка = Область.Лево По Область.Право Цикл
Попытка
Сумма = Сумма + Число(СтрЗаменить(ПолеТабличногоДокумента.Область("R" + Формат(ИндексСтрока, "ЧГ=0") + "C" + Формат(ИндексКолонка, "ЧГ=0")) .Текст, " ", ""));
Исключение
КонецПопытки;
КонецЦикла;
КонецЦикла;
КонецЕсли;
КонецЦикла;
Возврат Сумма;
КонецФункции
director04; +1 Ответить 1
9. Евгений Люлюк (Evg-Lylyk) 1994 28.09.09 19:04 Сейчас в теме
10. Евгений Люлюк (Evg-Lylyk) 1994 28.09.09 19:05 Сейчас в теме
(7) мой метод "нормальный" 8)
11. Алексей Башта (bashta.aleksey) 28.09.09 21:22 Сейчас в теме
12. Alex (4ish) 29.09.09 10:57 Сейчас в теме
Не сочтите за каприз, но попробовал выделять отдельные ячейки через Ctrl - не работает. :(
13. Александр Венгер (venger) 2034 29.09.09 12:07 Сейчас в теме
(1) > А я вот интересуюсь... а возможно такое на 7-ке?

Вот, например: http://infostart.ru/public/16000/
14. Евгений Люлюк (Evg-Lylyk) 1994 29.09.09 12:27 Сейчас в теме
(12) Мультивыделение работает и система оптимизации для мультивыделений тоже. Просто это пример... функция "ПолучитьИнформациюПоВыделеннымОбластям" возвращает информацию по каждой области в структуре дальше используете как хотите я просто не стал делать сумму выделенных областей т.к. просто пример. Сейчас поправлю.
15. Яков Коган (Yashazz) 1977 29.09.09 16:32 Сейчас в теме
О! Всё ждал, пока кто-нибудь сделает...
Спасибо!
16. Alex (4ish) 29.09.09 20:40 Сейчас в теме
17. Глеб Кондратьев (Gleb K.) 30.09.09 14:06 Сейчас в теме
Всем привет. А я себе сделал вот так.
У меня учитывается мультивыделение, наличие скрытых строк и/или столбцов, плюс парочка проверок "на дурака".

[1C-CODE]Процедура ТДПриАктивизацииОбласти(Элемент)
	Сумма = 0;
	Для Каждого Область из ЭлементыФормы.ТД.ВыделенныеОбласти Цикл
		Если Не Область = Неопределено И НЕ (Область.Верх = 0 И Область.Низ = 0) И НЕ (Область.Лево = 0 И Область.Право = 0) Тогда
		Для i = Область.Верх по Область.Низ Цикл
			Для j = Область.Лево по Область.Право Цикл
				Ячейка = ЭлементыФормы.ТД.Область(i,j);
				Если Ячейка.СодержитЗначение
					И Ячейка.Видимость
					И Ячейка.ТипЗначения = Новый ОписаниеТипов("Число")
					И Не Ячейка.Значение = Неопределено Тогда
					Сумма = Сумма + Ячейка.Значение;
				КонецЕсли;
			КонецЦикла;
		КонецЦикла;
		КонецЕсли;
	КонецЦикла;
КонецПроцедуры
...Показать Скрыть
[/1C-CODE]
director04; +1 Ответить 2
18. Евгений Люлюк (Evg-Lylyk) 1994 30.09.09 15:46 Сейчас в теме
(17) метод сабжа более оптимален почитайте внимательно и посмотрите код
19. Евгений Люлюк (Evg-Lylyk) 1994 30.09.09 16:09 Сейчас в теме
(17)
"Если Не Область = Неопределено И НЕ (Область.Верх = 0 И Область.Низ = 0) И НЕ (Область.Лево = 0 И Область.Право = 0) Тогда"
Нужно только "Если Не Область = Неопределено" и то не знаю пример когда
Во внутреннем условии тоже не все условия нужны
Строка 100 не будет суммироваться, что как мне кажется, неправильно.

Видимо волна материалов захлестнула инфостарт и все ждут примитивизма, а вот фиг :) это не ко мне
20. Глеб Кондратьев (Gleb K.) 01.10.09 13:06 Сейчас в теме
(18, 19) Если Не Область = Неопределено возникает когда щелкаешь мышью между заголовков колонок или строк.
С внутренними условиями я перемудрил, у вас лучше.
На счет 100 строки не понял.
А вот скрытые ячейки у вас будут суммироваться, что правильно, но не логично :) Хотя это зависит от процедуры вызывающей функцию ВычислитьСуммуОбласти.
21. Евгений Люлюк (Evg-Lylyk) 1994 01.10.09 15:45 Сейчас в теме
(20) Я имел ввиду что строка "100" не будет суммироваться т.к. имеет Тип("Строка")
На счет скрытых ячеек поправил так логичные (не подумал)
22. Артур Аюханов (artbear) 852 01.10.09 17:26 Сейчас в теме
(21) Пробовал писать ПолучитьЧислоИзСтроки(Текст) без блока Попытка-Исключение ?
ИМХО должно быть быстрее.
23. Евгений Люлюк (Evg-Lylyk) 1994 01.10.09 18:58 Сейчас в теме
(22) Рад тебя слышать. Конечно быстрее, а что с ошибками делать
24. Игорь Исхаков (Ish_2) 960 01.10.09 19:45 Сейчас в теме
Несколько выделенных областей могут имет непустое пересечение .
В этом случае подсчет сумм будет неверным.
Я правильно понял ?
25. Игорь Исхаков (Ish_2) 960 01.10.09 21:22 Сейчас в теме
В строке функции :
ОдиночнаяОбласть = ТабличныйДокумент.Область(ЯчВерт,ЯчГориз)
приведено неверное обращение к ячейке.
Правильным обращением при суммировании ячеек будет
ОдиночнаяОбласть = 
ТабличныйДокумент.Область(ЯчВерт,ЯчГориз,ЯчВерт,ЯчГориз)

При обращении к области по двум координатам можно получить не одинарную , а ячейку , которая объединяет несколько ячеек (объединенная ячейка). Подсчет сумм в этом случае будет неверным.
Evg-Lylyk; +1 Ответить
26. Игорь Исхаков (Ish_2) 960 01.10.09 22:46 Сейчас в теме
Не приводит к неправильно вычисленной сумме и обращение к ячейке , используемое в Бухгалтерии КОРП ("R..C..").
27. Евгений Люлюк (Evg-Lylyk) 1994 01.10.09 22:57 Сейчас в теме
(26) Спасибо понял поправлю ... по мне лучше ТабличныйДокумент.Область(ЯчВерт,ЯчГориз,ЯчВерт,ЯчГориз)
28. Евгений Люлюк (Evg-Lylyk) 1994 01.10.09 22:58 Сейчас в теме
(24) должно нормально отрабатывать кэш для каждой отдельно
29. Игорь Исхаков (Ish_2) 960 01.10.09 23:03 Сейчас в теме
(28) Не понял.
Если две выделенные области имеют пересечение (т.е. общие ячейки) , то эти ячейки будут просуммированы дважды :
сначала в одной выделенной области , потом в другой.
30. Игорь Исхаков (Ish_2) 960 01.10.09 23:07 Сейчас в теме
+28 Я налетел на этот эффект у себя в теме , где используется не одиночное выделение ячейки в табличном документе , а множественное выделение : "строка" или "крест".
31. Евгений Люлюк (Evg-Lylyk) 1994 01.10.09 23:11 Сейчас в теме
(30) да т.к. это две разные выделенные области.
32. Евгений Люлюк (Evg-Lylyk) 1994 01.10.09 23:13 Сейчас в теме
31+ будут показываться сумма каждой выделенной области + сумма
33. Serg Eli (elizarovs) 71 02.10.09 09:22 Сейчас в теме
(+) Классно! Еще бы в форме документа такое сделать...
34. Артур Аюханов (artbear) 852 02.10.09 09:38 Сейчас в теме
(23) Я к тому, что может быть быстрее вместо Попытки анализировать первый символ - если это цифра, то суммировать.
Также сначала можно использовать СокрЛ (не СокрЛП)
или вообще регулярным выражением проверить :)
35. Евгений Люлюк (Evg-Lylyk) 1994 02.10.09 12:23 Сейчас в теме
(33) добавить можно в любую форму с ТабДок это пример
(34) Это проверено еще на консоли медленнее, регуляры так вообще. Вариан описан в p.s. нужно функции ВычислитьСуммуОбласти, ПолучитьЧислоИзСтроки реализовать через ВК должно быть быстрее
36. Игорь Исхаков (Ish_2) 960 04.10.09 20:41 Сейчас в теме
(34) Странно.
Пусть текст ячейки начинается с цифры и мы начинаем его суммировать без попытки. В этом случае пользователь получит сообщение об ошибке, если в тексте ячейки - " 1 показатель".
Хрен редьки не слаще.
Применение ВК для подсчета сумм тоже смотрится , на мой взгляд, диковато.
Думаю ,при практическом применении ,например ,в бухгалтерских отчетах скорость подсчета мало существенна. Неоходим лишь быстро вычисляемоый грубый подсчет количества ячеек в выделенных ячейках. И ограничение на их количество.
37. zag2art (zag2art) 12.10.09 19:31 Сейчас в теме
А чем это лучше чем выделить группу ячее и нажать M+ в калькуляторе 8.1?
38. Евгений Люлюк (Evg-Lylyk) 1994 13.10.09 17:43 Сейчас в теме
(37) тем что не надо ничего нажимать плюс можно среднее посчитать или еще чтото
про М+ мало кто знает
39. Олеся Аникеева (banne) 34 03.11.09 05:01 Сейчас в теме
40. Serg Eli (elizarovs) 71 24.11.09 11:39 Сейчас в теме
(35) Вот именно, с ТабДок, а там везде ТЗ. А у ТЗ нет события ПриАктивизацииОбласти, как и объекта ВыделенныеОбласти.
41. Евгений Люлюк (Evg-Lylyk) 1994 25.11.09 00:59 Сейчас в теме
(40) В ТЗ нельзя выделить одну ячейку в Колонке1 Строке1 и одну ячейку в Колонке2 Строке2 только построчно.
42. Serg Eli (elizarovs) 71 25.11.09 06:55 Сейчас в теме
(41) Похоже, что так, во всяком случае я не нашёл описания такой возможности или примера. Хотя, если поставить в свойствах выделения строки - Ячейка, а в режиме выделения - множественное, то в форме прекрасно выделяются ячейки в любой комбинации. Выцепить же список выделенных ячеек из кода я не смог. Може кто поможет? Ну очень нужного свойства в 1С не хватает (сумма группы выделенных ячеек)...
43. Евгений Люлюк (Evg-Lylyk) 1994 25.11.09 12:41 Сейчас в теме
(42) опиши когда это нужно (я даже не представляю примера)
44. Serg Eli (elizarovs) 71 26.11.09 09:21 Сейчас в теме
(43) Большая организация, несколько подразделений и даже несколько баз данных оперативного учета. В базу бухгалтерии сливаются все документы из первичных баз. Любимое занятие бухов - сравнивать документы по наличию и по суммам. Открывают журнал, берут калькулятор и строчат, как из пулемёта. А так бы просто мышкой потыкали. Думаю, можно много ситуаций похожих найти.
Другой пример (реальный). На фирме, на базе 1С, стоит система, в которой итого по документу не сходится с итого по таблице. Не говорю, что это правильно, но так получилось. А я пытаюсь разгрести... Приходится вываливать каждый раз в список, чтобы сложить
45. Евгений Люлюк (Evg-Lylyk) 1994 26.11.09 15:51 Сейчас в теме
(44) как сделать подобное в ТЗ, ТЧ не представляю. Может поможет: для сравнения данных есть СравнениеФайлов очень полезная вещь
46. Kate123 (kate123) 28.01.10 13:18 Сейчас в теме
Спасибо за обработку, очень полезная функция. Подскажите, пожалуйста, как сделать подсчет для табличного поля документа. Для ТЧ документа нет "ПриАктивизацииОбласти",также нет свойства ВыделеннаяОбласть. Куда и как правильно прописать?
47. Евгений Люлюк (Evg-Lylyk) 1994 28.01.10 13:46 Сейчас в теме
(46) Для ТЧ не получится. Почитайте внимательно комментарии этот вопрос поднимали.
48. Михаил Ражиков (tango) 466 28.01.10 13:47 Сейчас в теме
ну, не знаю.
открыли калькулятор.
выделили область.
нажали кнопку.
чем встроеная фича хуже всей этой возни?
Прикрепленные файлы:
49. Евгений Люлюк (Evg-Lylyk) 1994 28.01.10 14:02 Сейчас в теме
(48) Потому что автоматически и не надо ничего нажимать
Вы не первый почитайте комментарии
Даже 1С решили что это нужно и в Бух. КОРП сделали в шаблонах отчетов эту функцию
50. Игорь Исхаков (Ish_2) 960 28.01.10 14:08 Сейчас в теме
(48),(49) И в скоро выходящей на замену 1.6 новой версии БП 2.0 предусмотрен этот функционал.

И получается , Миша, что автор предвосхитил появление такого функционала в типовых конфигурациях.
51. Михаил Ражиков (tango) 466 28.01.10 14:18 Сейчас в теме
или содрал в КОРПе :). Гоша.
52. Евгений Люлюк (Evg-Lylyk) 1994 28.01.10 17:30 Сейчас в теме
53. Константин (Fisherru) 79 16.02.10 09:59 Сейчас в теме
(13)
Ваша ссылочка хороша, плюсик поставил, но это не совсем тоже самое...
У вас там идет работа с печатными формами, а хочется с табличными частями документа и со справочниками в форме списка...
Вот что очень хочется http://infostart.ru/forum/forum19/topic31264/
54. Евгений Люлюк (Evg-Lylyk) 1994 16.02.10 10:08 Сейчас в теме
(53) на семерке не подскажу
А в 8.х вроде как нельзя так как в Таблицах, деревьях нельзя получить диапазон выделенных ячеек только выделенные строки
55. Sasha Забол (zba) 48 28.12.12 09:19 Сейчас в теме
В управляемой форме не побывал сделать, а то чета там данная функция не работает
56. Max Черепахин (tamaks) 85 10.12.13 18:00 Сейчас в теме
Использовал представленые в публикации процедуры для выгрузки привязаных фото для выделеной пользователем в отчете номенклатуры. Сформировал отчет - выделил строки с наименованием номенклатуры - нажал выгрузить фото.
57. leo zar (le0nard) 25.12.15 23:37 Сейчас в теме
вот чуть измененная из типовой, скрытые не учитывает.

Функция ВычислитьСуммуВыделенныхЯчеекТабличногоДокумента(ПолеТабличногоДокумента) Экспорт
	Сумма = 0;
	Для Каждого Область Из ПолеТабличногоДокумента.ВыделенныеОбласти Цикл
		Если ТипЗнч(Область) = Тип("ОбластьЯчеекТабличногоДокумента") Тогда
			Для ИндексСтрока = Область.Верх По Область.Низ Цикл
				Для ИндексКолонка = Область.Лево По Область.Право Цикл
					Попытка
						адресЯчейки="R" + Формат(ИндексСтрока, "ЧГ=0") + "C" + Формат(ИндексКолонка, "ЧГ=0");
						ячейка=ПолеТабличногоДокумента.Область(адресЯчейки);
						если ячейка.Видимость тогда
							ЧислоЯчейки=Число(СтрЗаменить(ячейка.Текст, " ", ""));
							Сумма = Сумма +ЧислоЯчейки;
						конецесли;
					Исключение
					КонецПопытки;
				КонецЦикла;
			КонецЦикла;
		КонецЕсли;
	КонецЦикла;
	Возврат Сумма;
КонецФункции
...Показать Скрыть