Unity は複数の方法でファイル選択と保存ウィンドウを実装します

Unityでのプロジェクト開発ではファイル選択ボックスがよく使われますが、その実装方法は大きく分けて3つあります。

1. エディターモードで

エディター モードは EditorUtility クラスのメソッドを使用して実装でき、UnityEditor 名前空間を参照する必要があります。

  //选择文件
   var filePath = EditorUtility.OpenFilePanel("选择打开文件", UnityEngine.Application.streamingAssetsPath, "json");
  //保存文件
   var fileName= EditorUtility.SaveFilePanel("选择保存路径", Application.streamingAssetsPath, "", "json");
  //选择文件夹
   var filePath = EditorUtility.OpenFolderPanel("选择打开的文件夹", UnityEngine.Application.streamingAssetsPath, "默认文件夹名");

このメソッドはエディタ モードでの実行のみをサポートしており、UnityEditor 名前空間を持つため、exe として公開した後は使用できません。

2. リリースモード時

まず引用する必要がありますSystem.Windows.Forms名前空間。

System.Windows.Forms を参照するときにエラーが報告される

エラーの理由は、System.Windows.Forms.dll ファイルが見つからないため、ファイルを手動でインポートする必要があることです。

  1. Unity のあるインストールパス配下に Editor\Data\MonoBleedingEdge\lib\mono\2.0-api\ を見つけます。コピーを間違えないように注意してください。他のパスにも同じ名前のライブラリがありますが、その後エラーが表示されます梱包。

  2. Unity プロジェクトのルート ディレクトリにある Plugins フォルダーにインポートすると、プロジェクトが自動的に DLL を参照するようになります。

ファイルポップアップウィンドウの呼び出し方法は以下のとおりです。

フォルダ選択ポップアップウィンドウ

  		/// <summary>
        /// 保存文件
        /// </summary>
        /// <param name="title">标题</param>
        /// <param name="onComplete">回调</param>
        /// <param name="fileExts">文件保存的类型</param>
         public static void SaveFile(string title, Action<bool, string> onComplete = null,
            params string[] fileExts)
        {
    
    
            var dialog = new SaveFileDialog
            {
    
    
                Title = title
            };
            string filter = "";
            foreach (var item in fileExts)
            {
    
    
                filter += $"{
      
      item}|";
            }

            filter = filter.Remove(filter.Length - 1);

            dialog.Filter = filter;
            DialogResult result = dialog.ShowDialog();

            if (result == DialogResult.OK)
            {
    
    
                string filepath = dialog.FileName;
               

                onComplete?.Invoke(true, filepath);
            }
            else
            {
    
    
                onComplete?.Invoke(false, "");
            }

        }
        /// <summary>
        /// 选择文件窗口
        /// </summary>
        /// <param name="title">弹窗标题</param>
        /// <param name="onComplete">完成回调</param>
        /// <param name="fileExts">文件类型</param>
        static void ChooseFile(string title, Action<bool, string> onComplete = null, params string[] fileExts)
        {
    
    

            var dialog = new OpenFileDialog();
            dialog.Title = title;
            string filter = "";
            foreach (var item in fileExts)
            {
    
    
                filter += $"{
      
      item}|";
            }
            filter = filter.Remove(filter.Length - 1);

            dialog.Filter = filter;
            DialogResult result = dialog.ShowDialog();

            if (result == DialogResult.OK)
            {
    
    
                onComplete?.Invoke(true,  dialog.FileName);
            }
            else
            {
    
    
                onComplete?.Invoke(false, "");
            }

        }

 		/// <summary>
        /// 选择文件夹
        /// </summary>
        /// <param name="title">选择框标题</param>
        /// <param name="onComplete">回调</param>
        public static void ChooseDictionaryOld(string title, Action<bool, string> onComplete = null)
        {
    
    
            var dialog = new FolderBrowserDialog();
            dialog.Description = title;
            dialog.ShowNewFolderButton = true;
            dialog.RootFolder = Environment.SpecialFolder.ApplicationData;
            DialogResult result = dialog.ShowDialog();

            if (result == DialogResult.OK)
            {
    
    
                onComplete?.Invoke(true, dialog.SelectedPath);
            }
            else
            {
    
    
                onComplete?.Invoke(false, "");
            }
        }
        
		/// <summary>
        /// 文件类型的格式
        /// </summary>
  		public class FileType
        {
    
    
            public const string doc = "doc文件(.doc)|*.doc";
            public const string txt = "文本文件(.txt)|*.txt";
            public const string json = "json文件(.json)|*.json";
            public const string xls = "xls表格(.xls)|*.xls";
            public const string ppt = "ppt文件(.ppt)|*.ppt";
        }

