2009-05-21 37 views
5

Gần đây tôi đã thực hiện một bài tập lập trình yêu cầu chúng tôi thực hiện trong mã một chương trình được chỉ định bởi biểu đồ UML. Tại một thời điểm, sơ đồ quy định rằng tôi đã phải tạo một JButton ẩn danh hiển thị một số (bắt đầu từ một) và giảm đi mỗi khi nó được nhấp. JButton và ActionListener của nó đều phải ẩn danh.Lớp ẩn danh Java triển khai ActionListener?

tôi đã đưa ra các giải pháp sau đây:

public static void main(String[] args) { 
    JFrame f = new JFrame("frame"); 
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    f.setSize(400, 400); 

    f.getContentPane().add(new JButton() { 

    public int counter; 

    { 
     this.counter = 1; 
     this.setBackground(Color.ORANGE); 
     this.setText(this.counter + ""); 

     this.addActionListener(new ActionListener() { 
     public void actionPerformed(ActionEvent arg0) { 
      counter --; 
      setText(counter + ""); 
     } 
     }); 

    } 
    }); 

    f.setVisible(true); 

}

này thêm vô danh JButton, sau đó thêm khác (bên trong) ActionListener nặc danh để xử lý các sự kiện và cập nhật nội dung của nút khi cần thiết. Có giải pháp nào tốt hơn không? Tôi khá chắc chắn tôi không thể tuyên bố một ẩn danh JButton implements ActionListener(), nhưng là có một cách thanh lịch hơn để đạt được cùng một kết quả?

+0

Look nơi bạn đang @ Tim – Insane

Trả lời

11

tôi thường đi một cái gì đó như thế này:

JPanel panel = new JPanel(); 
panel.add(new JButton(new AbstractAction("name of button") { 
    public void actionPerformed(ActionEvent e) { 
     //do stuff here 
    } 
})); 

AbstractAction thực hiện ActionListener vì thế này nên đáp ứng các nhiệm vụ.

Có thể thực hành không tốt để squish rất nhiều dòng mã với nhau, nhưng nếu bạn đang sử dụng để đọc nó sau đó nó có thể khá thanh lịch.

+0

này không thực sự cho phép bạn thay đổi các nút văn bản từ bên trong người nghe hành động ... Đó là một yêu cầu khá khó xử và tôi không thể nghĩ ra một cách để cải thiện những gì bạn có dy có. – Cogsy

+0

Vì vậy, tuyên bố công khai của truy cập trong JButton ẩn danh và truy cập không đủ tiêu chuẩn cho nó từ bên trong ActionListener là OK? – Tim

+0

Yup, đó là cách duy nhất bạn có thể nhận được 'xử lý' trên các trường đó. Chỉ cần nhớ rằng các trường trong lớp bên trong sẽ ẩn các trường có cùng tên được khai báo trong phạm vi bên ngoài. Hy vọng rằng trình biên dịch/IDE của bạn sẽ cảnh báo bạn một cách rõ ràng. – Cogsy

1

Tôi sẽ không làm điều gì đó như thế trong chương trình thực tế, nhưng với các yêu cầu trong nhiệm vụ của bạn, bạn khó có thể làm tốt hơn.

1

Cũng có một cách thanh lịch hơn để thực hiện điều đó.

Thật không may, đó không phải là phương pháp tiếp cận lõi Java/Swing.

Bạn có thể sử dụng SwingBuilder trong Groovy để đạt được kết quả tương tự, sử dụng cú pháp ngắn hơn một chút, ví dụ: mã giả:

button(text: '' + counter, 
     actionPerformed: {counter--; text = '' + counter + ''}, 
     constraints:BL.SOUTH) 

