web-dev-qa-db-ja.com

名前でSwingコンポーネントを取得する

別のJFrameで参照したいJFrameいくつかのコンポーネントがあり、それらを名前で取得し、それぞれに対してパブリックget/setメソッドを実行したくない。

Swingから、c#のような名前でコンポーネント参照を取得する方法はありますか?

例えばform.Controls["text"]

ありがとう

15
xdevel2000

私はこれが古い質問であることを知っていますが、私はたった今それを尋ねていることに気づきました。名前でコンポーネントを取得する簡単な方法が欲しかったので、さまざまなコンポーネントにアクセスするために毎回複雑なコードを記述する必要がありませんでした。たとえば、JButtonにテキストフィールドのテキストまたはリストの選択にアクセスさせる。

最も簡単な解決策は、すべてのコンポーネント変数をクラス変数にして、どこからでもアクセスできるようにすることです。ただし、誰もがそれを望んでいるわけではなく、一部(私のような)は、コンポーネントをクラス変数として生成しないGUIエディターを使用しています。

私の解決策は単純です。考えたいのですが、私が知る限り(プログラミングの標準がFortranで達成されていることを参照)違反していません。名前を使用してコンポーネントにアクセスする簡単で簡単な方法が可能になります。

  1. Mapクラス変数を作成します。少なくともHashMapをインポートする必要があります。わかりやすくするために、私は私のコンポーネントマップに名前を付けました。

    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. クラスで次の2つのメソッドを定義します。まだインポートしていない場合は、コンポーネントをインポートする必要があります。

    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を変更するメソッドを追加することを検討します。

27

Component には名前を付けることができ、getName()およびsetName()を介してアクセスできますが、独自のルックアップ関数を作成する必要があります。

6
trashgod

getComponentByName(フレーム、名前)

NetBeansまたは別のIDEを使用している場合、デフォルトですべてのAWT/Swingコンポーネントを保持するプライベート変数(フィールド)が作成されます)、次のコードが機能する場合があります。次のように使用します。

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

}

リフレクションを使用してクラスフィールドを調べ、同じ名前の変数によって参照されるコンポーネントを見つけることができるかどうかを確認します。

注:上記のコードはジェネリックスを使用して、結果を予想される型にキャストするため、場合によっては型キャストについて明示的にする必要があります。たとえば、myOverloadedMethodJButtonJTextFieldの両方を受け入れる場合、呼び出すオーバーロードを明示的に定義する必要があるかもしれません...

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
Jonathan

最初のJFrameへの参照を2番目のJFrameに保持し、JFrame.getComponents()をループして、各要素の名前を確認することができます。

2
Andy

単一のJPanel内にある複数のJFrames内の要素にアクセスする必要がありました。

@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コードとまったく同じです。

1
kazy

変数をパブリック変数として宣言し、テキストまたは必要な操作を取得し、パブリックであるため、他のフレーム(同じパッケージ内にある場合)でその変数にアクセスできます。

1
Mojo_Jojo

コンポーネントを操作しているのと同じクラス内で宣言した場合は、これらのコンポーネントにクラス名の属性としてアクセスするだけです。

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

                     ...
                     ...
                     ...

                }
    ...
    ...
    ...
}

そして、あなたはmayクラス名の属性としてクラスコンポーネントにアクセスできる同じ名前空間の他のクラスからも。保護された属性(クラスメンバー変数)にアクセスできます。パブリックコンポーネントにもアクセスできます。それを試してみてください!

0