문제

나는 현재 많은 ActionListener가 정의된 일부 Java 코드를 작업 중입니다(각각 하나씩). JButton) 약 60개의 버튼이 있습니다.이들은 모두 익명의 내부 클래스로 정의됩니다. JButton.addActionListener 방법.나는 코드를 더 깔끔하게 보이도록 리팩터링하는 방법을 생각해 왔습니다. 이로 인해 코드가 매우 복잡해 보이기 때문입니다.나는 각각이 리스너를 반환하는 정적 메서드가 많이 있는 별도의 클래스로 리스너를 가져오는 것에 대해 생각했습니다.이는 코드가 다음과 같이 보일 것임을 의미합니다. addActionListener(GetActionListener.addActionListener()).이렇게 하면 더 깔끔해지기는 하지만 실제로는 우아한 해결책은 아니라고 생각됩니다.나는 또한 청취자 이름과 함께 KV 쌍을 청취자 자체에 보유하는 정적 최종 맵을 생각했습니다.그러나 이것은 여전히 ​​매우 우아한 해결책처럼 보이지 않습니다.누구든지 아이디어가 있는지 궁금합니다.또한 모든 actionListener는 매우 다르다고 말씀드리고 싶습니다.

도움이 되었습니까?

해결책

다음을 사용하여 작업을 직접 추가하지 않는 것이 좋습니다. ActionListener.이렇게 하면 재사용이 불가능해집니다.대신에 당신의 행동을 포장하십시오 javax.swing.Action 수업.원하는 곳 어디에서나 작업을 재사용할 수 있습니다.예를 들어 이제 복사 작업의 메뉴 바로가기와 도구 모음의 복사 버튼에 동일한 작업을 사용할 수 있습니다.기본적으로 아이디어는 실행 가능한 작업을 GUI 요소와 직접 연결하지 않는 것입니다.

이제 귀하의 질문에 도달했습니다.나는 만들 것이다 repository of actions 예를 들어 공개 메소드가 있는 ActionRepsoiory라는 클래스에서 Action getAction(String).각 작업은 저장소에서 작업을 검색하는 데 사용하는 문자열 상수로 식별됩니다.일반적으로 해당 문자열은 actionCommand 요소에 대해.HasMap 등을 통해 ActionRepository에서 작업을 관리하는 방법은 전적으로 사용자에게 달려 있습니다.

이것이 대부분의 전문 코드인 AFAIK에서 수행되는 방식입니다.

다른 팁

이 질문과 중복되지 않음 (답변된 질문과 중복되지 않았습니다...와우) 하지만 대답은 적용되어야 합니다.

내부 클래스가 외부 클래스 내부에서 메서드를 호출하는 것 이상의 작업을 수행한다면 "잘못된" 작업을 수행하고 있는 것입니다(내 정의에 따르면 "올바른" 것입니다).게시된 코드에서는 increment() 및 decrement() 호출이 이를 수행하는 "올바른" 방법입니다.리스너가 메서드 호출을 외부 클래스로 전달하도록 코드를 리팩터링하는 것은 코드를 보다 쉽게 ​​관리할 수 있도록 시작하는 좋은 방법입니다.

그러고보니...UI에 버튼이 60개?!정말!아야!모두 한 화면에 표시됩니까, 아니면 탭 등으로 완료됩니까?(탭이거나 답변에서 더 많은 것을 제공할 수 있는 것인 경우)

당신은 특별한 하위 클래스를 만들 수 있습니다 ActionListener 리플렉션을 사용하여 주어진 메서드 이름을 호출하면 60개 작업을 모두 일반 메서드로 구현할 수 있습니다.

