문제
전체 면책 조항 : 저는 CS 학생 이며이 질문은 최근에 지정된 Java 프로그램과 관련이 있습니다. 우리는 콘솔 작업을 수행했지만 GUI 및 SWING 또는 AWT와 함께 일한 것은 이번이 처음입니다. 우리는 텍스트와 다른 색상으로 회전하는 텍스트와 버튼이있는 창을 만든 코드가 주어졌습니다. 그런 다음 대신 색상 용 라디오 버튼을 만들기 위해 프로그램을 수정하라는 요청을 받았습니다. 이는 또한 API를 연구하는 연습을 제공하기위한 것입니다. 나는 이미 과제를 건네 주었고 강사로부터 내 코드를 여기에 게시하도록 허가를 받았습니다.
Java에서 버튼 작업을 구현하는 가장 좋은 방법은 무엇입니까? 약간의 충격을받은 후, 나는 다음과 같은 버튼을 만들었습니다.
class HelloComponent3 extends JComponent
implements MouseMotionListener, ActionListener
{
int messageX = 75, messageY= 175;
String theMessage;
String redString = "red", blueString = "blue", greenString = "green";
String magentaString = "magenta", blackString = "black", resetString = "reset";
JButton resetButton;
JRadioButton redButton, blueButton, greenButton, magentaButton, blackButton;
ButtonGroup colorButtons;
public HelloComponent3(String message) {
theMessage = message;
//intialize the reset button
resetButton = new JButton("Reset");
resetButton.setActionCommand(resetString);
resetButton.addActionListener(this);
//intialize our radio buttons with actions and labels
redButton = new JRadioButton("Red");
redButton.setActionCommand(redString);
...
추가 액션 리스너 ...
redButton.addActionListener(this);
blueButton.addActionListener(this);
...
ActionPerformed 메소드를 위해 이미 사용하여 사용 방법에 대한 아이디어를 제공했지만 템플릿에 단일 버튼 만 있었기 때문에 여러 버튼을 구현하는 방법이 명확하지 않았습니다. 문자열을 켜고 시도했지만 문자열이 원시 유형이 아니기 때문에 스위치 문에 사용할 수 없다는 것을 빨리 깨달았습니다. 나는 if-else 체인으로 즉흥적으로 만들 수 있었지만 이것이 대신 내가 생각한 것입니다. 우아하지 않은 것처럼 보이며 더 나은 방법이 있어야합니다. 있다면 무엇입니까? 문자열을 켜는 방법이 있습니까? 아니면보다 확장 가능한 방식으로 행동을 선택 하시겠습니까?
public void actionPerformed(ActionEvent e){
if (e.getActionCommand().equals(resetString)) {
messageX = 75; messageY = 175;
setForeground(Color.black);
blackButton.setSelected(true);
repaint();
return;
}
if ( e.getActionCommand().equals(redString) ) {
setForeground(Color.red);
repaint();
return;
}
if ( e.getActionCommand().equals(blueString) ) {
setForeground(Color.blue);
repaint();
return;
}
if ( e.getActionCommand().equals(greenString) ) {
setForeground(Color.green);
repaint();
return;
}
if ( e.getActionCommand().equals(magentaString) ) {
setForeground(Color.magenta);
repaint();
return;
}
if ( e.getActionCommand().equals(blackString) ) {
setForeground(Color.black);
repaint();
return;
}
}
해결책
이것을 쓰는 대신 :
resetButton.addActionListener(this);
당신은 또한 이것을 쓸 수 있습니다 :
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
resetButtonActionPerformed(evt);
}
});
그리고 모든 작업에 대해 하나의 큰 ActionPerformed ()를 작성하는 대신 다음을 작성할 수 있습니다.
public void resetButtonActionPerformed(ActionEvent evt) {
messageX = 75; messageY = 175;
setForeground(Color.black);
blackButton.setSelected(true);
repaint();
}
이것이 가장 우아한 솔루션인지는 모르겠지만, 적어도 더 이상 크게 구성되지 않습니다.
다른 팁
두 가지 대체 접근법 :
- 액션 인터페이스를 구현하고 색상을 설정하는 actionperformed 메소드가있는 새 클래스를 만듭니다.
- Mantain 명령 이름에서 색상 인스턴스로의 해시 맵 및지도에서 명령 이름을 찾으십시오.
충분한 접근법 중 하나는 선언하는 것입니다 요소가 당신의 줄과 일치하는 열거 그리고 (str)의 가치를 켜십시오 (링크 된 예제는 상당한 양의 안전으로이를 수행하는 방법을 보여줍니다).
익명의 내부 클래스를 피하는 이유는 아마도 최상의 솔루션 일지라도 클래스에 해당 구성이 아직 없었기 때문일 수 있습니다.
이미 제안 된 바와 같이, 익명의 내부 클래스를 사용하여 ActionListener 인터페이스를 구현할 수 있습니다. 대안으로 익명의 내부 클래스를 사용할 필요는 없지만 대신 간단한 중첩 클래스를 사용할 수 있습니다.
resetButton = new JButton(new ResetAction());
redButton = new JButton(new ColorAction("Red", Color.red));
그리고...
private class ResetAction extends AbstractAction {
public ResetAction() {
super("Reset");
}
public void actionPerformed(ActionEvent e) {
messageX = 75; messageY = 175;
setForeground(Color.black);
blackButton.setSelected(true);
repaint();
}
}
private class ResetAction extends AbstractAction {
private Color color;
public ColorAction(String title, Color color) {
super(title);
this.color = color;
}
public void actionPerformed(ActionEvent e) {
setForeground(color);
repaint();
}
}
이 접근법 또는 내부 클래스와 관련된 접근 방식이 외부 클래스에서 ActionListener를 구현하는 것보다 낫습니다. "디자인 패턴"을 참조하십시오.
"호의적 인 객체 구성 '오버'클래스 상속 '." (1995 년 4 월 4 일 : 20)
익명의 내부 클래스 와이 명명 된 내부 클래스 중에서 선택하는 것은 대부분 스타일의 문제이지만,이 버전은 이해하기 쉽고 많은 행동이있을 때 더 명확하다고 생각합니다.
에르. 하나의 메가 클래스에서 관련없는 인터페이스를 구현하지 마십시오. 대신, 무성한 내부 클래스를 사용하십시오. 그것들은 약간의 장점이지만 당신이 원하는 것입니다. 각 이벤트마다 하나를 사용하면 큰 if-else 체인이 필요하지 않습니다. 내부 클래스 내에 충분한 코드를 유지하여 이벤트를 디코딩하고 대상 객체에 맞는 메소드를 호출하는 것이 좋습니다. 또한 내부 클래스를 매개 변수화 할 수 있습니다. 아마도 실제 위젯에 대한 참조를 유지할 필요가 없을 것입니다.
당신의 예에서 당신은 jcomponent를 jpanel로 사용하는 것 같습니다. 차이는 많지 않지만 위젯 블록을 수집하기 위해 JPanel을 사용하십시오. 또한 서브 클래스가 필요하지 않으므로하지 마십시오.
예를 들어 :
addColorButton("Green" , Color.GREEN );
addColorButton("Red" , Color.RED );
addColorButton("Yellow", Color.YELLOW);
addColorButton("Blue" , Color.BLUE );
...
private void addColorButton(String label, Color color) {
JRadioButton button = new JRadioButton(label);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
target.setForeground(color);
target.repaint();
}
});
colorGroup.add(button);
panel.add(button);
}