2013-04-26 41 views
8

Tôi đang nhúng JFileChooser vào chương trình của mình trong khung của riêng tôi với các thành phần tùy chỉnh khác trong khung. Dưới đây là một thiết kế của ứng dụng của tôi vì nó có thể giúp hình dung vấn đề của tôi:Làm cách nào để xóa hành động Ctrl + C trên JFileChooser?

How I'm using JFileChooser

Nếu bạn không thể nói, danh sách trực thuộc JFrame tiêu đề là JFileChoosers. Cách này được cho là hoạt động là bạn gán phím tắt cho các đích và sau đó khi bạn bấm các phím tắt đó, tập tin được chọn sẽ di chuyển đến đích.

Chiến lược của tôi để thực hiện việc này là gán lối tắt cho phạm vi javax.swing.JComponent.WHEN_IN_FOCUSED_WINDOW của InputMap toàn bộ khung.

Nhưng những gì gây phiền nhiễu là một cái gì đó (tôi giả định JFileChooser) tiếp tục đáp ứng/hấp thụ các phím bấm mà tôi không muốn. Ví dụ: nếu tôi nhấn Ctrl+C thao tác phím tắt của tôi sẽ không chạy. Tôi đã thử điều này với cái nhìn và cảm nhận bản địa (Tôi đang sử dụng windows 7) và mặc định L & F và cả hai tình huống đều có cùng một vấn đề. Tôi nghĩ rằng nó có thể là cố gắng để làm một hành động sao chép của tập tin được chọn trong JFileChooser bởi vì nếu tôi bấm vào một trong các nút để buộc nó để mất tập trung, tất cả các bất ngờ của tôi Ctrl+C lệnh nào hành động của tôi.

Nhưng, tôi không thực sự chắc chắn cách thức JFileChooser đang thực hiện việc này. Khi tôi gọi getKeyListeners() trên đó, nó sẽ trả về một mảng trống. Tôi cũng đã thử xóa bản đồ đầu vào của nó cho sự kết hợp quan trọng này ở cả ba phạm vi, và nó vẫn có vẻ hấp thụ phím bấm.

Có ai có thể cho tôi một số mã mẫu làm cho số JFileChooser bỏ qua Ctrl+C không? Ngoài ra, sẽ rất hữu ích nếu ai đó có thể cho tôi biết cách gỡ lỗi các vấn đề như thế này trong tương lai.


Dưới đây là một số mã về những gì tôi đã thử cho đến nay. Bạn cũng có thể sử dụng điều này để cố gắng kiểm tra điều này một mình, kể từ khi mã này biên dịch và chạy, như-là:

package com.sandbox; 

import javax.swing.*; 
import java.awt.event.ActionEvent; 

public class Sandbox { 

    public static void main(String[] args) { 
     JFrame frame = new JFrame(); 
     JPanel panel = new JPanel(); 
     panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("control C"), "println"); 
     panel.getActionMap().put("println", new AbstractAction() { 
      public void actionPerformed(ActionEvent e) { 
       System.out.println("The JPanel action was performed!"); 
      } 
     }); 

     panel.add(buildFileChooser()); //if you comment out this line, Ctrl+C does a println, otherwise my action is ignored. 

     frame.setContentPane(panel); 

     frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    private static JFileChooser buildFileChooser() { 
     JFileChooser fileChooser = new JFileChooser();   
     fileChooser.getActionMap().clear(); //I've tried lots of ideas like this, but the JFileChooser still responds to Ctrl+C 
     return fileChooser; 
    } 
} 

CẬP NHẬT: Tôi đã đi xa như để đệ quy xóa inputMaps và loại bỏ các keyListeners của JFileChooser và tất cả các thành phần con của nó và JFileChooser vẫn còn nuốt lệnh Ctrl + C của tôi. Đây là mã tôi đã sử dụng để thực hiện việc này (tôi đã chuyển JFileChooser của tôi vào đây):

private static void removeKeyboardReactors(JComponent root) { 
    System.out.println("I'm going to clear the inputMap of: " + root); 
    root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).clear(); 
    root.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).clear(); 
    root.getInputMap(JComponent.WHEN_FOCUSED).clear(); 
    root.getActionMap().clear(); 

    if (root.getRootPane() != null) { 
     removeKeyboardReactors(root.getRootPane()); 
    } 

    for (KeyListener keyListener : root.getKeyListeners()) { 
     root.removeKeyListener(keyListener); 
    } 

    for (Component component : root.getComponents()) { 
     if (component instanceof JComponent) { 
      removeKeyboardReactors((JComponent) component); 
     } else if (component instanceof Container) { 
      Container container = (Container) component; 
      for (Component containerComponent : container.getComponents()) { 
       if (containerComponent instanceof JComponent) { 
        removeKeyboardReactors((JComponent) containerComponent); 
       } else { 
        System.out.println("This Container Component was not a JComponent: " + containerComponent); 
       } 
      } 
     } else { 
      System.out.println("This was not a JComponent: " + component); 
     } 
    } 
} 
+0

