Saturday, June 17, 2006

Bug no JPopupMenu

Recentemente um bug com JPopupMenu foi detectado no projeto do qual faço parte. Não foram realizados testes no Windows, apenas no Linux (Suse 10).
O bug se dá quando abrimos o popup menu e logo em seguida sobrepomos a janela de uma outra aplicação. O resultado é que o popup menu continua aberto sobre essa outra janela, podendo até ter seus ítens selecionados.
Esse bug consta no site da sun (bug id: 5014550) e muitas soluções foram postadas pois ela alegou que a correção estará incorporada apenas na versão 6 (Mustang), claro que ninguém achou graça nessa notícia, mas paciência. Lógico que para quem não tem paciência ou realmente não pode esperar devido aos prazos de seus projetos (meu caso), segue uma solução "paleativa": Adicionar um WindowListener a janela que receberá o popup menu para quando ela for desativada, ou seja, perder o foco para outra aplicação, o menu seja fechado. Notem que o post passado é bem útil para quem não sabe muito de listeners e tiver alguma dúvida com o código abaixo.

public class MyFrame extends JFrame{
JPopupMenu menu = new JPopupMenu();

/*Window listener para fechar o popup menu quando o frame perder o foco*/
WindowListener windowListener = new WindowAdapter(){
public void windowDeactivated(WindowEvent e)(
if (menu != null || menu.isVisible()){
System.out.println("Frame desativado, o menu será fechado!");
menu.setVisible(false);
}
}
}

/*Mouse listener para abrir o popup menu*/
MouseListener mouseListener = new MouseAdapter(){
public void mousePressed(MouseEvenet e){
if (e.isPopupTrigger()){
menu.setVisible(true);
}
}
}

/*Construtor*/
public MyFrame(){
super("Teste JPopupMenu");
this.addWindowListener(this.windowListener);
this.getContentPane().addMouseListener(this.mouseListener);
}

public static void main(String[] args){
MyFrame frame = new MyFrame();
frame.setVisible(true);
}
}

Wednesday, June 07, 2006

Curiosidade sobre Listeners

Se você precisa usar listeners do tipo KeyListener, MouseListener, FocusListener e sempre odiou ter que implementar todos os métodos (claro, lembrando que quando implementamos uma interface é obrigatório a implementação de todos os métodos que a compõe, mesmo que o corpo esteja vazio), aqui vai uma pequena dica que me ajudou bastante:

Situação: Eu preciso de um MouseListener em que apenas do método mousePressed será utilizado, o que fazer?
Solução : Ao invés de implementar a interface MouseListener, extenda a classe MouseAdapter e sobrescreva apenas o mousePressed. Exemplo:

MouseListener myMouseListener = new MouseAdapter(){
public void mousePressed(MouseEvent e){
System.out.println("Pressionou o mouse!");
}
};

**Outros listeners também possuem seu proprio adapter:

FocusListener = FocusAdapter
WindowListener = WindowAdapter
KeyListener = KeyAdapter


Concluindo, a classe MouseAdapter simplesmente implementa a inteface MouseListener e seus metodos respectivamente, deixando-os com o corpo vazio e dessa forma a implementação dos metodos fica ao gosto do freguês.

Customizando Fontes Em Aplicações Java

Ás vezes distribuimos aplicações desktop que necessitam de fontes que em alguns casos não encontram-se instaladas no SO. Pode ser o caso de fontes orientais como chinês, japonês, koreano e etc. Essa solução elimina eventuais problemas de caracteres inválidos aparecendo no meio de um texto (aqueles quadradinhos), pois a aplicação não mais dependerá apenas de fontes previamente instaladas no ambiente gráfico. Essas situações são comumente observadas no linux, já que no Windows existem ótimas fontes orientais e em outros sistemas operacionais não fiz a constatação.

O UIManager gerencia (como diz o proprio nome) as propriedades de cada componente swing tais como: fonte, cor de fundo, borda. Essas configurações são refletidas ao se instanciar um componente swing, ou seja, se você deseja que todos os JLabels, por padrão, possuam a fonte "Comic sans" faça o seguinte:

UIManager.getDefaults().put("Label.font", new Font("Comic Sans",Font.PLAIN,12));

Sendo assim, segue abaixo um método que lê uma fonte dinamicamente a partir de um path informado e altera, para essa fonte, as respectivas propriedades no UIManager para cada componente:

public void setAppFonts(String path)
throws FontFormatException, IOException {
File file = new File(path);
FileInputStream in = new FileInputStream(file);
/* According to javadoc only true type fonts are recognized for while */
Font dynamicFont = Font.createFont(Font.TRUETYPE_FONT, in);
/* Changing all UIManager fonts to a derived font */
Hashtable defaults = UIManager.getDefaults();
Enumeration keys = defaults.keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if ((key instanceof String)
&& (((String) key).toLowerCase().endsWith("font"))) {
if (defaults.get(key) instanceof Font) {
Font currentFont = UIManager.getFont((String) key);
Font derivedFont = dynamicFont.deriveFont(new Float(
currentFont.getSize()).floatValue());
defaults.put(key, derivedFont);
}
}
}
}

Saturday, March 18, 2006

Verificando se o arquivo é binário

