В уроке 12 мы познакомились с составными строками и рассмотрели недокументированный способ их создания. В уроке 13 были представлены параграфы. Сегодня мы рассмотрим, как их использовать для создания составных строк. Для начала возьмем строки, включающие в свой состав отклонения и дроби, и познакомимся с такими компонентами составных строк, как надстрока, подстрока и спецсимволы.



Содержание цикла уроков «Работа с API КОМПАС-3D»


  1. Основы
  2. Оформление чертежа
  3. Корректное подключение к КОМПАС
  4. Основная надпись
  5. Графические примитивы
  6. Сохранение документа в различные форматы
  7. Знакомство с настройками
  8. Более сложные методы записи в основную надпись
  9. Чтение ячеек основной надписи
  10. Спецсимволы, включающие строку
  11. Простые текстовые надписи
  12. Составные строки
  13. Параграфы
  14. Многострочный текст
  15. Составные строки на основе параграфа

Верхнее и нижнее отклонения


Ниже приводится фрагмент программы, демонстрирующей вывод строки с верхним и нижним отклонениями с помощью параграфов. Для решения этой задачи используются флаги END_DEVIAT, LOWER_DEVIAT и UPPER_DEVIAT, упоминавшиеся в уроке 12.

Фрагмент кода программы
//Получаем необходимые интерфейсы массива строк
DynamicArrayPtr items;
items = static_cast<DynamicArrayPtr>(kompas->GetDynamicArray(TEXT_ITEM_ARR));
items->ksClearArray();

TextItemParamPtr itemParam;
itemParam = static_cast<TextItemParamPtr>(kompas->GetParamStruct(ko_TextItemParam));
itemParam->Init();

TextItemFontPtr itemFont;
itemFont = static_cast<TextItemFontPtr>(itemParam->GetItemFont());

//Наполняем массив строк
BSTR str = SysAllocString(OLESTR("Текст до отклонений"));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

itemFont->set_bitVector(UPPER_DEVIAT);
str = SysAllocString(OLESTR("Верхнее отклонение"));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

itemFont->set_bitVector(LOWER_DEVIAT);
str = SysAllocString(OLESTR("Нижнее отклонение"));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

itemFont->set_bitVector(END_DEVIAT);
str = SysAllocString(OLESTR("Текст после отклонений"));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

//Освобождаем интерфейсы, которые больше не нужны
itemFont.Unbind();
itemParam.Unbind();

//Подготавливаем интерфейс ksTextLineParam
TextLineParamPtr lineParam;
lineParam = static_cast<TextLineParamPtr>(kompas->GetParamStruct(ko_TextLineParam));
lineParam->Init();
lineParam->SetTextItemArr(items);

//Подготавливаем интерфейс ksParagraphParam
ParagraphParamPtr paragraphParam;
paragraphParam= static_cast<ParagraphParamPtr>(kompas->GetParamStruct(ko_ParagraphParam));
paragraphParam->Init();
paragraphParam->set_x(30.0);
paragraphParam->set_y(100.0);

//Строим параграф
Document2D->ksParagraph(paragraphParam);
Document2D->ksTextLine(lineParam);
Document2D->ksEndObj();

//Освобождаем интерфейсы
items->ksDeleteArray();
items.Unbind();
lineParam.Unbind();
paragraphParam.Unbind();


По сравнению с примером построения отклонений из урока 12 текущая программа имеет два важных преимущества:

  1. В ней используются документированные возможности системы КОМПАС.
  2. Нет необходимости пересчета положения строк. КОМПАС сам определяет все необходимые смещения.

Обратите внимание на использование флага END_DEVIAT. Он завершает формирование отклонений и отменяет флаги LOWER_DEVIAT и UPPER_DEVIAT. Если бы мы его не использовали, то строка «Текст после отклонений» выводилась бы как нижнее отклонение.

Флаги LOWER_DEVIAT и UPPER_DEVIAT отменяют друг друга. При их одновременном использовании строка выводится так, как она выводилась бы без указания этих флагов.

Так как в нашем примере флаг NEW_LINE не используется, то все строки могут быть выведены одним вызовом метода ksTextLine. Для этого они предварительно оформляются в виде интерфейса ksTextLineParam.

Результат работы программы показан на рисунке ниже.



Дробь


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

Пример программы
//Получаем необходимые интерфейсы массива строк
DynamicArrayPtr items;
items = static_cast<DynamicArrayPtr>(kompas->GetDynamicArray(TEXT_ITEM_ARR));
items->ksClearArray();

TextItemParamPtr itemParam;
itemParam = static_cast<TextItemParamPtr>(kompas->GetParamStruct(ko_TextItemParam));
itemParam->Init();

TextItemFontPtr itemFont;
itemFont = static_cast<TextItemFontPtr>(itemParam->GetItemFont());

//Наполняем массив строк
BSTR str = SysAllocString(OLESTR("Текст до дроби"));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

itemFont->set_bitVector(NUMERATOR);
str = SysAllocString(OLESTR("Числитель"));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

itemFont->set_bitVector(DENOMINATOR);
str = SysAllocString(OLESTR("Знаменатель"));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

itemFont->set_bitVector(END_FRACTION);
str = SysAllocString(OLESTR("Текст после дроби"));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

//Освобождаем интерфейсы, которые больше не нужны
itemFont.Unbind();
itemParam.Unbind();

//Подготавливаем интерфейс ksTextLineParam
TextLineParamPtr lineParam;
lineParam = static_cast<TextLineParamPtr>(kompas->GetParamStruct(ko_TextLineParam));
lineParam->Init();
lineParam->SetTextItemArr(items);

//Подготавливаем интерфейс ksParagraphParam
ParagraphParamPtr paragraphParam;
paragraphParam= static_cast<ParagraphParamPtr>(kompas->GetParamStruct(ko_ParagraphParam));
paragraphParam->Init();
paragraphParam->set_x(30.0);
paragraphParam->set_y(100.0);

//Строим параграф
Document2D->ksParagraph(paragraphParam);
Document2D->ksTextLine(lineParam);
Document2D->ksEndObj();

//Освобождаем интерфейсы
items->ksDeleteArray();
items.Unbind();
lineParam.Unbind();
paragraphParam.Unbind();


Построение дроби мало чем отличается от построения отклонений. Единственное различие– это используемые флаги. Флаг END_FRACTION отменяет действие флагов NUMERATOR и DENOMINATOR и действует так же, как и флаг END_DEVIAT применительно к отклонениям.
На рисунке ниже показан результат работы этой программы.



Данная строка выглядит аккуратнее по сравнению с аналогичным текстом, полученным в уроке 12.

Управление размером дроби


Выводимая дробь может иметь различный размер, управление которым осуществляется с помощью интерфейса ksTextItemParam. Если его свойство type равно FRACTION_TYPE, то данный интерфейс помимо прочего задает размер дроби. Сам размер указывается в свойстве iSNumb. Его допустимые значения приведены в таблице ниже.



Если в свойстве iSNumb указано недопустимое значение, то КОМПАС использует высоту по умолчанию.

Ниже приводится пример использования флага FRACTION_TYPE.

Пример использования флага
//Получаем необходимые интерфейсы
DynamicArrayPtr items;
items = static_cast<DynamicArrayPtr>(kompas->GetDynamicArray(TEXT_ITEM_ARR));
items->ksClearArray();

TextItemParamPtr itemParam;
itemParam = static_cast<TextItemParamPtr>(kompas->GetParamStruct(ko_TextItemParam));
itemParam->Init();

TextItemFontPtr itemFont;
itemFont = static_cast<TextItemFontPtr>(itemParam->GetItemFont());

//Наполняем массив строк
BSTR str = SysAllocString(OLESTR("Текст до дроби"));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

itemFont->set_bitVector(NUMERATOR);
itemParam->set_type(FRACTION_TYPE);
itemParam->set_iSNumb(3);
str = SysAllocString(OLESTR("Числитель"));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

itemFont->set_bitVector(DENOMINATOR);
str = SysAllocString(OLESTR("Знаменатель"));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

itemFont->set_bitVector(END_FRACTION);
str = SysAllocString(OLESTR("Текст после дроби"));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

//Освобождаем интерфейсы, которые больше не нужны
itemFont.Unbind();
itemParam.Unbind();

//Подготавливаем интерфейс ksTextLineParam
TextLineParamPtr lineParam;
lineParam = static_cast<TextLineParamPtr>(kompas->GetParamStruct(ko_TextLineParam));
lineParam->Init();
lineParam->SetTextItemArr(items);

//Подготавливаем интерфейс ksParagraphParam
ParagraphParamPtr paragraphParam;
paragraphParam= static_cast<ParagraphParamPtr>(kompas->GetParamStruct(ko_ParagraphParam));
paragraphParam->Init();
paragraphParam->set_x(30.0);
paragraphParam->set_y(100.0);

//Строим параграф
Document2D->ksParagraph(paragraphParam);
Document2D->ksTextLine(lineParam);
Document2D->ksEndObj();

//Освобождаем интерфейсы
items->ksDeleteArray();
items.Unbind();
lineParam.Unbind();
paragraphParam.Unbind();


Этот пример отличается от предыдущего только установкой типа FRACTION_TYPE в свойстве type интерфейса ksTextItemParam при выводе числителя. Тем не менее, этого достаточно чтобы изменить размер дроби. На рисунке ниже показан результат работы этой программы (сравните его с результатом предыдущего примера).



Обратите внимание: размер дроби задается при выводе числителя. Как показывают мои эксперименты, размер дроби заданный при выводе знаменателя игнорируется.

Надстрока и подстрока



Построение надстроки и подстроки управляется флагами, перечисленными в таблице ниже.



Ниже приводится пример программы, демонстрирующей вывод строки с надстрокой и подстрокой.

Пример программы
//Получаем необходимые интерфейсы
DynamicArrayPtr items;
items = static_cast<DynamicArrayPtr>(kompas->GetDynamicArray(TEXT_ITEM_ARR));
items->ksClearArray();

TextItemParamPtr itemParam;
itemParam = static_cast<TextItemParamPtr>(kompas->GetParamStruct(ko_TextItemParam));
itemParam->Init();

TextItemFontPtr itemFont;
itemFont = static_cast<TextItemFontPtr>(itemParam->GetItemFont());

//Наполняем массив строк
BSTR str = SysAllocString(OLESTR("Простой текст  "));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

itemFont->set_bitVector(S_BASE);
str = SysAllocString(OLESTR("Основная строка"));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

itemFont->set_bitVector(S_UPPER_INDEX);
str = SysAllocString(OLESTR("Надстрока"));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

itemFont->set_bitVector(S_LOWER_INDEX);
str = SysAllocString(OLESTR("Подстрока"));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

itemFont->set_bitVector(S_END);
str = SysAllocString(OLESTR("  Простой текст"));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

//Освобождаем интерфейсы, которые больше не нужны
itemFont.Unbind();
itemParam.Unbind();

//Подготавливаем интерфейс ksTextLineParam
TextLineParamPtr lineParam;
lineParam = static_cast<TextLineParamPtr>(kompas->GetParamStruct(ko_TextLineParam));
lineParam->Init();
lineParam->SetTextItemArr(items);

//Подготавливаем интерфейс ksParagraphParam
ParagraphParamPtr paragraphParam;
paragraphParam= static_cast<ParagraphParamPtr>(kompas->GetParamStruct(ko_ParagraphParam));
paragraphParam->Init();
paragraphParam->set_x(30.0);
paragraphParam->set_y(100.0);

//Строим параграф
Document2D->ksParagraph(paragraphParam);
Document2D->ksTextLine(lineParam);
Document2D->ksEndObj();

//Освобождаем интерфейсы
items->ksDeleteArray();
items.Unbind();
lineParam.Unbind();
paragraphParam.Unbind();


На рисунке ниже показан результат работы данной программы.



Построить надстроку и подстроку с помощью метода ksDocument2D::ksText нельзя.

Управление размером основной строки


Основная строка может иметь различный размер, изменение которого осуществляется с помощью интерфейса ksTextItemParam. Для этого в его свойстве type указывается константа SUM_TYPE, а в свойстве iSNumb – требуемый размер основной строки. Допустимые значения приведены в таблице ниже:



Если в свойстве iSNumb указано недопустимое значение, то КОМПАС использует значение по умолчанию.

Ниже приводится фрагмент программы, демонстрирующей использование константы SUM_TYPE.

Фрагмент программы
//Получаем необходимые интерфейсы
DynamicArrayPtr items;
items = static_cast<DynamicArrayPtr>(kompas->GetDynamicArray(TEXT_ITEM_ARR));
items->ksClearArray();

TextItemParamPtr itemParam;
itemParam = static_cast<TextItemParamPtr>(kompas->GetParamStruct(ko_TextItemParam));
itemParam->Init();

TextItemFontPtr itemFont;
itemFont = static_cast<TextItemFontPtr>(itemParam->GetItemFont());

