Customizar JButton

29/04/2010

Bom dia.

Preciso fazer um componente da classe JButton ficar com sua aparencia identica a de um JLabel
Tem como alguem de vcs me orientar no que devo fazer para alcançar meu objetivo?
Israel Barbosa

Israel Barbosa

Curtidas 0

Respostas

Henrique Weissmann

Henrique Weissmann

29/04/2010

Oi Israel:

há algumas alternativas para este problema. Repare que no objeto JButton não há um método como setBackgroundColor ou coisa similar. Isto porque a aparência destes componentes é definido a partir do look and feel que você está usando.

Sendo assim, as opções que temos são:

* Criar um look and feel customizado - é trabalhoso, mas resolveria o seu problema

* Usar um objeto JLabel como botão

* Tentar usar HTML para obter o resultado desejado

* Escolher algum look and feel que possibilite isto.

O que você acha destas alternativas?
GOSTEI 0
Israel Barbosa

Israel Barbosa

29/04/2010

"Criar um look and feel customizado - é trabalhoso, mas resolveria o seu problema"   Mesmo sendo trabalhoso acredito que talves esta seja a melhor opção para obter o resultado que quero.  

"Usar um objeto JLabel como botão"   Usar um JLabel não seria a melhor alternativa por que ele não possui o método addActionListener e adicionar este método em uma sub-classe do JLabel tambem é trabalhoso.           Eu até consegui fazer uma subClasse do JLabel executar uma ação passada como parametro, porem ele não executa a ação no pressionamento de mnmonicos e nem acelerators. Derrepente se vc quizer dar uma olhada pra ve se congue me ajudar a melhorar esta classe eu te envio o codigo.   O que acha?  

* Tentar usar HTML para obter o resultado desejado   Conheço muito pouco de HTML

"Escolher algum look and feel que possibilite isto."
Ja tentei vários Lafs mas nenhum deu certo.

GOSTEI 0
Henrique Weissmann

Henrique Weissmann

29/04/2010

Oi Israel,

outra opção que me veio à mente seria você criar uma classe que extenda JButton e em seguida sobrescrever o método paint.

Lembro que na época do awt (eras atrás) era muito comum fazer isto com os componentes do pacote java.awt. Aliás, é uma técnica também muito usada por programadores Java ME

O que acha?

Além disto, encontrei outra solução para o seu problema. De uma lida neste post no StackOverflow e me diga o que acha ok? http://stackoverflow.com/questions/1839074/howto-make-jbutton-with-simple-flat-style
GOSTEI 0
Israel Barbosa

Israel Barbosa

29/04/2010

Otima idéia, daqui a pouco te retorno, blz?
GOSTEI 0
Henrique Weissmann

Henrique Weissmann

29/04/2010

Ok, no aguardo.
GOSTEI 0
Israel Barbosa

Israel Barbosa

29/04/2010

Ola Henrique testei a solução do stackOverFlow porem sem exito, observe a imagem o botão escrito text foi criado apartir da solução do link que vc indicou.        *      Então Henrique eu preciso fazer um menu lateral na minha aplicação porem não posso usar  o JXHyperlink , JXTaskPane e nem a JTree do Java porque esses componentes são muito feios.   Tenho que dar um jeito de sumir com essa aparencia 3D do JButton e deixar aparencendo somente o texto dele assim como em (Cadastros, categorias, usuarios, clientes).   Com relação a escrita do método paint parece ser uma boa alternativa porem não sei como fazer   E quanto a escrever uma classe de Look & Feel alternativo tambem parece ser uma boa idéia, porem em ambos os casos não sei como proceder.   O que faço?
GOSTEI 0
Henrique Weissmann

Henrique Weissmann

29/04/2010

Oi Israel,

entre as duas alternativas, reescrever o método paint me parece ser a mais viável.
Há um tutorial excelente que você pode baixar aqui: http://java.sun.com/docs/books/tutorial/uiswing/painting/index.html


GOSTEI 0
Israel Barbosa

Israel Barbosa

29/04/2010