上記の方法を使用してファイル選択ポップアップ ウィンドウを呼び出すと、次のようなポップアップ ウィンドウが表示される場合があります:
ここに画像の説明を挿入します
これはユーザー エクスペリエンスに深刻な影響を及ぼします。このため、インターネットで解決策を見つけました。ハンドルを使用してポップを検出します。 -up ウィンドウを開き、表示されたら閉じます。次のようにコードを実装します。

 		[DllImport("user32.dll")]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        [DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);

        public const int WM_SYSCOMMAND = 0x0112;
        public const int SC_CLOSE = 0xF060;

        static FileTool()
        {
    
    
           //在类初始化的时候,调用此方法
            FindAndCloseWindow();
        }

        /// <summary>
        /// 关闭对应弹窗
        /// </summary>
        static void FindAndCloseWindow()
        {
    
    
            IntPtr lHwnd = FindWindow("ClearOOPs", "Oops");
            if (lHwnd != IntPtr.Zero)
            {
    
    
                SendMessage(lHwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
            }

        }

ただし、この方法は最終的には根本的な原因ではなく症状を治療するものであり、機能の実装が少し難しいため、3 番目の実装方法が登場しました。

3. C++ ダイナミック ライブラリを使用してポップアップ ウィンドウを実装する

この方法はインターネット上の多くのブロガーからも学ばれ参考にされているため、いくつかのパラメーターについてはよくわかりませんが、興味がある場合は、Windows アプリケーション開発のための公式の中国語の説明書を自分で勉強することもできます。ここにコードを貼り付けます。

	/// <summary>
    /// 文件类
    /// </summary>
 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public class FileOpenDialog
    {
    
    
        public int structSize = 0;
        public IntPtr dlgOwner = IntPtr.Zero;
        public IntPtr instance = IntPtr.Zero;
        public String filter = null;
        public String customFilter = null;
        public int maxCustFilter = 0;
        public int filterIndex = 0;
        public String file = null;
        public int maxFile = 0;
        public String fileTitle = null;
        public int maxFileTitle = 0;
        public String initialDir = null;
        public String title = null;
        public int flags = 0;
        public short fileOffset = 0;
        public short fileExtension = 0;
        public String defExt = null;
        public IntPtr custData = IntPtr.Zero;
        public IntPtr hook = IntPtr.Zero;
        public String templateName = null;
        public IntPtr reservedPtr = IntPtr.Zero;
        public int reservedInt = 0;
        public int flagsEx = 0;
    }

	/// <summary>
    /// 文件夹类
    /// </summary>
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public class OpenDialogDir
    {
    
    
        public IntPtr hwndOwner = IntPtr.Zero;
        public IntPtr pidlRoot = IntPtr.Zero;
        public String pszDisplayName = "123";
        public String lpszTitle = null;
        public UInt32 ulFlags = 0;
        public IntPtr lpfn = IntPtr.Zero;
        public IntPtr lParam = IntPtr.Zero;
        public int iImage = 0;
    }

    public class DialogShow
    {
    
    
        [DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
        public static extern bool GetOpenFileName([In, Out] FileOpenDialog dialog); 
        
        [DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
        public static extern bool GetSaveFileName([In, Out] FileOpenDialog dialog);

        [DllImport("shell32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
        public static extern IntPtr SHBrowseForFolder([In, Out] OpenDialogDir ofn);

        [DllImport("shell32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
        public static extern bool SHGetPathFromIDList([In] IntPtr pidl, [In, Out] char[] fileName);
    }

 static public class OpenFileByWin32
    {
    
    
        public static string OpenFile(Constant.EFileType filter, string title, string openPath = "")
        {
    
    
            FileOpenDialog dialog = new FileOpenDialog();
            dialog.structSize = Marshal.SizeOf(dialog);
            dialog.filter = Getfilter(filter);
            dialog.file = new string(new char[256]);
            dialog.maxFile = dialog.file.Length;
            dialog.fileTitle = new string(new char[64]);
            dialog.maxFileTitle = dialog.fileTitle.Length;
            dialog.initialDir = openPath==""?UnityEngine.Application.dataPath: openPath; //默认路径
            dialog.title = title;
            dialog.defExt = null; //显示文件的类型
            //注意一下项目不一定要全选 但是0x00000008项不要缺少
            dialog.flags =
                0x00080000 | 0x00001000 | 0x00000800 | 0x00000200 |
                0x00000008; //OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST| OFN_ALLOWMULTISELECT|OFN_NOCHANGEDIR

            if (DialogShow.GetOpenFileName(dialog))
            {
    
    
                return (dialog.file);
            }
            return "";
        }

        public static string SaveFile(Constant.EFileType filter, string title, string openPath = "")
        {
    
    
            FileOpenDialog dialog = new FileOpenDialog();
            dialog.structSize = Marshal.SizeOf(dialog);
            dialog.filter = Getfilter(filter);
            dialog.file = new string(new char[256]);
            dialog.maxFile = dialog.file.Length;
            dialog.fileTitle = new string(new char[64]);
            dialog.maxFileTitle = dialog.fileTitle.Length;
            dialog.initialDir = openPath == "" ? UnityEngine.Application.dataPath : openPath; //默认路径
            dialog.title = title;
            dialog.defExt = ""; //保存文件的类型
            //注意一下项目不一定要全选 但是0x00000008项不要缺少
            dialog.flags =
                0x00080000 | 0x00001000 | 0x00000800 | 0x00000200 |
                0x00000008; //OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST| OFN_ALLOWMULTISELECT|OFN_NOCHANGEDIR

            if (DialogShow.GetSaveFileName(dialog))
            {
    
    
                return (dialog.file);
            }
            return "";
        }

        /// <summary>
        /// 选择文件夹
        /// </summary>
        /// <param name="title">弹窗口标题</param>
        /// <param name="openPath"></param>
        /// <returns></returns>
        public static string ChooseDictionary( string title, string openPath = "")
        {
    
    
            OpenDialogDir openDir = new OpenDialogDir();
            openDir.pszDisplayName = new string(new char[2000]);
            openDir.lpszTitle = title;
            openDir.ulFlags = 1;// BIF_NEWDIALOGSTYLE | BIF_EDITBOX;
            IntPtr pidl = DialogShow.SHBrowseForFolder(openDir);

            char[] path = new char[2000];
            for (int i = 0; i < 2000; i++)
                path[i] = '\0';
            if (DialogShow.SHGetPathFromIDList(pidl, path))
            {
    
    
                string str = new string(path);
                string DirPath = str.Substring(0, str.IndexOf('\0'));
                Debug.LogError("路径" + DirPath);
                return DirPath;
            }

            return "";
        }

        #region 内部方法
        static string Getfilter(Constant.EFileType fileType)
        {
    
    
            string filter = "";
            switch (fileType)
            {
    
    
                case Constant.EFileType.word:
                    filter = "word Files(*word文档)\0*.doc\0xls Files(*xls表格)\0*.xls\0ppt Files(*ppt演示文档)\0*.ppt\0";
                    break;
                case Constant.EFileType.json:
                    filter = "Json Files(*json文件)\0*.json\0";
                    break;
                case Constant.EFileType.txt:
                    filter = "Text Files(*文本文件)\0*.txt\0";
                    break;
                case Constant.EFileType.all:
                    filter = "All Files(*.*)\0*.*\0\0";
                    break;
                case Constant.EFileType.Texture:
                    filter = "Png Files(*图片文件)\0*.png\0Jpg Files(*图片文件)\0*.jpg\0";
                    break;
                case Constant.EFileType.Video:
                    filter = "Video Files(*视频文件)\0*.mp4;*.mov\0";
                    break;
                case Constant.EFileType.Music:
                    filter = "wav Files(*音频文件)\0*.wav\0 mp3 Files(*音频文件)\0*.mp3\0";
                    break;

            }

            return filter;
        }

        #endregion
    }

おすすめ

転載: blog.csdn.net/qq_42914882/article/details/131456560
おすすめ