在用unity做項目開發(fā)的過程中,經(jīng)常會用到文件選擇框,一般有以下三種方式實現(xiàn):
一、編輯器模式下
編輯器的模式,可以利用EditorUtility類里面的方式實現(xiàn),需要引用UnityEditor命名空間。
//選擇文件
var filePath = EditorUtility.OpenFilePanel("選擇打開文件", UnityEngine.Application.streamingAssetsPath, "json");
//保存文件
var fileName= EditorUtility.SaveFilePanel("選擇保存路徑", Application.streamingAssetsPath, "", "json");
//選擇文件夾
var filePath = EditorUtility.OpenFolderPanel("選擇打開的文件夾", UnityEngine.Application.streamingAssetsPath, "默認文件夾名");
此種方式只支持在編輯器模式下運行,因為帶有UnityEditor命名空間,故發(fā)布成exe之后不能使用。
二、發(fā)布模式下
首先需要引用System.Windows.Forms命名空間。
引用System.Windows.Forms報錯
報錯的是原因是缺少System.Windows.Forms.dll文件,需要手動導入該文件。
-
找到unity所在的安裝路徑下的Editor\Data\MonoBleedingEdge\lib\mono\2.0-api\,注意不要復制錯了,其他路徑也會有同名的庫,但是打包之后會出現(xiàn)報錯的情況。
-
將其導入到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";
}
用上面的方法調用文件選擇彈窗,有時會出現(xiàn)以下彈窗:
這里嚴重影響使用體驗,為此我在網(wǎng)上找到了一個解決辦法,利用句柄檢測彈窗,在彈窗出現(xiàn)的時候關閉,實現(xiàn)代碼如下:
[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);
}
}
但此種辦法終究是治標不治本,功能實現(xiàn)起來略微別扭,于是出現(xiàn)了第三種實現(xiàn)方法。文章來源:http://www.zghlxwxcb.cn/news/detail-695213.html
三、利用C++動態(tài)庫實現(xiàn)彈窗
由于方法也是從網(wǎng)上多個博主學習參考過來的,有些參數(shù)我也不太了解,感興趣的可以自己研究一下Windows應用開發(fā)中文說明官網(wǎng),這里也就不多做介紹了,直接貼代碼:文章來源地址http://www.zghlxwxcb.cn/news/detail-695213.html
/// <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
}
到了這里,關于unity多種方式實現(xiàn)文件選擇和保存窗口的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!