美文网首页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的界面

    因工作过程中需要考虑游戏内中文显示方便国际化,游戏内涉及到中文的固定字符串用Excel存储。反复操作Excel对程...

  • 基本的widgets

    tkinter 是Python自带的GUI模块,相对于 Pyqt5 等其他界面模块,简单快捷;如对界面美观无需求,...

  • Excel常用7个快捷组合键

    说到Excel快捷键,它可以高效的完成我们日常的各类工作。Excel中使用频率最高的快捷键操作,莫过于Ctrl快捷...

  • JAVA 学习笔记之 GUI(图形用户界面)

    GUI概述 Graphical User Interface(图形用户接口)。用图形的方式,来显示计算机操作的界面...

  • java笔记--GUI

    GUI(Graphical User Interface):图形用户接口,用图形的方式,来显示计算机操作的界面,这...

  • Mac显示隐藏文件

    我这里就提供一种最简单的方式,直接GUI可视化界面上的操作。简单易懂 1、打开finder 2、快捷键 comma...

  • 第58节:Java中的图形界面编程-GUI

    欢迎到我的简书查看我的文集 前言: GUI是图形用户界面,在Java中,图形用户界面我们用GUI表示,而GUI的完...

  • 高效工作,需要这几个Excel的快捷方式

    Excel的基础录入工作需要的一些快捷操作,当你掌握一些快捷操作时,你会发现工作起来是多么的得心应手,今天给大家介...

  • 用excel写需求文档

    本文转载自枯叶老师的《需求文档2.0:三个原因,解答我为什么用excel写需求文档》 原文链接 需求文档2.0:三...

  • excel合并多个sheet到一个

    Excel自带VBA,可以实现批量性操作。 合并多个Sheet的工作页,用VBA写代码操作如下: 1.按下Alt+...

网友评论

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

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