web-dev-qa-db-ja.com

SwingはWindows7スタイルのファイルチューザーをサポートしていますか?

Swingの JFileChooserエントリに基づいて、作成している小さなデスクトップアプリに標準の "Open file"ダイアログを追加しました。チュートリアル 。次のようなウィンドウが生成されます。

screenshot of unwanted/XP-style window

しかし、私は次のようなウィンドウが必要です。

screenshot of desired/7-style window

つまり、ファイルチューザーにWindowsXPではなくWindowsVista/Windows7のスタイルを持たせたいのです。これはSwingで可能ですか?もしそうなら、それはどのように行われますか? (この質問では、コードがWindows 7コンピューターでのみ実行されると想定します。)

47
Pops

これはSwingin Java 6でサポートされているようには見えません。

現在、このダイアログを開くために私が見つけることができる最も簡単な方法は、SwingではなくSWTを使用することです。 SWTのFileDialog( javadoc )は、このダイアログを表示します。以下は、SWTの FileDialogスニペット を変更して、保存ダイアログの代わりに開くダイアログを使用するようにしたものです。これがまさにあなたが探しているものではないことは知っていますが、これをユーティリティクラスに分離し、この機能のためにクラスパスにswt.jarを追加することができます。

import org.Eclipse.swt.*;
import org.Eclipse.swt.widgets.*;

public class SWTFileOpenSnippet {
    public static void main (String [] args) {
        Display display = new Display ();
        Shell shell = new Shell (display);
        // Don't show the Shell.
        //Shell.open ();  
        FileDialog dialog = new FileDialog (Shell, SWT.OPEN | SWT.MULTI);
        String [] filterNames = new String [] {"All Files (*)"};
        String [] filterExtensions = new String [] {"*"};
        String filterPath = "c:\\";
        dialog.setFilterNames (filterNames);
        dialog.setFilterExtensions (filterExtensions);
        dialog.setFilterPath (filterPath);
        dialog.open();
        System.out.println ("Selected files: ");
        String[] selectedFileNames = dialog.getFileNames();
        for(String fileName : selectedFileNames) {
            System.out.println("  " + fileName);
        }
        Shell.close();
        while (!Shell.isDisposed ()) {
            if (!display.readAndDispatch ()) display.sleep ();
        }
        display.dispose ();
    }
} 
21
John McCarthy

ネイティブのWindowsアプリケーションでも、このタイプのダイアログをWindows 7に表示できます。これは通常、 OPENFILENAME 構造体のフラグと、WinAPI関数の呼び出しで渡されるそのサイズによって制御されます GetOpenFileName 。 Swing(Java)は、フックを使用して[ファイルを開く]ダイアログからイベントを取得します。これらのイベントは、WindowsXPバージョンとWindows7バージョンの間で異なる方法で渡されます。

したがって、答えは、SwingからFileChooserの外観を制御することはできないということです。ただし、Javaがこの新しい外観のサポートを取得すると、新しいスタイルが自動的に取得されます。

別のオプションは、 この回答 で提案されているように、SWTを使用することです。または、JNAを使用してWindows APIを呼び出すか、ネイティブメソッドを記述してこれを行うこともできます。

11
Alexey Ivanov

Swingがそれをカバーするとは思わないが、そうでない場合は、実際のネイティブコンポーネントを利用するSWTのようなものを調べたり、カスタムUI要素を実行したりする必要があるかもしれない。 「FilthyRichClients」の本。

7
mezmo

ちょっとしたハックで、Swingバージョンよりも少し権限がありませんが、Java.awt.FileDialogの使用を検討しましたか?これは、Windowsファイルチューザーのようにlookであるだけでなく、実際にはbe 1である必要があります。

7
Andrew Thompson

Java 8は最終的にこれに対する解決策をもたらすかもしれませんが、残念ながら(Swingアプリの場合)それはJavaFXクラスとしてのみ提供されます FileChooser

私はこのコードを ここ からテストしましたが、実際に最新のダイアログが表示されます(Windows 7はここ):

_FileChooser fileChooser = new FileChooser();

//Set extension filter
FileChooser.ExtensionFilter extFilterJPG = new FileChooser.ExtensionFilter("JPG files (*.jpg)", "*.JPG");
FileChooser.ExtensionFilter extFilterPNG = new FileChooser.ExtensionFilter("PNG files (*.png)", "*.PNG");
fileChooser.getExtensionFilters().addAll(extFilterJPG, extFilterPNG);

//Show open file dialog
File file = fileChooser.showOpenDialog(null);
_

これをSwingアプリに統合するには、_Platform.runLater_を介してjavafxスレッドで実行する必要があります( ここ を参照)。

