在插件开发过程中,随着功能越来越多,用户找寻功能入口将变得越来越困难,在Excel催化剂 ,将采用遍历所有功能的方式,让用户可以轻松使用简单的查找功能找到想要功能所在位置,查找的范围有:功能按钮的显示名称、功能说明等。

 
按钮功能查找关键词文本来源

这个遍历功能区按钮属性,不确定在xml功能区中能否实现,在设计器功能区,因其已经被强类型为一个类对象,用反射技术可以将这个Ribbon类下所有的控件及属性给遍历出来。详细可参考功能第78波说明。

 
功能区效果

同样地,自定义函数也可以用遍历的方式,列出所有自定义函数。前提是自定义函数是ExcelDna框架开发的。

 
自定义函数效果

代码实现

给用户一个按钮,点击后遍历到工作表中。

        private void btnShowFeatures_Click(object sender, RibbonControlEventArgs e)
{
try
{
Common.ExcelApp.ScreenUpdating = false;
Common.ExcelApp.DisplayAlerts = false; RibbonMenu ribbonMenu = sender as RibbonMenu;
GroupVisibleSetting groupVisibleSetting = new GroupVisibleSetting()
{
CurrentRibbon = this
};
groupVisibleSetting.ListTabFunctionInfo();
//遍历自定义函数清单
UdfListInfo.ListUdfInfo(); }
catch (Exception ex)
{ Common.OutMsgError(ex);
}
finally
{
Common.ExcelApp.ScreenUpdating = true;
Common.ExcelApp.DisplayAlerts = true;
}
}

做了个类,用于访问功能区的信息,里面用了反射技术,因笔者水平也是比较菜,是笔者师傅给予帮助下实现的,详细技术要点也讲不清,有兴趣深入的可以自行百度学习。

