2008-09-15 16 views
7

Đối với hầu hết GUI tôi đã sử dụng, khi điều khiển chứa văn bản lấy tiêu điểm, toàn bộ nội dung của điều khiển được chọn. Điều này có nghĩa là nếu bạn chỉ mới bắt đầu nhập, bạn hoàn toàn thay thế các nội dung cũ.Có cách nào dễ dàng để thay đổi hành vi của điều khiển Java/Swing khi nó được lấy nét không?

Ví dụ: Bạn có điều khiển xoay được khởi tạo với giá trị bằng không. Bạn tab vào nó và gõ "1" Giá trị trong điều khiển bây giờ là 1.

Với Swing, điều này không xảy ra. Văn bản trong điều khiển không được chọn và carat xuất hiện ở đầu này hoặc phần khác của văn bản hiện tại. Tiếp tục ví dụ trên:

Với Swing JSpinner, khi bạn đặt tab vào điều khiển xoay, carat ở bên trái. Bạn nhập "1" và giá trị trong điều khiển bây giờ là 10.

Điều này khiến tôi, (và người dùng của tôi) lên tường và tôi muốn thay đổi nó. Thậm chí quan trọng hơn, tôi muốn thay đổi nó trên toàn cầu để hành vi mới áp dụng cho JTextField, JPasswordField, JFormattedTextField, JTextArea, JComboBox, JSpinner, v.v. Cách duy nhất tôi đã tìm thấy để làm điều này để thêm một FocusAdapter cho mỗi điều khiển và ghi đè phương thức focusGained() để làm điều đúng [tm].

Có một cách dễ dàng hơn và ít dễ vỡ hơn. Xin vui lòng?

EDIT: Một phần thông tin bổ sung cho trường hợp cụ thể này. Biểu mẫu tôi đang làm việc được tạo ra bằng cách sử dụng trình thiết kế biểu mẫu của Idea. Điều đó có nghĩa là tôi thường không viết mã để tạo ra các thành phần. Có thể nói với Idea rằng bạn muốn tự tạo chúng, nhưng đó là một rắc rối mà tôi muốn tránh.

Phương châm: Tất cả những người lập trình giỏi về cơ bản đều lười biếng.

+0

Tôi đã tìm thấy giải pháp đáp ứng nhu cầu của mình. Nó được đăng như một câu trả lời. –

Trả lời

1

Sau khi đọc bài trả lời cho đến nay tôi đã thông qua JPanel ngoài cùng với phương pháp sau đây:

void addTextFocusSelect(JComponent component){ 
    if(component instanceof JTextComponent){ 
     component.addFocusListener(new FocusAdapter() { 
       @Override 
       public void focusGained(FocusEvent event) { 
        super.focusGained(event); 
        JTextComponent component = (JTextComponent)event.getComponent(); 
        // a trick I found on JavaRanch.com 
        // Without this, some components don't honor selectAll 
        component.setText(component.getText()); 
        component.selectAll(); 
       } 
      }); 

    } 
    else 
    { 
     for(Component child: component.getComponents()){ 
      if(child instanceof JComponent){ 
       addTextFocusSelect((JComponent) child); 
      } 
     } 
    } 
} 

Nó hoạt động!

+0

+1 cho thủ thuật 'setText (getText())'; Tôi đã tự mình làm mọi thứ khác cho bản thân mình, nhưng nó vẫn không hoạt động! –

0

Cách duy nhất tôi biết là tạo FocusListener và đính kèm nó vào thành phần của bạn. Nếu bạn muốn nó FocusListener này được toàn cầu cho tất cả các thành phần trong ứng dụng của bạn, bạn có thể xem xét sử dụng Aspect Oriented Programming (AOP). Với AOP có thể mã hóa nó một lần và áp dụng nghe tập trung của bạn cho tất cả các thành phần thuyết minh trong ứng dụng của bạn mà không cần phải sao chép và dán component.addFocusListener (listener) đang khắp ứng dụng của bạn ..

khía cạnh của bạn sẽ phải chặn việc tạo ra một JComponent (hoặc các lớp con bạn muốn thêm hành vi này vào) và thêm trình nghe tập trung vào cá thể mới được tạo ra. Cách tiếp cận AOP tốt hơn là sao chép và dán FocusListener vào toàn bộ mã của bạn bởi vì bạn giữ nó trong một đoạn mã duy nhất và không tạo ra cơn ác mộng bảo trì khi bạn quyết định thay đổi hành vi toàn cầu của mình như xóa người nghe JSpinners.

Có rất nhiều khung công tác AOP để bạn lựa chọn. Tôi thích JBossAOP vì nó là Java nguyên chất 100%, nhưng bạn có thể muốn xem AspectJ.