[http://groovy.codehaus.org/Swing+Builder][1]

sinh viên tôi sẽ không sử dụng này trong nhiệm vụ của mình, mặc dù tôi đã nhìn thấy thực sự đi chệch khỏi tiêu chuẩn và được đánh dấu xuống cho nó, nhưng ít nhất bạn có thể bao gồm nó như là một con đường có thể để điều tra thêm.

Tôi nghĩ rằng những gì bạn có hiện tại là hoàn toàn tốt mặc dù.

2

Triển khai nhiều loại thường là một ý tưởng tồi.

Rất hiếm khi cần mở rộng các lớp JComponent, mặc dù rất nhiều phần mềm và hướng dẫn không hoạt động. Một thành ngữ/hack đã đạt được mặt đất gần đây là Double Brace - một lớp chỉ là các lớp con để cung cấp cho nó một trình khởi tạo cá thể hoạt động như một câu lệnh with từ các ngôn ngữ khác.

Trong trường hợp này, các mã có liên quan có thể được viết như sau:

JButton button = new JButton(); 
button.addActionListener(new ActionListener() { 
    int counter = 1; 
    { 
     updateText(); 
    } 
    public void actionPerformed(ActionEvent arg0) { 
     --counter; 
     updateText(); 
    } 
    private void updateText() 
     setText(Integer.toString(counter)); 
    } 
}); 
f.getContentPane(button); 

Nếu nó trở nên phức tạp hơn, sau đó có thể bạn sẽ muốn thực hiện một lớp bên ngoài (mà không thực hiện ActionListener hoặc mở rộng JButton) để xử lý dữ liệu.

Cũng lưu ý, bạn nên sử dụng bản mẫu boiler EventQueue.invokeLater để đảm bảo rằng các thành phần Swing chỉ được sử dụng trên EDT AWT.

+2

updateText sẽ không hoạt động với chỉ setText - Tôi nghĩ bạn cần button.setText hoặc để lồng vào bên trong một lớp con ẩn danh mới của JButton. Ngoài ra, f.getContentPane không nhận bất kỳ đối số nào, tôi nghĩ bạn có nghĩa là f.getContentPane.add (nút). –

+0

+1 không mở rộng JButton vì lý do cấu hình – kleopatra

4

Đó là khá xấu xí, nhưng bạn có thể làm như sau bằng cách sử dụng phương pháp ActionListener và một lớp vô danh:

f.getContentPane().add(new JButton(new AbstractAction("name of button") { 
     private int counter = 0; 

     public void actionPerformed(ActionEvent e) { 
      ((JButton) e.getSource()).setText(Integer.toString(counter--)); 
     } 
    }) { 
     { 
      setText("1"); 
     } 
    }); 

Để làm cho nó dễ dàng hơn để truy cập truy cập bạn có thể di chuyển nó ra đến cấp cao nhất của lớp học của bạn và truy cập nó từ cả hai nơi setText được gọi.

+0

+1. Nó có thể là 'xấu' (từ của bạn, không phải của tôi), nhưng tôi thấy nó dễ hiểu hơn so với mã được cung cấp trong câu hỏi. Tôi đoán câu hỏi duy nhất là liệu nó có đáp ứng được các tiêu chí rằng 'The JButton và ActionListener của nó đều phải là ẩn danh'. AbstractAction thực hiện ActionListener, nhưng người hướng dẫn có thể cảm thấy rằng các tiêu chí không được đáp ứng. –

0

Đây là một trong những nhiệm vụ xấu thực hành buộc phải làm bài tập về nhà trong điều duy nhất ;-) Xấu:

  • sử dụng ActionListener thay vì hành động đó là xấu trong bản thân
  • như một hệ quả, xác định phạm vi các vấn đề bong bóng lên
    • phạm vi truy cập của rộng hơn mức cần thiết
    • cần truy cập vào nút bên trong actionPerformed (thông qua loại đúc hoặc truy cập vào api xung quanh đối tượng)
  • đọc (aka: unmaintainable) mã

Nhưng, sau đó .. chúng ta không thể cưỡng lại, chúng ta có thể ;-) Dưới đây là một phiên bản sử dụng hành động đó là sạch (hoặc vì vậy tôi nghĩ) là để là người đầu tiên hai vấn đề, không thể đọc được như tất cả các ví dụ khác (và tôi đã lừa dối, tất nhiên: đầu tiên thực hiện các lớp học vô danh, sau đó để cho các IDE làm inline

f.add(new JButton(new AbstractAction() { 

     int counter = 1; 
     { // constructor block of action 
      updateName(); 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      counter--; 
      updateName(); 
     } 

     private void updateName() { 
      putValue(Action.NAME, "" + counter); 
     } 

    }) { // subclass button 
      { // constructor block button 
      setBackground(Color.PINK); 
     }} 
    ); 
Các vấn đề liên quan