これには、javafxスレッドを初期化する必要があることに注意してください(この例では、これはシーンの初期化時にnew JFXPanel()で行われます)。

要約すると、swingアプリですぐに実行できるソリューションは次のようになります。

_new JFXPanel(); // used for initializing javafx thread (ideally called once)
Platform.runLater(() -> {
    FileChooser fileChooser = new FileChooser();

    //Set extension filter
    FileChooser.ExtensionFilter extFilterJPG = new FileChooser.ExtensionFilter("JPG files (*.jpg)", "*.JPG");
    FileChooser.ExtensionFilter extFilterPNG = new FileChooser.ExtensionFilter("PNG files (*.png)", "*.PNG");
    fileChooser.getExtensionFilters().addAll(extFilterJPG, extFilterPNG);

    //Show open file dialog
    File file = fileChooser.showOpenDialog(null);
});
_
7
Luke Usherwood

良い質問+ 1、Win7(defaultLookAndFeel)の何かをJava6に実装するのを「忘れた」ように見えますが、WinXPの場合は正しく機能します。また、そのためのメソッド/プロパティが存在する必要があることを願っています。

とにかく、あなたはこのコードでそれを試すことができます、

import Java.io.File;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;

class ChooserFilterTest {

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {
                String[] properties = {"os.name", "Java.version", "Java.vm.version", "Java.vendor"};
                for (String property : properties) {
                    System.out.println(property + ": " + System.getProperty(property));
                }
                JFileChooser jfc = new JFileChooser();
                jfc.showOpenDialog(null);
                jfc.addChoosableFileFilter(new FileFilter() {

                    @Override
                    public boolean accept(File f) {
                        return f.isDirectory() || f.getName().toLowerCase().endsWith(".obj");
                    }

                    @Override
                    public String getDescription() {
                        return "Wavefront OBJ (*.obj)";
                    }

                    @Override
                    public String toString() {
                        return getDescription();
                    }
                });
                int result = JOptionPane.showConfirmDialog(null, "Description was 'All Files'?");
                System.out.println("Displayed description (Metal): " + (result == JOptionPane.YES_OPTION));
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    SwingUtilities.updateComponentTreeUI(jfc);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                jfc.showOpenDialog(null);
                result = JOptionPane.showConfirmDialog(null, "Description was 'All Files'?");
                System.out.println("Displayed description (System): " + (result == JOptionPane.YES_OPTION));
            }
        };
        SwingUtilities.invokeLater(r);
    }

    private ChooserFilterTest() {
    }
}
2
mKorbel

しかし、これをディレクトリに対して機能させることはできませんでした!! DirectoryDialogは、質問にリストされているものと同じツリースタイルのディレクトリチューザーに戻ります。問題は、非表示のフォルダを選択/選択/開くことができないことです。また、AppData、ProgramDataなどのフォルダーへのナビゲーションも許可されていません。

Windows 7スタイルのファイルダイアログ(swt)はこれらのフォルダーへのナビゲーションを許可しますが、フォルダーの選択は許可しません:(

更新非表示のフォルダーを表示するには、JFileChooserを使用し、setFileHidingEnabled(false)を使用します。これに関する唯一の義務は、ユーザーが「隠しファイル、フォルダ、およびドライブを表示する」を選択する必要があることです。

フォルダオプション->表示

windowsエクスプローラーの

アドレスバーの柔軟性は得られませんが、Javaでツリーのようなものではないファイルチューザーを探していた場合は、隠しファイル/フォルダーを参照/表示することもできます-これで十分です

1
Rohan

ジョン・マッカーシーの答えは最高のようです。ここにいくつかの提案があります。

import org.Eclipse.swt.*;
import org.Eclipse.swt.widgets.*;
import org.Eclipse.swt.graphics.Image;

左上隅に画像を追加します。 「getResourceAsStream」を使用することが重要です。Runnablejarとしてエクスポートした後に気付くでしょう:

Display display = new Display();
Shell shell = new Shell(display);
InputStream inputImage = getClass().getResourceAsStream("/app/launcher.png");
if (inputImage != null) {
    Shell.setImage(new Image(display, inputImage));
}

ユーザーのホームディレクトリ:

String filterPath = System.getProperty("user.home");

他のドライブでは間違っている、フィルターに依存するパス名の代わりに絶対パス名を取得します。

String absolutePath = dialog.open();
1
User Rebo

SwingはさまざまなL&Fをエミュレートするため、JREを最新のものにアップグレードし、JFileChooserUIが更新されていることを期待するのが最善の策だと思います。

0
qwerty

JFileChooserは、Swingの外観が常に少し変わっていて、少し遅いです。

SWTのfilechooserを使用してみてください。そうしないと、C呼び出しをJNAでラップできます。

0
meverett