2

Khi tôi cần điều này trong quá khứ, tôi đã tạo các lớp con của các thành phần tôi cũng muốn thêm chức năng "tự động xóa". ví dụ:

public class AutoClearingTextField extends JTextField { 
    final FocusListener AUTO_CLEARING_LISTENER = new FocusListener(){ 
     @Override 
     public void focusLost(FocusEvent e) { 
     //onFocusLost(e); 
     } 

     @Override 
     public void focusGained(FocusEvent e) { 
     selectAll(); 
     } 
    }; 

    public AutoClearingTextField(String string) { 
     super(string); 
     addListener(); 
    } 

    private void addListener() { 
     addFocusListener(AUTO_CLEARING_LISTENER);  
    } 
} 

Vấn đề lớn nhất là tôi đã không tìm thấy một cách "tốt" để có được tất cả các nhà thầu chuẩn mà không cần viết ghi đè. Thêm chúng, và buộc một cuộc gọi đến addListener là cách tiếp cận chung nhất mà tôi đã tìm thấy.

Tùy chọn khác là xem các ContainerEvents trên vùng chứa cấp cao nhất với ContainerListeer để phát hiện sự hiện diện của các tiện ích mới và thêm trình nghe tập trung tương ứng dựa trên các tiện ích đã được thêm.(ví dụ: nếu sự kiện vùng chứa gây ra bằng cách thêm một TextField, sau đó thêm một người nghe tập trung biết cách chọn tất cả văn bản trong TextField, v.v.) Nếu một Vùng chứa được thêm vào, thì bạn cần phải đệ quy thêm ContainerListener vào vùng chứa con mới đó.

Dù bằng cách nào, bạn sẽ không cần phải muck về với người nghe tập trung trong mã UI thực tế của bạn - tất cả sẽ được chăm sóc ở cấp độ cao hơn.

2

Tôi đã không cố gắng này bản thân mình (chỉ dabbled trong nó một thời gian trước), nhưng có thể bạn có thể nhận được các thành phần tập trung hiện tại bằng cách sử dụng: KeyboardFocusManager (có một phương pháp tĩnh getCurrentKeyboardFocusManager()) một thêm một PropertyChangeListener cho nó. Từ đó, bạn có thể tìm hiểu xem thành phần có phải là JTextComponent hay không và chọn tất cả văn bản.

+0

+1 Theo kinh nghiệm của tôi, đây là giải pháp tốt nhất nếu bạn có nhiều điều khiển và/hoặc sử dụng trình thiết kế biểu mẫu trực quan. –

2

Một lớp riêng biệt gắn một FocusListener vào trường văn bản mong muốn có thể được viết. Tất cả người nghe tập trung sẽ làm là gọi selectAll() trên tiện ích văn bản khi nó tăng tiêu điểm.

public class SelectAllListener implements FocusListener { 
    private static INSTANCE = new SelectAllListener(); 

    public void focusLost(FocusEvent e) { } 

    public void focusGained(FocusEvent e) { 
    if (e.getSource() instanceof JTextComponent) { 
     ((JTextComponent)e.getSource()).selectAll(); 
    } 
    }; 

    public static void addSelectAllListener(JTextComponent tc) { 
    tc.addFocusListener(INSTANCE); 
    } 

    public static void removeSelectAllListener(JTextComponent tc) { 
    tc.removeFocusListener(INSTANCE); 
    } 
} 

Bằng việc chấp nhận một JTextComponent như một cuộc tranh cãi hành vi này có thể được bổ sung vào JTextArea, JPasswordField, và tất cả các thành phần soạn thảo văn bản khác trực tiếp. Điều này cũng cho phép lớp thêm tất cả các hộp kết hợp có thể chỉnh sửa và JSpinners, nơi quyền kiểm soát của bạn đối với thành phần trình soạn thảo văn bản có thể bị hạn chế hơn. phương pháp tiện lợi có thể được thêm vào:

public static void addSelectAllListener(JSpinner spin) { 
    if (spin.getEditor() instanceof JTextComponent) { 
    addSelectAllListener((JTextComponent)spin.getEditor()); 
    } 
} 

public static void addSelectAllListener(JComboBox combo) { 
    JComponent editor = combo.getEditor().getEditorComponent(); 
    if (editor instanceof JTextComponent) { 
    addSelectAllListener((JTextComponent)editor); 
    } 
} 

Ngoài ra, các phương pháp loại bỏ người nghe có thể sẽ không cần thiết, vì người nghe không chứa tài liệu tham khảo bên ngoài cho bất kỳ trường hợp khác, nhưng họ có thể được thêm vào để làm cho mã đánh giá đi mượt mà hơn. (! Cảm ơn)

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