//Наполняем массив строк
BSTR str = SysAllocString(OLESTR("Простой текст  "));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

itemFont->set_bitVector(S_BASE);
itemParam->set_type(SUM_TYPE);
itemParam->set_iSNumb(2);
str = SysAllocString(OLESTR("Основная строка"));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

itemFont->set_bitVector(S_UPPER_INDEX);
itemParam->set_type(0);
itemParam->set_iSNumb(0);
str = SysAllocString(OLESTR("Надстрока"));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

itemFont->set_bitVector(S_LOWER_INDEX);
str = SysAllocString(OLESTR("Подстрока"));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

itemFont->set_bitVector(S_END);
str = SysAllocString(OLESTR("  Простой текст"));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);

//Освобождаем интерфейсы, которые больше не нужны
itemFont.Unbind();
itemParam.Unbind();

//Подготавливаем интерфейс ksTextLineParam
TextLineParamPtr lineParam;
lineParam = static_cast<TextLineParamPtr>(kompas->GetParamStruct(ko_TextLineParam));
lineParam->Init();
lineParam->SetTextItemArr(items);

//Подготавливаем интерфейс ksParagraphParam
ParagraphParamPtr paragraphParam;
paragraphParam= static_cast<ParagraphParamPtr>(kompas->GetParamStruct(ko_ParagraphParam));
paragraphParam->Init();
paragraphParam->set_x(30.0);
paragraphParam->set_y(100.0);

//Строим параграф
Document2D->ksParagraph(paragraphParam);
Document2D->ksTextLine(lineParam);
Document2D->ksEndObj();

//Освобождаем интерфейсы
items->ksDeleteArray();
items.Unbind();
lineParam.Unbind();
paragraphParam.Unbind();



Константа SUM_TYPE заносится в свойство type интерфейса ksTextItemParam при выводе основной строки. Перед выводом надстроки интерфейс ksTextItemParam приводится в свое исходное состояние. Это единственное отличие данного примера от предыдущего.

На рисунке ниже показан результат работы программы (сравните его с результатом предыдущего примера).



Константа SUM_TYPE позволяет изменять размер основной строки, но не надстроки и подстроки. Изменение их размеров в КОМПАС не предусмотрено.

Спецсимволы, включающие подстроку


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

Фрагмент программы
//Подготавливаем массивы
DynamicArrayPtr items;
items = static_cast<DynamicArrayPtr>(kompas->GetDynamicArray(TEXT_ITEM_ARR));
items->ksClearArray();
DynamicArrayPtr lines;
lines = static_cast<DynamicArrayPtr>(kompas->GetDynamicArray(TEXT_LINE_ARR));
lines->ksClearArray();

//Подготавливаем другие интерфейсы
TextLineParamPtr lineParam;
lineParam = static_cast<TextLineParamPtr>(kompas->GetParamStruct(ko_TextLineParam));
lineParam->Init();


TextItemParamPtr itemParam;
itemParam = static_cast<TextItemParamPtr>(kompas->GetParamStruct(ko_TextItemParam));
itemParam->Init();

TextItemFontPtr itemFont = static_cast<TextItemFontPtr>(itemParam->GetItemFont());

//Наполняем массив строк
BSTR str = SysAllocString(OLESTR("Обычный текст"));
itemParam->set_s(str);
items->ksAddArrayItem(-1, itemParam);
lineParam->SetTextItemArr(items);
lines->ksAddArrayItem(-1, lineParam);
lineParam->Init();
SysFreeString(str);
str = NULL;
//Добавляем первый спецсимвол с подстрокой
itemFont->set_bitVector(NEW_LINE | SPECIAL_SYMBOL);
str = SysAllocString(OLESTR("Зачеркнутый текст"));
itemParam->set_s(str);
itemParam->set_type(SPECIAL_SYMBOL);
itemParam->set_iSNumb(169);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);
str = NULL;
//Отменяем действие спецсимвола
itemFont->set_bitVector(SPECIAL_SYMBOL_END);
itemParam->set_s(NULL);
itemParam->set_type(0);
itemParam->set_iSNumb(0);
items->ksAddArrayItem(-1, itemParam);
lineParam->SetTextItemArr(items);

lines->ksAddArrayItem(-1, lineParam);
lineParam->Init();