Không chắc lý do tại sao bạn yêu cầu tôi giúp đỡ đây. Bạn có câu trả lời. Ctrl C không hoạt động mọi lúc bởi vì các thành phần như JTextField và JList ánh xạ những ràng buộc khóa này. Bạn đã xóa ràng buộc này khỏi tất cả các thành phần trên trình chọn tệp để mã của bạn sẽ hoạt động ngay bây giờ. Tất nhiên vấn đề với giải pháp này là sẽ xóa chức năng Ctrl + C khỏi tất cả các thành phần trong ứng dụng của bạn, không chỉ các thành phần trên trình chọn tệp. Tôi không biết giải pháp nào khác. – camickr

+0

@camickr Để cụ thể, tôi đã liên kết bạn với nhận xét tôi đã đưa ra cho câu trả lời tôi nhận được. "Tôi tìm thấy một vấn đề với điều này.Nếu bạn chuyển nó sang chế độ xem chi tiết, hãy nhấp vào một tệp mà nó vẫn nuốt "Điều khiển C". Nhưng nếu bạn bấm vào các trường văn bản nó không phải là tốt bởi vì nó được sử dụng để trước. Bất kỳ ý tưởng gì gây ra điều đó? " –

Trả lời

4

chi tiết xem sẽ vẫn có một dân cư inputmap

tôi nghi ngờ sự khác biệt giữa xem chi tiết và xem danh sách là một trong những sử dụng một JTable kia một JList. Vì vậy, tôi đoán bạn chỉ cần loại bỏ các ràng buộc từ JTable của chế độ xem chi tiết.

Điều này có thể được thực hiện mà không cần tạo các chi tiết bảng điều khiển:

InputMap im = (InputMap)UIManager.get("Table.ancestorInputMap"); 
KeyStroke ctrlC = KeyStroke.getKeyStroke("control C"); 
//im.put(ctrlC, "none"); 
im.remove(ctrlC); 

Một lần nữa, cần lưu ý rằng giải pháp này (cùng với các giải pháp bạn đang có) sẽ loại bỏ các chức năng mặc định Ctrl + C cho tất cả các thành phần , không chỉ những cái được khởi tạo cho JFileChooser.

Edit:

nên không nó chỉ được gỡ bỏ nó từ những cái tôi loại bỏ nó từ đâu?

Mã của bạn sử dụng phương thức getParent() để lấy Bản đồ đầu vào chứa liên kết. InputMap này được chia sẻ bởi tất cả các trường hợp của một thành phần. Một thành phần sẽ chỉ có các ràng buộc duy nhất khi bạn sử dụng:

component.getInputMap(...).put(...); 

Đó là, ràng buộc được thêm vào các thành phần InputMap, không phải bố cục của nó InputMap.

Làm sao bạn biết bạn có thể làm điều này và đây là điều đúng đắn nên làm

Xem UIManager Defaults. Danh sách này mặc định cho LAF đã cho. Tôi không biết đây có phải là điều đúng hay không. Theo như tôi biết hiệu quả là giống như mã bạn sử dụng bây giờ. Đây chỉ là một cách khác hoặc loại bỏ một ràng buộc từ một InputMap mà không cần một thành phần thực tế để truy cập vào InputMap của cha mẹ.

Second chỉnh sửa:

Một số mã đơn giản để hiển thị các InputMaps đều giống nhau:

public static void main(String[] args) 
{ 
    JButton first = new JButton("button"); 
    System.out.println(first.getInputMap().getParent()); 

    InputMap im = (InputMap) UIManager.get("Button.focusInputMap"); 
    System.out.println(im); 
} 
+0

Tôi không quan tâm rằng nó sẽ xóa nó khỏi tất cả, nhưng tôi không hiểu tại sao nó xóa nó khỏi tất cả. Không phải nó chỉ được loại bỏ nó từ những cái tôi loại bỏ nó? –

+0

Câu hỏi # 2 (quan trọng hơn): Làm thế nào bạn biết bạn có thể làm điều này và đây là điều phải làm: 'InputMap im = (InputMap) UIManager.get (" Table.ancestorInputMap ");' –

+0

@tieTYT , Xem chỉnh sửa. – camickr

2

Rõ ràng InputMaps có thể có cha mẹ. Vì vậy, việc thanh lọc tất cả các "lò phản ứng" tích hợp của bạn không hoàn toàn hoàn chỉnh. Như bạn có thể đoán, Swing đăng ký một số ràng buộc bàn phím mặc định cho chính nó trên các thành phần nhất định. Trên Windows, điều này thường bao gồm Ctrl + C, vì đó là phím nóng tiêu chuẩn hệ điều hành để sao chép dữ liệu vào khay nhớ tạm.

Sửa đổi này removeKeyboardReactors nhận được System.out.println xuất hiện cho tôi:

