Java-Tipp 93: Fügen Sie JFileChooser ein Dateifinder-Zubehör hinzu
In diesem Tipp wird beschrieben, wie Sie die Funktionalität einer der am häufigsten verwendeten Komponenten der Benutzeroberfläche - des Standarddialogs zum Öffnen von Dateien - um ein Zubehör für die Suche nach Thread-Dateien erweitern.
Wenn Sie versuchen, eine Datei zu öffnen, diese aber nicht sofort finden können, geben Sie einfach Ihre Suchkriterien in die Suchfelder des Zubehörs ein, klicken Sie auf die Schaltfläche Start und warten Sie, bis eine Liste der gefundenen Dateien angezeigt wird. Dieses Suchzubehör ist in den Dialog zum Öffnen von Dateien integriert, und die Dateisuche ist mit einem Thread versehen, sodass Sie das Dateisystem weiterhin durchsuchen können, während die Suche ausgeführt wird.
Das Hinzufügen von Funktionen zum Standard-Dateidialog von Swing ist einfach, sobald Sie verstanden haben, wie eine Komponente in JFileChooser
das Dialogfeld integriert wird, wie die Komponente auf JFileChooser
Ereignisse reagiert und wie die JFileChooser
Dateianzeige und -auswahl der Komponente gesteuert wird . Ich werde mit diesem Artikel ein Beispielzubehör bereitstellen. Der vollständige Quellcode für die FindAccessory
Klasse ist in Ressourcen enthalten. In Jon Sharpes Java-Tipp 85 finden Sie eine Übersicht über die JFileChooser
Grundlagen.
Zubehör für JFileChooser
Das Anpassen JFileChooser
ist einfach. Anstatt den Standarddateidialog neu zu erfinden, um spezielle Funktionen einzuschließen, können Sie Ihre benutzerdefinierten Funktionen als JComponent implementieren und in JFileChooser
einen einzelnen Methodenaufruf integrieren.
JFileChooser chooser = neuer JFileChooser (); chooser.setAccessory (neues FindAccessory ());
Diese beiden Codezeilen sind täuschend einfach. An der Oberfläche wird eine FindAccessory
Komponente an einen Standarddialog zum Öffnen von Dateien angehängt, wie in Abbildung 1 dargestellt. Auf einer tieferen Ebene FindAccessory
wird das Verhalten von geändert JFileChooser
. Die Details der Integration sind in der Implementierung des Zubehörs verborgen.
Um die Leistungsfähigkeit des Zubehörs und die Flexibilität des Zubehörs voll zu nutzen JFileChooser
, müssen Sie die JFileChooser
Eigenschaften, Ereignisse und Steuerungsmethoden verstehen . Zunächst sollten Sie jedoch wissen, wie eine Zubehörkomponente im JFileChooser
Dialogfeld angezeigt wird .
Steuern des Zubehörlayouts
Es ist besonders wichtig zu verstehen, wie bestimmte Layout-Manager bei der Implementierung komplexer JFileChooser
Zubehörteile arbeiten. Einige Layout-Manager wie GridLayout ignorieren die bevorzugte Größe einer Komponente. In Java 1.2.2 JFileChooser
ist es zu eifrig, die Bildlaufliste der Dateien zu verkleinern, um ein Zubehör aufzunehmen. Ohne einige Dimensionsbeschränkungen kann ein komplexes Zubehör erweitert werden JFileChooser
, um die Dateianzeigeliste und die Steuertasten zu verdrängen.
Um das Layout noch schlimmer zu machen, werden einige Komponenten wie Textfelder und Listen tendenziell erweitert, um der Breite ihres Inhalts Rechnung zu tragen. Die Regeln für die Größe von JTextFields sind besonders komplex. Java Swing von Robert Eckstein, Marc Loy und Dave Wood bietet eine ausführliche Erklärung der Größe von Textfeldern (siehe Ressourcen).
In frühen Versuchen mit dem GridLayout-Manager wurde FindAccessory
die Breite während einer Suche erweitert, um das breiteste Element in der Ergebnisliste aufzunehmen. Diese Erweiterung hat die Dateianzeigeliste oft JFileChooser
auf eine lächerlich schmale Breite reduziert .
FindAccessory
Verwenden Sie den BorderLayout-Manager, der die bevorzugte Größe einer Komponente berücksichtigt, um Layout- und Erweiterungsprobleme zu umgehen. Darüber hinaus werden im Ergebnisbereich die bevorzugten und maximalen Abmessungen der Liste der Bildlaufergebnisse unmittelbar vor dem Start einer Suche festgelegt.
Dimension dim = resultsScroller.getSize (); resultsScroller.setMaximumSize (dim); resultsScroller.setPreferredSize (dim);
Wenn Sie die bevorzugten und maximalen Abmessungen spät oder kurz vor einer Suche festlegen, werden die FindAccessory
Bedienfelder beim JFileChooser
Anzeigen des Dialogfelds gut angezeigt, verhindern jedoch eine außer Kontrolle geratene Erweiterung, wenn die Ergebnisliste voll ist.
Swing kann das Erscheinungsbild verschiedener GUI-Plattformen durch seine Pluggable Look-and-Feel-Architektur (PLAF) emulieren. Swing 1.2.2 unterstützt drei Themen: Windows, Motiv und Metal. Das Erscheinungsbild des Zubehörs hängt davon ab, welches PLAF aktiv ist. Sie sollten Ihr Zubehörlayout mit jedem PLAF testen.
Antworten auf JFileChooser-Ereignisse
Das Anhängen eines Zubehörs an JFileChooser ist einfach. Die Integration eines Zubehörs in JFileChooser erfordert jedoch ein Verständnis der Listener für Ereignis- und Eigenschaftsänderungen. Ein Zubehör kann die Eigenschaftsänderungen und Aktionsereignisse seiner Eltern überwachen, um auf die Browsing- und Dateiauswahlaktivitäten des Benutzers zu reagieren. Komplexes Zubehör muss möglicherweise Threads beenden oder temporäre Dateien schließen, wenn der Benutzer auf die Schaltflächen Öffnen, Speichern oder Abbrechen klickt.
PropertyChangeListener
Listener für Eigenschaftsänderungen sind JavaBeans-Entwicklern als der Mechanismus bekannt, mit dem ein Objekt andere Objekte benachrichtigt, wenn sich ein gebundener Eigenschaftswert ändert. Mit Swing können Objekte problemlos PropertyChangeEvents
von jeder JComponent empfangen werden. Implementieren Sie einfach die java.beans.PropertyChangeListener
Schnittstelle und registrieren Sie Ihr Objekt mit der addPropertyChangeListener()
Methode der Komponente .
Zubehör, das die java.beans.PropertyChangeListener
Schnittstelle implementiert , kann sich registrieren JFileChooser
, um Benachrichtigungen über Verzeichnisänderungen, Auswahländerungen, Dateifilteränderungen und mehr zu erhalten. Eine vollständige Liste finden Sie in der JDK-Dokumentation.
FindAccessory
Zeigt den absoluten Pfad des Stammordners für Ihre Suche an. Diese Anzeige friert beim Ausführen einer Suche ein. Wenn eine Suche nicht ausgeführt wird, wird FindAccessory
der Suchpfad als Reaktion auf ein JFileChooser.DIRECTORY_CHANGED_PROPERTY
Ereignis aktualisiert . Mit anderen Worten, FindAccessory
verfolgt Ihre Bewegung durch das Dateisystem mit einem PropertyChangeEvent
von JFileChooser
.
Der Code ist sehr einfach:
public void propertyChange (PropertyChangeEvent e) {String prop = e.getPropertyName (); if (prop.equals (JFileChooser.DIRECTORY_CHANGED_PROPERTY)) {updateSearchDirectory (); }}
ActionListener
Zubehör, das die java.awt.event.ActionListener
Schnittstelle implementiert , kann benachrichtigt werden, wenn Sie auf die Schaltflächen Öffnen, Speichern oder Abbrechen klicken.
FindAccessory
stoppt eine Suche, wenn Sie auf die Schaltflächen Öffnen oder Abbrechen klicken. Die ActionListener
Methode ist einfach:
public void actionPerformed (ActionEvent e) {String command = e.getActionCommand (); if (command == null) return; // Kann das passieren? Wahrscheinlich nicht. Nenn mich paranoid. if (command.equals (JFileChooser.APPROVE_SELECTION)) quit (); sonst wenn (command.equals (JFileChooser.CANCEL_SELECTION)) quit (); }}
JFileChooser steuern
Ein Zubehör kann mehr als ein Slave für JFileChooser
Eigenschaften und Ereignisse sein. Es kann JFileChooser
mit Tastatur und Maus so viel Kontrolle ausüben wie ein Benutzer.
Wenn Sie auf ein Element in FindAccessory
der Suchergebnisliste doppelklicken, JFileChooser
wird dieses Element angezeigt und ausgewählt. FindAccessory
Verwendet JFileChooser
Methoden, um das aktuelle Verzeichnis festzulegen, die aktuelle Auswahl festzulegen und den Typ der angezeigten Dateien zu ändern.
Unten finden Sie den Code für FindAccessory
die goTo()
Methode, JFileChooser
mit der eine Datei angezeigt und ausgewählt werden kann, wenn Sie auf ein Element in der Suchergebnisliste doppelklicken. Der Vorgang ist etwas komplizierter als das Aufrufen JFileChooser.setSelectedFile()
. Zunächst legen Sie den JFileChooser
aktuellen Dateianzeigefilter fest, damit Ihre Datei angezeigt werden kann. Zweitens legen Sie das JFileChooser
aktuelle Verzeichnis auf den Ordner fest, der die angegebene Datei enthält. Schließlich rufen Sie auf JFileChooser.setSelectedFile()
.
Step 2 is only necessary if you're running a version prior to Java 1.2.2. A bug in JFileChooser.setSelectedFile()
didn't always change the current directory.
/** Set parent's current directory to the parent folder of the specified file and select the specified file. That method is invoked when the user double-clicks on an item in the results list. @param f File to select in parent JFileChooser */ public void goTo (File f) { if (f == null) return; if (!f.exists()) return; if (chooser == null) return; // Make sure that files and directories // can be displayed chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); // Make sure that parent file chooser will // show the type of file specified javax.swing.filechooser.FileFilter filter = chooser.getFileFilter(); if (filter != null) { if (!filter.accept(f)) { // The current filter will not // display the specified file. // Set the file filter to the // built-in accept-all filter (*.*) javax.swing.filechooser.FileFilter all = chooser.getAcceptAllFileFilter(); chooser.setFileFilter(all); } } // Tell parent file chooser to display contents of parentFolder. // Prior to Java 1.2.2 setSelectedFile() did not set the current // directory the folder containing the file to be selected. File parentFolder = f.getParentFile(); if (parentFolder != null) chooser.setCurrentDirectory(parentFolder); // Nullify the current selection if any. // Why is this necessary? // JFileChooser gets sticky (i.e., it does not // always relinquish the current selection). // Nullifying the current selection seems to yield better results. chooser.setSelectedFile(null); // Select the file chooser.setSelectedFile(f); // Refresh file chooser display. // Is this really necessary? Testing on a variety of systems with // Java 1.2.2 suggests that helps. Sometimes it doesn't work, // but it doesn't do any harm. chooser.invalidate(); chooser.repaint(); }
Caveats
JavaSoft's Bug Database contains 260 bug reports for JFileChooser
. Of those 260 reports, 12 are related to JFileChooser.setSelectedFile()
, but 10 have been fixed for JDK 1.2.2. You should make sure to run the most recent release of Java. FindAccessory
has been tested with JDK 1.2.2 on Windows NT/98/95. The only known problem is JFileChooser
's reluctance to display the selection when you double-click a file in the Found list. JFileChooser.setSelectedFile()
selects the specified file, but the selection is not always displayed in the scrolling file list. You will see the file name displayed correctly, but the file list does not highlight it. The Open button works. Double clicking the item a second time displays the selection correctly. That bug appears to be cosmetic.
FindAccessory implementation details
FindAccessory
extends JPanel and implements a threaded utility for finding files by name, date of modification, and content. FindAccessory
is comprised of three components: a controller, a user interface, and a search engine. For code simplicity, the controller and the search engine are implemented within the FindAccessory
class.
Search options are specified in three tab panes labeled Name, Date, and Content. Results are displayed in a fourth tab pane labeled Found. Searching is recursive from the current location (the path is displayed above the search tabbed panes). The search function is threaded so you can continue to browse the file system while a search is running. You may change the search criteria without affecting a running search.
Search results are displayed dynamically in a scrolling JList within the Found tab pane. You can double-click an entry in the results list to force JFileChooser
to show and select the entry in its main scrolling view.
Search progress is displayed as a text label in the lower right corner of the accessory as number of items found/number of items searched.
FindAccessory user interface
Accessory layout varies depending on which Pluggable Look-and-Feel (PLAF) is active. Windows and Metal PLAF render JFileChooser
with similar layouts and allocate comparable space for your accessory. By contrast, Motif PLAF allocates much less space for an accessory, so your components may appear scrunched. You could customize your layout for each PLAF. FindAccessory
uses a 10-point Helvetica font and arranges components to use minimal space. Test your accessory with each PLAF to make sure it looks right.
FindAccessory tab panes
In addition to the find-by-name tab illustrated in Figure 1,
FindAccessory
contains find-by-date, find-by-content, and found-items tabs, as shown by Figures 2 through 4.



Finding the right files
Implementing the selection functions for a search engine can be complicated. Ideally, the search controller and the search engine should know nothing about the implementation of a search function's selection algorithm. The FindAccessory
class implements a recursive search engine that uses an array of FindFilter
objects to test a file's acceptance. Each FindAccessory
tab pane is responsible for implementing a user interface for the search as well as a FindFilter
object. The search engine and the file selection functions enjoy separate responsibilities.
Jede der FindAccessory
Suchregisterkarten implementiert eine FindFilterFactory
Schnittstelle. Wenn eine Suche beginnt, FindAccessory
durchläuft der Controller die Registerkartenfenster und ruft newSearch()
bei jeder Instanz von FindFilterFactory
auf, um a abzurufen FindFilter
. Der Controller initialisiert die Suchmaschine mit dem Array von FindFilter
s. Jedes FindFilter
implementiert eine accept()
Methode, sodass die Auswahlalgorithmen vollständig vor der Suchmaschine verborgen sind.
Das Erweitern FindAccessory
um eine neue Suchkategorie ist ein einfacher dreistufiger Prozess: