【问题标题】:Get a Swing component by name按名称获取 Swing 组件
【发布时间】:2011-06-24 22:07:48
【问题描述】:

我在JFrame 中有一些我想要的组件 参考另一个JFrame 我想要 按名称而不是按名称获取它们 为每个执行公共 get/set 方法。

Swing 有没有办法像 do 一样通过名称获取组件引用 c#?

例如form.Controls["text"]

谢谢

【问题讨论】:

  • Window.getWindows() 然后扫描你需要的东西
  • 你到底为什么要这么做?通过这样做,您将丢失两个重要的静态编译器检查: - 首先,该字段存在。 - 其次,它是正确的类型。此外,动态查找比引用字段要慢。
  • 例如,由于可怕的 API,您无法直接访问要修改的某些组件。

标签: java swing jframe


【解决方案1】:

我知道这是一个老问题,但我发现自己刚刚问了这个问题。我想要一种简单的方法来按名称获取组件,这样我就不必每次都编写一些复杂的代码来访问不同的组件。例如,让 JButton 访问文本字段中的文本或列表中的选择。

最简单的解决方案是将所有组件变量都设为类变量,以便您可以在任何地方访问它们。然而,并不是每个人都愿意这样做,有些人(比如我自己)正在使用不将组件生成为类变量的 GUI 编辑器。

我想我的解决方案很简单,并且据我所知并没有真正违反任何编程标准(参考 fortran 的做法)。它允许以简单直接的方式按名称访问组件。

  1. 创建一个 Map 类变量。您需要在 非常少。为了简单起见,我命名了我的 componentMap。

    private HashMap componentMap;
    
  2. 像往常一样将所有组件添加到框架中。

    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. 在你的类中定义以下两个方法。如果您还没有导入组件,则需要导入:

    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. 现在您已经有了一个 HashMap,它将框架/内容窗格/面板/等中所有当前存在的组件映射到它们各自的名称。

  5. 现在要访问这些组件,只需调用 getComponentByName(String name) 即可。如果存在具有该名称的组件,它将返回该组件。如果不是,则返回 null。您有责任将组件转换为正确的类型。我建议使用 instanceof 来确定。

如果您计划在运行时的任何时候添加、删除或重命名组件,我会考虑添加根据您的更改修改 HashMap 的方法。

【讨论】:

  • 我在表单上遇到了链接 JPanel 的问题。所以稍微修改的版本也包含容器: private Component getComponentByName(String name) { return getComponentByName(getMainFrame().getRootPane(), name); } private Component getComponentByName(Container root, String name) { for (Component c : root.getComponents()) { if (name.equals(c.getName())) { return c; } if (c instanceof Container) { 组件结果 = getComponentByName((Container) c, name); if (result != null) { 返回结果; } } } 返回空值; }
【解决方案2】:

每个Component 都可以有一个名称,可通过getName()setName() 访问,但您必须编写自己的查找函数。

【讨论】:

    【解决方案3】:

    getComponentByName(frame, name)

    如果您使用 NetBeans 或其他默认创建私有变量(字段)来保存所有 AWT/Swing 组件的 IDE,那么以下代码可能适合您。使用如下:

    // 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());
    

    这是使上述成为可能的代码...

    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;
        }
    
    }
    

    它使用反射来查看类字段,以查看是否可以找到由同名变量引用的组件。

    注意:上面的代码使用泛型将结果转换为您期望的任何类型,因此在某些情况下,您可能必须明确类型转换。例如,如果myOverloadedMethod 同时接受JButtonJTextField,您可能需要明确定义您希望调用的重载...

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

    如果您不确定,您可以获取Component 并通过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
    }
    

    希望这会有所帮助!

    【讨论】:

      【解决方案4】:

      您可以在第二个 JFrame 中保存对第一个 JFrame 的引用,然后循环通过 JFrame.getComponents(),检查每个元素的名称。

      【讨论】:

        【解决方案5】:

        您可以将变量声明为公共变量,然后获取文本或您想要的任何操作,然后您可以在另一个框架中访问它(如果它在同一个包中),因为它是公共的。

        【讨论】:

          【解决方案6】:

          我需要访问单个JFrame 中的多个JPanels 中的元素。

          @Jesse Strickland 发布了一个很好的答案,但提供的代码无法访问任何嵌套元素(例如在我的情况下,在 JPanel 内部)。

          经过额外的谷歌搜索,我发现@aioobe here提供的这种递归方法。

          通过组合并稍微修改@Jesse Strickland 和@aioobe 的代码,我得到了一个可以访问所有嵌套元素的工作代码,无论它们有多深:

          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;
          }
          

          代码的用法与@Jesse Strickland 代码中的完全相同。

          【讨论】:

            【解决方案7】:

            如果您的组件是在您操作它们的同一个类中声明的,您只需将这些组件作为类名的属性进行访问。

            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();
            
                                 ...
                                 ...
                                 ...
            
                            }
                ...
                ...
                ...
            }
            

            而且,您也许能够从同一命名空间中的其他类访问作为类名属性的类组件。我可以访问受保护的属性(类成员变量),也许您也可以访问公共组件。试试看!

            【讨论】:

              【解决方案8】:

              Swing 确实提供了其他方法来实现这一点,因为这里练习的是我在组件层次结构上下文中实现查找的版本。

              /**
               * 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;
              }
              

              【讨论】:

                猜你喜欢
                • 2015-04-20
                • 1970-01-01
                • 2014-03-17
                • 2012-05-30
                • 2014-04-11
                • 2016-08-09
                • 1970-01-01
                相关资源
                最近更新 更多