2009-08-24 28 views
8

Thông thường khi tôi tạo ứng dụng Swing (hoặc bất kỳ giao diện người dùng) nào, tôi có nhiều Hành động khác nhau xuất hiện trên các mục và nút menu. Tôi thường tạo một đăng ký hành động và lưu trữ các hành động trong đó và sau đó khi một số điều xảy ra, tôi vô hiệu hóa/kích hoạt các hành động trong registry dựa trên trạng thái của ứng dụng. Tôi sẽ không gọi bản thân mình là một nhà phát triển Swing khao khát, mặc dù tôi biết cách của tôi xung quanh nó đủ tốt, nhưng đây có phải là một mô hình khá điển hình để quản lý Hành động không? Hoặc là có một cách tiêu chuẩn hơn để làm điều đó?Quản lý các hành động Swing với Registry

cảm ơn,

Jeff

Trả lời

10

Jeff, cách tiếp cận của bạn có vẻ như là một cách tiếp cận tốt. Tôi làm điều tương tự. Tôi gọi ActionHandler registry và nó trông như thế này:

import com.google.common.collect.ClassToInstanceMap; 
import com.google.common.collect.ImmutableClassToInstanceMap; 

import javax.swing.*; 
import javax.swing.text.DefaultEditorKit; 

public class ActionHandler { 

    private static final ClassToInstanceMap<Action> actionMap = 
      new ImmutableClassToInstanceMap.Builder<Action>(). 
        put(DefaultEditorKit.CutAction.class, new DefaultEditorKit.CutAction()). 
        put(DefaultEditorKit.CopyAction.class, new DefaultEditorKit.CopyAction()). 
        put(DefaultEditorKit.PasteAction.class, new DefaultEditorKit.PasteAction()). 
        put(RefreshAction.class, new RefreshAction()). 
        put(MinimizeAction.class, new MinimizeAction()). 
        put(ZoomAction.class, new ZoomAction()). 
        build(); 

    public static Action getActionFor(Class<? extends Action> actionClasss) { 
     return actionMap.getInstance(actionClasss); 
    } 
} 

Bây giờ để vô hiệu hóa, nói ZoomAction, tôi sử dụng

ActionHandler.getActionFor(ZoomAction.class).setEnabled(false); 
5

Từ kinh nghiệm của tôi, 'nhất' cách tiêu chuẩn xử lý các hành động được thực hiện trên một giao diện Swing là tạo ra ActionListener s và họ đã xử lý ActionEvent s trực tiếp cho các thành phần mà họ đã đăng ký. Nó là một thiết kế đơn giản và nó theo quy ước với các loại sự kiện GUI khác trong khung Swing (MouseListener/MouseEvent, TableModelListener/TableModelEvent, v.v ...).

Khuôn khổ Action bạn mô tả là công cụ mạnh mẽ cho phép chia sẻ hành động giữa nhiều phương thức nhập cả hai, v.v.) Sự trừu tượng này khá tuyệt vời, nhưng Sun cảnh báo rằng nó nặng hơn một chút so với những người quan sát đơn giản. Từ số Action JavaDoc:

Lưu ý rằng triển khai hành động có xu hướng tốn nhiều quyền kiểm soát chức năng và phát sóng thay đổi tài sản. Vì lý do này, bạn nên cẩn thận để chỉ sử dụng Hành động mà lợi ích của họ là mong muốn, và sử dụng ActionListeners đơn giản ở nơi khác.

+0

Điều đó tất cả đều có ý nghĩa đó là cách tiếp cận chung mà tôi thực hiện. Tôi đoán tôi chỉ cố gắng tìm ra cách tốt nhất để quản lý các hành động khi tôi cần sử dụng chúng ... –

5

Tôi thường lấy phương pháp sau đây:

  • Đăng ký Action với bản đồ chứa Component 's hành động.
  • Xác định công khai String liên tục cho phép mã khởi động ứng dụng "kéo ra" Action từ yêu cầu Component (ví dụ: thêm số này vào JToolBar, JMenuBar, v.v.).
  • Xác định phương thức riêng tư updateActionStates() trong Component, được gọi khi người dùng thực hiện một số hành động (ví dụ: chọn N hàng từ JTable). Phương thức này cho phép/vô hiệu hóa tất cả các hành động riêng biệt dựa trên trạng thái hiện tại của Component.

Ví dụ:

public class MyPanel extends JPanel { 
    public static final String MY_ACTION_NAME = "MyAction"; 

    private final JTable myTable;  

    public MyPanel() { 
    // Create action and define behaviour. 
    this.myAction = new AbstractAction(MY_ACTION_NAME, ...); 

    // Register with component's action map. 
    getActionMap().put(myAction.getValue(Action.NAME), myAction); 

    // Optionally register keyboard shortcuts using component's input map. 
    getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(...); 

    // Create JTable and add a call to updateActionStates when the selection changes. 
    myTable = new JTable(...); 
    myTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { 
     public void valueChanged(ListSelectionEvent evt) { 
     updateActionStates(); 
     } 
    }); 
    } 

    private void updateActionStates() { 
    // Action will only be enabled if one table row is selected. 
    getActionMap.get(MY_ACTION_NAME).setEnabled(myTable.getSelectedRowCount == 1); 
    } 
} 

// Application start-up code: 

MyPanel pnl = new MyPanel(); 
JToolBar toolBar = new JToolBar(); 
// Pull out action from action map and add to toolbar. 
toolBar.add(pnl.getActionMap().get(MyPanel.MY_ACTION_NAME)); 

Ngẫu nhiên, tôi thường thích Action s để ActionListener s cho phơi bày Action s hình thành nên một phần của API Component 's của tôi. Đối với Tác vụ chỉ tồn tại trong Component (ví dụ: nút "Xóa" của hộp thoại), tôi thường sử dụng ActionListener. Tuy nhiên, tôi không đồng ý với akf về ActionListener là cách tiếp cận tiêu chuẩn nhất - Điều này có thể đúng với các GUI nhỏ hơn nhưng không phức tạp hơn các ứng dụng Swing.

0

Tôi đang sử dụng chú thích về hành động, sau đó tìm kiếm chúng phản tư.

Tidier một chút và các hành động mới được quản lý tự động.

Các vấn đề liên quan