unity文件选择框的三种实现方式
在用unity做项目开发的过程中,经常会用到文件选择框,一般有以下三种方式实现:
一、编辑器模式下
编辑器的模式,可以利用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之后不能使用。
二、发布模式下
首先需要引用System.Windows.Forms命名空间。
引用System.Windows.Forms报错
报错的是原因是缺少System.Windows.Forms.dll文件,需要手动导入该文件。
-
找到unity所在的安装路径下的Editor\Data\MonoBleedingEdge\lib\mono\2.0-api\,注意不要复制错了,其他路径也会有同名的库,但是打包之后会出现报错的情况。
-
将其导入到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";
}
用上面的方法调用文件选择弹窗,有时会出现以下弹窗:
这里严重影响使用体验,为此我在网上找到了一个解决办法,利用句柄检测弹窗,在弹窗出现的时候关闭,实现代码如下:
[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);
}
}
但此种办法终究是治标不治本,功能实现起来略微别扭,于是出现了第三种实现方法。
三、利用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
}
转载自CSDN-专业IT技术社区
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_42914882/article/details/131456560