using Microsoft.Office.Tools.Excel;
using Microsoft.Office.Tools.Ribbon;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using Excel = Microsoft.Office.Interop.Excel;
namespace Excel催化剂
{
class GroupVisibleSetting
{
public Ribbon1 CurrentRibbon { get; set; }
public RibbonMenu MenuSwitch { get; set; } public void ListTabFunctionInfo()
{
DataTable dt = new DataTable();
dt.Columns.Add("一级分组");
dt.Columns.Add("二级分组");
dt.Columns.Add("三级分组");
dt.Columns.Add("功能名称");
dt.Columns.Add("功能说明"); foreach (var grp in CurrentRibbon.Tabs.Cast<RibbonTab>().FirstOrDefault(s => s.Name == "excelCatalyzer").Groups)
{
foreach (var grpItem in grp.Items)
{
if (grpItem is RibbonButton)
{
var btn = grpItem as RibbonButton;
DataRow dr = dt.NewRow();
dr["一级分组"] = grp.Label;
dr["二级分组"] = grp.Label;
dr["三级分组"] = grp.Label;
dr["功能名称"] = btn.Label;
dr["功能说明"] = btn.SuperTip; dt.Rows.Add(dr);
}
else if (grpItem is RibbonMenu)
{
var grpItemMenu = grpItem as RibbonMenu;
MenuItemsLoad(grpItemMenu); foreach (var grpItemMenuItem in grpItemMenu.Items)
{
if (grpItemMenuItem is RibbonButton)
{
var btn = grpItemMenuItem as RibbonButton;
DataRow dr = dt.NewRow();
dr["一级分组"] = grp.Label;
dr["二级分组"] = grpItemMenu.Label;
dr["三级分组"] = grpItemMenu.Label;
dr["功能名称"] = btn.Label;
dr["功能说明"] = btn.SuperTip;
dt.Rows.Add(dr);
}
else if (grpItemMenuItem is RibbonSeparator)
{
var btn = grpItemMenuItem as RibbonSeparator;
DataRow dr = dt.NewRow();
dr["一级分组"] = grp.Label;
dr["二级分组"] = grpItemMenu.Label;
dr["三级分组"] = grpItemMenu.Label;
dr["功能名称"] = btn.Title;
dr["功能说明"] = "分隔符,组合以下内容";
dt.Rows.Add(dr);
}
else if (grpItemMenuItem is RibbonGallery)
{
var itemGal = grpItemMenuItem as RibbonGallery;
DataRow dr = dt.NewRow();
dr["一级分组"] = grp.Label;
dr["二级分组"] = grpItemMenu.Label;
dr["三级分组"] = grpItemMenu.Label;
dr["功能名称"] = itemGal.Label;
dr["功能说明"] = itemGal.SuperTip;
dt.Rows.Add(dr); }
else if (grpItemMenuItem is RibbonMenu)
{
var itemMenu = grpItemMenuItem as RibbonMenu;
foreach (var itemMenuItem in itemMenu.Items)
{ DataRow dr = dt.NewRow();
dr["一级分组"] = grp.Label;
dr["二级分组"] = grpItemMenu.Label;
dr["三级分组"] = itemMenu.Label;
if (itemMenuItem is RibbonButton)
{
var btn = itemMenuItem as RibbonButton;
dr["功能名称"] = btn.Label;
dr["功能说明"] = btn.SuperTip;
}
else if (itemMenuItem is RibbonSeparator)
{
var btn = itemMenuItem as RibbonSeparator;
dr["功能名称"] = btn.Title;
dr["功能说明"] = "分隔符,组合以下内容";
}
dt.Rows.Add(dr);
} } }
}
else if (grpItem is RibbonToggleButton)
{
var tglBtn = grpItem as RibbonToggleButton;
DataRow dr = dt.NewRow();
dr["一级分组"] = grp.Label;
dr["二级分组"] = grp.Label;
dr["三级分组"] = grp.Label;
dr["功能名称"] = tglBtn.Label;
dr["功能说明"] = tglBtn.SuperTip;
dt.Rows.Add(dr);
}
else if (grpItem is RibbonGallery)
{
var grpGal = grpItem as RibbonGallery; foreach (var grpGalItem in grpGal.Items)
{
DataRow dr = dt.NewRow();
dr["一级分组"] = grp.Label;
dr["二级分组"] = grp.Label;
dr["三级分组"] = grp.Label;
dr["功能名称"] = grpGalItem.Label;
dr["功能说明"] = grpGalItem.SuperTip;
dt.Rows.Add(dr); }
} }
} ListObject listObject = Common.CreateNewVSTOListObject("功能清单",false);
Common.OutputDataToListObject(listObject, dt, false);
} private void MenuItemsLoad(RibbonMenu grpItemMenu)
{
if (grpItemMenu.Name == "menuNumberFormatSetting")
{
CurrentRibbon.menuNumberFormatSetting_ItemsLoading(grpItemMenu, null);
var panel = Utilities.TaskPanelUtility.GetCusTomTaskPaneByTitle(Utilities.TaskPanelUtility.NumberFormatPanelTitle);
panel.Visible = false; }
else if (grpItemMenu.Name == "menuVisualData")
{
CurrentRibbon.menuVisualData_ItemsLoading(grpItemMenu, null);
var panel = Utilities.TaskPanelUtility.GetCusTomTaskPaneByTitle(Utilities.TaskPanelUtility.DataVisualPanelTitle);
panel.Visible = false;
}
else if (grpItemMenu.Name == "menuInsertPicture")
{
CurrentRibbon.menuInsertPicture_ItemsLoading(grpItemMenu, null);
var panel = Utilities.TaskPanelUtility.GetCusTomTaskPaneByTitle(Utilities.TaskPanelUtility.BatchPicInsertPanelTitle);
panel.Visible = false;
}
else if (grpItemMenu.Name == "menuBarCode")
{
CurrentRibbon.menuBarCode_ItemsLoading(grpItemMenu, null);
var panel = Utilities.TaskPanelUtility.GetCusTomTaskPaneByTitle(Utilities.TaskPanelUtility.QrCodePanelTitle);
panel.Visible = false;
}
} public void GrpVisibleSetting()
{
var grpInfos = GetGrpInfosSetting();
foreach (var item in grpInfos)
{
var grp = Globals.Ribbons.Ribbon1.GetGrpByGroupName(item.GrpName);
if (grp != null)
{
grp.Visible = item.GrpVisible;
} }
} public void menuSwitch_ItemsLoading()
{ this.MenuSwitch.Items.Clear(); //从反射中得到grp的集合
RibbonGroup[] grpfields = GetGrpFields();
//从setting里提取grp信息 var grpInfosSetting = GetGrpInfosSetting(); foreach (var item in grpfields)
{
var grpInfo = grpInfosSetting.FirstOrDefault(s => s.GrpName == item.Name);
RibbonCheckBox control = Globals.Ribbons.Ribbon1.Factory.CreateRibbonCheckBox();
control.Name = "btn" + item.Name;
control.Label = item.Label;
control.Checked = grpInfo.GrpName != null ? grpInfo.GrpVisible : true; //当setting信息里有保存的话,用setting的信息显示关闭与否,否则用true
control.Click += Control_Click;
this.MenuSwitch.Items.Add(control);
}
} private void Control_Click(object sender, RibbonControlEventArgs e)
{
RibbonCheckBox checkBox = sender as RibbonCheckBox;
string grpName = checkBox.Name.Substring(3);//去除btn字符 RibbonGroup grp = Globals.Ribbons.Ribbon1.GetGrpByGroupName(grpName);
grp.Visible = checkBox.Checked; SaveSwithSetting();
} private void SaveSwithSetting()
{
List<string> grpInfos = new List<string>();
foreach (RibbonCheckBox item in this.MenuSwitch.Items)
{
grpInfos.Add(item.Name.Substring(3) + "," + item.Label + "," + item.Checked.ToString());
}
Properties.Settings.Default.SwitchSetting = string.Join(";\n", grpInfos);
Properties.Settings.Default.Save();
} /// <summary>
/// 反射的方式获得组的对象
/// </summary>
/// <returns></returns>
private RibbonGroup[] GetGrpFields()
{
BindingFlags bf = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField;
Type t = typeof(Ribbon1);
return t.GetFields(bf)
.Where(s => s.Name.StartsWith("grp") && s.Name != "grpSwitch" && s.Name != "grpAbout")
.Select(s => Globals.Ribbons.Ribbon1.GetGrpByGroupName(s.Name))
.ToArray();
} private (string GrpName, string GrpCaption, bool GrpVisible)[] GetGrpInfosSetting()
{
string switchSettingString = Properties.Settings.Default.SwitchSetting; return switchSettingString.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)
.Select(s =>
(
GrpName: s.Split(',')[0].Trim(new char[] { '\r', '\n', '\0' }),
GrpCaption: s.Split(',')[1].Trim(new char[] { '\r', '\n', '\0' }),
GrpVisible: bool.Parse(s.Split(',')[2].Trim(new char[] { '\r', '\n', '\0' }))
)
).ToArray();
} }
}

