Показать сообщение отдельно
Старый 29.01.2010, 20:47   #5  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Немного сумбурно, но всё же завершу трудовую неделю на мажорной ноте. Потом неспешно покомментирую.

В общем, прислушавшись к коллегам, родил получение состава и порядка колонок - вроде, правильно. Ковырялся с достаточно сложной формой, поэтому наступил, как мне кажется, уже на все возможные грабли.

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

Для участия надо:
  1. открыть любую форму с гридом и желательно большим количеством закладок
  2. выделить несколько строк грида, скопировать и вставить в Excel
  3. не закрывая форму с гридом, открыть окно с кодом джоба, подправив gridName
  4. "макнуть" мышку в форму, вернуться в джоб и нажать F5 (см.комментарии в джобе)
  5. получившийся список меток скопировать из инфолога в Excel на отдельный лист
  6. "развернуть" вертикальный список горизонтально при помощи команды Специальная вставка \ Транспонировать
  7. сравнить названия колонок из грида и из моего списка, расположив обе строки на одном листе Excel
  8. сообщить в ветку об успехе или неудаче
Вот мой джоб:
X++:
static void Job2192_exportGridColumnOrder(Args _args)
{
    // перед запуском ткнуть мышкой в желаемую форму,
    // затем ткнуть в текст этого джоба и нажать F5
    // (для наглядности лучше сначала закрыть (или свернуть) все ненужные окна,
    // а оставшиеся открытые расположить мозаикой)

    str     gridName = 'RequestList';  // ПОДПРАВЬ ДЛЯ СВОЕЙ ФОРМЫ ИМЯ ИССЛЕДУЕМОГО ГРИДА!
    FormRun formRun;

    FormGridControl grid;
    FormDataSource  gridDataSource;

    int j, k, m;
    Map colNames  = new Map(Types::String, Types::Integer);
    Map colLabels = new Map(Types::Integer, Types::String);

    boolean hasClassMethod(Object _obj, str _methodName)
    {   // функция заимствована у Russland'а
        ClassId         classId      = classIdGet(_obj);
        SysDictClass    sysDictClass = new sysDictClass(classId);
        ;
        return sysDictClass.hasObjectMethod(_methodName);
    }

    void nextControl(Object _obj)
    {
        Object      control;
        int         i;
        DictField   dictField;
        DictType    dictType;
        DictMethod  dictMethod;

        str         columnLabel;
        str         columnName;
        ;

        for(i=1; i<=_obj.controlCount(); i++)
        {
            control = _obj.controlNum(i);

            if (hasClassMethod(control, 'dataSource') &&
                hasClassMethod(control, 'dataField' ) &&
                hasClassMethod(control, 'dataMethod'))
            {
                if (!control.isContainer()  &&
                     control.isVisible()    &&
                     control.dataSource() == gridDataSource.id())
                {
                    if (!control.dataMethod())
                    {
                        dictField = new DictField(gridDataSource.table(), control.dataField());
                        dictType  = new DictType (dictField.typeId());

                        columnLabel = 
                            control.label() ? control.label()
                                            : dictField.label() ? dictField.label()
                                                                : dictType.label();
                        columnName  = dictField.name();
                    }
                    else
                    {
                        // обращение с dictMethod заимствовано у EVGL
                        dictMethod = new DictMethod(UtilElementType::TableInstanceMethod, gridDataSource.table(), control.dataMethod());
                        dictType   = new DictType(dictMethod.returnId());

                        columnLabel =
                            control.label() ? control.label()
                                            : (dictMethod.returnType()==Types::UserType) ? dictType.label() 
                                                                                         : dictMethod.name();
                        m++;
                        columnName = strFmt('%1(%2)', control.dataMethod(), m);
                    }

                    if (! colNames.exists(columnName))
                    {
                        k++;
                        colNames.insert(columnName, k);
                        colLabels.insert(k, columnLabel);
                    }
                }
            }

            if(control.isContainer())
            {
                nextControl(control);
            }
        }
    }
    ;

    formRun = infolog.parmLastActivatedForm().object();

    grid = formRun.design().controlName(gridName);

    // ищем датасорс грида
    for (j=1; j<=formRun.dataSourceCount(); j++)
    {
        if (formRun.dataSource(j).id() == grid.dataSource())
        {
            gridDataSource = formRun.dataSource(j);
            break;
        }
    }

    k = 0; // счетчик уникальных имен
    m = 0; // счетчик дисплей-методов
    nextControl(formRun.design());  

    for (k=1;k<=colNames.elements();k++)
    {
        info(strFmt('%1 -- %2', k, colLabels.lookup(k)));
    }
}
P.S. Теперь несколько тезисов по теме русским бытовым языком:
  1. После копировании строк грида и последующей вставки в Excel выводятся столбцы, соответствующие всем видимым (visible=Yes) управляющим элементам ("контролам") формы, у которых в свойстве dataSource указан датасоурс копируемого грида.
    .
  2. Порядок следования колонок в Excel определяется порядком рекурсивного перебора контролов работающей (перебор по AOT не годится!) формы (см. джоб) по всем вкладкам, начиная с первой (обычно это вкладка "Обзор", на которой расположен сам грид). То, что первыми идут колонки самого грида - не более, чем следствие того, что грид расположен именно на первой вкладке. Перетащите вкладку "Обзор" в конец набора вкладок - и колонки ее грида станут последними на листе Excel.
    .
  3. Копируются данные контролов, соответствующих как полям датасорса, так и дисплей-методам базовой таблицы (у меня Axapta 3.0 sp4, со слов glibs'а вывод дисплей-методов появился с версии 3.0 sp3).
    .
  4. Если одно и то же поле выводится на форму несколько раз, то в Excel попадает только самый первый по порядку перебора контрол с этим полем. Оставшиеся контролы с этим полем не выводятся, даже если имеют различные метки (становящиеся в Excel названиями колонок).
    .
  5. В отличие от полей, контролы, ссылающиеся на один и тот же дисплей-метод, выводятся в Excel все (а не только самый первый). Не знаю, фича это или бага, но это так.
    .
  6. Видимость (visible) проверяется непосредственно по самому контролу. Если контрол входит в группу и имеет visible=Yes, а у группы стоит visible=No, то контрол не виден на форме, НО (!) появляется в Excel!
    .
  7. Пока не проверял контролы с разными ключами безопасности. Надеюсь, там всё хорошо.

Последний раз редактировалось Gustav; 29.01.2010 в 23:33.
За это сообщение автора поблагодарили: mazzy (2), EVGL (2), lev (2), Player1 (1).