Olá pessoal.
A alguns dias um cliente fez uma solicitação que me obrigou a suar a camisa fazendo a minha primeira implementação em swing.
O pessoal aqui “como sempre” ajudou e eu não sei se é por gratidão ou em função do espírito de fim de ano (Natal, Ano novo,…) gostaria de compartilhar o resultado do trabalho. :lol:
Agradecimento especial ao MarceloS e Mikhas.
Valew!!!
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.text.AttributeSet;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import javax.swing.text.StyledEditorKit;
/**
* <p>Title: CampoTextPane</p>
* <p>Description:
* Componente que apresenta uma caixa de texto juntamente com botões para aplicação de estilos no texto digitado.
* São três (3) botões que disponibilizam o estilo negrito, itálico e sublinhado.
* Para que os estilos aplicados estejam disponíveis para a posteridade é necessário que além do texto,
* todo os estilos aplicados sejam persistidos. Sendo assim, ao utilizar esse componente é necessário ter em
* mente que o campo que armazenará o conteúdo texto deverá suportar também a string que representa os estilos
* aplicados.
* Sugiro fortemente a utilização de campos de armazenamento de tamanhos consideráveis como "LONGTEXT" do MySQL.
* Esse componente também disponibiliza a obtenção do conteúdo informado no campo texto juntamente com todo
* o estilo aplicado para fins de impressão em relatórios desenvolvidos em Jasper.</p>
* @author Hudson de Paula Romualdo
*/
public class CampoTextPane extends JPanel{
private JTextPane txtObservacoes = null;
private StyledDocument doc;
private Icon negritoIcone;
private Icon italicoIcone;
private Icon sublinhadoIcone;
private String pdfFonteNome = "Helvetica";
private final String NEGRITO = "b";
private final String ITALICO = "i";
private final String SUBLINHADO = "u";
public final char CARACTER_SEPARADOR = '§'; //Caracter que separa o texto do vetor de estilos
/**
* Construtor padrão
*/
public CampoTextPane() {
super();
this.exec();
}
/**
* Construtor sobrescrito para inserção de ícones nos botões
* @param negritoIcone
* @param italicoIcone
* @param sublinhadoIcone
*/
public CampoTextPane(Icon negritoIcone, Icon italicoIcone, Icon sublinhadoIcone){
super();
this.negritoIcone = negritoIcone;
this.italicoIcone = italicoIcone;
this.sublinhadoIcone = sublinhadoIcone;
this.exec();
}
/**
* Método que constroi o componente
*/
private void exec(){
setLayout(new BorderLayout());
final JPanel pnlPrincipal = new JPanel();
pnlPrincipal.setLayout(new BorderLayout());
add(pnlPrincipal, BorderLayout.CENTER);
final JScrollPane scrollObservacoes = new JScrollPane();
pnlPrincipal.add(scrollObservacoes, BorderLayout.CENTER);
this.txtObservacoes = new JTextPane();
this.txtObservacoes.addKeyListener(new KeyAdapter() {
public void keyTyped(final KeyEvent e) {
//Impede que o caracter especial que separa o texto do vetor de estilos seja inserido
if(e.getKeyChar() == CARACTER_SEPARADOR)
e.setKeyChar('\u0000');
}
});
scrollObservacoes.setViewportView(this.txtObservacoes);
final JPanel pnlControles = new JPanel();
pnlControles.setPreferredSize(new Dimension(20, 0));
pnlControles.setMinimumSize(new Dimension(0, 0));
pnlControles.setLayout(null);
add(pnlControles, BorderLayout.EAST);
Action action = new StyledEditorKit.BoldAction();
action.putValue(Action.NAME, "");
final JButton btnNegrito = new JButton(action);
btnNegrito.setToolTipText("Negrito");
btnNegrito.setBounds(0, 0, 20, 20);
if(this.negritoIcone != null)
btnNegrito.setIcon(this.negritoIcone);
pnlControles.add(btnNegrito);
action = new StyledEditorKit.ItalicAction();
action.putValue(Action.NAME, "");
final JButton btnItalico = new JButton(action);
btnItalico.setToolTipText("Itálico");
btnItalico.setBounds(0, 20, 20, 20);
if(this.italicoIcone != null)
btnItalico.setIcon(this.italicoIcone);
pnlControles.add(btnItalico);
action = new StyledEditorKit.UnderlineAction();
action.putValue(Action.NAME, "");
final JButton btnSublinhado = new JButton(action);
btnSublinhado.setToolTipText("Sublinhado");
btnSublinhado.setBounds(0, 40, 20, 20);
if(this.sublinhadoIcone != null)
btnSublinhado.setIcon(this.sublinhadoIcone);
pnlControles.add(btnSublinhado);
this.doc = this.txtObservacoes.getStyledDocument();
Style style = doc.addStyle("default", null);
style = doc.addStyle(this.NEGRITO, null);
StyleConstants.setBold(style, true);
style = doc.addStyle(this.ITALICO, null);
StyleConstants.setItalic(style, true);
style = doc.addStyle(this.SUBLINHADO, null);
StyleConstants.setUnderline(style, true);
}
/**
* Método que retorna o conteúdo do campo texto sem o vetor de estilos (caso exista).
* @return String
*/
public String getTexto(){
return this.txtObservacoes.getText();
}
/**
* Método que retorna o conteúdo do campo texto com o vetor de estilos (caso exista).
* Esse método deve ser utilizado sempre que o conteúdo do campo for persistido, caso contrário,
* todo os estilos aplicados serão perdidos.
* @return String
*/
public String getTextoPersistencia(){
StringBuffer strTexto = new StringBuffer();
//Armazenando texto
strTexto.append(this.txtObservacoes.getText());
//Caso nenhum conteúdo tenha sido adicionado
if( strTexto.length() == 0 )
return "";
//Removendo caracter especial que separa o texto do vetor de estilos (caso tenha sido informado)
while (true){
int indice = strTexto.indexOf(new Character(this.CARACTER_SEPARADOR).toString());
if( indice != -1)
strTexto.deleteCharAt(indice);
else
break;
}
//Obtendo a lista de estilos aplicados no texto (caso exista);
List listaEstilo = this.mapearVetorEstilo();
if( listaEstilo.isEmpty() )
return strTexto.toString();
//Preparando String para receber as informações de estilo
strTexto.append(new Character(this.CARACTER_SEPARADOR).toString());
//Transformando lista de estilos em uma String
for (int i = 0; i < listaEstilo.size(); i++)
strTexto.append(listaEstilo.get(i)).append(";");
//Removendo o último ";" marcador de índice
strTexto.replace(strTexto.lastIndexOf(";"), strTexto.toString().length() , "");
return strTexto.toString();
}
/**
* Método que retorna o texto para ser impresso em relatório Jasper
* Para que os estilos aplicados sejam apresentados é necessário que a opção (Texto possui estilo)
* esteja marcada no campo que receberá o texto.
* @return String
* @throws Exception
*/
public String getTextoPDF() throws Exception{
TextoPDF textoPDF = new TextoPDF(this);
return textoPDF.getTextoPDF();
}
/**
* Método que atribui conteúdo ao campo texto
* @param texto
*/
public void setTexto(String texto){
//Caso o texto passado por parâmetro esteja nulo o processamento é interrompido
if(texto == null)
return;
int indice = texto.indexOf(new Character(this.CARACTER_SEPARADOR).toString());
//Caso um texto sem estilo seja informado
if ( indice == -1 ){
this.txtObservacoes.setText(texto);
return;
}
//Atribuindo conteúdo ao campo texto
this.txtObservacoes.setText(texto.substring(0,indice));
//Separando o vetor de estilos do texto
texto = texto.substring(indice + 1, texto.length());
//Caso o vetor de estilos esteja vazio o processamento é interrompido
if( texto.indexOf(";") < 0 )
return;
//Obtendo o vetor de estilos
String[] vetorEstilo = texto.substring(0, texto.length()).split(";");
//Aplicando estilos
for(int i = 0; i < vetorEstilo.length; i++ ){
int indice2 = this.getIndiceTexto(vetorEstilo[i]);
this.txtObservacoes.select(indice2, indice2);
String estilo = this.getEstiloTexto(vetorEstilo[i]);
this.aplicarEstilo(estilo);
}
}
/**
* Método que atribui o nome da fonte utilizada nos arquivo PDF.
* @param pdfFonteNome the pdfFonteNome to set
*/
public final void setPdfFonteNome(String pdfFonteNome) {
this.pdfFonteNome = pdfFonteNome;
}
/**
* Método que obtém o índice do caracter no qual deve ser aplicado o estilo.
* @param conteudo
* @return int
*/
private int getIndiceTexto(String conteudo){
StringBuffer indice = new StringBuffer();
for(int i = 0; i < conteudo.length(); i++){
String caracter = conteudo.substring(i, i + 1);
try{
new Integer(caracter);
indice.append(caracter);
}catch(Exception e){
//Em caso de excepção, quer dizer que o resto do conteúdo é Estilo
break;
}
}
return Integer.parseInt(indice.toString());
}
/**
* Método que obtém o estilo que deve ser aplicado para o caracter selecionado.
* @param estilo
* @return String
*/
private String getEstiloTexto(String conteudo){
StringBuffer retorno = new StringBuffer();
for(int i = 0; i < conteudo.length(); i++){
String caracter = conteudo.substring(i, i + 1);
try{
new Integer(caracter);
}catch(Exception e){
//Em caso de excepção, quer dizer que o estilo do conteúdo está sendo processado.
retorno.append(caracter);
}
}
return retorno.toString();
}
/**
* Método que varre o conteúdo o conteúdo informado no campo texto armazenando qualquer estilo
* que por ventura tenha sido aplicado.
* @param indice - posição onde o cursor se encontra no texto
* @param atributos - atributos do caracter onde se encontra o cursor
* @param listaEstilo - lista que armazena os estilo processados
*/
private List mapearVetorEstilo(){
List listaEstilo = new ArrayList();
//Obtendo o estilo de cada um dos caracteres do texto
for(int i = 0; i < this.txtObservacoes.getText().length(); i++){
this.txtObservacoes.setCaretPosition(i);
AttributeSet atributos = this.txtObservacoes.getCharacterAttributes();
int contador = 0;
StringBuffer conteudo = new StringBuffer(new Integer(i).toString());
Enumeration e = atributos.getAttributeNames();
while(e.hasMoreElements()) {
Object key = e.nextElement();
Object attr = atributos.getAttribute(key);
if( attr == null) continue;
if( new Boolean(attr.toString()).booleanValue() )
conteudo.append(key.toString().substring(0,1));
contador++;
}
if( contador > 0 )
listaEstilo.add(conteudo);
}
return listaEstilo;
}
/**
* Método que aplica estilo ao texto selecionado
* @param estilo
* @param sobrepor
*/
private void aplicarEstilo(String estilo){
int inicioSelecao = this.txtObservacoes.getSelectionStart();
int finalSelecao = this.txtObservacoes.getSelectionEnd() - inicioSelecao;
//Para os casos onde o texto está sendo selecionado caracter por caracter
if( finalSelecao < 1 ) finalSelecao = 1;
//Caso mais de um estilo tenha sido aplicado a um determinado caracter
for(int i = 0; i < estilo.length(); i++)
this.doc.setCharacterAttributes(inicioSelecao , finalSelecao,
this.txtObservacoes.getStyle(estilo.substring(i, i + 1)), false);
}
/**
* Classe interna que encapsula os método que tratam o texto para impressão em PDF.
*/
private class TextoPDF{
private final CampoTextPane campoTextPane;
private List lstTextoPDF = new LinkedList();
/**
* Construtor
* @param campoTextPane
*/
public TextoPDF(CampoTextPane campoTextPane){
this.campoTextPane = campoTextPane;
}
/**
* Método que retorna o texto para ser impresso em relatório Jasper
* @return String
* @throws Exception
*/
public String getTextoPDF() throws Exception{
//Obtendo o conteúdo
String conteudo = this.campoTextPane.getTexto();
//Atribuindo o texto ao vetor de conteúdo
for(int i = 0; i < conteudo.length(); i++)
this.lstTextoPDF.add(new Character(conteudo.charAt(i)).toString());
//Obtendo o vetor de estilos
List vetorEstilo = this.campoTextPane.mapearVetorEstilo();
//Aplicando estilos
for(int i = 0; i < vetorEstilo.size(); i++ ){
int indice = this.campoTextPane.getIndiceTexto(vetorEstilo.get(i).toString());
String caracter = this.lstTextoPDF.get(indice).toString();
String estilo = this.campoTextPane.getEstiloTexto(vetorEstilo.get(i).toString());
this.lstTextoPDF.set(indice, this.aplicarEstiloPDF(estilo, caracter));
}
//Transformando vetor em texto
StringBuffer textoPDF = new StringBuffer();
for (Iterator iterator = this.lstTextoPDF.iterator(); iterator.hasNext();)
textoPDF.append((String) iterator.next());
return textoPDF.toString();
}
/**
* Método que aplica estilo PDF ao texto.
* @param estilo
* @param caracter
* @return String
*/
private String aplicarEstiloPDF(String estilo, String caracter)throws Exception{
StringBuffer conteudoPDF = new StringBuffer("<style ");
try{
//Caso mais de um estilo tenha sido aplicado a um determinado caracter
for(int i = 0; i < estilo.length(); i++)
if( estilo.substring(i, i + 1).equals(this.campoTextPane.NEGRITO) )
conteudoPDF.append(" isBold=\"true\" ");
else if( estilo.substring(i, i + 1).equals(this.campoTextPane.ITALICO) )
conteudoPDF.append(" isItalic=\"true\" ");
else
conteudoPDF.append(" isUnderline=\"true\" ");
//Fonte PDF
StringBuffer pdfFontName = new StringBuffer(this.campoTextPane.pdfFonteNome);
if( estilo.indexOf(this.campoTextPane.ITALICO) > -1 && estilo.indexOf(this.campoTextPane.NEGRITO) > -1 )
pdfFontName.append("-BoldOblique");
else if( estilo.indexOf(this.campoTextPane.NEGRITO) > -1 )
pdfFontName.append("-Bold");
else if( estilo.indexOf(this.campoTextPane.ITALICO) > -1 )
pdfFontName.append("-Oblique");
conteudoPDF.append(" pdfFontName=\"").append(pdfFontName).append("\" >");
conteudoPDF.append(caracter).append("</style>");
}catch(Exception e){
throw new Exception("Falha ao aplicar o estilo PDF no texto");
}
return conteudoPDF.toString();
}
}
}
Importante: obviamente correções e melhorias (as vezes agente inventa de “coçar a orelha com o cotovelo”) são bem vindas. :lol: