2013-04-26 18 views
8

Ich bin ein JFileChooser in meinem Programm in meinem eigenen Rahmen mit anderen benutzerdefinierten Komponenten in den Rahmen eingebettet. Ist hier ein Entwurf von meiner app, wie es helfen kann, meine Probleme zu visualisieren:Wie entfernen Sie die Aktion Strg + C auf einem JFileChooser?

How I'm using JFileChooser

Wenn Sie nicht sagen können, die Listen direkt unter den JFrame Titel sind JFileChoosers. Die Art und Weise, wie dies funktionieren soll, ist, dass Sie Verknüpfungen zu Zielen zuweisen, und wenn Sie dann diese Tastenkombinationen drücken, bewegt sich die ausgewählte Datei zum Ziel.

Meine Strategie dafür ist, die Verknüpfung zu einem javax.swing.JComponent.WHEN_IN_FOCUSED_WINDOW Bereich der InputMap des gesamten Rahmens zuweisen.

Aber was ist ärgerlich ist, dass etwas (ich gehe davon aus, dass JFileChooser) reagiert/absorbieren Tasten drücken Ich will es nicht. Wenn ich beispielsweise Ctrl+C drücke, wird meine Verknüpfungsaktion nicht ausgeführt. Ich habe dies mit dem nativen Look and Feel (ich benutze Windows 7) und der Standard L & F und beide Situationen haben das gleiche Problem. Ich denke, es könnte versuchen, eine Kopieraktion der ausgewählten Datei in der JFileChooser zu tun, weil, wenn ich auf eine der Schaltflächen klicken, um es den Fokus zu verlieren, plötzlich mein Ctrl+C Befehl meine Aktion.

Aber ich bin nicht wirklich sicher, wie die JFileChooser dies tut. Wenn ich getKeyListeners() darauf anrufe, wird ein leeres Array zurückgegeben. Ich habe auch versucht, seine Eingabekarte für diese Tastenkombination in allen drei Bereichen zu löschen, und es scheint immer noch den Tastendruck zu absorbieren.

Kann mir jemand einen Beispielcode geben, der die JFileChooser ignoriert Ctrl+C? Es wäre auch hilfreich, wenn mir jemand sagen könnte, wie man solche Probleme in der Zukunft beheben kann.


Hier ist ein Code von dem, was ich bisher versucht habe. Sie können dies auch zu testen, diese auf eigene Faust, um zu versuchen, da dieser Code und läuft kompiliert, wie sie ist:

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; 
    } 
} 

UPDATE: Ich habe so weit gegangen, wie rekursiv die löschen inputMaps und entfernen Sie die keyListeners der JFileChooser und alle seine untergeordneten Komponenten und der JFileChooser immer noch schluckt meine Strg + C-Befehl. Hier ist der Code, den ich verwendet habe, dies zu tun (gab ich meine JFileChooser in this):

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

nicht sicher, warum Sie mich fragen, hier zu helfen. Du hast eine Antwort. Ctrl C funktioniert nicht immer, da Komponenten wie JTextField und JList diese Key Bindings zuordnen. Sie haben diese Bindung aus allen Komponenten in der Dateiauswahl entfernt, damit der Code jetzt funktioniert. Natürlich ist das Problem mit dieser Lösung, dass die Strg + C-Funktionalität von allen Komponenten in Ihrer Anwendung entfernt wird, nicht nur die Komponenten in der Dateiauswahl. Ich kenne keine andere Lösung. – camickr

+0

@camickr Um genau zu sein, habe ich dich mit einem Kommentar verbunden, den ich über die Antwort, die ich bekommen habe, gemacht habe. "Ich habe ein Problem damit gefunden.Wenn Sie es in die Detailansicht umschalten, klicken Sie auf eine Datei, die immer noch "Control C" verschluckt. Aber wenn du auf das Textfeld klickst, ist das nicht gut, weil es früher so war. Irgendeine Idee, was das verursacht? " –

Antwort

4

der Detailansicht wird noch ein inputmap

bevölkert habe ich den Verdacht, den Unterschied zwischen der Detailansicht und die Listenansicht ist, dass man eine JTable nutzt der andere ein JList. Ich nehme an, dass Sie nur die Bindungen aus der JTable der Detailansicht entfernen müssen.