同样地在自定义函数方面,通过在自定义函数里作了一个自定义函数,专门用于遍历自定义函数的属性,已经开源在自定义函数项目中。

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using Excel = Microsoft.Office.Interop.Excel;
using Microsoft.Office.Tools.Excel;
namespace Excel催化剂
{
class UdfListInfo
{
private static string shtName = "功能清单";
internal static void ListUdfInfo()
{
try
{ Excel.Worksheet sht = Common.ExcelApp.ActiveWorkbook.Worksheets[shtName];
DataTable dt = new DataTable();
dt.Columns.Add("函数类别");
dt.Columns.Add("函数名称");
dt.Columns.Add("函数注释"); var result = Common.ExcelApp.Run("ListUdfDesc"); if (result is Array)
{
var arrResult = Utilities.ArrayUtility.ConvertExcelArrayToDotNetArray(result as Array);
foreach (var item in arrResult)
{
var strSplits = item.ToString().Split(new string[] { "#|#" }, StringSplitOptions.RemoveEmptyEntries);
if (strSplits.Length == 3)
{
DataRow dr = dt.NewRow();
dr[0] = strSplits[0];
dr[1] = strSplits[1];
dr[2] = strSplits[2];
dt.Rows.Add(dr);
}
}
Excel.Range listRange = sht.ListObjects[shtName].Range;
Excel.Range firstCell = listRange.Offset[0, listRange.Columns.Count + 2].Cells[1, 1]; Worksheet vstoSht = Globals.Factory.GetVstoObject(sht);
var listObject = vstoSht.Controls.AddListObject(firstCell, "自定义函数清单"); Common.OutputDataToListObject(listObject, dt, false); }
}
catch (Exception)
{ } }
}
}

