开发者

Get a Swing component by name

开发者 https://www.devze.com 2023-02-09 23:12 出处:网络
I have in a JFrame some components that I开发者_开发问答 want to refer into another JFrame and I want

I have in a JFrame some components that I开发者_开发问答 want to refer into another JFrame and I want to get them by name and not do public get/set methods for each.

Is there a way from Swing to get a component reference by its name like do c#?

e.g. form.Controls["text"]

Thanks


I know this is an old question, but I found myself asking it just now. I wanted an easy way to get components by name so I didn't have to write some convoluted code each time to access different components. For example, having a JButton access the text in a text field or a selection in a List.

The easiest solution is to make all of the component variables be class variables so that you can access them anywhere. However, not everyone wants to do that, and some (like myself) are using GUI Editors that don't generate the components as class variables.

My solution is simple, I'd like to think, and doesn't really violate any programming standards, as far as I know (referencing what fortran was getting at). It allows for an easy and straightforward way to access components by name.

  1. Create a Map class variable. You'll need to import HashMap at the very least. I named mine componentMap for simplicity.

    private HashMap componentMap;
    
  2. Add all of your components to the frame as normal.

    initialize() {
        //add your components and be sure
        //to name them.
        ...
        //after adding all the components,
        //call this method we're about to create.
        createComponentMap();
    }
    
  3. Define the following two methods in your class. You'll need to import Component if you haven't already:

    private void createComponentMap() {
            componentMap = new HashMap<String,Component>();
            Component[] components = yourForm.getContentPane().getComponents();
            for (int i=0; i < components.length; i++) {
                    componentMap.put(components[i].getName(), components[i]);
            }
    }
    
    public Component getComponentByName(String name) {
            if (componentMap.containsKey(name)) {
                    return (Component) componentMap.get(name);
            }
            else return null;
    }
    
  4. Now you've got a HashMap that maps all the currently existing components in your frame/content pane/panel/etc to their respective names.

  5. To now access these components, it is as simple as a call to getComponentByName(String name). If a component with that name exists, it will return that component. If not, it returns null. It is your responsibility to cast the component to the proper type. I suggest using instanceof to be sure.

If you plan on adding, removing, or renaming components at any point during runtime, I would consider adding methods that modify the HashMap according to your changes.


Each Component can have a name, accessed via getName() and setName(), but you'll have to write your own lookup function.


getComponentByName(frame, name)

IF you're using NetBeans or another IDE that by default creates private variables (fields) to hold all of your AWT/Swing components, then the following code may work for you. Use as follows:

// get a button (or other component) by name
JButton button = Awt1.getComponentByName(someOtherFrame, "jButton1");

// do something useful with it (like toggle it's enabled state)
button.setEnabled(!button.isEnabled());

Here's the code to make the above possible...

import java.awt.Component;
import java.awt.Window;
import java.lang.reflect.Field;

/**
 * additional utilities for working with AWT/Swing.
 * this is a single method for demo purposes.
 * recommended to be combined into a single class
 * module with other similar methods,
 * e.g. MySwingUtilities
 * 
 * @author http://javajon.blogspot.com/2013/07/java-awtswing-getcomponentbynamewindow.html
 */
public class Awt1 {

    /**
     * attempts to retrieve a component from a JFrame or JDialog using the name
     * of the private variable that NetBeans (or other IDE) created to refer to
     * it in code.
     * @param <T> Generics allow easier casting from the calling side.
     * @param window JFrame or JDialog containing component
     * @param name name of the private field variable, case sensitive
     * @return null if no match, otherwise a component.
     */
    @SuppressWarnings("unchecked")
    static public <T extends Component> T getComponentByName(Window window, String name) {

        // loop through all of the class fields on that form
        for (Field field : window.getClass().getDeclaredFields()) {

            try {
                // let us look at private fields, please
                field.setAccessible(true);

                // compare the variable name to the name passed in
                if (name.equals(field.getName())) {

                    // get a potential match (assuming correct &lt;T&gt;ype)
                    final Object potentialMatch = field.get(window);

                    // cast and return the component
                    return (T) potentialMatch;
                }

            } catch (SecurityException | IllegalArgumentException 
                    | IllegalAccessException ex) {

                // ignore exceptions
            }

        }

        // no match found
        return null;
    }

}