Dies kann ohne die Erstellung der Detailfenster erfolgen:

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

Auch hier ist zu beachten, dass diese Lösung (zusammen mit der Lösung, die Sie zur Zeit haben) wird die Standard Strg + C-Funktionalität für alle Komponenten entfernen , nicht nur diejenigen, die für den JFileChooser instanziiert wurden.

Edit:

Sollte es nicht nur sie von denen, werden entfernt ich es von entfernen?

Ihr Code verwendet die Methode getParent(), um die InputMap abzurufen, die die Bindung enthält. Diese InputMap wird von allen Instanzen einer Komponente gemeinsam genutzt. Eine Komponente wird nur einzigartige Bindungen, wenn Sie verwenden:

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

Das heißt, die Bindung an den Komponenten InputMap hinzugefügt, nicht seine Eltern InputMap.

Woher wusstest du, können Sie dies tun, und das ist genau das Richtige

Siehe UIManager Defaults zu tun. Dies listet die Standardwerte für den gegebenen LAF auf. Ich weiß nicht, ob das richtig ist. Soweit ich weiß, ist der Effekt der gleiche wie der Code, den Sie jetzt verwenden. Dies ist nur eine andere Möglichkeit oder das Entfernen einer Bindung aus einer InputMap, ohne dass eine tatsächliche Komponente für den Zugriff auf die InputMap der Eltern benötigt wird.

Zweite edit:

Einige einfachen Code zu erhalten die InputMaps sind die gleichen:

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

Es macht mir nichts aus, dass es von allem entfernt wird, aber ich verstehe nicht, warum es es von allem entfernt. Sollte es nicht nur von denen entfernt werden, von denen ich es entferne? –

+0

Frage # 2 (die wichtigere): Woher wussten Sie, dass Sie dies tun können und das ist das Richtige: 'InputMap im = (InputMap) UIManager.get (" Table.ancestorInputMap ");' –

+0

@tieTYT , Siehe Bearbeiten. – camickr

2

Offenbar InputMaps können Eltern haben. Daher ist die Reinigung aller eingebauten Schlüssel- "Reaktoren" nicht vollständig. Wie Sie wahrscheinlich schon vermutet haben, registriert Swing bestimmte Tastaturbelegungen für bestimmte Komponenten. Unter Windows enthält dies oft Ctrl + C, da dies der OS-Standard-Hotkey zum Kopieren von Daten in die Zwischenablage ist.

Diese modifizierte removeKeyboardReactors bekommt die System.out.println für mich mit:

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(); 
    } 
} 

ich von removeKeyboardReactors diesen Code entfernen musste, weil es einen Stapelüberlauf verursacht wurde:

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

Die gesamte modifizierte Sandbox-Klasse unten folgt. Hoffentlich reicht das, um dich auf den Weg zu bringen. Wenn Sie möchten, dass das Entfernen der Schlüsselbindung key-specific ist, werfen Sie einen Blick auf 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

Ich werde das bald ausprobieren, danke für die Antwort. Hast du irgendwelche Ratschläge, wie man diese Art von Problemen in der Zukunft debuggen kann? EG: gibt es eine Möglichkeit," Swing Debugging "einzuschalten? so dass ich eine Protokollmeldung sehen konnte, dass "Strg + C wurde von X-Aktion in Inputmap Y behandelt" –

+0

Ich habe ein Problem mit diesem gefunden.Wenn Sie es in die Detailansicht wechseln dann klicken Sie auf eine Datei, die es immer noch schluckt "Control C ". Aber wenn Sie auf das Textfeld klicken, tut es nicht das was gut ist, weil es vorher verwendete. Irgendeine Idee, was das verursacht? –

+0

Anscheinend hat der JFileChooser ein FilePane. Dieses Objekt hat ein JPanel (oder etwas), um das gegenwärtige anzuzeigen view und getComponents geben nur das aktuell angezeigte on zurück, dh wenn Sie die inputMap und THEN in die details-Ansicht wechseln, wird in der details-Ansicht noch eine ausgefüllte inputmap angezeigt, die ich lösen kann, indem ich auf beide Ansichten wechsle und die Eingabe-Map lösche in jedem t Sie gehen zurück zu dem, wo Sie waren, aber ich denke, das ist Hacky. –