Eu sei a diferença entre variable name e name de um Component.
É óbvio que não se pode (nem se deve!!!) modificar o conteúdo da variable name durante a execução.
Mas por favor me digam, não tem nenhuma forma de eu pegar o valor da variable name em tempo de execução?
Já pesquisei, e nada! Todo lugar fala pra preencher o atributo name e usar ele…
Digamos que você tenha a seguinte classe derivada de JFrame:
class MeuJFrame extends JFrame {
private JLabel meuLabel = new JLabel ("abobora");
private JPanel meuPanel = new JPanel();
public MeuJFrame () {
super ("exemplo");
meuLabel.setName ("rotulo");
add (meuLabel);
add (meuPanel);
JSpinner meuSpinner = new JSpinner();
add (meuSpinner);
}
}
Como você sabe:
Variáveis têm nomes, mas objetos não têm nomes. Isso porque um mesmo objeto pode ser referenciado por mais de uma variável.
Os nomes das variáveis de instância você consegue pegar via reflection. Dá trabalho mas é possível. Entretanto, dado apenas o valor da variável da instância (o objeto) você não consegue pegar o tal nome, porque o objeto não tem uma referência “de volta”.*
Os nomes das variáveis locais não dá para pegar nem via reflection. Eles são perdidos. (A rigor, se o programa for compilado com informação de debug, é possível, com muito trabalho, obter os nomes das variáveis locais).
Você consegue pegar o atributo “name” de um JComponent com getName() se você atribuí-lo com setName() (digamos durante a construção).
A rigor, nesse caso em particular você pode até determinar qual é o parent se você adicionar o componente ao JFrame, mas é por dedução e nem sempre é algo que funciona corretamente. Por isso, simplificando, eu digo que o objeto em si “não tem nome”.
Digamos que você tenha a seguinte classe derivada de JFrame:
class MeuJFrame extends JFrame {
private JLabel meuLabel = new JLabel ("abobora");
private JPanel meuPanel = new JPanel();
public MeuJFrame () {
super ("exemplo");
meuLabel.setName ("rotulo");
add (meuLabel);
add (meuPanel);
JSpinner meuSpinner = new JSpinner();
add (meuSpinner);
}
}
Como você sabe:
Variáveis têm nomes, mas objetos não têm nomes. Isso porque um mesmo objeto pode ser referenciado por mais de uma variável.
Os nomes das variáveis de instância você consegue pegar via reflection. Dá trabalho mas é possível. Entretanto, dado apenas o valor da variável da instância (o objeto) você não consegue pegar o tal nome, porque o objeto não tem uma referência “de volta”.*
Os nomes das variáveis locais não dá para pegar nem via reflection. Eles são perdidos. (A rigor, se o programa for compilado com informação de debug, é possível, com muito trabalho, obter os nomes das variáveis locais).
Você consegue pegar o atributo “name” de um JComponent com getName() se você atribuí-lo com setName() (digamos durante a construção).
A rigor, nesse caso em particular você pode até determinar qual é o parent se você adicionar o componente ao JFrame, mas é por dedução e nem sempre é algo que funciona corretamente. Por isso, simplificando, eu digo que o objeto em si “não tem nome”. [/quote]
Certo thingol, entendi… então é bem o caso que vc mencionou msm, podemos dizer que meu objeto “não tem nome”, pq eu não tenho como pegar o tal nome… Que peninha!!!
Que peninha é modo de dizer. Vou dar um exemplo simples:
import java.awt.*;
import javax.swing.*;
import java.lang.reflect.*;
class Util {
// Varre cada variável de instância do objeto, e vê se é um Component. Se for,
// então seta a propriedade "name" do objeto associado a essa variável.
public static void atribuirNomes (Container container) {
Class<?> containerClass = container.getClass();
Field[] fields = containerClass.getDeclaredFields ();
if (fields == null) return;
for (Field field : fields) {
Object obj = null;
try {
field.setAccessible (true);
obj = field.get (container);
} catch (IllegalAccessException ex) {
ex.printStackTrace();
}
if (obj != null && Component.class.isAssignableFrom (obj.getClass())) {
// Neste caso, devemos chamar setName:
((Component) obj).setName (field.getName());
}
}
}
}
class TesteNomesComponentes extends JFrame {
private JLabel jlLabel1 = new JLabel ("Passe o cursor para ver um tooltip");
private JLabel jlLabel2 = new JLabel ("com o nome deste componente");
private JButton jbButton1 = new JButton ("Botão 1");
private void initComponents() {
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
setBounds (0, 0, 300, 100);
add (jlLabel1, BorderLayout.NORTH);
add (jlLabel2, BorderLayout.CENTER);
add (jbButton1, BorderLayout.SOUTH);
}
public TesteNomesComponentes() {
super ("Teste de Nomes de Componentes");
initComponents();
Util.atribuirNomes (this); // isto atribui ao atributo "name" o nome da variável.
// Só para brincar, vamos setar um tooltip para cada JComponent deste JFrame
// com o valor de getName.
jlLabel1.setToolTipText (jlLabel1.getName());
jlLabel2.setToolTipText (jlLabel2.getName());
jbButton1.setToolTipText (jbButton1.getName());
}
public static void main(String[] args) {
TesteNomesComponentes tnc = new TesteNomesComponentes();
tnc.setVisible (true);
}
}
Não resolve meu probleminha mas gostei muito de aprender isso!
No meu caso, pra resumir, digamos q tenho um método que recebe um Component (para que possa receber diversos objetos).
Gostaria de a partir desse Component pegar o nome dele (bem, não o atributo name, mas o variable name, vc deve ter entendido).
Mas pelo que vc me explicou, não tem jeito de fazer oque quero pq o Component que recebo no meu método é só uma referência para o Object declarado na minha classe. Certo? Ou viajei?
Re
acho que ninguem entendeu o que vc realmente precisa :oops:
eu entendi que tu sabe o que eh
como faz
mas naum o que que
pode mandar pm que sempre q possivel t respondo
Não resolve meu probleminha mas gostei muito de aprender isso!
No meu caso, pra resumir, digamos q tenho um método que recebe um Component (para que possa receber diversos objetos).
Gostaria de a partir desse Component pegar o nome dele (bem, não o atributo name, mas o variable name, vc deve ter entendido).
Mas pelo que vc me explicou, não tem jeito de fazer oque quero pq o Component que recebo no meu método é só uma referência para o Object declarado na minha classe. Certo? Ou viajei?
Grata [/quote]
É isso aí mesmo, dona Renata, mas como você deve ter entendido, você sempre pode dar um jeito (como é o caso do que escrevi acima).
Então thingol, seguindo sua idéia, eu fiz um esquema aqui que funciona como preciso, ou seja, passo o Component e ele me dá o nome com o qual ele foi declarado. Vou postar o código aqui, me ajude com dicas pra melhorar a performace, penso que funciona mas quando se tratar de uma classe que tem muitos objetos vai ficar lento…
private void initComponents() {
jlLabel1 = new JLabel ("Passe o cursor para ver um tooltip");
jlLabel2 = new JLabel ("com o nome deste componente");
jbButton1 = new JButton ("Botão 1");
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
setBounds (0, 0, 300, 100);
jbButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
clicouBotao(evt);
}
});
add (jlLabel1, BorderLayout.NORTH);
add (jlLabel2, BorderLayout.CENTER);
add (jbButton1, BorderLayout.SOUTH);
}
public TesteNomesComponentes() {
super ("Teste de Nomes de Componentes");
initComponents();
}
public static void main(String[] args) {
TesteNomesComponentes tnc = new TesteNomesComponentes();
tnc.setVisible (true);
}
private void clicouBotao(java.awt.event.ActionEvent evt){
if (evt.getSource() == jbButton1){
jbButton1.setText(pegaNome(this,jbButton1));
}
}
private String pegaNome(Container container, Component comp){
String retorno = "";
Class<?> containerClass = container.getClass();
Field[] fields = containerClass.getDeclaredFields();
if (fields.length > 0){
for (Field f : fields){
Object obj = null;
try {
f.setAccessible(true);
obj = f.get(container);
} catch (IllegalAccessException ex) {
ex.printStackTrace();
}
if ((obj != null) && ((Component)obj == comp)){ // achei o componente que estou procurando
if (Component.class.isAssignableFrom (obj.getClass()))
retorno = f.getName(); // pego o nome
break; // paro o loop
}
}
}
return retorno;
}
Você pode fazer um “cache” dos nomes desses objetos, para que isso não fique muito lento. Mas acho que para uma tela com menos de 100 componentes nem precisa fazer algo muito complicado (talvez você possa fazer como eu fiz, ou seja, atribuir os nomes aos componentes com setName, tal como sugerido, e fazer isso apenas quando necessário. Se o componente já estiver com a propriedada “name” setada, nem precisa recalcular o nome dele novamente.).