Доброго времени суток, коллеги! Не так давно передо мной встала одна задача, решив которую я подумал, что стоит поделиться опытом. Разработка велась в среде 1с версии 8.2, поэтому я буду использовать соответствующие данной платформе термины.
Итак, суть задачи была в следующем.
Имеем рисунок табличного документа, типа «Надпись». Необходимо реализовать функцию автоматического подбора размера шрифта в данном поле, чтобы текст произвольной длины размещался в нем оптимальным образом, не выходил за границы, и не был бы слишком мелким.
Стало быть, само решение:
Для начала о настройках свойств самого рисунка табличного документа. Опытным путем установлено, что лучший результат получается при таких значениях свойств:
Таблица 1.
Свойство |
Значение |
РазмещениеТекста |
Авто |
ГоризонтальноеПоложение |
Лево |
ВертикальноеПоложение |
Центр |
Теперь о самом принципе.
В целом все, что нужно сделать, - это вычислить физический размер строки символов (в миллиметрах) в высоту и длину.
Рассмотрим этот принцип на примере шрифта Arial, как шрифта по умолчанию в 1С v8.
Я решил, что вернее всего будет взять одну из самых широких букв кириллицы – букву «Ш» - поскольку любой текст в ширину уж точно не будет длиннее, чем текст, состоящий из одних только букв «Ш», и вычислить соотношения ее кегля и физической высоты. Я распечатал эту букву используя шрифт Arial, высотой 100 пунктов, после чего измерил ее высоту и ширину на бумаге в миллиметрах и вычислил соотношение. Честно говоря, я предполагаю, что есть и некий более красивый способ вычислить это соотношение. Однако я такого не нашел, и пошел по простому пути. Как выяснилось, он работает, поэтому прошу не судить строго. Вычислить из расчета 1 пункт = 1/72 дюйма оказалось невозможным, поскольку кегль – величина весьма относительная, как вы знаете, и текст высотой в 100 пунктов, набранный шрифтом Arial будет совсем другой высоты, нежели текст, набранный шрифтом, скажем Colibri, той же высоты кегля.
Вы можете спросить, почему я не использовал букву «Щ», ведь она выше – я отвечу – потому, что выносной элемент не влияет на саму высоту строки, а ведь нам важна именно высота строки, а не самого символа.
Итак, для любого текста в рисунке табличного документа его высота, при оптимальном размещении будет равна (см. рис 1):
Hт = 2×Hп + Hш×N+ Hми×N, где
Hт– высота текста
Hп– высота поля
Hш– высота шрифта
Hми– высота междустрочного интервала
N – количество строк
Рисунок 1 |
В этой формуле нам еще неизвестны высоты поля Hп и междустрочного интервала Hми
Их также замерил и соотнес с размером шрифта, логично, что это оказались постоянные величины.
Ну, и есть еще такая величина, как длина текста. Она, соответственно, равна ширине символа, умноженной на количество символов в строке. Вы можете подумать, что я забыл про правое и левое поля. Как показала практика, то, что я взял в качестве исходного символа букву «Ш» с лихвой компенсирует эти поля. Хотя, для большей точности, можно ввести и эти коэффициенты. Они, соответственно, вычисляются по тому же принципу, что и коэффициент для верхнего поля – как отношение ширины символа к ширине поля в мм. На самом деле длина текста нужна лишь для вычисления общего количества строк текста. Подробнее – в демонстрационной обработке.
Вот, собственно, и все нужные данные.
Вычисленные значения для шрифта Arial приведены в таблице 2.
Таблица 2.
Kвыс |
» 0.25 |
Отношение высоты в мм к высоте в пт |
Kшир |
» 0.27 |
Отношение высоты поля в мм к высоте символа в пт |
Kполяв |
» 0.44 |
Отношение высоты верхнего поля в мм к высоте символа в мм |
Kполял |
» 0.4 |
Отношение ширины левого поля в мм к ширине символа в мм |
Kми |
» 0.48 |
Отношение высоты межстрочного интервала в мм к высоте символа в мм |
Формулу высоты, для лучшего понимания я перепишу в стиле 1С:
Hп= ВысотаШрифтаММ/КВыс
Hш=ВысотаШрифтаММ
Hми=ВысотаШрифтаММ /КМИ
N= СчСтрокОбщ
ВысотаТекста = 2 * ВысотаШрифтаММ*КВыс + ВысотаШрифтаММ*СчСтрокОбщ + ВысотаШрифтаММ*КМИ*СчСтрокОбщ;
отсюда
ВысотаТекста = ВысотаШрифтаММ * (2*КПолей + СчСтрокОбщ * (1 + КМИ));
Формула ширины, соответственно
ШиринаТекста = ШиринаТекстаММ * ЧислоСимволов
Ну, или с полями
ШиринаТекста = ШиринаТекстаММ * (ЧислоСимволов + 2 * ТекСтруктураШрифта.КПолейЛев)
Конечно, такой метод не особо универсален, но, в принципе такая задача и не актуальна для большого количества разных шрифтов. В моем конкретном случае это был макет ценника, состоящий из множества полей. Там применялся всего один вид шрифта.
Поэтому, я думаю, данное решение может быть полезно во множестве случаев. Если же кто-нибудь укажет мне на большую универсальность расчетов – буду крайне признателен.
Обработка, демонстрирующая механизм прилагается.
Вот код самой обработки если лень скачивать.
Перем СоответствиеШрифтов; Процедура ПодобратьШрифт() ТабДокумент = ЭлементыФормы.ТабДок; Если ТабДокумент.Рисунки.Количество() = 1 Тогда ПолеТекста = ТабДокумент.Рисунки[0]; ШиринаПоляИсх = ПолеТекста.Ширина; ВысотаПоляИсх = ПолеТекста.Высота; ИсхШрифт = ПолеТекста.Шрифт; //получим соответствующие параметры для данного шрифта ТекСтруктураШрифта = СоответствиеШрифтов.Получить(ИсхШрифт.Имя); //начинаем с самого мелкого шрифта, и будем увеличивать пока весь текст помещается в пределы поля ТекРазмерШрифта = 1; ЧислоСимволов = СтрДлина(ВыбТекст); СчСтрок = 0; СтрПроверка = ""; ДлинаТекстаВСтроку = 0; Пока Истина Цикл СчСтрок = 0; СчСтрокОбщ = 0; ШиринаТекстаММ = ТекРазмерШрифта * ТекСтруктураШрифта.КШир; //подбор ширины, в общем-то, нужен для вычисления количества строк текста Для а = 1 По СтрЧислоСтрок(ВыбТекст) Цикл СчСтрокОбщ = СчСтрокОбщ + 1; ЧислоСимволов = СтрДлина(СтрПолучитьСтроку(ВыбТекст,а)); //Длина текста равна произведению физической ширины символа на количество символов ////ДлинаТекстаВСтроку = [ШиринаТекстаММ * ЧислоСимволов] + [2 * ШиринаТекстаММ * ТекСтруктураШрифта.КПолейЛев]; //ДлинаТекстаВСтроку = ШиринаТекстаММ * (ЧислоСимволов + 2 * ТекСтруктураШрифта.КПолейЛев); ДлинаТекстаВСтроку = ШиринаТекстаММ * ЧислоСимволов; СчСтрок = СчСтрок + ЦЕЛ(ДлинаТекстаВСтроку/ШиринаПоляИсх); КонецЦикла; СчСтрокОбщ = СчСтрокОбщ + СчСтрок; ////высота текста состоит из: ////1. верхнего и нижнего поля, они примерно в 2.5 раза меньше высоты шрифта ////2. высот строк текста - они равны высоте шрифта ////3. межстрочных интервалов - они примерно в 1.6 раз меньше высоты шрифта //// 1 2 3 ////ВысотаТекста = [2 * ВысотаШрифтаММ * КПолей] + [ВысотаШрифтаММ * СчСтрок] + [ВысотаШрифтаММ * СчСтрок * КМИ]; //итак: ВысотаШрифтаММ = ТекРазмерШрифта * ТекСтруктураШрифта.КВыс; ВысотаТекста = ВысотаШрифтаММ * (2*ТекСтруктураШрифта.КПолейВерх + СчСтрокОбщ * (1 + ТекСтруктураШрифта.КМИ)); //все, по высоте не влез - прекращаем Если ВысотаТекста >= ВысотаПоляИсх Тогда Прервать; КонецЕсли; ТекРазмерШрифта = ТекРазмерШрифта + 1; КонецЦикла; //поскольку размер шрифта превысил допустимый отступим на шаг назад РезШрифт = Новый Шрифт(ИсхШрифт,,ТекРазмерШрифта-1); ПолеТекста.Шрифт = РезШрифт; ПолеТекста.Текст = ВыбТекст; КонецЕсли; КонецПроцедуры Процедура КнопкаВыполнитьНажатие(Кнопка) ПодобратьШрифт(); КонецПроцедуры Процедура ПриОткрытии() ПодобратьШрифт(); КонецПроцедуры КВыс = 0.25; КШир = 0.27; КПолейВерх = 0.44; КПолейЛев = 0.4; КМИ = 0.6; ВыбТекст = "Вы можете менять размеры рисунка и текст. Размер шрифта подбирается нажатием кнопки ""Подогнать"""; СоответствиеШрифтов = Новый Соответствие; СтруктураПараметровШрифта = Новый Структура("КВыс,КШир,КПолейВерх,КПолейЛев,КМИ",КВыс,КШир,КПолейВерх,КПолейЛев,КМИ); СоответствиеШрифтов.Вставить("Arial",СтруктураПараметровШрифта);
Спасибо за внимание, надеюсь, статья была полезна.
P.S. В интернете также имеется пример решения похожей задачи для ЯчейкиТабличногоДокумента располагается вот здесь
http://infostart.ru/public/123769/
Автор товарищ Александр Гладких - ему спасибо за статью. В ней, кроме всего прочего, упоминается мой метод для рисунка и альтернативный вариант решения, который я попробовал в первую очередь когда озадачился данной проблемой и отверг, поскольку он слишком долго работал при большом количестве многострочного текста.