//Добавляем второй спецсимвол с подстрокой
itemFont->set_bitVector(NEW_LINE | SPECIAL_SYMBOL);
str = SysAllocString(OLESTR("Подчеркнутый текст"));
itemParam->set_s(str);
itemParam->set_type(SPECIAL_SYMBOL);
itemParam->set_iSNumb(96);
items->ksAddArrayItem(-1, itemParam);
SysFreeString(str);
str = NULL;

//Отменяем действие спецсимвола
itemFont->set_bitVector(SPECIAL_SYMBOL_END);
itemParam->set_s(NULL);
itemParam->set_type(0);
itemParam->set_iSNumb(0);
items->ksAddArrayItem(-1, itemParam);
lineParam->SetTextItemArr(items);

lines->ksAddArrayItem(-1, lineParam);
lineParam->Init();

//Добавляем простую строку
itemFont->set_bitVector(NEW_LINE);
str = SysAllocString(OLESTR("Обычный текст"));
itemParam->set_s(str);
itemParam->set_type(0);
itemParam->set_iSNumb(0);
items->ksAddArrayItem(-1, itemParam);
lineParam->SetTextItemArr(items);
lines->ksAddArrayItem(-1, lineParam);
lineParam->Init();
SysFreeString(str);
str = NULL;

itemParam.Unbind();
lineParam.Unbind();
itemFont.Unbind();
items.Unbind();

//Подготавливаем интерфейс параметров параграфа
ParagraphParamPtr paragraphParam;
paragraphParam= static_cast<ParagraphParamPtr>(kompas->GetParamStruct(ko_ParagraphParam));

paragraphParam->Init();
paragraphParam->set_x(100.0);
paragraphParam->set_y(100.0);
paragraphParam->set_width(60.0);
paragraphParam->set_hFormat(2);

//Подготавливаем интерфейс параметров текста
TextParamPtr textParam = static_cast<TextParamPtr>(kompas->GetParamStruct(ko_TextParam));
textParam->SetParagraphParam(paragraphParam);
textParam->SetTextLineArr(lines);

//Выводим текст
Document2D->ksTextEx(textParam, 1);

lines->ksDeleteArray();
lines.Unbind();
paragraphParam.Unbind();
textParam.Unbind();


Пример выглядит очень сложным, но если внимательно присмотреться к нему, то можно увидеть, что он состоит из повторяющихся кусков. В нем с помощью спецсимволов выводятся зачеркнутый и подчеркнутый текст. После каждого такого блока выводится пустая строка с флагом SPECIAL_SYMBOL_END. Ее задача – отменить действие спецсимвола. Если ее не выводить, то параграф может быть построен неправильно. Действие спецсимвола распространяется на весь блок ksTextLineParam, на всю его длину независимо от его фактического содержимого (этот тезис проиллюстрирован на рисунке ниже).



Отменяющая строка должна входить в состав блока ksTextLineParam. В противном случае параграф может быть построен неправильно. В состав блока ksTextLineParam может входить несколько управляющих символов. Для каждого из них должна быть своя отменяющая строка.

Флаг SPECIAL_SYMBOL_END используется только для спецсимволов, имеющих подстроку. Для обычных спецсимволов он не нужен.

На рисунке ниже показан результат работы нашего примера.



Заключение

В данном уроке мы научились использовать параграфы для создания составных строк, включающих в себя отклонения и дроби, рассмотрели документированные способы создания составных строк на основе параграфа. Это не единственный и далеко не самый простой способ их создания. Другой, значительно более простой способ мы рассмотрим в следующем уроке.

Продолжение следует, следите за новостями блога.

Сергей Норсеев, к.т.н., автор книги «Разработка приложений под КОМПАС в Delphi».

Комментарии (4)


  1. kovserg
    04.06.2019 22:53

    Вот интересно: что мешает АСКОН-у сделать Компасу нормальный скриптовый SDK для расширений с API с которым будет удобно работать, а не эти обёртки поверх COM объёктов которые что в C++ что в python-е смотрятся чужеродно.


    1. kompas_3d Автор
      05.06.2019 16:45

      API КОМПАСа развивается с момента его создания. Мы постоянно добавляем что-то новое и дорабатываем существующее. Возможно со временем появится и скриптовый SDK.


      1. kovserg
        05.06.2019 17:48

        Было бы очень здорово автоматизировать действия небольшими текстовыми скриптами. Не требующими SDK и компиляторов.


        1. kompas_3d Автор
          05.06.2019 18:39

          Вы КОМПАС-Макро или PyKompasMacro не использовали?