上述代码中,在VSTO项目里,仅需用Application.Run就可以访问到xll里的自定义函数ListUdfDesc,同时有个小要点是自定义函数返回的数组,下标是从1开始的Excel特有的,和.net的0为下标的不一样,需要作下转换。
var arrResult = Utilities.ArrayUtility.ConvertExcelArrayToDotNetArray(result as Array);

 public static object ListUdfDesc()
{
List<string> list = new List<string>();
var funcs = ExcelRegistration.GetExcelFunctions();
foreach (var funcInfo in funcs)
{
string name = funcInfo.FunctionAttribute.Name;
string desc = funcInfo.FunctionAttribute.Description.Replace("Excel催化剂出品,必属精品!", "");
string catalog = funcInfo.FunctionAttribute.Category;
if (!string.IsNullOrEmpty( catalog))
{
list.Add($"{catalog}#|#{name}#|#{desc}");
}
}
if (list.Count>0)
{
return list.ToArray();
}
else
{
return string.Empty;
} }
        public static object[] ConvertExcelArrayToDotNetArray(Array arr)
{
int lb = arr.GetLowerBound(0);
var ret = new object[arr.GetUpperBound(0) - lb + 1];
for (int ix = 0; ix < ret.Length; ++ix)
{
ret[ix] = arr.GetValue(ix + lb);
}
return ret;
}

结语

使用遍历的方式,让用户可以更轻松地查找相应功能,将极大地提升查找功能的友好度,本篇用到反射技术,比较高级的技术,若代码不甚明白,可自行进行相关知识点的学习补充。

再一次验证了VSTO给一般开发者带来的便利性,特别是在设计器功能区上,带来了强类型的Ribbon类,可轻松访问此类里的所有对象,而增加此类的内容,仅需类似Winform那般拖拉控件即可完成,敏捷开发首选。

技术交流QQ群

QQ群名:Excel催化剂开源讨论群, QQ群号:788145319

 
Excel催化剂开源讨论群二维码

关于Excel催化剂

Excel催化剂先是一微信公众号的名称,后来顺其名称,正式推出了Excel插件,插件将持续性地更新,更新的周期视本人的时间而定争取一周能够上线一个大功能模块。Excel催化剂插件承诺个人用户永久性免费使用!

Excel催化剂插件使用最新的布署技术,实现一次安装,日后所有更新自动更新完成,无需重复关注更新动态,手动下载安装包重新安装,只需一次安装即可随时保持最新版本!

Excel催化剂插件下载链接:https://pan.baidu.com/s/1Iz2_NZJ8v7C9eqhNjdnP3Q

 
联系作者
 
公众号

