问题
Unix / Linux support auto-complete of files and directories when pressing "tab". I need to create this ability in my windows application. I have a text field for user input of file name, which I want to respond to a "tab" press like it will do when we're in a unix console:
- If there is one option - Auto-complete.
- Some options - show a list of the options.
- No options - nada.
For my SSH connection to my unix machine I use the ch.ethz.ssh API.
Is there a way to do so?
回答1:
First you want to have a text field without focus cycling, and tab suppression:
jTextField1.setFocusCycleRoot(true);
jTextField1.setFocusTraversalKeysEnabled(false);
Then a data model for the files (here local directory, but SSH is likewise):
private File dir = new File("C:/Work");
private String typedPrefix = null;
private List<String> filesWithPrefix = new ArrayList<>();
Then a key pressed handling for the TAB:
- Consume the event.
- Get the prefix upto the caret for searching file names.
- If you merely need to restrict already found file names, so do, otherwise physical search them.
Look for the longest common prefix in the file names. Display that.
private void jTextField1KeyPressed(java.awt.event.KeyEvent evt) { System.out.println("KeyPressed " + evt); if (evt.getKeyCode() == KeyEvent.VK_TAB) { evt.consume(); int caretPos = jTextField1.getCaretPosition(); try { final String newPrefix = jTextField1.getText(0, caretPos); System.out.println("newPrefix: " + newPrefix); if (!newPrefix.isEmpty()) { if (typedPrefix == null || !newPrefix.startsWith(typedPrefix)) { // Must physically reload possible values: String[] fileNames = dir.list(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.startsWith(newPrefix); } }); filesWithPrefix.clear(); Collections.addAll(filesWithPrefix, fileNames); typedPrefix = newPrefix; } else { // Can reduce prior selection: for (ListIterator<String> it = filesWithPrefix.listIterator(); it.hasNext(); ) { String fileName = it.next(); if (!fileName.startsWith(newPrefix)) { it.remove(); } } typedPrefix = newPrefix; } System.out.println("filesWithPrefix: " +filesWithPrefix); if (!filesWithPrefix.isEmpty()) { // Find longest common prefix: String longestCommonPrefix = null; for (String fileName : filesWithPrefix) { if (longestCommonPrefix == null) { longestCommonPrefix = fileName; } else { while (!fileName.startsWith(longestCommonPrefix)) { longestCommonPrefix = longestCommonPrefix.substring(0, longestCommonPrefix.length() - 1); } } } if (longestCommonPrefix.length() > typedPrefix.length()) { jTextField1.setText(longestCommonPrefix); jTextField1.setCaretPosition(longestCommonPrefix.length()); typedPrefix = longestCommonPrefix; } if (filesWithPrefix.size() > 1) { // Show popup: ;;; } else if (filesWithPrefix.size() == 1) { // File selected: System.beep(); } } } } catch (BadLocationException ex) { Logger.getLogger(TabsJFrame.class.getName()).log(Level.SEVERE, null, ex); } } }
What is missing is the display of the ambiguous file names. Popup menu would be nice, wouldn't it?
Popup:
// Show popup:
JPopupMenu popup = new JPopupMenu();
for (String fileName : filesWithPrefix) {
popup.add(new AbstractAction(fileName) {
@Override
public void actionPerformed(ActionEvent e) {
jTextField1.setText(e.getActionCommand());
}
});
}
Point pt = jTextField1.getCaret().getMagicCaretPosition();
popup.show(jTextField1, pt.x, pt.y + 5);
来源:https://stackoverflow.com/questions/8476223/windows-application-with-auto-complete-using-tab-of-unix-machine-files-and-direc