Construção do Editor de
Textos
Vamos dar os primeiros passos na
construção de um Editor de Textos.
Clique em File e depois em New Application.
Pegue um componente RichEdit
na palleta Win32 (ou Win95) e a coloque no Form.
Altere a propriedade BorderStyle do Form para bsNone (para tirar a
barra de títulos e suas propriedades).
Altere a propriedade Align do RichEdit
para alCliente (Assim o RichEdit
ocupará toda a área cliente do Form).
Na palleta Standart pegue
um componente PopudMenu (para criarmos alguns menus
pop-up), e coloque no Form.
Dê um clique com o botão direito do mouse sobre o componente PopupMenu e escolha a opção Menu Designer ...
Abrir-se-á o Menu Designer (Editor de Menus). Na propriedade Caption (no Object Inspector) do Editor digite:Arquivo
Dê um clique na parte selecionada
do Menu Designer. Aparecerá a palavra Arquivo
selecionada no menu flutuante, e abrir-se-á, logo
abaixo, um novo campo para menu.
Dê um clique nesse novo campo (que ficará selecionado) e, na propriedade Caption, digite:
Editar
Muito bem, já sabemos criar o Menu Popup.
Agora, no Menu Designer, onde tem a palavra Arquivo dê um clique para
selecionar o menu correspondente. Depois, com o botão direito do mouse, dê um
clique sobre o menu Arquivo já selecionado. Aparecerá
um menu Pop-up. Escolha a
opção Create Submenu.
Na propriedade Caption digite:&Abrir
O Símbolo & cria um atalho
(tecla de atalho + a letra sublinhada) para o menu.
Abaixo do menu Abrir, Crie o menu Locali&zar; abaixo do menu Localizar crie o menu
&Salvar; abaixo do menu Salvar crie o traço separador de menus digitando
apenas um traço: - ;abaixo do traço, crie o menu Sai&r.
Nota: quando criamos atalho,
tomemos cuidado para não usar as mesmas teclas de atalho para funções
diferentes.
Construção do Editor de Textos
Segunda parte
Agora dê um duplo clique no menu Sair. Abrir-se-á o
Editor Properties que é o Editor de Códigos do
programa. Digite:
Close();
O Código deve ficar assim:
void __fastcall
TForm1::Sair1Click(TObject *Sender)
{
Close();
}
|
Para ativar o PopupMenu, no evento OnCreate
do Form1 digite:
PopupMenu1->AutoPopup = true;
RichEdit1->PopupMenu = PopupMenu1;
O Código deve ficar assim:
void __fastcall
TForm1::FormCreate(TObject *Sender)
{
PopupMenu1 -> AutoPopup =
true;
RichEdit1 -> PopupMenu =
PopupMenu1;
}
|
Rode o Programa (Tecla F9). Você
perceberá que criou um Editor de Textos bem estranho. Digite ou delete letras e palavras.
Para fechar o programa, dê um
clique com o botão direito do mouse sobre o Editor e escolha a opção Sair no menu Arquivo.
Se você seguiu os passos
corretamente, e o programa fechou sem problemas, na propriedade WindowState do Form1 escolha a
opção: wsMaximized, e rode novamente o programa.
Ele ocupará toda a tela do Windows. Siga o mesmo procedimento para encerrar o
programa. Uma outra forma de encerrar o aplicativo é
pressionando simultaneamente as teclas alt + F4.
Dê um duplo clique na propriedade Lines de RichEdit1. No editor
que se abrir, delete a palavra RichEdit1 e dê um OK,
o que fará que essa string não apareça mais na execução do programa.
Na palette Dialogs, pegue
um componente OpenDialog e coloque no projeto. Na
propriedade InitialDir de OpenDialog podemos digitar o caminho do diretório onde queremos
que a Caixa de Diálogo Abrir inicialize (por exemplo: C:\Meus documentos) e,
feito isso, podemos completar o caminho e escolher um arquivo inicial na
propriedade FileName (por exemplo: C:\Meus
documentos\Tutorial.txt). Na propriedade Filter,
nós podemos escolher os arquivos que o Editor pode abrir, por meio do Filter Editor.
No Filter Editor digite:
Filter Name
|
Filter
|
arquivos richtext *.rtf
|
*.rtf
|
arquivos de texto *.txt
|
*.txt
|
todos os arquivo *.*
|
*.*
|
e dê um OK.
Abra o MenuDesigner e dê um duplo clique no submenu Abrir para abrir o Editor Properties.
Entre as chaves { e } digite:
if
(OpenDialog1 -> Execute())
RichEdit1 -> Lines -> LoadFromFile(OpenDialog1
-> FileName);
else
MessageBeep(0);
O código deverá ficar assim:
void __fastcall
TForm1::Abrir1Click(TObject *Sender)
{
if (OpenDialog1 -> Execute())
RichEdit1 ->
Lines -> LoadFromFile(OpenDialog1 -> FileName);
else
MessageBeep(0);
}
|
Nosso Editor já está em condições
de abrir documentos. Rode o programa e abra alguns documentos de texto (*.txt) ou richtext
(*.rtf).
Passemos ao submenu
Localizar.
Coloque um componente FindDialog
no projeto. Em seguida abra o Menu Designer e dê um
duplo clique em
Localizar. No Editor Properties,
entre as chaves { e } que se abrirem, digite:
FindDialog1->Execute();
int FoundAt,
StartPos, ToEnd; //
declara três variáveis int
////////////////////////////////////////////////////////////////////////
// INICIA A BUSCA A PARTIR DA SELEÇÃO ATUAL
// OU DE OUTRA FORMA
// INICIA A PARTIR DO INÍCIO DO TEXTO
/*SelLength
devolve o número de caracteres selecionados*/
if (RichEdit1->SelLength) /* se há caracteres selecionados em
RichEdit1*/
/*SelStart devolve a posição do
primeiro caracter selecionado no texto*/
/*o código abaixo devolve a posição do último caracter selecionado*/
StartPos = RichEdit1->SelStart + RichEdit1->SelLength;
else
StartPos = 0;
///////////////////////////////////////////////////////////////////////////
/*Length() retorna o número de caracteres de AnsiString*/
/*Ou ToEnd será igual a Text.Lengt() ou igual ao
número dos
caracteres a serem contados após o último caracter selecionado*/
ToEnd = RichEdit1->Text.Length() - StartPos;
/*FindText busca o texto num
controle rich edit para
a string
especificada no parametro
SearchStr (no exemplo: FindDialog1->FindText)*/
FoundAt = RichEdit1->FindText(FindDialog1->FindText,
StartPos, ToEnd, TSearchTypes());
if (FoundAt !=
-1) // se a variável for difetente de -1
RichEdit1->SetFocus(); //
coloca o foco em RichEdit1
// coloca o cursor na primeira ocorrência
RichEdit1->SelStart = FoundAt;
// seleciona a string procurada no texto do RichEdit1
RichEdit1->SelLength =
FindDialog1->FindText.Length();
|
No Object
Inspector, no evento (Events)
OnFind de FindDialog1
escolha a opção Localizar1Click. Em Properties, dê
um duplo clique em Options. Altere
de false para true as seguintes
opções:
frHideMatchCase
|
true
|
frHideWholeWord
|
true
|
frHideUpDown
|
true
|
Agora seu editor já se encontra
apto para efetuar algumas buscas de textos ou caracteres.
Coloque um componente SaveDialog no projeto, abra o
Menu Designer e dê um duplo clique em Salvar. No Editor
Properties, entre as chaves { e
} que se abrirem, digite:
if
(SaveDialog1 -> Execute())
RichEdit1 -> Lines ->
SaveToFile(SaveDialog1 -> FileName);
else
MessageBeep(0);
|
Em SaveDialog, temos funcionando de forma semelhante
ao funcionamento em OpenDialog, as propriedades InitialDir, FileName e Filter, com a diferença de que, no presente caso, estamos
cuidando de salvar arquivos, e não abri-los.
Como experiência, no Filter Editor digite:
Filter Name
|
Filter
|
arquivos richtext *.rtf
|
*.rtf
|
arquivos de texto *.txt
|
*.txt
|
todos os arquivo *.*
|
*.*
|
e escolha um diretório inicial para salvar
os arquivos.
Pois bem, todos os submenus do menu Arquivo já
estão funcionando. Agora vamos criar mais alguns menus e submenus.
Selecione o menu Editar no Menu Designer e crie os
seguintes submenus: Cortar, Copiar, Colar, Deletar
e Selecionar Tudo.
Vamos aos códigos:
submenu
Cortar:
void __fastcall
TForm1::Cortar1Click(TObject *Sender)
{
TComponent *pComponent = PopupMenu1->PopupComponent;
if (pComponent)
{
if
(pComponent->ClassNameIs("TRichEdit"))
((TRichEdit *)pComponent)->CutToClipboard();
else
MessageBeep(0);
}
}
|
submenu
Copiar
void __fastcall
TForm1::Copiar1Click(TObject *Sender)
{
TComponent *pComponent = PopupMenu1->PopupComponent;
if (pComponent)
{
if (pComponent->ClassNameIs("TRichEdit"))
((TRichEdit *)pComponent)->CopyToClipboard();
else
MessageBeep(0);
}
}
|
submenu
Colar
void __fastcall
TForm1::Colar1Click(TObject *Sender)
{
TComponent *pComponent = PopupMenu1->PopupComponent;
if (pComponent)
{
if
(pComponent->ClassNameIs("TRichEdit"))
((TRichEdit *)pComponent)->PasteFromClipboard();
else
MessageBeep(0);
}
}
|
Agora vamos trabalhar com um
código mais simples nas funções Deletar e Selecionar
Tudo.
submenu
Deletar
void __fastcall
TForm1::Deletar1Click(TObject *Sender)
{
RichEdit1 ->
ClearSelection();
}
|
submenu
Selecionar Tudo
void __fastcall TForm1::SelecionarTudo1Click(TObject
*Sender)
{
RichEdit1 -> SelectAll();
}
|
Exercício: Pesquise TComponent no Help do C++Builder e procure entender seu papel nas funções que
usaram-no. Depois insira comentários documentando detalhadamente os códigos
acima.
Abaixo do menu
Editar, crie o menu Formatar com dois submenus:
Fontes e Cores.
submenu Fontes
Coloque um componente FontDialog no projeto.
Eis o código:
void __fastcall TForm1::Fontes1Click(TObject
*Sender)
{ /*coloca os atributos do texto
selecionado no RichEdit1
em FontDialog1*/
FontDialog1->Font->Assign(RichEdit1->SelAttributes);
/*Sendo chamada a caixa de
diálogo de fontes*/
if(FontDialog1->Execute())
/*as fontes selecionadas de
RichEdit1 receberão os atributos
da caixa de diálogos de fontes*/
RichEdit1->SelAttributes->Assign(FontDialog1->Font);
}
|
Nota: TtextAttributes::Assign
Coloca as propriedades de um objeto TTextAttributes em conformidade com as propriedades
especificadas em outro objeto TTextAttributes ou
num objeto TFont.
Use Assign para mudar todos os atributos de
texto simultaneamente. Assign pode colocar as
características das fonts selecionadas num texto
em conformidade com as características default da font
ou vice-versa. Quando o início é um objeto TTextAttributes, Assign
adapta somente Color, Name,
Style, e propriedades Pitch. Quando o início é um
objeto TFont, Assign também adapta o Size.
Nota: Assign somente substitui em tempo de
execução quando ´início
é um objeto TTextAttributes, um objeto TFont, ou um objeto que tenha implementado um método AssignTo que trate o objeto TTextAttributes.
Outras origens produzem exceções de erro.
|
Coloque um componente ColorDialog no projeto.
Eis o código:
void __fastcall TForm1::Cores1Click(TObject
*Sender)
{
if (ColorDialog1 -> Execute())
/*a cor de RichEdit1 será a cor escolhida em ColorDialog1*/
RichEdit1 -> Color
= ColorDialog1 -> Color;
}
|
O código de Cores1Click não é subsistente.
Ou seja, se você alterar a cor do editor de textos e fechar o aplicativo, na
próxima vez que abrir o editor de textos, ele abrirá na cor padrão,
estabelecida inicialmente no Object Inspector. Futuramente nós veremos um modo de conservar a
cor atrávés de arquivos .INI.
Vamos alterar algumas
propriedades:
Para colocar uma barra de rolagem vertical, altere a propriedade ScrollBarss de RichEdit1 para ssVertical.
Normalmente os componentes Memo e RichEdit têm uma limitação na quantidade de dados que
podem receber, que é uma quantia padrão. Podemos aumentá-la ou diminui-la bastante. Na verdade, tudo depende da
quantidade de dados que trabalharemos. Para alterar essa quantia de dados
devemos mudar a propriedade MaxLength
(no Object Inspector ou
em tempo de execução). Por exemplo, se colocarmos a propriedade MaxLength para 2147483645 (que é
um tamanho praticamente incomensurável) tais componentes poderão receber dois
bilhões, cento e quarenta e sete milhões, quatrocentos e oitenta e três mil,
seiscentos e quarenta e cinco caracteres.
No momento, nosso projeto deve estar com esta aparência:
Exercícios:
1) O submenu Localizar
deve ser retirado do menu Arquivo e colocado no menu Editar;
2) Falta uma função que ative a impressora
para imprimir textos. Providencie a colocação do componente e do código
correspondente.
3) Coloque atalhos nos menus. Use as
propriedades ShortCut
correspondentes.
Feito isso, continuemos. Vamos dar
ao nosso Editor a possibilidade de alterar seu tamanho.
Abra o MenuDesigner e,
abaixo do menu Formatar, crie o menu Janela que deverá conter os seguintes submenus: Maximizar, Normal, Minimizar.
Vamos aos códigos:
void __fastcall
TForm1::Maximizar1Click(TObject *Sender)
{
BorderStyle = bsNone;
WindowState = wsMaximized;
}
//------------------------------------------------------
void __fastcall TForm1::Normal1Click(TObject *Sender)
{
BorderStyle = bsNone;
WindowState = wsNormal;
}
//------------------------------------------------------
void __fastcall TForm1::Minimizar1Click(TObject *Sender)
{
BorderStyle = bsSizeable;
WindowState = wsMinimized;
}
|
Execute o programa e experimente
todos os menus. Observe se todos os comandos estão obedecendo perfeitamente.
Caso haja algum problema, dê uma olhada se não digitou algum código errado.
Agora vamos deixá-lo mais parecido
com aqueles editores que estamos acostumados a trabalhar. Em primeiro lugar,
altere o nome do submenu Salvar
para Salvar Como. Feito isso, dê um clique com o botão direito do
mouse sobre o submenu Salvar Como e, em seguida, um
clique em insert. Abrir-se-á um espaço para um
novo submenu. Dê-lhe o nome de Salvar e, como
exercício, digite para ele o código que o usuário salva o texto
automaticamente sem chamar a caixa de diálogo Salvar Como (caso o arquivo já
esteja gravado em disco). Caso você não consiga, não se preocupe. Em lições
futuras estudaremos esse evento.
Abra novamente o Menu Designer e crie o menu Visualizar, com os seguintes submenus: Barra de títulos, Barra de Ferramentas e Régua.
Vamos ao primeiro código:
void __fastcall
TForm1::BarradeTtulos1Click(TObject *Sender)
{
if(BorderStyle == bsSizeable)
BorderStyle = bsNone;
else
BorderStyle = bsSizeable;
}
|
Vamos colocar uma Barra de
Ferramentas e uma Régua em nosso Editor.
Primeiramente coloque um componente TPanel (Panel), da página
Standard no Form. Desse componente, no Object Inspector, delete qualquer caracter
da propriedade Caption, altere a propriedade Align para alTop e a
Propriedade Visible para false.
Feito isso, eis o código do menu correspondente:
void __fastcall
TForm1::BarradeFerramentas1Click(TObject *Sender)
{
if(Panel1->Visible == true)
Panel1->Visible = false;
else
Panel1->Visible = true;
}
|
Após terminar de digitar o código,
coloque um segundo TPanel
no Form. As Propriedades são rigorosamente as mesmas: Caption
= “”; Align = alTop
e Visible = false. Você
perceberá que esse segundo Panel se instalará
abaixo do primeiro (de Panel1). Eis o código:
void __fastcall
TForm1::Rgua1Click(TObject *Sender)
{
if(Panel2->Visible == true)
Panel2->Visible = false;
else
Panel2->Visible = true;
}
|
O primeiro Panel
será usado para construírmos a Barra de Ferramentas
e o segundo, a régua.
Rode a aplicação e experimente o resultado parcial.
O C++Builder
possui componentes Buttons que podem carregar
imagens. Trata-se dos SpeedButtons
e BitBtns. Para colocar imagens nesses botões,
basta editar sua propriedade Glyph no Object Inspector. As imagens a
seguir, tiradas dos próprios exemplos do C++Builder,
sendo que algumas delas podem ser editadas para ser carregadas no botão
adequado do nosso editor de textos.
Caso você ainda não tenha providenciado, vamos agora estudar como podemos
colocar um botão (ou menu) Salvar em nosso Editor. Antes,
porém, certifique-se de ter providenciado a alteração solicitada no final da
seção: Construção do Editor de Textos - Nona parte.
Dificuldade: Quando o botão for
pressionado (ou o menu respectivo receber o evento
correspondente), o programa deverá fazer uma verificação para saber se o
arquivo já se encontra gravado em disco; em caso afirmativo, deverá conhecer
o caminho completo para salvar o arquivo; em caso negativo, deverá chamar a
caixa de diálogos Salvar Como. Comecemos trabalhando com os menus. Vá para o
Editor de Códigos e lhe dê um clique com o botão direito do mouse. No menu pop-up que se abrir,
escolha a opção: Open Source/Header File, ou simplesmente pressione as teclas
Ctrl + F6 simultaneamente. Abrir-se-á o arquivo de
cabeçalho Unit1.h. Na parte de baixo do arquivo,
Depois da linha que inicia as declarações privadas da classe, declare duas AnsiString que servirão para guardar os caminhos dos
arquivos que forem abertos ou salvos, respectivamente. Eis as declarações.
private:
// User declarations
AnsiString
Caminho_Abrir;
AnsiString
Caminho_Salvar;
public:
// User declarations
Nota: Futuramente entenderemos melhor a finalidade deste arquivo.
Agora vamos implementar
algumas modificações nos códigos dos eventos Abrir e Salvar Como do nosso
Editor de Textos:
void
__fastcall TForm1::Abrir1Click(TObject *Sender)
{
if (OpenDialog1 -> Execute())
{
RichEdit1 -> Lines -> LoadFromFile(OpenDialog1 -> FileName);
//Caminho_Abrir atribuída com caminho do último
arquivo aberto
Caminho_Abrir = OpenDialog1->FileName;
//atribui Caminho_Abrir para Caminho_Salvar
(para ficarem iguais)
Caminho_Salvar
= Caminho_Abrir;
}
else
MessageBeep(0);
}
//---------------------------------------------------------------------------
void
__fastcall Tform1::Salvar1Click/*atual Salvar Como*/(TObject *Sender)
{
if (SaveDialog1 -> Execute())
{
RichEdit1 -> Lines ->
SaveToFile(SaveDialog1 -> FileName);
// Caminho_Salvar atribuída com caminho do último
arquivo salvo
Caminho_Salvar
= SaveDialog1->FileName;
// atribui Caminho_Salvar
para Caminho_Abrir (para ficarem iguais)
Caminho_Abrir
= Caminho_Salvar;
}
else
MessageBeep(0);
}
//---------------------------------------------------------------------------
Agora basta digitarmos o código para o menu salvar:
void __fastcall
TForm1::Salvar2Click/*Salvar*/(TObject *Sender)
{
// se o arquivo aberto já foi salvo ...
if((Caminho_Abrir == Caminho_Salvar)
&& (Caminho_Salvar != ""))
// o arquivo será salvo sem chamar a caixa Salvar
Como
RichEdit1->Lines->SaveToFile(Caminho_Abrir);
else // senão
// a
caixa de diálogos Salvar Como será Chamada
Salvar1Click(Sender);
}
Vamos agora suspender, por algum tempo, a construção do Editor de Textos, a
fim de abordarmos alguns pontos muito importantes. Brevemente retornaremos às
lições.
Dando continuidade à construção de
nosso Editor de Textos, vamos providenciar alguns botões (SpeedButtons) que realizarão as mesmas tarefas realizadas
pelos menus correspondentes. Esses botões devem ser agrupados. Por exemplo,
um primeiro grupo de botões realizará as mesmas tarefas executadas pelos
principais menus normalmente inseridos no menu
Arquivo (Novo, Abrir, Salvar e Salvar Como). Depois disso, deixamos um
pequeno espaço entre os botões para iniciar o segundo grupo (correspondente
ao menu Editar) e assim sucessivamente você colocará
aquelas tarefas que você entende como principais e, portanto,
obrigatoriamente disponíveis em menus e em botões. Veja abaixo
uma ilustração de como poderiam se dar tais
agrupamentos:
A partir daqui (referente à barra
de ferramentas), deixaremos você um pouco mais à vontade com relação ao
layout do Editor. Ou seja, Você decidirá quais botões serão criados (tarefas
desejadas). Mesmo porque estaremos trabalhando de uma forma um tanto
repetitiva. Forneceremos código para tarefas que você ainda não conhece, bem
como do botão Abrir. Os demais, seguirão o mesmo
caminho, baseando-se nos códigos prontos dos menus equivalentes. As imagens
para os botões você poderá escolher livremente, tomando o cuidado de escolher
aquelas que se encaixam no perfil da tarefa a ser executada e no tamanho do
botão.
Se você quiser dar uma aparência
tridimensional nos botões (SpeedButtons)
altere a propriedade Flat para True.
Nota: Toolbars oferecem um modo
fácil de organizar e administrar controles visuais. Podemos criar uma barra
de botões com um componente panel e alguns speed buttons, ou simplesmente
usar o componente ToolBar.
Para maiores esclarecimentos, clique aqui
Eis o código para a opção Novo (no
caso um menu) que pode ser colocado no grupo
Arquivo:
void __fastcall
TForm1::Novo1Click(TObject *Sender)
{
ShellExecute(0, "open", Application->ExeName.c_str(), 0, 0,
SW_SHOW);
}
|
Vamos colocar o código do botão Abrir, o qual alteramos a propriedade Name para SpButtonAbrir:
void __fastcall
TForm1::SpButtonAbrirClick(TObject *Sender)
{
Abrir1Click(Sender);
}
|
Exercício: Baseando-se no código
acima, coloque o código dos outros botões.
Também podemos colocar um comando
(menu e/ou botão) que desfaz a última ação do
usuário (o famoso Ctrl + z). Eis o código:
void __fastcall
TForm1::Desfazer1Click(TObject *Sender)
{
SendMessage(RichEdit1->Handle, WM_UNDO, 0, 0);
}
|
Caso você não tenha conseguido
inserir um código para imprimir, veja um exemplo:
/*Envia o Text do RichEdit para a impressora imprimeir*/
if ( PrintDialog1->Execute() ) RichEdit1->Print(RichEdit1->Text);
|
Assumimos que você já se encontra
apto a completar o códigos da maioria dos botões da
Barra de Ferramentas (os estudados nos menus).
Nenhum Editor seria completo sem
as opções de alinhamento de texto. Vamos possibilitar, ao nosso Editor, o
alinhamento à esquerda, ao centro e à direita. Para tanto, devemos colocar
três SpeedButton na Barra
de Ferramentas. Esses botões devem trabalhar em conjunto, pois quando o
evento de um estiver produzindo efeitos, os dos outros dois deverão
permanecer inativados. Assinale a Propriedade GroupIndex de todos eles para 1.
Isso fará que eles pertençam ao mesmo grupo. Assinale, também, a propriedade Down do Botão Responsável pelo alinhamento à esquerda
para True. Dessa forma, esse alinhamento à esquerda
será padrão para o Editor.
Eis os códigos para os SpeedButton já com os novos
nomes (Name):
void __fastcall
TForm1::SpdBtAlinhEsqClick(TObject *Sender)
{
RichEdit1->Paragraph->Alignment = taLeftJustify;
}
//------------------------------------------------------
void __fastcall TForm1::SpdBtAlinhCentClick(TObject *Sender)
{
RichEdit1->Paragraph->Alignment = taCenter;
}
//------------------------------------------------------
void __fastcall TForm1::SpdBtAlinhDirClick(TObject *Sender)
{
RichEdit1->Paragraph->Alignment = taRightJustify;
}
|
Agora precisamos forçar a mudança
espontânea do estado (Down) dos botões. O código
abaixo verifica a necessidade de alterar o estado dos botões através do
evento OnKeyUp.
void __fastcall
TForm1::RichEdit1KeyUp(TObject *Sender, WORD &Key,
TShiftState Shift)
{
if(RichEdit1->Paragraph->Alignment == taLeftJustify)
SpdBtAlinhEsq->Down = true;
else if(RichEdit1->Paragraph->Alignment == taCenter)
SpdBtAlinhCent->Down = true;
else if(RichEdit1->Paragraph->Alignment == taRightJustify)
SpdBtAlinhDir->Down = true;
}
|
Que tal acrescentarmos alguns
botões para alterar atributos de texto (negrito, itálico
e sublinhado).
Nota: SelAttributes descreve as características de um
texto selecionado num controle RichEdit
Use SelAttributes para revelar ou adaptar as
características de font do texto selecionado. SelAttributes é um objeto TTextAttributes, que especifica características como font face, color, size, style, e pitch (número de
caracteres). Para mudar um único atributo de um texto selecionado, interprete
SelAttributes, e adapte
uma de suas propriedades. Para mudar todos os atributos de um texto selecionado,
coloque SelAttributes para
um objeto TTextAttributes que represente a
configuração desejada dos atributos. Se não há texto selecionado, SelAttributes representa a
posição do cursor.
Quando inserimos um novo texto, as características da font
são compatíveis com SelAttributes.
SelAttributes está disponível apenas em tempo de
execução.
Introduziremos juntos
o código responsável pelo sublinhamento do texto.
Os códigos necessários ao negrito e itálico ficarão por sua conta.
Não é novidade para você SpeedButtons
trabalhando em grupo (GroupIndex). Já imaginou um
grupo de apenas um botão? Pois bem, é o que faremos agora. Cada um dos botões
deverá ter um número único na propriedade GroupIndex, ou seja, apenas um botão com tal
número.
Coloque três SpeedButtons
no Form. Do botão responsável pelo sublinhamento do
texto, altere a propriedade Name para SpdBtUnderline. Altere a propriedade AllowAllUp desse botão para true;
e altere o número do GroupIndex do mesmo para 2
(lembre-se de que nenhum outro botão poderá ter esse mesmo número para essa
propriedade). Com esses dois simples procedimentos nós damos um primeiro
passo para forçar o botão a trabalhar down ou up corretamente. Vejamos o código responsável pelas ações
de sublinhamento:
void __fastcall TForm1::SpdBtUnderlineClick(TObject
*Sender)
{
// Se o texto selecionado em RichEdit1 não está sublinhado
if(RichEdit1->SelAttributes->Style ==
RichEdit1->SelAttributes->Style >> fsUnderline)
// ele será sublinhado
RichEdit1->SelAttributes->Style = RichEdit1->SelAttributes->Style
<< fsUnderline;
else if // ou então
// se o texto estiver sublinhado
(RichEdit1->SelAttributes->Style ==
RichEdit1->SelAttributes->Style << fsUnderline)
// ele será desmarcado
RichEdit1->SelAttributes->Style = RichEdit1->SelAttributes->Style
>> fsUnderline;
}
|
Agora nós vamos acrescentar uma
linha de código no evento OnKeyUp
de RichEdit1:
void __fastcall
TForm1::RichEdit1KeyUp(TObject *Sender, WORD &Key,
TShiftState Shift)
{
//atualiza o estado (Down) do botão de sublinhado
SpdBtUnderline->Down =
RichEdit1->SelAttributes->Style.Contains(fsUnderline);
//atualiza o estado
(Down) dos botões - alinhamento de texto
if(RichEdit1->Paragraph->Alignment == taLeftJustify)
SpdBtAlinhEsq->Down = true;
else if(RichEdit1->Paragraph->Alignment == taCenter)
SpdBtAlinhCent->Down = true;
else if(RichEdit1->Paragraph->Alignment == taRightJustify)
SpdBtAlinhDir->Down = true;
}
|
Com isso encerramos esta seção do
Editor, cabendo lembrar que para negrito usamos fsBold, enquanto para itálico usamos fsItalic.
Vamos agora colocar comando para
alterar o tipo (Name) e o tamanho (Size) das fontes de nosso Editor. Para manejar o tipo,
usaremos um ComboBox e,
para o tamanho, um Edit conjugado com um UpDown.
Desta feita, como exercício, forneceremos apenas os códigos necessários ao
funcionamento destas ações, com um comentário básico. Caberá a você quebrar
um pouquinho a cabeça para entendê-los. Se você vem acompanhando este curso
desde o seu início, a compreensão será moleza!
Notas: 1º. Observe que alguns códigos são novos; outros, não (visto que já
estavam no Editor); 2º Impeça que o usuário digite no ComboBox e altere o seu texto inicial, de acordo
com a fonte padrão em seu sitema.
UpDown:
Associate = Edit1; Max = 72; Min = 1.
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
// ComboBox com os nomes das fontes
instaladas no sistema
ComboBox1->Items->Assign(Screen->Fonts);
PopupMenu1 -> AutoPopup = true;
RichEdit1 -> PopupMenu =
PopupMenu1;
}
//---------------------------------------------------------------------------
void __fastcall
TForm1::RichEdit1KeyUp(TObject *Sender, WORD &Key,
TShiftState Shift)
{
//atualiza o tipo (Name) de font no ComboBox
ComboBox1->Text = RichEdit1->SelAttributes->Name;
//Atualiza o tamanho
(Size) da font em Edit1
Edit1->Text = RichEdit1->SelAttributes->Size;
//atualiza o estado
(Down) do botão de sublinhado
SpeedButton10->Down = RichEdit1->SelAttributes->Style.Contains(fsUnderline);
//atualiza o estado
(Down) dos botões - alinhamento de texto
if(RichEdit1->Paragraph->Alignment == taLeftJustify)
SpdBtAlinhEsq->Down = true;
else if(RichEdit1->Paragraph->Alignment == taCenter)
SpdBtAlinhCent->Down = true;
else if(RichEdit1->Paragraph->Alignment == taRightJustify)
SpdBtAlinhDir->Down = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ComboBox1Change(TObject
*Sender)
{
// O tipo de font de RichEdit1 será igual
os especificado em ComboBox1
RichEdit1->SelAttributes->Name = ComboBox1->Items->Strings[ComboBox1->ItemIndex];
// Coloca o foco em RichEdit1
RichEdit1->SetFocus();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Edit1Change(TObject
*Sender)
{
// O size da font
de RichEdit1 será
// igual ao especificado em Edit1
RichEdit1->SelAttributes->Size = atoi(Edit1->Text.c_str());
}
//---------------------------------------------------------------------------
void __fastcall
TForm1::Edit1MouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int
X, int Y)
{
// impede que o usuário digite no Edit
RichEdit1->SetFocus();
}
//---------------------------------------------------------------------------
|
A seguir, entraremos na parte
final da construção do nosso editor, aprendendo a construir uma régua através
da qual poderemos estabelecer limites para os textos com os quais estivermos
trabalhando.
Passemos agora à construção da
régua naquele segundo componente Panel já colocado
no Editor. Visualize previamente a disposição dos componentes da régua:
Eis as propriedades de Panel2:
Propriedades
|
Align = alTop
Alignment = taLeftJustify
Bevellnner = bvLowered
BevelWidth = 1 //profundidade da borda
BorderWidth = 1 //largura da borda
|
Coloque um Bevel
(paleta Additional) dentro do Panel
e procure deixá-lo parecido com uma linha que divida o comprimento do Panel em duas partes iguais (conforme ilustração). Eis as
propriedades:
Propriedades de Bevel1
|
Align = alNone
Height = 2
Left = 4
Shape = bsTopLine
Stile = bsLowered
|
Coloque um Label
(Label1) acima do Bevel e outro abaixo (Label2)
Propriedades de Label1
|
AutoSize = true
|
Caption = ê
|
DragCursor = crArrow
|
Font = Charset =
DEFAULT_CHARSET
Color = clRed
Height = -11
Name = Wingdings
Pitch = fpDefault
Size = 8
Stile = []
|
Height = 11
|
Left = 2
|
No Label2 as propriedades são as
mesmas, exceto Caption = é
Coloque outro Label
no Panel. O Label3 deverá ser colocado próximo à
extremidade direita inferior do componente Panel1, com as mesmas propriedades
supramencionadas para Label1 e Label2, excetuando sua propriedades Caption que será = ñ, Font Color = clBlue
e Left = 770. Uma vez adotadas essas providências,
a régua de nosso projeto já deverá estar parecida com a ilustração acima.
Vá para o Editor de Códigos e, na
paleta onde está escrito o nome do arquivo (se não foi alterado quando salvo,
deve chamar-se: Unit1.cpp)
dê um clique com o botão direito do mouse e escolha: Open Sourse/Hearder File ou simplesmente aperte as teclas Ctrl + F6. Será aberto outro arquivo, o Unit1.h.
Em class
TForm1 : public TForm, __published: declare o
protótipo da função MudarParag() e, na parte
privada da Classe, declare os dados membros: int
Arrastar e bool Arrastando e a função void __fastcall Regua(void). A parte privada
fica entre a declaração private e a declaração
public. Observe abaixo como deverá ficar o código:
(...)
class TForm1 : public TForm
{
__published:
(...)
void __fastcall
MudarParag(TObject *Sender);
private:
// User declarations
(...)
int Arrastar;
bool Arrastando;
void __fastcall Regua(void);
public:
// User declarations
__fastcall TForm1(TComponent* Owner);
};
(...)
|
Nota: os trechos (...) não
constituem parte integrante do código, mas indicam que trechos do mesmo foram
suprimidos porque, no momento, não nos interessa vê-los.
Não se esqueça de introduzir comentários indicando tratar-se de linhas de
código para régua!
Volte para o arquivo Unit1.cpp
e faça o seguinte:
Declare e inicialize duas constantes globais:
//-------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include
"Unit1.h"
//distância que o cursor fica da seta conforme a movimentamos
const float Reg = 4.0 / 3.0;
//Distância dos dois Labels da margem esquerda
const int Semp = 6;
//-------------------------------------------------------------------
#pragma package(smart_init)
|
Passemos à definição da função void __fastcall TForm1::MudarParag(TObject * Sender):
/************digite todo o código abaixo, inclusive o cabeçalho da
função, pois essa função não foi criada automaticamente
pelo compilador, mas por nós.
observe que os comandos if()
estabelecem posições
limítrofres para os componentes Label***************/
void __fastcall
TForm1::MudarParag(TObject
* Sender)
{
Label1->Left = int(RichEdit1->Paragraph->FirstIndent*Reg)-4+Semp;
if (Label1->Left >= 772)
Label1->Left = 770;
Label2->Left =
int((RichEdit1->Paragraph->LeftIndent+
RichEdit1->Paragraph->FirstIndent)*Reg)-4+Semp;
if
(Label2->Left >= 770)
Label2->Left = 748;
Label3->Left = Panel1->ClientWidth-6-int(
(RichEdit1->Paragraph->RightIndent+Semp)*Reg);
if
(Label3->Left >= 772)
Label3->Left = 770;
if (Label3->Left <= 12)
Label3->Left = 13;
}
|
TparaAttributes::FirstIndent - FirstIndent
especifica a distância, em pixels, da primeira linha de um parágrafo
relativa à margem esquerda.
TparaAttributes::LeftIndent
- LeftIndent especifica a distância, em pixels,
do parágrafo relativa à margem esquerda.
TparaAttributes::RightIndent
- RightIndent especifica a distância, em pixels,
do parágrafo relativa à margem direita.
TcustomRichEdit.Paragraph
- Paragraph especifica a informação de formatação
do atual parágrafo. Interprete Paragraph para
colocar objeto TParaAttributes
usado por controle rich edit
para especificar a informação da formatação do parágrafo. Use o objeto TParaAttributes para ler ou
escrever a informação da formatação do parágrafo para o atual parágrafo.
Estas informações incluem alignment, indentation, numbering e tabs. Paragraph é uma
propriedade read-only, porque um objeto TCustomRichEdit possui somente
um objeto TParaAttributes, que não pode ser
mudado. Os atributos do corrente parágrafo, entretanto, pode ser mudado
pela colocação marcação da propriedade do objeto TParaAttributes. Estes pode ser setados um por um, ou todos podem ser setados para um valor de um objeto TParaAttributes existente pelo uso Paragraph->Assign.
O parágrafo atual são os parágrafos que contém o texto selecionado. Se não
há texto selecionado, o atual parágrafo é aquele que contém o cursor.
Nota: Paragraph está disponível somente em tempo
de execução.
|
Na paleta Events
de RichEdit1, em OnSelectionChange
selecione a função MudarParag, o que fará que as
setas Lable(s) sejam atualizadas conforme o
movimento do cursor no texto.
Nota: para efetuar a associação acima, dê um clique no lado direito do evento
mencionado no Object Inspector.
Dê um clique na seta que aparecerá e escolha a função mencionada no combobox que se abrirá.
Passaremos agora à definição da função void __fastcall TForm1::Regua(void). Não se esqueça de
que esta função não foi criada automaticamente pelo C++Builder:
void __fastcall TForm1::Regua(void)
{
int Distanc
= 0; // variável para o contador
while (Distanc < 15) // números da régua
{
Distanc++;
//incremento
// imprime os números de 1 a 15 na régua
Panel1->Caption
= Panel1->Caption + '\t' + Distanc;
}
}
|
Nota: Seria interessante colocar,
manualmente, aquelas linhas de comentários usadas pelo compilador C++Builder (//----------) para separar essas instruções.
Precisamos fazer o compilador chamar a função acima na criação do formulário
(evento OnCreate do Form):
void __fastcall TForm1::FormCreate(TObject *Sender)
{
// chama a função régua na criação do formulário
Regua();
(...)
}
|
Ajuste a propriedade Height de Bevel1 para 1.
A régua ainda não está funcional, mas já pode ser visualizada em tempo de
execução.
Inicialmente vamos nos lembrar das
funcionalidades básicas dos eventos OnMouseDown,
OnMouseMove e OnMouseUP:
Tcontrol::OnMouseDown - OnMouseDown
ocorre quando, estando o ponteiro do mouse sobre um controle, o usuário
pressiona um botão do mouse. O evento OnMouseDown
pode responder ao pressionamento sobre os botões esquerdo, direito e
central do mouse, bem como sobre combinações entre botões do mouse com as
teclas Shift, Ctrl, e
Alt. X e Y são as coordenadas (pixel) do ponteiro do mouse na client area do Sender.
Tcontrol::OnMouseMove -
OnMouseMove ocorre quando o usuário move o
ponteiros do mouse, enquanto o ponteiro do mouso
está sobre algum controle. Podemos usar o parâmetro Shift
do evento OnMouseDown
para determinar o estado das teclas (ou combinações) mencionadas no tópico
anterior ( OnMouseDown ). X e Y são as
coordenadas (pixel) da nova localização do ponteiro do mouse client area do Sender .
Tcontrol::OnMouseUp
– OnMouseUp ocorre no momento em que o
usuário está liberando o botão do mouse que estava pressionando um
componente com o ponteiro do mouse. O evento OnMouseUp pode responder a ações sobre os botões
esquerdo, direito e central do mouse, bem como sobre combinações entre
botões do mouse com as teclas Shift, Ctrl, e Alt. X e Y são as coordenadas (pixel) do
ponteiro do mouse na client area
do Sender.
|
Passemos ao tratamento desses
eventos nos componentes envolvidos nas ações respectivas. Inicialmente vamos
escrever uma função responsável pelo evento OnMouseDown, associando-a aos componentes
respectivos. Em Unit1.h, na parte __published, declare o protótipo da função AreguaMouseDown():
void __fastcall
AReguaMouseDown(TObject *Sender, TMouseButton Button,
TShiftState Shift, int X, int Y);
|
Agora, em Unit1.cpp:
void __fastcall TForm1::AReguaMouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int
X, int Y)
{
TLabel * oTmpLabel = (TLabel *)Sender;
Arrastar = oTmpLabel->Width / 2;
oTmpLabel->Left =
oTmpLabel->Left+X-Arrastar;
Arrastando = True;
}
|
Vá ao Object
Inspector e, na guia Events,
associe os eventos OnMouseDown
de Label1, Label2 e Label3 à função AreguaMouseDown
(do mesmo modo que procedemos para associar RichEdit1 a OnSelectionChange).
Agora vamos tratar o evento OnMouseMove. O procedimento é
bem parecido com o anterior. Em __published de Unit1.h:
void __fastcall
AReguaMouseMove(TObject *Sender, TShiftState Shift,
int X, int Y);
|
Em Unit1.cpp:
void __fastcall
TForm1::AReguaMouseMove(TObject *Sender, TShiftState Shift,
int X, int Y)
{
if (Arrastando) {
TLabel * oTmpLabel = (TLabel
*)Sender;
oTmpLabel->Left =
oTmpLabel->Left+X-Arrastar;
}
}
|
Vá ao Object
Inspector e, na guia Events,
associe os eventos OnMouseMove
de Label1, Label2 e Label3 à função AReguaMouseMove.
No que se refere a OnMouseUP, Label1, Label2 e
Label3 não compartilham o mesmo evento. Devemos, então, proceder ao
tratamento individual para cada componente. Iniciemos por Label1. Na guia Events, dê um clique em OnMouseUp, para chamar o método correspondente. Eis
o código:
void __fastcall
TForm1::Label1MouseUp(TObject *Sender, TMouseButton Button,
TShiftState Shift, int X, int Y)
{
Arrastando = False;
RichEdit1 -> Paragraph -> FirstIndent =
int((Label1->Left+Arrastar-Semp) / Reg);
Label2MouseUp(Sender, Button, Shift, X, Y);
}
|
Eis o código para o evento OnMouseUp de Label2:
void __fastcall
TForm1::Label2MouseUp(TObject *Sender, TMouseButton Button,
TShiftState Shift, int X, int Y)
{
Arrastando = False;
RichEdit1->Paragraph->LeftIndent =
int((Label2->Left+Arrastar-Semp) /
Reg)-RichEdit1 ->Paragraph ->FirstIndent;
MudarParag(Sender);
}
|
Aqui está o código para o mesmo
evento de Label3:
void __fastcall TForm1::Label3MouseUp(TObject
*Sender, TMouseButton Button,
TShiftState Shift, int X, int Y)
{
Arrastando = False;
RichEdit1->Paragraph->RightIndent =
int((Panel2->ClientWidth-Label3->Left+Arrastar-2) /
Reg)-2*Semp;
MudarParag(Sender);
}
|
Ajuste a Propriedade TabStop dos controles RichEdi1,
ComboBox1 e Edit1 para false (para impedir que o
foco saia de RichEdit1 quando for pressionada a tecla de tabulação); Ajuste a
Propriedade WantTabs de RichEdit1 para true (ativará a marcação de textos com tabulações nesse
componente).
Assim, conforme prometido no
início deste curso, completamos o nosso Editor de Textos. Na verdade, fomos
além daquilo que propusemos, uma vez que esse editor não está limitado a edição de textos não formatados como o Bloco de Notas do
Windows. Para criar um Editor como o NotePad,
use um componente Memo no lugar do RichEdit, mas com consciência de que as formatações
possibilitadas por este Editor estarão ausentes naquele!
Por fim, informamos que o nosso Editor
pode ser melhorado. Agora cabe a você procurar as falhas e corrigi-las, uma
vez que o tratamento de erros ou melhora na lógica dos comandos é uma
obrigação fundamental de todos os programadores.
A seguir, dando continuidade no
curso, estaremos trabalhando na finalização do projeto Paint,
visto que já possuímos praticamente todos os conceitos necessários à sua
conclusão.
VMS Desenvolvimentos
Diversas Dicas, Apostilas, Arquivos Fontes,
Tutoriais, Vídeo Aula, Download de Arquivos Relacionado a Programação em C++ Builder.
Voltar ao Site
|