2011-08-29 35 views
7

Tôi đang tạo trình chỉnh sửa cấp cho trò chơi của mình. Tôi có một bảng điều khiển thuộc tính, nơi tôi có thể sửa đổi đối tượng đã chọn thuộc tính của nó. Tôi cũng có một nút Lưu để viết cấp xml.Java Swing: Tập trung vấn đề

Một lĩnh vực chỉnh sửa được gửi (*) khi các thành phần biên tập mất tập trung hoặc Nhập được nhấn. Đây là hoạt động rất tốt, nhưng vấn đề duy nhất là khi tôi có chuỗi hành động này:

  1. Sửa một lĩnh vực
  2. Nhấn nút lưu

Bởi vì, những gì sẽ xảy ra đây là:

  1. tôi sửa ruộng
  2. tôi nhấn vào nút lưu
  3. các le vel được lưu
  4. Các lĩnh vực bị mất trọng tâm
  5. Tóm lược sửa đổi được gửi

Như bạn có thể thấy, đây là thứ tự sai. Tất nhiên tôi muốn lĩnh vực mất tập trung của nó, gây ra trình và sau đó lưu mức.

Có mẹo, hack hoặc giải pháp để làm cho trường đầu tiên mất tập trung và sau đó thực hiện trình xử lý tác vụ của nút lưu không?

Xin cảm ơn trước.

(* nộp = chỉnh sửa để lĩnh vực này cũng được thực hiện trong các đối tượng sở hữu)


EDIT: Đối với lĩnh vực này tôi đang sử dụng một FocusAdapter với focusLost:

FocusAdapter focusAdapter = new FocusAdapter() 
{ 

    @Override 
    public void focusLost(FocusEvent e) 
    { 
     compProperties.setProperty(i, getColor()); 
     record(); // For undo-redo mechanism 
    } 
}; 

Và cho nút một đơn giản ActionListener với actionPerformed`.

btnSave.addActionListener(new java.awt.event.ActionListener() { 
    public void actionPerformed(java.awt.event.ActionEvent evt) { 
     // Save the level 
    } 
}); 
+1

không biết mã của bạn hoạt động như thế nào, vui lòng đăng mã có liên quan ở đây, vì có một tùy chọn khác bằng cách sử dụng 'DocumentListener' hoặc bằng cách sử dụng' AncesorListener' hoặc chỉ đưa bạn 'FocucHell' vào' invokeLater' với 'myTextField.setText (myTextField.getText); ' – mKorbel

+0

@mKorbel: Tôi đã thử gói quá trình lưu vào một' invokeLater', nhưng nó vẫn theo thứ tự sai. –

+1

Xem thêm [Hỏi & Đáp] này (http://stackoverflow.com/questions/6803976/focusevent-doesnt-get-the-last-value-of-jformattedtextfield-how-i-can-get-it/6804749#6804749) . – trashgod

Trả lời

3

Hmm ... không thể tái tạo: trong đoạn mã dưới mất luôn thông báo trước khi actionPerfomed, độc lập về việc liệu tôi bấm vào nút hoặc sử dụng ghi nhớ:

final JTextField field = new JTextField("some text to change"); 
    FocusAdapter focus = new FocusAdapter() { 

     @Override 
     public void focusLost(FocusEvent e) { 
      LOG.info("lost: " + field.getText()); 
     } 

    }; 
    field.addFocusListener(focus); 

    Action save = new AbstractAction("save") { 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      LOG.info("save: " + field.getText()); 
     } 
    }; 
    save.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_S); 
    JButton button = new JButton(save); 
    JComponent box = Box.createHorizontalBox(); 
    box.add(field); 
    box.add(button); 

Trên Mặt khác, tập trung là một tài sản phức tạp để dựa vào, thứ tự có thể phụ thuộc vào hệ thống (tôi là win vista). Kiểm tra cách đoạn mã hoạt động trên máy của bạn.

  • Nếu bạn thấy trình tự giống như tôi làm, vấn đề là ở một nơi khác
  • nếu bạn nhận được lưu trước khi mất, cố gắng quấn hành động tiết kiệm vào invokeLater (trong đó đặt nó ở cuối của EventQueue, vì vậy nó được thực hiện sau khi tất cả các sự kiện cấp phát)

    Action save = new AbstractAction("save") { 
    
        @Override 
        public void actionPerformed(ActionEvent e) { 
         SwingUtilities.invokeLater(new Runnable() { 
          public void run() { 
           LOG.info("save: " + field.getText()); 
          } 
         }); 
        } 
    }; 
    
+0

'vấn đề là một nơi khác' bởi OP của tôi thêm I/O suối 1) loại bỏ Focus & ActionListener bên trong javax.swing.Action 2) chuyển hướng I/O Streams đến Runnable # thread, 3) tất cả được thực hiện sau đó thêm Focus & ActionListener trở lại, 4) cùng một cách mà hoạt động nếu tôi trì hoãn rằng trong hai bước mỗi thành hai invokeLater(), 5) dealyed Sự kiện từ ActionListener bằng cách sử dụng javax.swi ng.Timer & javax.swing.Action, 6) trông giống như Action có chút khác biệt với ActionListener 7) tất cả về việc di chuyển Focus từ JButton đến JTexfield được gói vào invokeLater() +1 – mKorbel

0

Thông thường, gói tiết kiệm của bạn mã vào một SwingUtilities.invokeLater() nên làm các trick. Như bạn đã đề cập, điều này không hoạt động? Hãy thử điều này:

private boolean editFocus = false; 
FocusAdapter focusAdapter = new FocusAdapter() 
{ 
    @Override 
    public void focusGained(FocusEvent e){ 
     editFocus = true; 
    } 
    @Override 
    public void focusLost(FocusEvent e){ 
     compProperties.setProperty(i, getColor()); 
     record(); // For undo-redo mechanism 
     editFocus = false; 
     if (saveRequested){ 
      save();    
     } 
    } 
}; 

và cho nút bấm của bạn:

private boolean saveRequested = false; 

btnSave.addActionListener(new java.awt.event.ActionListener() { 
    public void actionPerformed(java.awt.event.ActionEvent evt) { 
     if (editFocus){ 
      saveRequested = true; 
      return; 
     } else { 
      save(); 
     } 
    } 
}); 

và sau đó bạn phương pháp tiết kiệm:

private void save(){ 
    // do your saving work 
    saveRequested = false; 
} 

này chỉ hoạt động khi focusLost của bạn được gọi sau khi hành động của nút bấm của bạn. Nếu đột nhiên thứ tự là chính xác, mã này sẽ nhận được lưu() được gọi là hai lần.

Nhưng một lần nữa, việc gói mã lưu() trong cách tiếp cận ban đầu của bạn sẽ hoạt động, vì mã lưu sẽ thực thi sau khi xử lý tất cả các sự kiện. Đó là sau khi xử lý nhấp vào nút của bạn và các sự kiện focusLost của bạn. Bởi vì mã focusLost của bạn thực thi ngay lập tức (nó không được bao bọc trong một invokeLater()), nên mã focusLost phải được thực hiện luôn trước mã lưu của bạn. Điều này không có nghĩa là thứ tự sự kiện sẽ chính xác! Nhưng mã liên quan đến các sự kiện sẽ được thực thi theo thứ tự đúng.

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