Antes de avançar para maneiras documentadas de criar seqüências compostas, precisamos nos familiarizar com um objeto como um parágrafo. É um bloco de texto formatado automaticamente, composto por várias linhas. Nesta lição, examinaremos a construção de parágrafos simples.

O conteúdo da série de lições “Trabalhando com a API COMPASS-3D”
- O básico
- Desenho de desenho
- Conexão correta com o KOMPAS
- Inscrição principal
- Primitivas gráficas
- Salvando um documento em vários formatos
- Conhecendo as configurações
- Métodos de escrita mais sofisticados no bloco de título
- Lendo células de legenda
- Caracteres especiais, incluindo uma sequência
- Etiquetas de texto simples
- Cordas compostas
- Parágrafos
- Texto de várias linhas
Parâmetros de parágrafo ( ksParagraphParam )
Um parágrafo é descrito pela interface 
ksParagraphParam . Para obtê-lo, você precisa usar o método 
GetParamStruct da interface 
KompasObject , para isso, você deve passar a constante 
ko_ParagraphParam ( 
0x0000001B ) para ele. Considere as propriedades da interface 
ksParagraphParam .
ang - o ângulo do texto em graus. Está atrasado da linha horizontal no sentido anti-horário. Semelhante ao parâmetro 
ang do método 
ksText .
height - a altura do parágrafo em milímetros.
hFormat - formatação de texto horizontalmente. Esta propriedade é usada quando o texto não cabe no parágrafo em largura. Os valores válidos estão listados na tabela abaixo.
 estilo
estilo - estilo do texto (descrito na 
lição 11 ).
vFormat - formatar texto verticalmente. Esta propriedade é usada quando o texto não cabe no parágrafo em altura. Os valores válidos estão listados na tabela abaixo.

Há duas 
coisas a serem 
lembradas ao trabalhar com a propriedade 
vFormat :
- De acordo com a documentação do KOMPAS, os valores válidos da propriedade vFormat são 0 e -1 , mas não é assim. Os valores válidos são 0 e 1 .
- COMPASS não altera a altura dos caracteres. Apenas altera a distância entre as linhas. Se a altura das linhas for menor que a altura do parágrafo, elas poderão se sobrepor. Um exemplo dessa sobreposição está na figura abaixo.
 width
width - a largura do parágrafo em milímetros.
As propriedades 
height , 
hFormat , 
vFormat e 
width nos permitem resolver o problema de colocar texto em um determinado retângulo. Esse método é muito mais confiável e eficiente do que o método 
ksGetTextLength discutido na 
Lição 11 .
x e 
y são as coordenadas do ponto de ancoragem. A posição do parágrafo em relação ao ponto de ancoragem ao longo do eixo horizontal é ajustada pelo método 
ksSetTextAlign da interface 
ksDocument2D (embora essa possibilidade não esteja documentada). O ponto de ancoragem vertical sempre corresponde à parte inferior da primeira linha do parágrafo. Este comportamento não pode ser alterado.
A interface 
ksParagraphParam possui apenas um método: 
Init () . Inicializa os valores da propriedade da interface. Não possui parâmetros de entrada. Se for bem-sucedido, retorna 
verdadeiro .
Construção de parágrafo
A criação de um parágrafo consiste em três etapas seqüenciais.
- Declaração do início do parágrafo. Para fazer isso, o método ksParagraph da interface ksDocument2D é chamado . Como único parâmetro, esse método aceita a interface ksParagraphParam , que define os parâmetros do parágrafo. Se for bem-sucedido, o método ksParagraph retorna um e, em caso de erro, retorna zero .
- Preenchendo o parágrafo. Para cada linha exibida em um parágrafo, o método ksTextLine da interface ksDocument2D é chamado . Como único parâmetro, ele aceita a interface ksTextItemParam ou ksTextLineParam (discutida nas lições anteriores do loop) que descrevem a sequência. Observe que as linhas de saída não devem conter os caracteres @ , $ , & , ~ , ^ e # , pois são caracteres de controle. O trabalho com eles será considerado nas próximas lições do ciclo.
- Fim do parágrafo. Para fazer isso, o método ksEndObj () da interface ksDocument2D é chamado . Não possui parâmetros de entrada e, se for bem-sucedido, retorna um ponteiro inteiro para o objeto criado (parágrafo). Em caso de erro, ele retorna zero .
Um exemplo O parágrafo mais simples
Abaixo está o código fonte do programa, demonstrando a construção de um parágrafo simples.//  ksTextItemParam TextItemParamPtr textItemParam; textItemParam = static_cast<TextItemParamPtr>(kompas->GetParamStruct(ko_TextItemParam)); //    ParagraphParamPtr paragraphParam; paragraphParam = static_cast<ParagraphParamPtr>(kompas->GetParamStruct(ko_ParagraphParam)); paragraphParam->Init(); paragraphParam->set_x(100.0); paragraphParam->set_y(100.0); //  Document2D->ksParagraph(paragraphParam); //  BSTR str = SysAllocString(L" "); textItemParam->set_s(str); Document2D->ksTextLine(textItemParam); SysFreeString(str); str = SysAllocString(L" "); textItemParam->set_s(str); Document2D->ksTextLine(textItemParam); SysFreeString(str); //  Document2D->ksEndObj(); paragraphParam.Unbind(); textItemParam.Unbind(); 
 Como sempre, aqui, por simplicidade, o código responsável pela criação e execução do documento é omitido (este tópico foi discutido nas lições anteriores).