取名催化剂,因Excel本身的强大,并非所有人能够立马享受到,大部分人还是在被Excel软件所虐的阶段,就是头脑里很清晰想达到的效果,而且高手们也已经实现出来,就是自己怎么弄都弄不出来,或者更糟的是还不知道Excel能够做什么而停留在不断地重复、机械、手工地在做着数据,耗费着无数的青春年华岁月。所以催生了是否可以作为一种媒介,让广大的Excel用户们可以瞬间点燃Excel的爆点,无需苦苦地挣扎地没日没夜的技巧学习、高级复杂函数的烧脑,最终走向了从入门到放弃的道路。

最后Excel功能强大,其实还需树立一个观点,不是所有事情都要交给Excel去完成,也不是所有事情Excel都是十分胜任的,外面的世界仍然是一个广阔的世界,Excel只是其中一枚耀眼的明星,还有其他更多同样精彩强大的技术、工具等。*Excel催化剂也将借力这些其他技术,让Excel能够发挥更强大的爆发!

关于Excel催化剂作者

姓名:李伟坚,从事数据分析工作多年(BI方向),一名同样在路上的学习者。
服务过行业:零售特别是鞋服类的零售行业,电商(淘宝、天猫、京东、唯品会)

技术路线从一名普通用户,通过Excel软件的学习,从此走向数据世界,非科班IT专业人士。
历经重重难关,终于在数据的道路上达到技术平原期,学习众多的知识不再太吃力,同时也形成了自己的一套数据解决方案(数据采集、数据加工清洗、数据多维建模、数据报表展示等)。

擅长技术领域:Excel等Office家族软件、VBA&VSTO的二次开发、Sqlserver数据库技术、Sqlserver的商业智能BI技术、Powerbi技术、云服务器布署技术等等。

2018年开始职业生涯作了重大调整,从原来的正职工作,转为自由职业者,暂无固定收入,暂对前面道路不太明朗,苦重新回到正职工作,对Excel催化剂的运营和开发必定受到很大的影响(正职工作时间内不可能维护也不可能随便把工作时间内的成果公布于外,工作外的时间也十分有限,因已而立之年,家庭责任重大)。