package com.example;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MethodAsActionListener implements ActionListener {

    private Object receiver;
    private Method method;

    public MethodAsActionListener(Object receiver, String name) {
        this.receiver = receiver;
        try {
            this.method = receiver.getClass().getDeclaredMethod(name);
        } catch (SecurityException e) {
           throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void actionPerformed(ActionEvent event) {
        try {
            method.invoke(receiver);
        } catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

}

그리고 당신이 방법이라면 call 당신의 수업에

private call(String name) {
    return new MethodAsActionListener(this, name);
}

그런 다음 다음과 같이 작업을 추가할 수 있습니다.

button1.addActionListener(call("methodName1"));
button2.addActionListener(call("methodName2"));
button3.addActionListener(call("methodName3"));
button4.addActionListener(call("methodName4"));
button5.addActionListener(call("methodName5"));

이러한 메소드 중 하나가 없으면 UI가 빌드될 때 프로그램이 실패합니다(액션 리스너가 생성될 때 메소드를 조회하므로).컴파일 타임만큼 좋지는 않지만 작업이 트리거될 때 완전히 늦게 바인딩되는 것보다는 낫습니다.

나는 당신이 제안한 것과 같은 것을 추천하고 싶습니다. 모든 이벤트를 구독하는 단일 리스너 클래스를 생성하십시오.하지만 각 이벤트에 대해 클래스의 다른 인스턴스를 사용하여 이 특정 이벤트에 대해 일반적으로 수행할 작업을 일반적으로 인스턴스(생성자 내)에 지시하고 싶을 것입니다.

이것의 장점은 일반적으로 매우 유사하기 때문에 리스너 내부의 코드를 더 적은 수의 메소드로 분해하기 시작할 수 있다는 것입니다.때로는 단일 메서드로 가져올 수도 있습니다.

메뉴 생성을 위한 "순수 디스패치" 상황에 사용한 한 가지 비결은 메뉴, 메뉴 구조 및 각 메뉴 항목이 데이터에 링크되는 방법을 지정하는 것이었습니다.약간의 반성이 필요하지만 작동합니다.

사실 -- 한번 살펴보겠습니다.

네, Google 문서에 클래스를 보관했습니다. :) 데이터는 다음과 같이 지정되었습니다.

final static String[] menus = { "File:*", "Save:save", "Load:load", "(", "Print:-", "Preview:preview", ")", "Quit:quit" };

방금 이것을 분석했습니다.시작으로 인해 파일이 최상위 항목이 되고, 저장은 "Save" 메서드를 호출하고, 로드는 "Load" 메서드를 호출하고, 인쇄는 하위 메뉴(따라서 괄호)이며 그 아래에 미리보기가 있고 인쇄는 바인딩되지 않습니다. 무엇이든.

이 문자열은 한 번의 호출로 전체 메뉴를 생성하고 바인딩할 수 있습니다.

여기 내 소스코드 당신이 그것을 가지고 놀고 싶다면.

상단의 "TestMenu" 클래스는 buildMenus 메소드 사용 방법을 보여주는 테스트 클래스입니다.

이 작업은 몇 년 전에 수행되었으므로 지금은 다르게 수행할 수도 있지만 작동합니다.실제로 메뉴를 생성하는 것이 마음에 들지 않으며 문자열 파서가 각 항목에 대한 문자열로 나누는 대신 단일 문자열을 사용하도록 할 것이라고 생각합니다. 각 항목이 공백으로 구분되어 있는지 확인하기가 쉬워야 합니다. ..

더 나은 API는 다음과 같은 바인딩 메서드일 수 있습니다.

bind(this, new JButton("Save"), "save", this);

여기서 저장 버튼을 누르면 이 항목(또는 전달한 다른 개체)에 대해 저장 메서드가 호출됩니다."save" 매개변수를 선택사항으로 만들고 JButton.getText().toLower()를 매개변수가 없을 때 호출하는 메소드로 사용할 수도 있습니다(구성 전의 관례인 것 같습니다).

메뉴 생성 및 메뉴 관계를 내 데이터로 추상화하고 싶었기 때문에 메뉴에 대해 이런 방식으로 작업을 수행하지 않았습니다.

이 방법으로 코딩하는 것은 Java에서 MVC를 분리하는 멋진 방법입니다. 모든 컨트롤러 코드를 보기에서 제거할 수 있습니다.

package hEvil;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.border.EmptyBorder;

public class JDial extends JDialog {

private static final long serialVersionUID = -26565050431585019L;
private final JPanel contentPanel = new JPanel();

public static void main(String[] args) {
    try {

        JDial dialog = new JDial();
        dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        dialog.setVisible(true);
        dialog.setTitle("Heavy Evil");
        dialog.setBackground(Color.WHITE);

    } catch (final Exception e) {
        e.printStackTrace();
    }
}

public JDial() {
    setBounds(0, 0, 1300, 800);
    getContentPane().setLayout(new BorderLayout());
    contentPanel.setLayout(new FlowLayout());
    contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
    getContentPane().add(contentPanel, BorderLayout.CENTER);

    JPanel windowPane = new JPanel();
    windowPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
    getContentPane().add(windowPane, BorderLayout.SOUTH);

    {
        JButton cancelButton = new JButton("Exit");
        cancelButton.setActionCommand("Exit");
        windowPane.add(cancelButton);
        cancelButton.setBounds(0, 0, 1200, 700);

    }

    {
        JPanel textPane = new JPanel();
        textPane.setLayout(new FlowLayout(FlowLayout.LEFT));
        getContentPane().add(textPane, BorderLayout.NORTH);
        textPane.setVisible(true);

        {
            JTextArea textArea = new JTextArea("Username", 2, 15);
            textPane.add(textArea);
            textArea.setWrapStyleWord(true);
            textArea.setEditable(true);
            textArea.setFont(Font.getFont(Font.SANS_SERIF));
            textArea.setVisible(true);
            textArea.enableInputMethods(isEnabled());
            textArea.computeVisibleRect(getBounds());
            textArea.setBackground(Color.GRAY);

            JTextArea textArea2 = new JTextArea("Password", 2, 15);
            textPane.add(textArea2);
            textArea2.setWrapStyleWord(true);
            textArea2.setEditable(true);
            textArea2.setFont(Font.getFont(Font.SANS_SERIF));
            textArea2.setVisible(true);
            textArea2.enableInputMethods(isEnabled());
            textArea2.computeVisibleRect(getBounds());
            textArea2.setBackground(Color.GRAY);

        }
        {

            JButton registerButton = new JButton("Register");
            textPane.add(registerButton);

        }
        {
            JButton newButton = new JButton("Submit");
            textPane.add(newButton);
            newButton.setEnabled(true);
            getRootPane().setDefaultButton(newButton);
            newButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent evt) {

                    JFrame newFrame = new JFrame("Welcome");
                    newFrame.setVisible(true);
                    newFrame.setBackground(Color.BLACK);
                    newFrame.setBounds(0, 0, 580, 200);

                    JPanel newPanel = new JPanel();
                    newFrame.add(newPanel);
                    dispose();

                    JButton nuButton = new JButton("Mario");
                    newPanel.add(nuButton);

                    JButton nuButton2 = new JButton("Kirby");
                    newPanel.add(nuButton2);

                    JButton nuButton3 = new JButton("Mew Two");
                    newPanel.add(nuButton3);

                    JButton nuButton4 = new JButton("Vegeta");
                    newPanel.add(nuButton4);

                    JButton nuButton5 = new JButton("Tidus");
                    newPanel.add(nuButton5);

                    JButton nuButton6 = new JButton("Link");
                    newPanel.add(nuButton6);

                    JButton nuButton7 = new JButton("Master Chief");
                    newPanel.add(nuButton7);

                    JButton nuButton8 = new JButton("Snake");
                    newPanel.add(nuButton8);

                    JButton nuButton9 = new JButton("Cash");
                    newPanel.add(nuButton9);

                    JButton nuButton10 = new JButton("Lara");
                    newPanel.add(nuButton10);

                    JButton nuButton11 = new JButton("Max");
                    newPanel.add(nuButton11);

                    JButton nuButton12 = new JButton("Spyro");
                    newPanel.add(nuButton12);

                    JButton nuButton13 = new JButton("Sephiroth");
                    newPanel.add(nuButton13);

                    JButton nuButton14 = new JButton("Scorpion");
                    newPanel.add(nuButton14);

                }
            });

        }

    }

}

}
//AND I WANT TO BE ABLE TO IMPLEMENT EACH BUTTON FROM ANOTHER CLASS
//FROM ACTIONEVENT WITH SOMETHINGS SIMILAR TO nuButtonX.actionImplemented...
//CALLING THE SAME ACTIONLISTENER IF I CAN AND THEN CREATING A CLASS FOR
//MODIFICATIONS AT EACH INSTANCE. 
enter code here
package hEvil;

import java.awt.event.ActionEvent;

import javax.swing.JFrame;

public class ActoEve extends ActionEvent {

/**
 * 
 */
private static final long serialVersionUID = -2354901917888497068L;
public ActoEve(Object arg0, int arg1, String arg2) {
    super(ActionEvent.ACTION_PERFORMED, arg1, "flame_001.jpg");
    // TODO Auto-generated constructor stub
}
public void actionImplemented(ActionEvent evt1) {


    JFrame nuFrame = new JFrame();
    nuFrame.setVisible(true);
    nuFrame.setBounds(0, 0, 300, 200);



    // TODO Auto-generated constructor stub
}

}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top