It uses reflection to look through the class fields to see if it can find a component that is referred to by a variable of the same name.

NOTE: The code above uses generics to cast the results to whatever type you are expecting, so in some cases you may have to be explicit about type casting. For example if myOverloadedMethod accepts both JButton and JTextField, you may need to explicitly define the overload you wish to call ...

myOverloadedMethod((JButton) Awt1.getComponentByName(someOtherFrame, "jButton1"));

And if you're not sure, you can get an Component and check it with instanceof...

// get a component and make sure it's a JButton before using it
Component component = Awt1.getComponentByName(someOtherFrame, "jButton1");
if (component instanceof JButton) {
    JButton button = (JButton) component;
    // do more stuff here with button
}

Hope this helps!


you could hold a reference to the first JFrame in the second JFrame and just loop through JFrame.getComponents(), checking the name of each element.


You can declare a variable as a public one then get the text or whatever operation you want and then you can access it in the other frame(if its in the same package) because it's public.


I needed to access elements inside several JPanels which were inside a single JFrame.

@Jesse Strickland posted a great answer, but the provided code is not able to access any nested elements (like in my case, inside JPanel).

After additional Googling I found this recursive method provided by @aioobe here.

By combining and slightly modifying the code of @Jesse Strickland and @aioobe I got a working code that can access all the nested elements, no matter how deep they are:

private void createComponentMap() {
    componentMap = new HashMap<String,Component>();
    List<Component> components = getAllComponents(this);
    for (Component comp : components) {
        componentMap.put(comp.getName(), comp);
    }
}

private List<Component> getAllComponents(final Container c) {
    Component[] comps = c.getComponents();
    List<Component> compList = new ArrayList<Component>();
    for (Component comp : comps) {
        compList.add(comp);
        if (comp instanceof Container)
            compList.addAll(getAllComponents((Container) comp));
    }
    return compList;
}

public Component getComponentByName(String name) {
    if (componentMap.containsKey(name)) {
        return (Component) componentMap.get(name);
    }
    else return null;
}

Usage of the code is exactly the same as in @Jesse Strickland code.


If your components are declared inside the same class you're manipulating them from, you simply access these components as attributes of the class name.

public class TheDigitalClock {

    private static ClockLabel timeLable = new ClockLabel("timeH");
    private static ClockLabel timeLable2 = new ClockLabel("timeM");
    private static ClockLabel timeLable3 = new ClockLabel("timeAP");


    ...
    ...
    ...


            public void actionPerformed(ActionEvent e)
            {
                ...
                ...
                ...
                    //set all components transparent
                     TheDigitalClock.timeLable.setBorder(null);
                     TheDigitalClock.timeLable.setOpaque(false);
                     TheDigitalClock.timeLable.repaint();

                     ...
                     ...
                     ...

                }
    ...
    ...
    ...
}

And, you may be able to access class components as attributes of the class name from other classes in the same namespace too. I can access protected attributes(class member variables), maybe you can access public components, too. Try it!


Swing does provide other ways to implement this, for the sake as exercising here is my version that implements a find in Component hierarchy context.

/**
 * Description          : Find a component having the given name in container  desccendants hierarchy
 * Assumptions          : First component with the given name is returned
 * @return java.awt.Component
 * @param component java.awt.Component
 * @param componentName java.lang.String
 */
public static Component findComponentByName(Component component, String componentName) {
  if (component == null ) {
    return null;
  }

  if (component.getName() != null && component.getName().equalsIgnoreCase(componentName)) {
    return component;
  } 

  if ( (component instanceof Container )  ) {       
    Component[] children = ((Container) component).getComponents();
    for ( int i=0; i<children.length; i++ ) {
        Component child = children[i];
        Component found = findComponentByName( child, componentName );
        if (found != null ) {
            return found;
        }
    }
  }
  return null;
}
0

精彩评论

暂无评论...
验证码 换一张
取 消