Тоже наконец "посчастливилось" повозиться с рисованием сетки и расчетом высоты вертикальных "палок" (которые shapes). С благодарностью воспринял идеи этой темы и, творчески передрав и реорганизовав код из упоминаемого источника (отчет SalesPurchInvoice_RU, метод prepareDynamicSection), оформил метод с параметрами. Мне нужно было рисовать сразу 3 разные сетки, поэтому вопрос о некоторой универсальной процедуре естественным образом встал сам собой. Получившийся метод я гордо поместил в класс Global и теперь тихо радуюсь. Приглашаю к этой тихой радости всех желающих.
Параметры метода:
1. секция, подлежащая динамическому расчету;
2. контейнер пар "control - значение" (где "значение" - характерная "максимальная" строка, по которой происходит расчет требуемой высоты контрола);
3. минимально допустимая высота элемента в секции (ниже которой не опускаемся, чтобы не было очень низких строк; unit - 1/100 mm, т.е. значение, например, 1200 соответствует в миру 12 миллиметрам)
Каждая пара "контрол - значение" в свою очередь тоже контейнер. Кол-во передаваемых пар - по вашему желанию. Может быть достаточно и одного контрола, потенциально самого высокого в секции в плане DynamicHeight. Но можно - для уверенности - перечислить и все имеющиеся в секции контролы, задав им в качестве значения соответствующие поля таблиц или дисплей-методы.
Метод, помещенный в класс Global:
X++:
static void prepareReportDynamicSection( ReportSection _section,
container _pairsControlValue,
int _minHeight100mm = 0)
{
ReportControl reportControl;
ReportShapeControl reportShapeControl;
Counter i;
int childNodesCount;
int maxHeight100mm,
maxTop100mm;
str currControl,
currValue;
void processControl( ReportControl _control, str _fieldValue )
{
int ht100, tp100;
;
ht100 = max( _control.heightOfWordWrappedString100mm( _fieldValue ),
_control.heightOfWordWrappedString100mm(' '), // ' \n \n \n '
_minHeight100mm);
tp100 = _control.top100mm();
maxHeight100mm = max( maxHeight100mm, ht100 );
maxTop100mm = max( maxTop100mm, tp100 );
}
;
for(i = 1; i <= conlen(_pairsControlValue); i++)
{
[currControl, currValue] = conpeek(_pairsControlValue, i);
processControl( _section.controlName(currControl), currValue);
}
childNodesCount = _section.AOTchildNodeCount();
for(i = 0; i < childNodesCount; i++)
{
reportControl = _section.controlNo(i);
if (! reportControl)
continue;
if(reportControl.controlType() == ReportFieldType::BOX)
{
reportShapeControl = reportControl;
if(reportShapeControl.type() != ShapeType::Horizontal)
{
reportShapeControl.height100mm(maxHeight100mm + 1 + maxTop100mm);
}
else
{
if(reportShapeControl.top100mm())
{
reportShapeControl.top100mm(maxHeight100mm + 1 + maxTop100mm);
}
}
}
else
{
reportControl.height100mm(maxHeight100mm);
}
}
}
Примечание: Наличие вложенного метода processControl - не более, чем рудимент от первоначальной попытки декомпозиции задачи. При желании можно смело избавиться от него, перенеся необходимые операторы в общий цикл.
Пример вызова - в методе executeSection соответствующей секции:
X++:
public void executeSection()
{
prepareReportDynamicSection
( this,
[
['Control_1', element.getLineNum() ],
['Control_2', element.getItemDescr()],
['Control_3', table1.field1 ],
['Control_4', 'bla-bla-bla' ]
],
1200 );
super();
}