Mais uma vez me deparei com um problema sem solução encontrada no google: Pecisava importar dados de um arquivo texto (padrão CSV), mas antes de efetuar essa leitura teria que verificar se era um arquivo binário, ou seja, algum infeliz poderia ter renomeado uma figura com extensão JPG para CSV ou TXT. Pois bem, nao encontrei a solução e parti para o plano B.
Costumo chamar de plano B a segunda alternativa, e mais chata, que é quando temos que encontrar a solução por si só. Então, voltei aos tempos de faculdade, revendo conceitos de bits, bytes, hexadecimais, códigos ASCII e etc. Foi quando percebi que a solução não era tão complicada quanto parecia. Já que eu queria ler um arquivo formado TOTALMENTE por caracteres ASCII, então deveria verificar símbolo a símbolo se seu código ASCII estava entre 0 e 127.
Testei com vários tipos de documentos (doc, jpg, wmv, pps, jar, mp3, pdf) e todos foram reconhecidos como binários. Caso você queira testar com mais algum tipo de arquivo, nos comunique os resultados. O código está abaixo:

public boolean isBinaryFile(String file){
boolean isBinary = false;
BufferedReader in = null;
try {
/*Reads the file*/
in = new BufferedReader(new FileReader(file));
String str;
/*Walking through the file until a binary character is founded*/
while((str = in.readLine()) != null && !isBinary){
for (int i = 0; i < str.length(); i++){
isBinary = (int) str.charAt(i) > 127;
}
}
in.close();
} catch (FileNotFoundException e) {

} catch (IOException e) {

}
return isBinary;
}

Wednesday, November 09, 2005

LG lança primeiro celular com SO baseado totalmente em java

A LG, assim como muitas outras grandes corporações, está apostando alto em Java e acaba de lançar o primeiro celular com sistema operacional totalmente baseado nessa linguagem.

Algumas características do dispositivo:
  • 176x220 color TFT display;
  • 1.3MPixel camera;
  • Bluetooth, and an SD Card memory card for storage of up to 1GB of applications, music, video and pictures;
  • The handset plays MP3, AAC and AAC+ music formats as well as H.263 and MPEG4 videos.

clique aqui para ler a notícia na íntegra.

Quem disse que informática não dá dinheiro?

Essa notícia causou-me um grande contentamento, afinal para nós da área da informática nos trás alguma perspectiva. Eu também terei o meu avião.

Donos do Google usam Boeing 767 como jatinho particular

Tuesday, November 08, 2005

Coisas Interessantes Feitas em Java

Abaixo seguem alguns frameworks interessantes para conhecermos:

  • Swixml
    • Para quem quiser colocar todo o código Swing em XML (para quem ainda não entendeu: GERAR TELAS DESKTOP A PARTIR DE ARQUIVOS XML), esse framework é o melhor que já testei. É leve, robusto e faz com que a camada de visão fique totalmente separada do controle, deixando o código mais legível, além de facilitar a manutenção. Seu criador, Wolf Paulus, possui um fórum muito bacana e sempre responde a qualquer dúvida.

  • Apache Derby
    • Trata-se de um banco de dados de fácil instalação e manuseio, como citado no próprio site, o que elimina a instalação de um gerenciador em cada máquina cliente. Possui driver JDBC, suporta procedimentos e funções em Java, chave estrangeira (FK) e check constraints, triggers, múltiplas conexões, backup on-line. Realmente vale a pena visitar o site e conhecê-lo de perto.

Monday, November 07, 2005

Probleminhas com Swing 2ª Edição

Trabalhar com interface desktop em Java, com Swing, nos obriga a conhecer algumas particularidades para poder trabalhar de modo correto.
A biblioteca Swing oferece dois tipos de janela (alguns chamam de "Formulário" - deve ser herança do Delphi ou VB, acredito eu) que são: JFrame e JDialog. A classe JFrame tem a característica de ser a janela principal da aplicação, enquanto a JDialog é mais voltada para ser as janelas filhas do sistema, pois ele pode guardar uma referência a janela que a invocou (parent), pode ser "modal" ou não (quando uma janela é modal significa que quando ativa o usuário só consegue operar nesta janela e em mais nenhuma).
Não entrarei nos detalhes de herança ou métodos, afinal o javadoc foi criado para isso mesmo. O objetivo aqui é mostrar como centralizar as janelas no desktop ou relativamente ao componente que a invocou.

1. Centralizando no desktop do sistema operacional:
Essa método espera como parâmetro alguma classe filha de Component. No caso, JFrame e JDialog herdam dela.

public void windowCentered(Component window){
/*Capturando a resolução do desktop do sistema operacional*/
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int w = dialog.getSize().width;
int h = dialog.getSize().height;
int x = (screenSize.width-w)/2;
int y = (screenSize.height-h)/2;
dialog.setLocation(x, y);
}

2. Centralizando um objeto Component dentro de outro:
O método setLocationRelativeTo(Component c) centraliza um componente em relação a outro informado no parâmetro. Esse método pertence a classe Window e é extendida por JFrame e JDialog.

Exemplo:

/*Este JFrame é a tela principal*/
JFrame mainWindow = new JFrame();
/*Este dialog será aberto e sua posição será no centro do frame acima*/
JDialog diag = new JDialog();
diag.setLocationRelativeTo(mainWindow);

Friday, November 04, 2005

Probleminhas com Swing 1ª Edição

Se você está querendo pintar uma imagem no fundo de um JPanel e escrever por cima dela com um JLabel transparente, leia o código abaixo:

/*Painel com a imagem.
Note que ao instanciá-lo, o método paintComponent é sobreposto para
desenhar a figura no painel.
*/
final ImageIcon image = new ImageIcon(this.getClass().getResource(
"/resources/images/my_splash_screen.png"));
JPanel imagePanel = new JPanel(){
/**/
public void paintComponent(Graphics g){
g.drawImage(image.getImage(), 0, 0, this.getWidth(), this.getHeight(), null);

}
};

para deixar o JLabel transparente configure a propriedade "opaque" para false (label.setOpaque(false)) e insira-o no painel que contem a imagem.

Se alguém possuir alguma dúvida, poste um comentário.