Neste exemplo, o próprio COMPASS determina o tamanho do parágrafo com base em seu conteúdo. A figura abaixo mostra o parágrafo gerado.

Observe: o texto é exibido como uma única linha. Como não especificamos a largura do parágrafo, o KOMPAS aumenta automaticamente conforme necessário. Se a largura fosse definida, o comportamento COMPASS seria determinado pelo valor da propriedade 
hFormat da interface 
ksParagraphParam .
Para formar um texto composto por várias linhas e linhas, você precisa usar os recursos de desenho discutidos parcialmente na lição anterior.
Um exemplo Texto de várias linhas
Para 
quebrar explicitamente em uma nova linha, use o sinalizador 
NEW_LINE ( 
0x1000 ).
A seguir, é apresentado um exemplo de programa que demonstra a construção de um parágrafo com várias linhas usando esse sinalizador. //  ksTextItemParam TextItemParamPtr textItemParam; textItemParam = static_cast<TextItemParamPtr>(kompas->GetParamStruct(ko_TextItemParam)); //    ParagraphParamPtr paragraphParam; paragraphParam = static_cast<ParagraphParamPtr>(kompas->GetParamStruct(ko_ParagraphParam)); paragraphParam->Init(); paragraphParam->set_x(100.0); paragraphParam->set_y(100.0); //  Document2D->ksParagraph(paragraphParam); //  BSTR str = SysAllocString(L" "); textItemParam->set_s(str); Document2D->ksTextLine(textItemParam); SysFreeString(str); TextItemFontPtr textItemFont; textItemFont = static_cast<TextItemFontPtr>(textItemParam->GetItemFont()); textItemFont->SetBitVectorValue(NEW_LINE, true); str = SysAllocString(L" "); textItemParam->set_s(str); Document2D->ksTextLine(textItemParam); SysFreeString(str); textItemFont.Unbind(); str = SysAllocString(L" "); textItemParam->set_s(str); Document2D->ksTextLine(textItemParam); SysFreeString(str); //  Document2D->ksEndObj(); paragraphParam.Unbind(); textItemParam.Unbind(); 
 Neste exemplo, um parágrafo de três linhas é criado. A primeira linha é exibida como de costume. Para o segundo, o sinalizador 
NEW_LINE está 
definido . Ele fala sobre o início de uma nova linha. O terceiro é exibido normalmente, mas o sinalizador 
NEW_LINE ainda está ativo, pois estamos trabalhando com a mesma instância da interface 
ksTextItemParam . A figura abaixo mostra o parágrafo gerado por este programa.

Agora as linhas são exibidas corretamente.
Desafios para trabalhar com parágrafos
Alinhamento de texto
O alinhamento do texto é definido pelo método 
ksSetTextLineAlign da interface 
ksDocument2D . Ele possui apenas um parâmetro inteiro - ajuste o alinhamento. Seus valores válidos estão listados na tabela abaixo.

Se for bem-sucedido, o método 
ksSetTextLineAlign retorna o sinalizador de alinhamento anterior e, em caso de erro, retorna 
-1 .
Observe que o método 
ksSetTextLineAlign pode ser usado apenas dentro do bloco (no nosso caso, é usado dentro do parágrafo). Isso significa que ele não pode ser usado para definir o alinhamento da saída de texto pelo método 
ksText . Essa limitação se deve ao fato de que, neste caso, o KOMPAS não sabe com relação a quais limites o texto precisa ser alinhado.
Outro ponto importante está relacionado ao escopo do método 
ksSetTextLineAlign - quais linhas de saída ele afeta. Considere um exemplo (uma sintaxe muito simplificada é usada aqui em comparação com seus originais):
 ksSetTextLineAlign(1); ksTextLine(“ ”); ksSetTextLineAlign(2); ksTextLine(“  ”); 
Como as linhas serão alinhadas? Ao contrário de nossas expectativas, ambas as linhas serão alinhadas à direita. Porque O fato é que o método 
ksSetTextLineAlign altera primeiro o alinhamento da última linha de saída. Aqui está o que acontece em nosso exemplo: a primeira linha define o alinhamento central. Como não há linha de saída anterior, esta chamada altera o alinhamento padrão (esquerda).
Em seguida, imprimimos a linha "Centro". Inicialmente, ele usa o alinhamento central definido anteriormente.
Na terceira linha, alteramos novamente o alinhamento. Primeiro de tudo, o método altera o alinhamento da linha anterior ("Centro"). Portanto, está alinhado à direita, e não ao centro, como planejamos. O mesmo alinhamento fica alinhado por padrão.
Exibimos a linha "Direita". Como o método 
ksSetTextLineAlign não 
é mais chamado, ele usa o alinhamento definido anteriormente (à direita).
Assim, as duas linhas estão alinhadas à direita. Agora vamos mudar um pouco o exemplo:
 ksSetTextLineAlign(1); ksTextLine(“ ”); ksTextLine(“”); ksSetTextLineAlign(2); ksTextLine(“  ”); 
Tudo o que mudamos foi adicionar a saída de uma string vazia sem alterar o alinhamento. Agora as linhas são exibidas corretamente. Isso acontece porque a saída de uma sequência vazia "absorve" o alinhamento correto definido. A segunda chamada para o método 
ksSetTextLineAlign afeta uma linha vazia e não afeta a linha central de forma alguma.
O exemplo abaixo mostra o alinhamento correto sem exibir uma sequência vazia.
 ksTextLine(“ ”); ksSetTextLineAlign(1); ksTextLine(“  ”); ksSetTextLineAlign(2); 
As chamadas 
ksTextLine e 
ksSetTextLineAlign são trocadas. Como o método 
ksSetTextLineAlign afeta principalmente a última linha exibida, os alinhamentos são definidos corretamente e as linhas são exibidas como desejávamos.
Exemplo
A seguir, é apresentado o código fonte de um programa que demonstra o alinhamento do texto em um parágrafo. //  ksTextItemParam TextItemParamPtr textItemParam; textItemParam = static_cast<TextItemParamPtr>(kompas->GetParamStruct(ko_TextItemParam)); //    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); //  Document2D->ksParagraph(paragraphParam); //  BSTR str = SysAllocString(L"    "); textItemParam->set_s(str); Document2D->ksTextLine(textItemParam); SysFreeString(str); TextItemFontPtr textItemFont; textItemFont = static_cast<TextItemFontPtr>(textItemParam->GetItemFont()); textItemFont->SetBitVectorValue(NEW_LINE, true); str = SysAllocString(L""); textItemParam->set_s(str); Document2D->ksTextLine(textItemParam); SysFreeString(str); textItemFont.Unbind(); str = SysAllocString(L" "); textItemParam->set_s(str); Document2D->ksTextLine(textItemParam); SysFreeString(str); Document2D->ksSetTextLineAlign(1); str = SysAllocString(L""); textItemParam->set_s(str); Document2D->ksTextLine(textItemParam); SysFreeString(str); str = SysAllocString(L"    "); textItemParam->set_s(str); Document2D->ksTextLine(textItemParam); SysFreeString(str); Document2D->ksSetTextLineAlign(3); //  Document2D->ksEndObj(); paragraphParam.Unbind(); textItemParam.Unbind(); 
 Neste exemplo, além do alinhamento do texto, também é demonstrado o uso das propriedades 
width e 
hFormat da interface 
ksParagraphParam . Eles são usados para limitar sua largura. Se não os mudássemos, o KOMPAS aumentaria a largura do parágrafo e não veríamos alinhamento à esquerda e à largura.
Linhas em branco são exibidas para melhorar a legibilidade do parágrafo. Eles não afetam o alinhamento correto.
A figura abaixo mostra o parágrafo gerado por este programa.

Ativar ou desativar o estilo
Na 
11ª lição do ciclo, examinamos os sinalizadores que controlam o estilo ( 
ITALIC_ON , 
ITALIC_OFF , 
BOLD_ON , 
UNDERLINE_ON e 
UNDERLINE_OFF ). Em seguida, os examinamos em relação ao método 
ksText . Uma diferença importante entre o uso em um parágrafo é que a ação não se limita a chamar o método 
ksTextLine , mas se estende ao parágrafo inteiro. Vejamos alguns exemplos.
 TextItemFont->SetBitVectorValue(BOLD_ON, true); TextItemParam->s = SysAllocString(L” ”); Document2D->ksTextLine(TextItemParam); TextItemFont->Init(); TextItemParam->s = SysAllocString(L” ”); Document2D->ksTextLine(TextItemParam); 