和广大拥护者一同期盼:Excel催化剂一直能运行下去,我所惠及的群体们能够给予支持(多留言鼓励下、转发下朋友圈推荐、小额打赏下和最重点的可以和所在公司及同行推荐推荐,让我的技术可以在贵司发挥价值,实现双赢(初步设想可以数据顾问的方式或一些小型项目开发的方式合作)。

技术交流QQ群

QQ群名:Excel催化剂开源讨论群, QQ群号:788145319

 
Excel催化剂开源讨论群二维码

关于Excel催化剂

Excel催化剂先是一微信公众号的名称,后来顺其名称,正式推出了Excel插件,插件将持续性地更新,更新的周期视本人的时间而定争取一周能够上线一个大功能模块。Excel催化剂插件承诺个人用户永久性免费使用!

Excel催化剂插件使用最新的布署技术,实现一次安装,日后所有更新自动更新完成,无需重复关注更新动态,手动下载安装包重新安装,只需一次安装即可随时保持最新版本!

Excel催化剂插件下载链接:https://pan.baidu.com/s/1Iz2_NZJ8v7C9eqhNjdnP3Q

 
联系作者
 
公众号

取名催化剂,因Excel本身的强大,并非所有人能够立马享受到,大部分人还是在被Excel软件所虐的阶段,就是头脑里很清晰想达到的效果,而且高手们也已经实现出来,就是自己怎么弄都弄不出来,或者更糟的是还不知道Excel能够做什么而停留在不断地重复、机械、手工地在做着数据,耗费着无数的青春年华岁月。所以催生了是否可以作为一种媒介,让广大的Excel用户们可以瞬间点燃Excel的爆点,无需苦苦地挣扎地没日没夜的技巧学习、高级复杂函数的烧脑,最终走向了从入门到放弃的道路。

最后Excel功能强大,其实还需树立一个观点,不是所有事情都要交给Excel去完成,也不是所有事情Excel都是十分胜任的,外面的世界仍然是一个广阔的世界,Excel只是其中一枚耀眼的明星,还有其他更多同样精彩强大的技术、工具等。*Excel催化剂也将借力这些其他技术,让Excel能够发挥更强大的爆发!

关于Excel催化剂作者

姓名:李伟坚,从事数据分析工作多年(BI方向),一名同样在路上的学习者。
服务过行业:零售特别是鞋服类的零售行业,电商(淘宝、天猫、京东、唯品会)

技术路线从一名普通用户,通过Excel软件的学习,从此走向数据世界,非科班IT专业人士。
历经重重难关,终于在数据的道路上达到技术平原期,学习众多的知识不再太吃力,同时也形成了自己的一套数据解决方案(数据采集、数据加工清洗、数据多维建模、数据报表展示等)。

擅长技术领域:Excel等Office家族软件、VBA&VSTO的二次开发、Sqlserver数据库技术、Sqlserver的商业智能BI技术、Powerbi技术、云服务器布署技术等等。

2018年开始职业生涯作了重大调整,从原来的正职工作,转为自由职业者,暂无固定收入,暂对前面道路不太明朗,苦重新回到正职工作,对Excel催化剂的运营和开发必定受到很大的影响(正职工作时间内不可能维护也不可能随便把工作时间内的成果公布于外,工作外的时间也十分有限,因已而立之年,家庭责任重大)。

和广大拥护者一同期盼:Excel催化剂一直能运行下去,我所惠及的群体们能够给予支持(多留言鼓励下、转发下朋友圈推荐、小额打赏下和最重点的可以和所在公司及同行推荐推荐,让我的技术可以在贵司发挥价值,实现双赢(初步设想可以数据顾问的方式或一些小型项目开发的方式合作)。

Excel催化剂开源第12波-VSTO开发遍历功能区所有菜单按钮及自定义函数清单的更多相关文章

  1. Excel催化剂开源第23波-VSTO开发辅助录入功能关键技术

    Excel催化剂开源第23波-VSTO开发辅助录入功能关键技术 Excel催化剂   2019.01.12 14:10* 字数 2948 阅读 41评论 0喜欢 0 编辑文章 在Excel催化剂的几大 ...

  2. Excel催化剂开源第16波-VSTO开发之脱离传统COM交互以提升性能

    在VSTO开发或其他COM技术开发过程中,甚至VBA也是,在和Excel交互中,难免会遇到性能瓶颈问题,COM技术的交互实在太慢,对大量数据读写等操作,耗时太长,容易卡用户界面以为是程序死机等等. 在 ...

  3. Excel催化剂开源第10波-VSTO开发之用户配置数据与工作薄文件一同存储

    在传统的VBA开发中,若是用的是普通加载项方法,是可以存储数据在xlam上的,若用的是Com加载项方法同时是Addins程序级别的项目开发的,配置文件没法保存到工作薄中,一般另外用配置文件来存放供调用 ...

  4. Excel催化剂开源第32波-VSTO开发的插件让WPS顺利调用的方法-注册表增加注册信息

    VSTO插件开发完成后,鉴于现在WPS用户也不少,很多时候用户没办法用OFFICE软件,只能在WPS环境下办公,VSTO开发的插件,只需增加一句注册表信息,即可让WPS识别到并调用VSTO开发的功能, ...

  5. Excel催化剂开源第14波-VSTO开发之单元格区域转DataTable

    在Excel开发过程中,大部分时候是和Range单元格区域打交道,在VBA开发中,大家都知道的一点是,不能动不动就去遍历所有单元格,那性能是非常糟糕的,很多时候,是需要把整个单元格区域装入数组中再作处 ...

  6. Excel催化剂开源第9波-VSTO开发图片插入功能,图片带事件

    图片插入功能,这个是Excel插件的一大刚需,但目前在VBA接口里开发,如果用Shapes.AddPicture方法插入的图片,没法对其添加事件,且图片插入后需等比例调整纵横比例特别麻烦,特别是对于插 ...

  7. Excel催化剂开源第8波-VSTO开发之异步调用方法

    在VSTO开发过程中,因其和普通的Winform开发有点差别,具体细节笔者也说不清楚,大概是VSTO的插件是寄生在Excel中,不属于独立的进程之类的,其异步方法调用时,未能如Winform那样直接用 ...

  8. Excel催化剂开源第7波-VSTO开发中Ribbon动态加载菜单

    在VS开发环境中,特别是VSTO的开发,微软已经现成地给开发者准备了设计器模式的功能区开发,相对传统的VBA.ExcelDna和其他方式的COM加载项开发来说,不需要手写xml功能区,直接类似拖拉窗体 ...

  9. Excel催化剂开源第22波-VSTO的帮助文档在哪里?

    Excel催化剂开源第22波-VSTO的帮助文档在哪里? Excel催化剂   2019.01.12 14:10 字数 2930 阅读 55评论 0喜欢 0 编辑文章 对于专业程序猿来说,查找文档不是 ...

随机推荐

  1. PRML Chapter2

    参考文献:PRML2 参数方法和非参数方法 机器学习上的方法分为参数方法(根据先验知识假定模型服从某种分布,然后利用训练集估计出模型参数,也就弄清楚了整个模型,例如感知器)和非参数方法(基于记忆训练集 ...

  2. 使用MinGW编译Boost,MSVC编译Boost的几种链接方式 good

    1.下载Boost(http://www.boost.org) 我目前用的是1.61.0版本 2.将MinGW下的bin目录完整路径设置到系统环境变量Path中,保证cmd命令行能找到gcc,g++等 ...

  3. CSS3 GENERATOR可以同时为一个元素完成border-radius、box-shadow、gradient和opacity多项属性的设置

    CSS3 GENERATOR可以同时为一个元素完成border-radius.box-shadow.gradient和opacity多项属性的设置 CSS3 GENERATOR 彩蛋爆料直击现场 CS ...

  4. Qt系统对话框中文化及应用程序实现重启及使用QSS样式表文件及使用程序启动界面

    一.应用程序中文化 1).Qt安装目录下有一个目录translations/,在此目录下有qt_zh_CN.ts和 qt_zh_CN.qm把它们拷贝到你的工程目录下. 2).在main函数加入下列代码 ...

  5. windows下进程间通信的(13种方法)

    转自:http://blog.csdn.NET/shiqz/article/details/5862936 摘 要 随着人们对应用程序的要求越来越高,单进程应用在许多场合已不能满足人们的要求.编写多进 ...

  6. jquery事件和动画操作集锦

    一,事件 1,加载事件 1 2 3 4 5 6 $(document).ready(function(){   //todo }); //dom准备就绪后执行ready里面的函数,此时dom对应的相关 ...

  7. Google C++测试框架系列高级篇:第二章 让GTest学习打印自定义对象

    上一篇:更多关于断言的知识 原始链接:Teaching Google Test How to Print Your Values 词汇表 版本号:v_0.1 让GTest学习打印自定义对象 当一个断言 ...

  8. [2017.02.15] 《C++Primer5》 复习笔记

    编程语言主要是提供一个框架,用计算机能够处理的方式来表达问题的解决方法. 自定义数据类型class的基本思想是数据抽象dataabstraction和封装encapsulation.数据抽象是一种依赖 ...

  9. Hadoop 三剑客之 —— 分布式计算框架 MapReduce

    一.MapReduce概述 二.MapReduce编程模型简述 三.combiner & partitioner 四.MapReduce词频统计案例         4.1 项目简介      ...

  10. vue.js执行mounted的实例

    代码如下: <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" c ...