美文网首页unity
结合工作需求用GUI写一个快捷操作Excel的界面

结合工作需求用GUI写一个快捷操作Excel的界面

作者: braveheart_ | 来源:发表于2018-09-02 23:31 被阅读196次

    因工作过程中需要考虑游戏内中文显示方便国际化,游戏内涉及到中文的固定字符串用Excel存储。反复操作Excel对程序员来说很麻烦,于是有了写这样一个偷懒工具的想法。

    初版界面如图:


    ExcelEditor.png

    代码分为四块:
    1、Strings.cs
    序列化生成strings.asset的数据结构。

    using UnityEngine;
    using UnityEditor;
    using System.Collections.Generic;
    
    [CreateAssetMenu]
    public class Strings : ScriptableObject
    {
        public static readonly string STRING_ASSET_PATH = "Assets/Game/strings.asset";
    
        public List<string> _keys;
        public List<string> _vals;
        public Dictionary<string, string> _dic;
    
        private static Strings _instance;
        public static Strings Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = AssetDatabase.LoadAssetAtPath<Strings>(STRING_ASSET_PATH);
                }
                return _instance;
            }
        }
    
        public void UpdateDictionary(List<string> keys, List<string> vals)
        {
            _keys = keys;
            _vals = vals;
    
            if (_keys == null)
            {
                return;
            }
    
            _dic = new Dictionary<string, string>(_keys.Count);
            for (int i = 0; i < _keys.Count; ++i)
            {
                _dic.Add(_keys[i], _vals[i]);
            }
        }
    
        public string Get(string key)
        {
            string val;
            if (_dic.TryGetValue(key, out val))
            {
                return val;
            }
            return key;
        }
    
    }
    

    2、ExcelHelper.cs
    封装的一些需要用到的操作Excel的公用方法。

    using OfficeOpenXml;
    using System.Collections.Generic;
    using System.IO;
    using System.Text.RegularExpressions;
    using UnityEngine;
    
    public class ExcelHelper
    {
        public static void GetStringsFromFiles(List<string> keys, List<string> vals)
        {
            string[] files = GetFiles();
    
            foreach (string file in files)
            {
                string extension = Path.GetExtension(file);
                string pattern = ".xlsx$";
                bool isMatch = Regex.IsMatch(extension, pattern);
                if (isMatch)
                {
                    ReadSingleExcel(file, keys, vals); ;
                }
            }
        }
    
        public static string[] GetFiles()
        {
            string dataPath = Application.dataPath;
            int lastIndex = dataPath.LastIndexOf('/');
            string rootPath = dataPath.Substring(0, lastIndex);
            rootPath = Path.Combine(rootPath, "Strings");
            string[] files = Directory.GetFiles(rootPath);
            return files;
        }
    
        public static void ReadSingleExcel(string path, List<string> keys, List<string> vals)
        {
            Debug.Log("read path:" + path);
    
            FileStream fs = new FileStream(path, FileMode.Open);
            ExcelPackage package = new ExcelPackage(fs);
    
            ExcelWorksheet sheet = package.Workbook.Worksheets[1];
            int rowCount = sheet.Dimension.End.Row;
    
            for (int row = 2; row <= rowCount; ++row)
            {
                string key = sheet.GetValue(row, 1).ToString();
                string cnVal = sheet.GetValue(row, 2).ToString();
                keys.Add(key);
                vals.Add(cnVal);
            }
    
            fs.Close();
            fs.Dispose();
        }
    
        public static void ModifiedItem(string path, int row, string key, string cnVal = "", string enVal = "en")
        {
            Debug.Log("write to path:" + path + "   key:" + key + " cnVal:" + cnVal);
            FileInfo fi = new FileInfo(path);
            if (!fi.Exists)
            {
                return;
            }
            ExcelPackage package = new ExcelPackage(fi);
            ExcelWorksheet sheet = package.Workbook.Worksheets[1];
            int operateRow = row;
            sheet.SetValue(operateRow, 1, key);
            sheet.SetValue(operateRow, 2, cnVal);
    
            package.SaveAs(fi);
        }
    
        public static void AddItem(string path, string key, string val)
        {
            Debug.Log("add to path:" + path + "   key:" + key + "   val:" + val);
            FileInfo fi = new FileInfo(path);
            if (!fi.Exists)
            {
                return;
            }
            ExcelPackage package = new ExcelPackage(fi);
            ExcelWorksheet sheet = package.Workbook.Worksheets[1];
            int rowCount = sheet.Dimension.Rows;
            int operateRow = rowCount + 1;
            sheet.SetValue(operateRow, 1, key);
            sheet.SetValue(operateRow, 2, val);
            package.SaveAs(fi);
        }
    
        public static void DeleteItem(string path, int row)
        {
            Debug.Log("delete row:" + row + " in path:" + path);
            FileInfo fi = new FileInfo(path);
            if (!fi.Exists)
            {
                return;
            }
            ExcelPackage package = new ExcelPackage(fi);
            ExcelWorksheet sheet = package.Workbook.Worksheets[1];
            sheet.DeleteRow(row);
            package.SaveAs(fi);
        }
    }
    

    3、ExcelTempInstance.cs
    可视化编辑界面的一些临时缓存的数据信息。

    using UnityEngine;
    using UnityEditor;
    using System.Collections.Generic;
    using System.Text.RegularExpressions;
    
    /// <summary>
    /// ExcelEditorWindow内容显示临时缓存结构
    /// </summary>
    public class ExcelTempInstance
    {
        private List<string> _cacheKeys = new List<string>();
        private List<string> _cacheVals = new List<string>();
        
        public List<string> keys;
        public List<string> vals;
    
        private string _path;
        public string newKey = "";
        public string newVal = "";
    
        /// <summary>
        /// all string k-v
        /// </summary>
        private Dictionary<string, string> _dic;
        /// <summary>
        /// all string v-k
        /// </summary>
        private Dictionary<string, string> _dicReverse;
    
        internal void SerializedExcelData(string path)
        {
            _path = path;
            newKey = "";
            newVal = "";
            _cacheKeys.Clear();
            _cacheVals.Clear();
            ExcelHelper.ReadSingleExcel(_path, _cacheKeys, _cacheVals);
    
            keys = new List<string>(_cacheKeys);
            vals = new List<string>(_cacheVals);
    
            _dic = new Dictionary<string, string>(Strings.Instance._keys.Count);
            _dicReverse = new Dictionary<string, string>(Strings.Instance._keys.Count);
            //Strings.Instance._vals;
            for (int i = 0; i < Strings.Instance._keys.Count; ++i)
            {
                _dic.Add(Strings.Instance._keys[i], Strings.Instance._vals[i]);
                _dicReverse.Add(Strings.Instance._vals[i], Strings.Instance._keys[i]);
            }
            
        }
    
        //modified
        internal void ModifiedItem(int index)
        {
            string cacheKey = _cacheKeys[index];
            string key = keys[index];
    
            string cacheVal = _cacheVals[index];
            string val = vals[index];
    
            bool isKeyModified = !cacheKey.Equals(key);
            bool isValModified = !cacheVal.Equals(val);
    
            if (!isKeyModified && !isValModified)
            {
                EditorUtility.DisplayDialog("ERROR!", "No modified here!!!", "OK");
                return;
            }
    
            ExcelHelper.ModifiedItem(_path, index + 2, keys[index], vals[index]);
            SerializedExcelData(_path);
            Debug.Log("apply modified success~");
        }
    
        //delete
        internal void DeleteItem(int index)
        {
            _cacheKeys.RemoveAt(index);
            _cacheVals.RemoveAt(index);
    
            keys.RemoveAt(index);
            vals.RemoveAt(index);
    
            ExcelHelper.DeleteItem(_path, index + 2);
            SerializedExcelData(_path);
        }
    
        //add
        internal void AddItem()
        {
            if (string.IsNullOrEmpty(newKey) || string.IsNullOrEmpty(newVal))
            {
                EditorUtility.DisplayDialog("ERROR!", "Empty param!!!", "OK");
                return;
            }
    
            string val;
            if (_dic.TryGetValue(newKey, out val))
            {
                EditorUtility.DisplayDialog("ERROR!", "param \"" + newKey + "\" is repeated!!!", "OK");
                return;
            }
    
            string valReverse;
            if (_dicReverse.TryGetValue(newVal, out valReverse))
            {
                EditorUtility.DisplayDialog("ERROR!", "param \"" + newVal + "\" is repeated!!!", "OK");
                return;
            }
    
            ExcelHelper.AddItem(_path, newKey, newVal);
            SerializedExcelData(_path);
        }
    
        internal void SearchItems(string matchKey, string matchVal)
        {
            keys.Clear();
            vals.Clear();
    
            bool isEmptyKey = string.IsNullOrEmpty(matchKey);
            bool isEmptyVal = string.IsNullOrEmpty(matchVal);
            if (isEmptyKey && isEmptyVal)
            {
                return;
            }
    
            string baseKey;
            string baseVal;
            for (int i = 0; i < Strings.Instance._keys.Count; ++i)
            {
                baseKey = Strings.Instance._keys[i];
                baseVal = Strings.Instance._vals[i];
    
                if (!isEmptyKey)
                {
                    if (Regex.IsMatch(baseKey, matchKey))
                    {
                        keys.Add(baseKey);
                        vals.Add(baseVal);
                        continue;
                    }
                }
    
                if (!isEmptyVal)
                {
                    if (Regex.IsMatch(baseVal, matchVal))
                    {
                        keys.Add(baseKey);
                        vals.Add(baseVal);
                    }
                }
            }
        }
    
        internal void RestoreItem(int index)
        {
            keys[index] = _cacheKeys[index];
            vals[index] = _cacheVals[index];
        }
    }
    
    /// <summary>
    /// Excel内容展示类型
    /// </summary>
    enum ExcelShowType
    {
        /// <summary>
        /// 可操作状态
        /// </summary>
        Default = 0,
        /// <summary>
        /// 搜索状态,不可操作
        /// </summary>
        Search = 1 << 0,
    }
    

    4、ExcelEditorWindow.cs
    可视化操作界面。

    using UnityEngine;
    using UnityEditor;
    using System.IO;
    
    public partial class ExcelEditorWindow : EditorWindow
    {
        [MenuItem("Tools/Strings/Excel Editor")]
        static void DoMain()
        {
            EditorWindow.GetWindowWithRect(typeof(ExcelEditorWindow), new Rect(0, 0, 960, 640), true, "ExcelEditor");
        }
    
        //head
        private string _searchKey = "";
        private string _searchVal = "";
        //file list
        string[] _filePaths;
        string[] _fileNames;
        private int _nameSelectedIdx = 0;
        private Vector2 _nameScrollPos = Vector2.zero;
        private ExcelTempInstance _excelInst = new ExcelTempInstance();
        //file content
        private Vector2 _contentScrollPos = Vector2.zero;
    
        //status
        ExcelShowType _showType;
    
        //use for initialize
        private void OnEnable()
        {
            _filePaths = ExcelHelper.GetFiles();
            _fileNames = new string[_filePaths.Length];
    
            for (int i = 0; i < _filePaths.Length; ++i)
            {
                _fileNames[i] = Path.GetFileNameWithoutExtension(_filePaths[i]);
            }
    
            SerializedExcelData();
        }
    
        private void SerializedExcelData()
        {
            string path = _filePaths[_nameSelectedIdx];
            _excelInst.SerializedExcelData(path);
    
            _showType = ExcelShowType.Default;
        }
    
        private void OnGUI()
        {
            DrawHeadTool();
            DrawFileNameList();
            DrawFileContent();
    
            Event e = Event.current;
            if (e.keyCode == KeyCode.KeypadEnter)
            {
                GUI.FocusControl(null);
            }
        }
    
        private void DrawHeadTool()
        {
            Rect boxRect = new Rect(15f, 8.0f, Screen.width * 0.965f, Screen.height * 0.05f);
            GUI.Box(boxRect, "");
    
            Rect areaRect = new Rect(18f, 12f, Screen.width * 0.965f, Screen.height * 0.05f);
            GUILayout.BeginArea(areaRect);
            GUILayout.BeginHorizontal(GUILayout.Height(20));
            GUILayout.Space(5);
            if (GUILayout.Button("open path", GUILayout.Width(100), GUILayout.Height(20)))
            {
                string dataPath = Application.dataPath;
                int lastIndex = dataPath.LastIndexOf('/');
                string rootPath = dataPath.Substring(0, lastIndex);
                rootPath = Path.Combine(rootPath, "Strings");
                System.Diagnostics.Process.Start(rootPath);
            }
    
            DrawHeadSearch();
    
            GUILayout.EndHorizontal();
            GUILayout.EndArea();
        }
    
        private void DrawHeadSearch()
        {
            GUILayout.Space(60);
            GUILayout.Label("key:", GUILayout.Width(30));
            _searchKey = EditorGUILayout.TextField(_searchKey, GUILayout.Width(180));
            GUILayout.Space(10);
            GUILayout.Label("value:", GUILayout.Width(40));
            _searchVal = EditorGUILayout.TextField(_searchVal, GUILayout.Width(180));
            GUILayout.Space(5);
            if (GUILayout.Button("search", GUILayout.Width(60), GUILayout.Height(20)))
            {
                _showType = ExcelShowType.Search;
                _excelInst.SearchItems(_searchKey, _searchVal);
            }
        }
    
        private void DrawFileNameList()
        {
            Vector2 boxStartPosition = new Vector2(15f, Screen.height * 0.08f);
            Vector2 boxSize = new Vector2(150f, Screen.height * 0.9f);
            Rect boxRect = new Rect(boxStartPosition, boxSize);
            GUI.Box(boxRect, "Files List");
    
            Vector2 offsetPosition = new Vector2(0f, 25f);
            Vector2 offsetSize = new Vector2(0f, -30f);
            Rect areaRect = new Rect(boxStartPosition + offsetPosition, boxSize + offsetSize);
            GUILayout.BeginArea(areaRect);
            _nameScrollPos = EditorGUILayout.BeginScrollView(_nameScrollPos);
    
            EditorGUI.BeginChangeCheck();
            _nameSelectedIdx = GUILayout.SelectionGrid(_nameSelectedIdx, _fileNames, 1, GUILayout.Height(30f * _fileNames.Length), GUILayout.Width(125));
            if (EditorGUI.EndChangeCheck())
            {
                SerializedExcelData();
            }
    
            EditorGUILayout.EndScrollView();
            GUILayout.EndArea();
        }
    
        private void DrawFileContent()
        {
            Vector2 boxStartPosition = new Vector2(180f, Screen.height * 0.08f);
            Vector2 boxSize = new Vector2(Screen.width - 200f, Screen.height * 0.9f);
            Rect boxRect = new Rect(boxStartPosition, boxSize);
            GUI.Box(boxRect, "");
    
            Vector2 offsetPosition = new Vector2(0f, 10f);
            Vector2 offsetSize = new Vector2(0f, -15f);
            Rect areaRect = new Rect(boxStartPosition + offsetPosition, boxSize + offsetSize);
            GUILayout.BeginArea(areaRect);
    
            EditorGUILayout.BeginHorizontal();
            GUILayout.Space(150);
            EditorGUILayout.LabelField("key");
            EditorGUILayout.LabelField("value");
            EditorGUILayout.EndHorizontal();
    
            GUILayout.Space(10);
    
            _contentScrollPos = EditorGUILayout.BeginScrollView(_contentScrollPos);
            
            for (int i = 0; i < _excelInst.keys.Count; ++i)
            {
                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("no." + (i + 1), GUILayout.MaxWidth(40));
                EditorGUI.BeginChangeCheck();
                _excelInst.keys[i] = EditorGUILayout.TextField(_excelInst.keys[i], GUILayout.MaxWidth(180));
                _excelInst.vals[i] = EditorGUILayout.TextField(_excelInst.vals[i]);
                if (EditorGUI.EndChangeCheck())
                {
                    //Debug.Log(_excelInst.keys[i] + "  ---> " + _excelInst.vals[i]);
                }
                EditorGUILayout.EndHorizontal();
    
                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("");
    
                if (_showType == ExcelShowType.Default)
                {
                    if (GUILayout.Button("apply", GUILayout.Width(100), GUILayout.Height(20)))
                    {
                        if (EditorUtility.DisplayDialog("CONFIRM", "Are you sure to change???", "OK", "NO"))
                        {
                            _excelInst.ModifiedItem(i);
                            GUIUtility.keyboardControl = 0;
                        }
                        else
                        {
                            _excelInst.RestoreItem(i);
                            GUIUtility.keyboardControl = 0;
                        }
                    }
                    if (GUILayout.Button("delete", GUILayout.Width(80), GUILayout.Height(20)))
                    {
                        if (EditorUtility.DisplayDialog("CONFIRM", "Are you sure to delete???", "OK", "NO"))
                        {
                            _excelInst.DeleteItem(i);
                            GUIUtility.keyboardControl = 0;
                        }
                    }
                }
                
                EditorGUILayout.EndHorizontal();
                GUILayout.Space(15);
            }
            
            EditorGUILayout.EndScrollView();
    
            if (_showType == ExcelShowType.Default)
            {
                DrawFileContentBottom();
            }
    
            GUILayout.EndArea();
        }
    
        private void DrawFileContentBottom()
        {
            GUILayout.Space(20);
    
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("new", GUILayout.MaxWidth(45));
            _excelInst.newKey = EditorGUILayout.TextField(_excelInst.newKey, GUILayout.MaxWidth(180));
            _excelInst.newVal = EditorGUILayout.TextField(_excelInst.newVal);
            EditorGUILayout.EndHorizontal();
    
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("");
            if (GUILayout.Button("add", GUILayout.Width(120), GUILayout.Height(20)))
            {
                _excelInst.AddItem();
                GUIUtility.keyboardControl = 0;
            }
            EditorGUILayout.EndHorizontal();
        }
    }
    

    相关文章

      网友评论

        本文标题:结合工作需求用GUI写一个快捷操作Excel的界面

        本文链接:https://www.haomeiwen.com/subject/avuvwftx.html