A primeira linha será exibida em negrito. Não há perguntas com isso. Mas como a segunda linha será exibida? A bandeira 
BOLD_ON foi redefinida para ela. Portanto, podemos assumir que ele será exibido em fonte regular. Mas isso não é verdade. Tendo cumprido o sinalizador 
BOLD_ON , o KOMPAS entende o comando da seguinte maneira: todas as linhas subseqüentes deste parágrafo são exibidas em negrito. Portanto, todas as linhas subseqüentes são exibidas em negrito até o parágrafo ser concluído ou o KOMPAS encontrar o sinalizador 
BOLD_OFF associado a ele . Considere um exemplo:
 TextItemFont.SetBitVectorValue(BOLD_ON, true); TextItemParam.s = SysAllocString(L” ”); Document2D.ksTextLine(TextItemParam); TextItemFont.Init(); TextItemFont.SetBitVectorValue(BOLD_OFF, true); TextItemParam.s = SysAllocString(L“ ”); Document2D.ksTextLine(TextItemParam); TextItemFont.Init(); TextItemParam.s = SysAllocString(L” ”); Document2D.ksTextLine(TextItemParam); 
A primeira linha é exibida em negrito. Para a segunda linha, 
limpamos o sinalizador 
BOLD_ON e posicionamos o sinalizador BOLD_OFF 
associado a ele , o que cancela o estilo negrito. Por esse motivo, a segunda e a terceira linhas são exibidas sem negrito.
Esse comportamento se aplica aos sinalizadores 
ITALIC_ON , 
ITALIC_OFF , 
UNDERLINE_ON e 
UNDERLINE_OFF , mas não se aplica ao sinalizador 
NEW_LINE , pois não possui um par de sinalizadores de substituição.
Exemplo
A seguir está o código fonte do programa, mostrando a saída de texto com estilos diferentes usando parágrafos. //  ksTextItemParam TextItemParamPtr textItemParam; textItemParam = static_cast<TextItemParamPtr>(kompas->GetParamStruct(ko_TextItemParam)); //    ParagraphParamPtr paragraphParam; paragraphParam = static_cast<ParagraphParamPtr>(kompas->GetParamStruct(ko_ParagraphParam)); paragraphParam->Init(); paragraphParam->set_x(100.0); paragraphParam->set_y(100.0); //  Document2D->ksParagraph(paragraphParam); //  BSTR str = SysAllocString(L" "); textItemParam->set_s(str); Document2D->ksTextLine(textItemParam); SysFreeString(str); TextItemFontPtr textItemFont; textItemFont = static_cast<TextItemFontPtr>(textItemParam->GetItemFont()); textItemFont->set_bitVector(NEW_LINE | ITALIC_OFF); // str = SysAllocString(L"  "); textItemParam->set_s(str); Document2D->ksTextLine(textItemParam); SysFreeString(str); textItemFont->set_bitVector(NEW_LINE | ITALIC_ON | BOLD_ON); // str = SysAllocString(L" "); textItemParam->set_s(str); Document2D->ksTextLine(textItemParam); SysFreeString(str); textItemFont->set_bitVector(NEW_LINE | BOLD_OFF | UNDERLINE_ON); // str = SysAllocString(L" "); textItemParam->set_s(str); Document2D->ksTextLine(textItemParam); SysFreeString(str); //  Document2D->ksEndObj(); paragraphParam.Unbind(); textItemFont.Unbind(); textItemParam.Unbind(); 
 A parte mais importante deste programa é a configuração adequada de sinalizadores para as linhas de saída. Vamos analisá-lo em mais detalhes (as linhas correspondentes do programa são marcadas com um par de caracteres “ 
// ”).
A primeira linha é exibida sem nenhuma alteração. Portanto, nenhum sinalizador está definido para ele.
A segunda linha deve ser exibida sem inclinação e com uma nova linha. Portanto, os sinalizadores são definidos para ele: 
NEW_LINE (inicie em uma nova linha) e 
ITALIC_OFF (desative o 
itálico ).
A terceira linha deve aparecer em itálico e negrito. Para isso, 
exibimos os sinalizadores: 
NEW_LINE , 
ITALIC_ON ( 
ativar itálico) e 
BOLD_ON ( 
ativar faces em negrito). Todos os outros sinalizadores são redefinidos.
A quarta linha deve ser impressa em itálico, sublinhada e não em negrito. Para fazer isso, 
exibimos os sinalizadores: 
NEW_LINE , 
BOLD_OFF (desative negrito, deixado na linha anterior) e 
UNDERLINE_ON (ative sublinhado).
Se houvesse mais linhas no parágrafo, elas seriam exibidas em fonte sublinhada em itálico. Para desativar o estilo sublinhado, você deve limpar o sinalizador UNDERLINE_ON e armar o sinalizador 
UNDERLINE_OFF .
A figura abaixo mostra o resultado deste programa.

Separando informações da apresentação
Se você seguir a estrutura de seus programas, provavelmente notou uma séria desvantagem do exemplo anterior: o código responsável por gerar a saída é misturado ao código responsável por implementar sua saída. Com um bom estilo de programação, é habitual separar as informações da sua apresentação.
Se as informações de saída consistirem em várias linhas de 
ksTextItemParam , elas poderão ser combinadas em uma interface 
ksTextLineParam . O método 
ksTextLine pode manipular essas duas interfaces. Mas essa abordagem tem uma limitação desagradável: se o método 
ksTextLine aceitar a interface 
ksTextLineParam , os sinalizadores 
NEW_LINE (e 
SPECIAL_SYMBOL_END ) serão ignorados. Ou seja, todas as informações serão exibidas em uma linha, mesmo se o sinalizador 
NEW_LINE estiver 
definido para algumas 
instâncias do ksTextItemParam . Para contornar essa limitação, você deve chamar manualmente 
ksTextLine para cada linha.
A seguir, é apresentado o código fonte de um exemplo que demonstra essa técnica. //    DynamicArrayPtr dynamicArray; dynamicArray = static_cast<DynamicArrayPtr>(kompas->GetDynamicArray(TEXT_ITEM_ARR)); dynamicArray->ksClearArray(); //  ksTextItemParam TextItemParamPtr textItemParam; textItemParam = static_cast<TextItemParamPtr>(kompas->GetParamStruct(ko_TextItemParam)); //   BSTR str = SysAllocString(L" "); textItemParam->set_s(str); dynamicArray->ksAddArrayItem(-1, textItemParam); SysFreeString(str); TextItemFontPtr textItemFont; textItemFont = static_cast<TextItemFontPtr>(textItemParam->GetItemFont()); textItemFont->set_bitVector(NEW_LINE | ITALIC_OFF); str = SysAllocString(L"  "); textItemParam->set_s(str); dynamicArray->ksAddArrayItem(-1, textItemParam); SysFreeString(str); textItemFont->set_bitVector(NEW_LINE | ITALIC_ON | BOLD_ON); str = SysAllocString(L" "); textItemParam->set_s(str); dynamicArray->ksAddArrayItem(-1, textItemParam); SysFreeString(str); textItemFont->set_bitVector(NEW_LINE | BOLD_OFF | UNDERLINE_ON); str = SysAllocString(L" "); textItemParam->set_s(str); dynamicArray->ksAddArrayItem(-1, textItemParam); SysFreeString(str); //    ParagraphParamPtr paragraphParam; paragraphParam = static_cast<ParagraphParamPtr>(kompas->GetParamStruct(ko_ParagraphParam)); paragraphParam->Init(); paragraphParam->set_x(100.0); paragraphParam->set_y(100.0); //  Document2D->ksParagraph(paragraphParam); //     for(unsigned int i = 0; i < dynamicArray->ksGetArrayCount(); ++i) { dynamicArray->ksGetArrayItem(i, textItemParam); Document2D->ksTextLine(textItemParam); } //  Document2D->ksEndObj(); //  textItemFont.Unbind(); textItemParam.Unbind(); paragraphParam.Unbind(); dynamicArray->ksDeleteArray(); dynamicArray.Unbind(); 
 Neste exemplo, as linhas de saída são gravadas primeiro no 
DynamicArray e somente depois são exibidas no parágrafo. Isso permite que você separe as informações de sua apresentação. Se o sinalizador 
NEW_LINE não foi usado em nosso exemplo, poderíamos 
conviver com uma chamada para o método 
ksTextLine .
O resultado deste programa é semelhante ao resultado do exemplo anterior.
ConclusãoNesta lição, vimos como criar um parágrafo e como usá-lo para exibir texto de várias linhas. Também aprendemos a separar as informações de sua apresentação. Infelizmente, a saída correta do texto de várias linhas requer a passagem manual de uma matriz de seqüências de caracteres. Isso não é muito conveniente. Na próxima lição, mostrarei como resolver esse problema.
Para continuar, acompanhe as notícias do blog.
 Sergey Norseev, Ph.D., autor do livro "Application Development for COMPAS in Delphi".