Modificar o comportamento padrão do JButton - registrar novo método padrão p qualquer JButton

9 respostas
jdaffonso

Bom dia a todos.

Estou com um problema que ja há alguns dias tenho tentado encontrar uma solução. Vamos la.

Hoje precisamos levantar estatísticas, que serão persistidas de alguma forma, no momento em que clico no botão para gerar um relatório. Isso deverá ser realizado, inicialmente, para todos os JButtons dos relatórios.

Para isso, ja pensei em 3 possibilidades:

1º Poderia criar uma classe responsável por realizar a persistência de alguma forma. O problema é que teria que instanciá-la no actionPerformed de cada botão;

2º Pensei em criar uma classe JButtonP extends JButton e implementar a persistência na mesma. Desta forma teria um único método de persistência, mas teria que alterar toda a aplicação para utilizar esse novo controle;

A 3º possibilidade acredito ser a melhor, mas não sei se é possivel:

Sei que a classe BasicButtonUI possui o método installUI a qual registra novos defaults, listeners etc… O que gostaria de fazer é de alguma forma modificar o comportamento do JButton, talvez registrando um novo listener padrão, que quando eu clicar em qualquer botão JButton, esse método seja executado, no caso, chamando a minha persistência.

Alguém tem algum conhecimento a respeito.

Desde ja agradeço a ajuda.

Jefferson

9 Respostas

F

Estude essa interface Action. Assim você pode definir um comportamento padrão pra diferentes botões (ou menuItems).

http://www.devdaily.com/java/java-action-abstractaction-actionlistener

http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html

http://docs.oracle.com/javase/1.4.2/docs/api/javax/swing/Action.html

jdaffonso

Obrigado pelo retorno fasts.

Ja trabalhei com essa interface e se torna muito fácil trabalhar com classes distintas para eventos individiais ou mesmo genéricos para um ou mais controles.

Mas o que preciso, na verdade, é alterar o comportamento do todos os botões dos formulários sem ter que mexer no código dos mesmos.

Estou tentando criar um novo LookAndFeel que extende do MetalLookAndFeel e desta forma sobrescrever a ação dos botões de uma única vez, mas esta complicado. Ainda não consegui.

Algum outro conselho ou caminho a seguir ?

Obrigado.

E

Dica: você se perguntou por que é que o método de JButton é “addActionListener”, não “setActionListener”? Isso é porque você pode adicionar vários ActionListeners a um mesmo botão (o único problema é que você não sabe a ordem exata em que são instanciados, sorry. Que eu saiba, é na ordem em que são adicionados ao JButton.)
Se você criar cada botão de forma que o tal ActionListener que faça a persistência seja adicionado junto e além disso na ordem que você precisa (não sei se é antes ou depois da ação particular de cada botão), você pode usar o mesmo ActionListener para todos, por exemplo.

jdaffonso

Oi entanglement, obrigado também pela responsta.

Esse é o grande problema. Querem que eu faça de uma forma que não tenha que alterar controle a controle, por isso procuro uma soluão mais genérica, como criar uma classe extendendo de BasicButtonUI .

E

Faça o seguinte: crie o seu JFrame do jeito que você está acostumado. Crie um método recursivo (e que seria chamado, por exemplo, no método de inicialização do seu JFrame) que varra os componentes inseridos nesse JFrame (ou nos JComponents desse JFrame) e cheque se ele é um JButton. Se ele for, você chama addActionListener com o ActionListener que faz o que você quer.

Então você não precisa modificar todos os botões, apenas os JFrames (que provavelmente são herdados de um JFrame genérico).

E

O problema desse método que lhe indiquei é que, provavelmente, o ActionListener que você precisa instalar em todos os botões será chamado apenas depois do ActionListener que você já deve ter configurado para cada botão. Se isso for tolerável, então não será difícil fazer as coisas desse jeito.

jdaffonso

Perfeito entanglement. Essa foi minha ultima tentativa que também foi negada.

Consegui resolver parcilamente da seguinte forma:

Criei uma classe chamada SEBasicButtonUI que extende de BasicButtonUI como segue;

public class SEButtonUI extends BasicButtonUI {

     private final static SEButtonUI SE_BUTTON_UI = new SEButtonUI();  
    
     public static ComponentUI createUI(JComponent c){  
          return SE_BUTTON_UI;  
     }  

protected void paintButtonPressed(Graphics g, AbstractButton b) {
     System.out.println("Execução após click do mouse");
}
}

Criei tambem uma nova classe LookAndFeel que extenda da MetalLookAndFeel

public class SELookAndFeel extends MetalLookAndFeel {  

	private static final long serialVersionUID = 43261493765577340L;

	public String getDescription() {  
	    return "Software Express Look And Feel";  
    }  
  
    public String getID() {  
        return "SELookAndFeel";  
    }  
  
    public String getName() {  
        return "SELookAndFeel";  
    }  
  
    public boolean isNativeLookAndFeel() {  
        return false;  
    }  
  
    public boolean isSupportedLookAndFeel() {  
        return true;  
    }  
  
    protected void initClassDefaults(UIDefaults table) {
    	super.initClassDefaults(table);
    	final String sePackageName = "swing.JButtonSE.newLookAndFeel.";
    	Object[] uiDefaults = {"ButtonUI", sePackageName + "SEButtonUI"};
    	table.putDefaults(uiDefaults);
    }
  
    protected void initSystemColorDefaults(UIDefaults table) {  
        super.initSystemColorDefaults(table);  
    }  
  
    protected void initComponentDefaults(UIDefaults table) {  
        super.initComponentDefaults(table);  
    }  
}

E para finalizar, na minha classe principal registrei o novo lookAndFeel

UIManager.put("ButtonUI", "swing.JButtonSE.newLookAndFeel.SEButtonUI");

Desta forma, mesmo criando controles JButton, o evento paintButtonPressed da classe SEButtonUI sempre e disparado.

Porem, minha dúvida agora é como recuperar o nome da classe que disparou o evento.

Obrigado novamente a todos.

F

Não sei se hoje há uma forma melhor, mas desse jeito funciona:

http://www.artima.com/forums/flat.jsp?forum=1&thread=1451

jdaffonso

fasts, realmente, talvez exista outra forma, mas como descrito por você, consegui resgatar a informação que preciso. Para isso, alterei minha classe como descrito abaixo.

Muito obrigado a todos pela ajuda.

public class SEButtonUI extends BasicButtonUI {
	private final static SEButtonUI SE_BUTTON_UI = new SEButtonUI();  
    
	 public static ComponentUI createUI(JComponent c){  
		 return SE_BUTTON_UI;  
	}
	 
	protected void paintButtonPressed(Graphics g, AbstractButton b) {

		 StackTraceElement[] erros = new Throwable().fillInStackTrace().getStackTrace();

		 for (StackTraceElement stack : erros) {
			 if (!stack.getClassName().toLowerCase().startsWith("java")) {
				 System.out.println(stack.getClassName());
				 System.out.println(stack.getMethodName());
				 System.out.println(stack.getFileName());
				 System.out.println(stack.getLineNumber());
			 }
		 }
	}
Criado 29 de junho de 2012
Ultima resposta 3 de jul. de 2012
Respostas 9
Participantes 3