Показать сообщение отдельно
Старый 29.04.2009, 13:16   #32  
gl00mie is offline
gl00mie
Участник
MCBMSS
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,684 / 5788 (200) ++++++++++
Регистрация: 28.11.2005
Адрес: Москва
Записей в блоге: 3
А я во вспомогательном канале вывода в Excel зашел с другого конца: при создании структуры ADO.Recordset я указываю опциональный признак того, надо ли в соотв. колонке избавиться от "незначащих" значений, и после вывода просто делают замену средствами самого Excel таких значений на то, что возвращает COMVariant::createNoValue()
X++:
// очистка ячеек с "пустыми" значениями (ноль для чисел либо 01.01.1900 для дат), чтоб не надо было докручивать шаблон для их сокрытия
// _cell - ячейка, на которой в outputReportBody() вызывается метод CopyFromRecordset()
protected void clearEmptyCells(COM _cell)
{
    COMVariant  cvSrcValue;
    COMVariant  cvDstValue;
    str         strAddr;
    container   conFieldInfo;
    boolean     bClearEmpty;
    Counter     cnRows;
    Counter     n;
    COM         oRng;                                           // область, в которой будет производиться замена
    ;
    cnRows      = rstAxa.RecordCount();                         // количество выведенных строк данных
    cvDstValue  = COMVariant::createNoValue();                  // создаем пустое значение
    for (n = 1; n <= arrFields.lastIndex(); n++)
    {
        conFieldInfo = arrFields.value( n );
        if (conlen(conFieldInfo) >= #ConPosFieldInfoClearEmpty) // по умолчанию этого поля в контейнеере быть не должно
        {
            bClearEmpty = conpeek( conFieldInfo, #ConPosFieldInfoClearEmpty );
            if (!bClearEmpty)
                continue;
            cvSrcValue  = this.getEmptyVariantValue( conpeek( conFieldInfo, #ConPosFieldInfoType ) );
            if (!cvSrcValue)                                    // если вернулся null, значит, тип не поддерживается
                continue;
            // формируем адрес диапазона ячеек *относительно* _cell
            strAddr = ComExceldocument_RU::numToNameCell( n, 1 );
            if (cnRows > 1)
                strAddr += @':' + ComExceldocument_RU::numToNameCell( n, cnRows );
            oRng = _cell.range( strAddr );                      // получаем столбец внутри диапазона _cell
            oRng.Replace( cvSrcValue, cvDstValue, #xlWhole, #xlByColumns );
        }
    }
}
// возвращает COMVariant, представляющий "пустое" значение для указанного типа ADO, либо null, если указанный тип не поддерживается
protected COMVariant getEmptyVariantValue( Integer _adoType )
{
    COMVariant  ret;
    ;
    switch( _adoType )
    {
        case #adDate :
        case #adDBDate :
        case #adDBTimeStamp :
            ret = COMVariant::createFromDateAndTime( datenull(), 0 );
            break;
        case #adSingle :
        case #adDouble :
        case #adCurrency :
        case #adDecimal :
        case #adNumeric :
            ret = COMVariant::createFromReal( 0.0 );
            break;
        case #adTinyInt :
        case #adSmallInt :
        case #adInteger :
        case #adBigInt :
        case #adUnsignedTinyInt :
        case #adUnsignedSmallInt :
        case #adUnsignedInt :
        case #adUnsignedBigInt :
            ret = COMVariant::createFromInt( 0 );
            break;
        default :
            ret = null;
            break;
    }
    return ret;
}
Хотя, конечно, просто не устанавливать значение ячейки в Recordset, пожалуй, как-то "прямее"
PS. По ходу реализации наткнулся на одни "грабли": оказалось, что COMVariant::createFromDate( datenull() ) возвращает COMVariant не со значением 01.01.1900 00:00, как можно было бы ожидать, а со значением 01.01.1900 <текущее_время>!