private static void removeKeyboardReactors(JComponent root) { 
    System.out.println("I'm going to clear the inputMap of: " + root); 
    clearInputMap(root.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)); 
    clearInputMap(root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)); 
    clearInputMap(root.getInputMap(JComponent.WHEN_FOCUSED)); 

    for (KeyListener keyListener : root.getKeyListeners()) { 
     root.removeKeyListener(keyListener); 
    } 

    for (Component component : root.getComponents()) { 
     if (component instanceof JComponent) { 
      removeKeyboardReactors((JComponent) component); 
     } else if (component instanceof Container) { 
      Container container = (Container) component; 
      for (Component containerComponent : container.getComponents()) { 
       if (containerComponent instanceof JComponent) { 
        removeKeyboardReactors((JComponent) containerComponent); 
       } else { 
        System.out.println("This Container Component was not a JComponent: " + containerComponent); 
       } 
      } 
     } else { 
      System.out.println("This was not a JComponent: " + component); 
     } 
    } 
} 

private static void clearInputMap(InputMap inputMap) { 
    inputMap.clear(); 
    while ((inputMap = inputMap.getParent()) != null) { 
     inputMap.clear(); 
    } 
} 

tôi phải loại bỏ mã này từ removeKeyboardReactors bởi vì nó đã gây ra một stack overflow:

if (root.getRootPane() != null) { 
    removeKeyboardReactors(root.getRootPane()); 
} 

Toàn bộ lớp Sandbox sửa đổi sau dưới đây. Hy vọng rằng điều này là đủ để giúp bạn trên con đường của bạn. Nếu bạn muốn xóa khóa ràng buộc cụ thể hơn, hãy xem InputMap#remove(KeyStroke).

public class Sandbox 
{ 

    public static void main(String[] args) 
    { 
     JFrame frame = new JFrame(); 
     JPanel panel = new JPanel(); 
     panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("control C"), "println"); 
     panel.getActionMap().put("println", new AbstractAction() 
     { 
      public void actionPerformed(ActionEvent e) 
      { 
       System.out.println("The JPanel action was performed!"); 
      } 
     }); 

     JFileChooser fileChooser = buildFileChooser(); 
     panel.add(fileChooser); //if you comment out this line, Ctrl+C does a println, otherwise my action is ignored. 

     frame.setContentPane(panel); 

     frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
     frame.pack(); 

     removeKeyboardReactors(fileChooser); 

     frame.setVisible(true); 
    } 

    private static JFileChooser buildFileChooser() 
    { 
     JFileChooser fileChooser = new JFileChooser(); 
     fileChooser.getActionMap().clear(); //I've tried lots of ideas like this, but the JFileChooser still responds to Ctrl+C 
     return fileChooser; 
    } 

    private static void clearInputMap(InputMap inputMap) 
    { 
     inputMap.clear(); 
     while ((inputMap = inputMap.getParent()) != null) 
     { 
      inputMap.clear(); 
     } 
    } 

    private static void removeKeyboardReactors(JComponent root) { 
     System.out.println("I'm going to clear the inputMap of: " + root); 
     clearInputMap(root.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)); 
     clearInputMap(root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)); 
     clearInputMap(root.getInputMap(JComponent.WHEN_FOCUSED)); 

     for (KeyListener keyListener : root.getKeyListeners()) { 
      root.removeKeyListener(keyListener); 
     } 

     for (Component component : root.getComponents()) { 
      if (component instanceof JComponent) { 
       removeKeyboardReactors((JComponent) component); 
      } else if (component instanceof Container) { 
       Container container = (Container) component; 
       for (Component containerComponent : container.getComponents()) { 
        if (containerComponent instanceof JComponent) { 
         removeKeyboardReactors((JComponent) containerComponent); 
        } else { 
         System.out.println("This Container Component was not a JComponent: " + containerComponent); 
        } 
       } 
      } else { 
       System.out.println("This was not a JComponent: " + component); 
      } 
     } 
    } 
} 
+0

Tôi sẽ cố gắng này ra sớm, cảm ơn cho câu trả lời.Bạn có bất cứ lời khuyên về cách gỡ lỗi các loại vấn đề trong tương lai? EG: là có một số cách để bật" swing gỡ lỗi " để tôi có thể thấy thông báo tường trình cho biết "Ctrl + C đã được xử lý bởi hành động X trong inputmap Y" –

+0

Tôi đã tìm thấy sự cố với điều này. Nếu bạn chuyển sang chế độ xem chi tiết, hãy nhấp vào tệp vẫn nuốt "Điều khiển C ". Nhưng nếu bạn click vào textfield nó không được tốt bởi vì nó được sử dụng để trước.Bất cứ ý tưởng gì gây ra điều đó? –

+0

Rõ ràng JFileChooser có một FilePane. Đối tượng này có một JPanel (hoặc một cái gì đó) để hiển thị hiện tại view và getComponents sẽ chỉ trả về hiện đang được hiển thị, điều đó có nghĩa là nếu bạn xóa inputMap và THEN chuyển sang khung nhìn chi tiết, khung nhìn chi tiết sẽ vẫn có một inputmap được điền vào. trong mỗi t hen quay trở lại nơi bạn đang ở, nhưng tôi nghĩ rằng đó là hacky. –