Vou ler o tutorial, logo mais entro em contato, blz. E quanto a adicionar um método addActionListener ao JLabel?   veja a classe que encontrei na Internet, ela executa um ação que passada ao componente quando ele é clicado, porém ela não configura outras propriedades provindas de um objeto que extende AbstractAction, como Mnemonicos, Acelerators, Icon ... Se o método de paint não funcionar talves possa-mos melhorar esta classe.   O que me diz?     package br.com.fap.uif_lite.component; import java.awt.AWTEvent;
import java.awt.AWTEventMulticaster;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent; import javax.swing.Action; import org.jdesktop.swingx.JXLabel; public class ActionLabel extends JXLabel {
 public final int XMARGIN = 2, YMARGIN = 2;
 public final int ACTIVE = 1, IDLE = 0, PRESSED = 2;
 static final Color[] clr = { Color.blue, Color.red, Color.black };
 ActionListener lst;
 String txt, cmd;
 public int state;
 int align;  // ctor
 public ActionLabel(String str, int alg) {
  align = alg;
  cmd = txt = str;
  state = IDLE;
  enableEvents(AWTEvent.MOUSE_EVENT_MASK);
  lst = null;
 }  public ActionLabel(String str) {
  this(str, Label.LEFT);
 }
 
 public ActionLabel(String title, Action action) {
  super.setText(title);
  this.lst = action;
 }  public ActionLabel() {
  this("", Label.LEFT);
 }  // paint
// public void paint(Graphics g) {
//  FontMetrics fm = getFontMetrics(getFont());
//  int wt = fm.stringWidth(txt);
//  int ht = fm.getHeight();
//  Rectangle r = getBounds();
//  int w = r.width;
//  int h = r.height;
//  int x = (w - wt) >> 1;
//  int y = ((h + ht) >> 1) - 2;
//  if (align == Label.LEFT)
//   x = 0;
//  else if (align == Label.RIGHT)
//   x = w - wt;
//  g.setColor(clr[state]);
//  g.drawString(txt, x, y);
//  g.drawLine(x, y + 1, x + wt, y + 1);
// }  // getMinimumSize
 public Dimension getMinimumSize() {
  FontMetrics fm = getFontMetrics(getFont());
  int h = fm.getHeight() + YMARGIN + YMARGIN;
  int w = fm.stringWidth(txt) + XMARGIN + XMARGIN;
  return new Dimension(w, h);
 }  // minimumSize
 public Dimension minimumSize() {
  return getMinimumSize();
 }  // preferredSize
 public Dimension preferredSize() {
  return getMinimumSize();
 }  // getPreferredSize
 public Dimension getPreferredSize() {
  return getMinimumSize();
 }  //
 public void released() {
  int a = state;
  state = ACTIVE;
  if (a != state)
   repaint();
  postAction();
 }  //
 public void pressed() {
  int a = state;
  state = PRESSED;
  if (a != state)
   repaint();
 }  //
 public void entered() {
  int a = state;
  state = ACTIVE;
  if (a != state)
   repaint();
 }  //
 public void exited() {
  int a = state;
  state = IDLE;
  if (a != state)
   repaint();
 }  //
 public void processEvent(AWTEvent e) {
  if (e.getID() == MouseEvent.MOUSE_PRESSED)
   pressed();
  else if (e.getID() == MouseEvent.MOUSE_ENTERED)
   entered();
  else if (e.getID() == MouseEvent.MOUSE_EXITED)
   exited();
  else if (e.getID() == MouseEvent.MOUSE_RELEASED)
   released();
  super.processEvent(e);
 }  //
 public void setActionCommand(String c) {
  cmd = c;
 }  //
 public void addActionListener(ActionListener l) {
  lst = AWTEventMulticaster.add(lst, l);
 }  //
 public void removeActionListener(ActionListener l) {
  lst = AWTEventMulticaster.remove(lst, l);
 }  //
 private void postAction() {
  if (lst != null) {
   ActionEvent event = new ActionEvent(this,
     ActionEvent.ACTION_PERFORMED, cmd);
   lst.actionPerformed(event);
  }
 }
}
GOSTEI 0
Henrique Weissmann

Henrique Weissmann

29/04/2010

Entendi.

Não há como adicionar um actionListener a um JLabel. Mas encontrei uma "alternativa" bem interessante no Java Ranch. Da uma olhada neste link: http://www.coderanch.com/t/345978/Swing-AWT-SWT-JFace/java/actionListener-JLabel

Mais especificamente neste trecho:

No you can't. You can add a MouseListener though.

There is a trick that can give you a "label" that acts like a button. This is based on the notion that a radio button looks very much like a label with a button in front of it:
view plaincopy to clipboardprint?JRadioButton button = new JRadioButton("label");  // other button methods  button.setIcon(new Icon()  {      public void paintIcon(Component c, Graphics g, int x, int y)      {          // do nothing      }         public int getIconWidth()      {          return 0;      }         public int getIconHeight()      {          return 0;      }  });  JRadioButton button = new JRadioButton("label"); // other button methods button.setIcon(new Icon() { public void paintIcon(Component c, Graphics g, int x, int y) { // do nothing } public int getIconWidth() { return 0; } public int getIconHeight() { return 0; } });
Now keep in mind that this is just quick & dirty. A better way would be to create your own subclass of AbstractButton, then use a ButtonUI to do the painting. You can use JRadioButton as an example, but strip the specific radio button behaviour.
GOSTEI 0
Israel Barbosa

Israel Barbosa

29/04/2010

Blz, vou ler o post inteiro para entender e testar a solução, ja te retorno
GOSTEI 0
Israel Barbosa

Israel Barbosa

29/04/2010

Então Henrique, o código funciona porem o problema do mnemonicos e teclas de Atalho ainda persistem.  Tem mais alguma alternativa?
GOSTEI 0
Henrique Weissmann

Henrique Weissmann

29/04/2010

Pois é. O problema dos mnemonicos com JLabel é que eles são usados para redirecionar o foco para outro componente (uma caixa de texto relacionada por exemplo).

Neste caso, o que eu sugiro é você adicionar um keylistener ao seu formulário que intercepte as chamadas de teclado relacionadas aos mnemonicos.

Interceptando-as, execute as ações relativas ao seu JLabel.

Não é uma solução elegante, confesso: mas é a única que consigo ver neste momento.
GOSTEI 0
Israel Barbosa

Israel Barbosa

29/04/2010

Mas esta tecla ´só vai funcionar se o componente tiver focado. Eu precisava que funcionasse quando o componente  estivesse na janela que contem o foco. Tem jeito de fazer? 
GOSTEI 0
Henrique Weissmann

Henrique Weissmann

29/04/2010

Sim, implementando o evento keylistener no formulário.
GOSTEI 0
Devmedia

Devmedia

29/04/2010

Israel,
a resposta do consultor oi suficiente? Podemos encerrar o chamado?
GOSTEI 0
Israel Barbosa

Israel Barbosa

29/04/2010

Eu mesmo encontrei a solução!
GOSTEI 0
POSTAR