현재 많은 ActionListeners (각 JButton
에 대해 하나)가 정의되어 있고 약 60 개의 버튼이있는 일부 Java 코드를 작성하고 있습니다. 이들은 모두 JButton.addActionListener
메서드에서 익명 내부 클래스로 정의됩니다. 나는 코드를 더 깔끔하게 보이게하기 위해 이것을 리팩토링하는 방법을 생각해 보았다. 필자는 청취자를 반환하는 정적 클래스의로드가있는 별도의 클래스로 리스너를 가져갈 수 있다고 생각했습니다. 이는 코드가 addActionListener(GetActionListener.addActionListener())
과 같은 모양을 갖게됨을 의미합니다. 이것이 이것이 더 깔끔하게 만드는 동안 나는 그것이 정말로 우아한 해결책이 아니라고 느낍니다. 나는 청취자 이름 자체와 함께 KV 쌍을 지닌 정적 인 최종지도도 생각했다. 그러나 이것은 여전히 아주 우아한 해결책처럼 보이지 않습니다. 아무도 아이디어가 있다면 궁금해하던가요? 나는 또한 모든 actionListeners가 꽤 다르다고 말해야한다.여러 ActionListener 리팩토링
답변
ActionListener
을 사용하여 직접 작업을 추가하지 않는 것이 좋습니다. 이런 식으로하면 재사용 할 수 없게됩니다. 대신 귀하의 행동을 javax.swing.Action
클래스로 감싸십시오. 따라서 원하는 곳 어디에서나 작업을 재사용 할 수 있습니다. 예를 들어 복사 동작의 메뉴 바로 가기와 툴바의 복사 버튼에 대해 동일한 동작을 사용할 수 있습니다. 기본적으로 아이디어는 실행 가능한 동작을 GUI 요소와 직접 연결하는 것이 아닙니다.
이제 질문에 올 것입니다. public 메서드 public Action getAction(String)
을 사용하여 ActionRepsoitory라는 클래스에 repository of actions
을 만들 것입니다. 각 작업은 저장소에서 작업을 검색하는 데 사용하는 String 상수로 식별됩니다. 일반적으로 해당 문자열은 요소에 대해 actionCommand
이됩니다. HasMap 등을 통해 ActionRepository에서 액션을 관리하는 방법은 전적으로 당신에게 달려 있습니다.
이것은 AFAIK에서 가장 많이 사용되는 코드입니다.
Not a duplication of this question (질문에 대한 대답은 ... 과우가 아니지만) 대답이 적용되어야합니다.
내부 클래스가 외부 클래스 내부에서 메서드를 호출하는 것 이상의 기능을 수행하고 있다면 "잘못된"("올바른"이라는 정의에 따라)하고있는 것입니다. 게시 된 코드에서 increment() 및 decrement()에 대한 호출은이를 수행하는 "올바른"방법입니다. 코드를 리팩토링하면 리스너가 메서드 호출을 외부 클래스로 전달하여 코드를 더 쉽게 관리 할 수 있습니다.
UI에서 60 개의 버튼이 표시됩니다. 정말! 아야! 그것들은 모두 한 화면에 있습니까? 아니면 탭이나 다른 것으로 끝났습니까? (그것이 탭이거나 뭔가 대답할만한 것이 있다면).
다양한 창에 걸쳐 있습니다. 나는 그가 버튼으로 메뉴 아이템을 포함하고 있다고 생각한다. (저는 같은 프로젝트에서 일하고 있습니다.) –
그래서 한 클래스가 모든 청취자를 처리합니까? – TofuBeer
reflection을 사용하여 주어진 메소드 이름을 호출하는 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
다음 방법 중 하나가 누락 된 경우
button1.addActionListener(call("methodName1"));
button2.addActionListener(call("methodName2"));
button3.addActionListener(call("methodName3"));
button4.addActionListener(call("methodName4"));
button5.addActionListener(call("methodName5"));
을 다음과 같이
private call(String name) {
return new MethodAsActionListener(this, name);
}
는 다음 프로그램이 것, 당신의 행동을 추가 할 수 있습니다 클래스 UI가 빌드 될 때 실패합니다 (액션 리스너가 생성 될 때 메소드를 조회하기 때문에). 컴파일 시간만큼 좋지는 않지만, 액션이 트리거 될 때 완전히 늦은 시각보다 나은 것입니다.
나는 당신이 제안한 것과 비슷한 것을 권하고 싶다 - 모든 이벤트를 구독하는 하나의 청취자 클래스를 만든다. 당신은 아마도 각 이벤트에 대해 클래스의 다른 인스턴스를 사용하고, 생성자의 인스턴스에이 특정 이벤트로 수행 할 작업을 알리고 싶을 것입니다.
이점은 일반적으로 꽤 비슷하기 때문에 리스너 내부의 코드를 더 적은 수의 메소드로 분해 할 수 있다는 것입니다. 때때로 당신은 그것을 하나의 방법으로 얻을 수 있습니다.
"순수한 디스패치"상황에서 사용한 메뉴 작성 방법은 메뉴, 메뉴 구조 및 각 메뉴 항목이 데이터에 링크하는 방법을 지정하는 것이 었습니다. 약간의 반사가 필요하지만 작동합니다.
사실 - 보겠습니다.
그래
, 나는 Google 문서의 클래스를 유지 :) 데이터는 다음과 같이 지정 :final static String[] menus = { "File:*", "Save:save", "Load:load", "(", "Print:-", "Preview:preview", ")", "Quit:quit" };
그냥이 구문 분석. 파일은 시작으로 인해 최상위 항목이되고, 저장은 "저장"메소드를 호출하고,로드는 "로드"메소드를 호출하고 인쇄는 하위 메뉴 (따라서 괄호)이며 그 아래의 미리보기와 인쇄는 바운드되지 않습니다 무엇이든.
이 문자열은 한 번의 호출로 전체 메뉴를 만들고 바인딩 할 수 있습니다.
놀고 싶다면 여기 my source code입니다.
맨 위에있는 "TestMenu"클래스는 buildMenus 메서드를 사용하는 방법을 보여주는 테스트 클래스입니다.
이것은 수년 전에 행해졌 다. 지금은 다르게 할 수도 있지만 작동한다. 나는 실제로 메뉴를 생성하는 것을 좋아하지 않는다. 그리고 나는 문자열 파서가 각 항목에 대해 문자열로 나누는 대신 하나의 문자열을 사용하도록 만들 것이라고 생각한다. - 각 항목이 공백으로 구분되도록 보장해야한다. 이 (당신이 전달 또는 다른 어떤 객체)에서 호출되는 저장 방법을 야기 저장 버튼을 눌러 곳
bind(this, new JButton("Save"), "save", this);
..
더 좋은 API는이 같은 바인드 방법이 될 수 있습니다. "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
}
}
- 1. Java ActionListener
- 2. ActionListener 문제
- 3. JFrame ActionListener
- 4. ActionListener 문제
- 5. GUI - actionListener 메서드
- 6. Java Simple ActionListener Questions
- 7. 중첩 된 클래스의 ActionListener
- 8. 된 ActionListener 단계는 JSF
- 9. 의 ActionListener 오류
- 10. ActionListener 이벤트 처리
- 11. 이름없는 JButton을위한 Java actionListener?
- 12. Facelets의 JSF, actionlistener
- 13. 중첩 된 자바의 ActionListener
- 14. ActionListener/actionPerformed 클래스의 스캐너 오류
- 15. Windows와 Linux 간의 ActionListener 차이점
- 16. JLabel 또는 JTable 셀의 ActionListener
- 17. ActionListener 이벤트에서 JList를 다시 채우기
- 18. 리팩토링 도구?
- 19. 리팩토링 브라우저
- 20. Ruby에서 리팩토링
- 21. 리팩토링 질문
- 22. LINQ 리팩토링
- 23. 리팩토링 도구
- 24. 세션 범위 관리 Bean 및 actionListener
- 25. 세션 변수 리팩토링
- 26. 리팩토링 SQL 스키마
- 27. C# : 리소스 파일 리팩토링
- 28. 일부 코드 리팩토링
- 29. 하위 도메인을 사용한 사용자 인증을 위해 여러 if 문 리팩토링
- 30. 전자 상거래 소프트웨어의 여러 인스턴스를 단일 코드 기반으로 리팩토링
많은 간단한 GUI에서 Action 프레임 워크를 사용하면 잔인합니다. 그러나 여기에서는 60 개 정도의 ActionListeners를 관리하려고 할 때 메뉴 나 바로 가기가없는 경우에도 리팩터링을 수행하는 것이 좋습니다. – akf
@akf ... 나는 그것에 동의해야하지만 특정 매개 변수에 따라 달라집니다 : a) 다른 장소에서 사용되는 작업 b) 유지 보수. 결정하기 전에이 두 가지 이상을 고려해야합니다. –
개인적으로 ActionListener를 일회적으로 사용하면 거의 항상 Action을 사용합니다. a) 메뉴와 툴바 + 버튼을 대화 상자에 붙이려면 b) 메뉴를 자유롭게 사용할 수 있고 모두 활성화/아이콘/이름 변경과 동기화됩니다. – PSpeed