编辑器加载中...http://www.cnblogs.com/yangecnu/p/Excel-Menu-System-Introduction.html

在开始Excel开发之前,需要把架子搭起来。最直接的那就是Excel里面的菜单了,他向用户直观的展现了我们的插件具有哪些功能。菜单出来之后我们就可以实现里面的事件和功能了。Excel菜单有两种形式,一种是Excel 2003及之前的传统菜单样式,一种是Excel 2007及之后的Ribbon菜单。本文首先讲解Excel 2007中菜单的创建,包括使用Visual Studio可视化设计菜单,菜单的RibbonXml配置,然后讲解如何在Excel 2003中创建自定义菜单。最后演示如何使用SharedAddin技术将两者结合起来,即在2003版本中显示原始的菜单样式,在以2003上版本中动态加载Ribbon菜单,从而达到版本的兼容。

一 Excel 的Ribbon菜单及Ribbon Xml文件
要演示菜单的创建,我们首先创建一个VSTO程序,如图在VS中创建一个Excel外接程序:

然后接下来,添加项,添加一个Ribbon菜单:

在创建菜单之前,需要明确我们的插件具有哪些模块。这里为了演示如何创建菜单以及后面的功能点,我们的插件打算做四个功能点。 首先是财经模块,包括从一些开放的财经API如新浪财经API,雅虎API中获取实时或者历史行情数据;地图模块,包括地图显示,地址检索,专题制图等;天气模块,获取天气,天气保表;系统模块,包括登录,帮助,关于模块等。确定好功能点之后,就可以开始创建菜单了。

添加了Ribbon菜单之后,就可以打开ToolBox开始设计了,如下图。下面介绍各个菜单项的功能及设计要点。

基本控件
2.1 Tab控件

首先介绍的是RibbonTab控件,它是所有控件的容器,当我们添加一个Ribbon菜单的时候,VS默认会给我们创建一个RibbonTab控件,一个VSTO项目可以创建多个Tab控件,您需要做的只是从ToolBox中推拽一个Tab至设计界面上即可。Tab控件有一些属性。

其中比较重要的属性为ControlIdType,如果类型是Office的话,他会嵌入到Office内置系统的 Tab页中,而不是默认的新创建一个以Label为名称的Tab页。下图是ControlIdType为Office的效果,如果PositionType属性设置为Default的话,会出现在Office加载项 这个标签页中。

如果将ControlIdType设置为Custom,则在界面上会显示以Label命名的一个新的Tab页,这里将Label改为歪歪插件。效果如下图:

一般的,我们会采用Custom的方式,让我们的插件以独立的Tab页展现出来。

Tab控件还有一个重要的名为Position的属性,他决定了我们的Tab在哪个地方展现,PositionType的默认值为Default,这时,如果ControlIdType为Office,我们的插件会在加载项中显示,如果为Custom,插件会显示在Office里面的最后一个加载项后面,如果有多个加载项,则按顺序往后面排列。PositionType属性还有BeforeOfficeId和AfterOfficeId两值,设置这两个属性时,需要指定OfficeId,Office内置的菜单的ID值,您可以到MSDN上下载。指定好OfficeId后,我们的Tab也会在该内置Tab页里面,前面或者后面显示。一般的,我们保持这个属性为空即可。让我们的插件在Office系统Tab页之后显示。

2.2 Group控件

Group控件的作用是将我们的功能进行分组。回到我们之前的规划,我们的歪歪插件有财经,地图,天气,关于这几大功能。所以我们需要在界面上放置4个Group控件,并对其进行命名。

2.3 Menu控件和SpliterButton控件

在分好类之后,我们需要对每个分类的细小功能进行设计,这里面我们需要放置各种控件,首先我们可能会接触到的就是Menu控件,里面可以包含Button,SplitButton等。我们规划的财经项主要包括,实时行情,历史行情和导入功能。实时行情和历史行情包括从Sina或者Yahoo财经API接口中获取所有股票的实时和历史行情数据,导入功能即是从本地或者网络上导入数据。所以在页面上添加三个Menu控件。

Menu控件几个比较重要的属性,一个是ControlSize,它确定了控件的大小,一般地,如果功能较重要,或者是有比较明显的分类用途,使用RibbonControlSizeLarge。然后需要设置菜单的图标,可以指定自定义的图片,也可以使用默认的Office内置的菜单的图片,如果要使用内置的图片,需要设置OfficeImageId,具体内置Id及图片可以查看该网址。一般地,我们会为我们的菜单设计图标,您只需要指定其Image属性即可。

SplitButton控件和Menu控件类似,它可以包含Button,Seperator控件,不同的是,SplitButton控件本身自己可以响应Click事件,通常在Menu中如果需要将该菜单项中常用的功能设置为默认的,那么可以使用SplitButton控件,将最常用的功能设置到该控件的Click事件上来。

2.4 Button,Seperator控件

Button控件是最基础的响应单击事件的UI控件。点开Menu的下拉图标,然后向里面添加Button按钮即可,可以设置按钮的Image属性。在设计按钮的时候,可能我们需要对其进行分组,这时候,使用Seperator控件是一种比较好的选择,直接在ToolBox中拖动一个Seperator控件到界面上想分割的地方即可。默认情况下Seperator控件是一条竖线,但是当设置Seperator控件的Title属性时,他可以以文本的形式来进行分割,这和其他系统中的Seperator控件不一样。

同理,按照规划,我们将所有的菜单设计好,并注册其Click事件。这里只讲解了这几个基本的菜单项控件,更多的控件您可能以自己往界面上拖拽试试看,利用这些内置的控件,您可以设计出和Office内置的Ribbon菜单媲美的自定义菜单界面来。

RibbonXml
在Office中Ribbon菜单时可以通过RibbonXML进行配置,也就是说,上面的可视化界面设计其实是为我们提供了编辑RibbonXML的设计时支持。其实我们也可以直接创建一个XML文件进行设计,然后在代码中进行加载,同样能够实现这样的功能。在有些情况下,比如我们创建SharedAddin程序时,根本没有设计时支持。所以了解RibbonXML对于创建可兼容多版本Excel菜单系统显得尤为重要。

要创建RibbonXML最好的做法是对着新建的可视化菜单,然后右键->将功能区导出到XML。然后项目会自动创建Ribbon.xml和Ribbon.cs文件,其中Ribbon.xml是布局文件,Ribbon.cs是事件处理代码。

打开Ribbon.xml可以看到如下代码,可以看到这个UI界面的展现即是使用了该XML文件来进行渲染的,其中在XML中还可以声明一些事件,后面会讲。

现在,如何在我们的应用程序中加载该RibbonXML并渲染出Ribbon菜单呢?首先,我们将之前的添加的可视化设计的Ribbon菜单YYMenu.cs排除到项目外。然后转到ThisAddIn.cs中,覆写Office.IRibbonExtensibility 接口的CreateRibbonExtensibilityObject方法,实例化自动生成的Ribbon类,然后返回。

private Ribbon customerRibbon;

protected override Office.IRibbonExtensibility CreateRibbonExtensibilityObject()
{
customerRibbon = new Ribbon();
return customerRibbon;
}运行程序,即可看到如下效果:

可以看到图片不见了,这是因为在导出功能区为XML的时候,VS没有帮我们处理图片,所以需要我们自己来添加。在RibbonXML文档中, customUI节点下有loadImage事件,Button有getImage事件和image属性。customUI节点的loadImage方法和子节点的image属性一起使用,image属性作为loadImage方法的参数。

loadImage方法如下:

public Image LoadImage(string imageName)
{
Assembly assembly = Assembly.GetExecutingAssembly();
//String[] all =assembly.GetManifestResourceNames();//GetResourceName
Stream stream = assembly.GetManifestResourceStream("YYAddIn.Resources." + imageName);
return Image.FromStream(stream);
}其中,imageName即为Button控件的image属性要设置的图片名称。资源文件图片,要设置为嵌入的资源。所有的按钮的单击事件,我们使用GeneralButton_Click事件来处理。运行程序,我们又看到了之前采用设计器时编辑的菜单时的界面了。

二 Excel 2003下面的菜单系统
创建工程
由于Excel2003及以下版本不支持Ribbon菜单,所以以上的程序在03版本下并不能运行。但是,如果开发企业级应用的话,仍不能忽视广大使用 Office 2003 版本的客户,所以您还需要创建2003下面的菜单系统。下面就介绍如何在Excel2003系统中创建Excel菜单及工具条。

要创建在Excel 03下的插件,我们可以创建Shared Add-in程序,如下图,首先新建一个名为YYSharedAddin的Shared Add-in项目:

然后下一步下一步, 设置编程语言,我们这里选择C#

下一步,设置插件的目标应用程序,可以看到,我们的Shared Add-in程序可以为多个目标应用程序编写同一个插件,这在前一篇文章中介绍SharedAddin和VSTO的差别时已经介绍过了。因为我们主要是编写Excel插件,所以仅勾选Excel即可。

下一步,设置Addin的展现名称和在编程时的名称

创建完成之后,我们可以看到工程项目非常简单,只有一个Connect.cs文件。打开该文件,可以看到其中实现了Extensibility.IDTExtensibility2 接口,所有Office应用程序都是用IDTExtensibility2接口与COM加载项进行通信的,该接口提供了一种通用的初始化机制,并具有在Office应用程序的对象模型中传递数据的能力,因此Com加载项可以与Office应用程序通信,该接口中有5个方法,分别是:

Office在对Com加载项进行实例化时,会创建Connect类,注意我们不能用Connect的构造函数创建类的实例,应该在OnConnection方法中进行初始化操作,比如菜单项的加载,自定义函数的加载,变量的初始化等等;类似的,加载项的关闭不能调用析构函数,而要用OnDisconnection方法,在该方法中需要释放非托管的资源,进行资源清理等一系列操作。下图展示了这5个方法的执行顺序。该图引用了MYM]Brooks同学博文中的图片。

由分析得之,我们对菜单及工具栏的初始化,需要放到OnConnection方法中。

在OnConnection方法中,有一个很重要的参数就是application,我们声明一个类型为

Microsoft.Office.Interop.Excel.Application的applicationObject对象,然后将这个对象保存起来,以备后面创建菜单以及对Excel进行操作时使用。

private Application applicationObject;

///

/// Implements the OnConnection method of the IDTExtensibility2 interface.
/// Receives notification that the Add-in is being loaded.
///

///
/// Root object of the host application.
///
///
/// Describes how the Add-in is being loaded.
///
///
/// Object representing this Add-in.
///
///
public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom)
{
applicationObject = application as Application;
addInInstance = addInInst as COMAddIn;

if (applicationObject.Version == "11.0")
{
if (menuDesigner == null)
{
menuDesigner = new MenuDesigner(applicationObject);
}
menuDesigner.AddMenus();
menuDesigner.AddToolBars();
}
}在OnConnection方法中,我们首先判断Excel的版本号,版本号可以通过Version对象获取,如果版本号为11,即为2003版本的Excel,我们需要手动的动态创建菜单和工具条。我们新建了一个名为MenuDesigner的用来创建菜单和工具条的类,在其构造函数中传入了applicationObject对象。

添加菜单

我们把添加菜单放到了MenuDesigner的AddMenus方法中。Excel中的一个菜单项和子菜单其实都是一个MSOffice.CommandBarPopup对象,菜单项里面的菜单按钮是MSOffice.CommandBarButton对象。首先我们定义菜单项以及菜单按钮,这里只列出部分。

//YY插件菜单
MSOffice.CommandBarPopup YYMenu = null;
//实时行情函数菜单按钮
MSOffice.CommandBarButton btnQuoteFunctionMenuCommand = null;
//Sina实时行情函数菜单按钮
MSOffice.CommandBarButton btnQuoteSinaFunctionMenuCommand = null;
//Yahoo实时行情函数菜单按钮
MSOffice.CommandBarButton btnQuoteYahooFunctionMenuCommand = null;在创建菜单时,我们要首先创建YYMenu对象,然后再在该对象上添加菜单项。创建YYMenu菜单的方法如下:

public void AddMenus()
{
MSOffice.CommandBar menubar = (MSOffice.CommandBar)application.CommandBars.ActiveMenuBar;
int controlCount = menubar.Controls.Count;
string menuCaption = "歪歪插件";
// Add the menu.
try
{
YYMenu = (MSOffice.CommandBarPopup)
application.CommandBars.ActiveMenuBar.FindControl(
MSOffice.MsoControlType.msoControlPopup, System.Type.Missing, menuTag, true, true);
}
catch { }

if (YYMenu != null)
{
YYMenu.Delete(Type.Missing);
}
YYMenu = (MSOffice.CommandBarPopup)menubar.Controls.Add(MSOffice.MsoControlType.msoControlPopup, missing, missing, controlCount, true);
YYMenu.Tag = menuTag;
YYMenu.Caption = menuCaption;
YYMenu.BeginGroup = true;

LoginGroup();
FinancialGroup();
MapServiceGroup();
WeatherReportGroup();
AboutGroup();
}需要注意的是,在创建菜单之前,我们需要判断之前是否已经存在相同Tag值得菜单,如果存在,需要先将之前创建的菜单项删除,然后再重新创建。否则,在用户在Com加载项中显示或者隐藏菜单项时,会重复创建菜单项。创建完主菜单后,我们可以在主菜单上创建子菜单了。这些方法都写到了最后的几个以Group结尾的方法中。现在以创建财务项菜单的FinancalGroup方法为例讲解。

private void FinancialGroup()
{
//实时行情
MSOffice.CommandBarPopup realTimeButton = AddPopupButton(YYMenu.Controls, MenuNameEnum.Quote);
realTimeButton.BeginGroup = true;
//添加子菜单
btnQuoteFunctionMenuCommand = AddCommandButton(realTimeButton.Controls, MenuNameEnum.Quote, YYSharedAddin.Properties.Resources.QuoteReal);
btnQuoteSinaFunctionMenuCommand = AddCommandButton(realTimeButton.Controls, MenuNameEnum.QuoteSina, YYSharedAddin.Properties.Resources.SinaQuote_64);
btnQuoteSinaFunctionMenuCommand.BeginGroup = true;
btnQuoteYahooFunctionMenuCommand = AddCommandButton(realTimeButton.Controls, MenuNameEnum.QuoteYahoo, YYSharedAddin.Properties.Resources.Yahoo_Quote);

//历史行情
MSOffice.CommandBarPopup historyButton = AddPopupButton(YYMenu.Controls, MenuNameEnum.QuoteHistory);
realTimeButton.BeginGroup = true;
//添加子菜单
btnQuoteHistoryFunctionMenuCommand = AddCommandButton(historyButton.Controls, MenuNameEnum.QuoteHistory, YYSharedAddin.Properties.Resources.QuoteHist);
btnQuoteHistorySinaFunctionMenuCommand = AddCommandButton(historyButton.Controls, MenuNameEnum.QuoteHistorySina, YYSharedAddin.Properties.Resources.SinaQuote_64);
btnQuoteHistorySinaFunctionMenuCommand.BeginGroup = true;
btnQuoteHistoryYahooFunctionMenuCommand = AddCommandButton(historyButton.Controls, MenuNameEnum.QuoteHistoryYahoo, YYSharedAddin.Properties.Resources.Yahoo_HistoryQuote);

//导出
MSOffice.CommandBarPopup importButton = AddPopupButton(YYMenu.Controls, MenuNameEnum.Import);
importButton.BeginGroup = true;
btnImportFromLocalMenuCommand = AddCommandButton(importButton.Controls, MenuNameEnum.ImportFromLocal, YYSharedAddin.Properties.Resources.ImportFromDisk);
btnImportFromWebMenuCommand = AddCommandButton(importButton.Controls, MenuNameEnum.ImportFromWeb, YYSharedAddin.Properties.Resources.ImportFromWeb);
}对于财务大类菜单,其中有三个一级菜单,分别是实时行情,历史行情,导入。创建一级菜单的方法AddPopupButton代码为:

///

/// 添加子菜单项
///

/// 该字菜单的父菜单容器
/// 菜单名称
///
private MSOffice.CommandBarPopup AddPopupButton(MSOffice.CommandBarControls controls, MenuNameEnum menu)
{
String tag = menu.ToString();
String caption = String.Empty;
Menus.menus.TryGetValue(tag, out caption);
MSOffice.CommandBarPopup command = null;
try
{
command = controls[caption] as MSOffice.CommandBarPopup;
}
catch { }
if (command == null)
{
command = controls.Add(MSOffice.MsoControlType.msoControlPopup, Type.Missing, Type.Missing, Type.Missing, Type.Missing) as MSOffice.CommandBarPopup;
command.Caption = caption;
}
return command;
}其中第一个参数为最大的根节点菜单YYMenu对象的所有Controls容器。所以创建第一个实时行情一级菜单的方法为:

//实时行情
MSOffice.CommandBarPopup realTimeButton = AddPopupButton(YYMenu.Controls, MenuNameEnum.Quote);
realTimeButton.BeginGroup = true;得到realTimeButton这个一级菜单之后,我们将其BeginGroup属性设置为true表示在之前添加一个Seperator控件(一条横线或者竖线)。有了这个realTimeButton一级菜单之后,我们可以在该对象上创建三个二级菜单按钮项。

//添加子菜单
btnQuoteFunctionMenuCommand = AddCommandButton(realTimeButton.Controls, MenuNameEnum.Quote, YYSharedAddin.Properties.Resources.QuoteReal);
btnQuoteSinaFunctionMenuCommand = AddCommandButton(realTimeButton.Controls, MenuNameEnum.QuoteSina, YYSharedAddin.Properties.Resources.SinaQuote_64);
btnQuoteSinaFunctionMenuCommand.BeginGroup = true;
btnQuoteYahooFunctionMenuCommand = AddCommandButton(realTimeButton.Controls, MenuNameEnum.QuoteYahoo, YYSharedAddin.Properties.Resources.Yahoo_Quote);创建子菜单按钮的方法封装到了AddCommandButton方法中,方法第一个参数为第一级子菜单的所有控件的容器类。

private MSOffice.CommandBarButton AddCommandButton(MSOffice.CommandBarControls controls, MenuNameEnum menu, System.Drawing.Image icon)
{
string tempName = menu.ToString();
String tag = String.Format("{0}|{1}", menu, DateTime.Now.ToBinary());
String caption = String.Empty;
Menus.menus.TryGetValue(tempName, out caption);
MSOffice.CommandBarButton command = null;
try
{
command = controls[caption] as MSOffice.CommandBarButton;
command.Tag = tag;
command.Click += new MSOffice._CommandBarButtonEvents_ClickEventHandler(command_Click);
}
catch { }
if (command == null)
{
command = controls.Add(MSOffice.MsoControlType.msoControlButton, Type.Missing, Type.Missing, Type.Missing, Type.Missing) as MSOffice.CommandBarButton;
command.Style = MSOffice.MsoButtonStyle.msoButtonIconAndCaption;
command.Caption = caption;
command.Tag = tag;
command.Picture = ImageConverterHelper.ImageToPictureDisp(icon);
command.Click += new MSOffice._CommandBarButtonEvents_ClickEventHandler(command_Click);
}
return command;
}在创建菜单按钮时,我们需要先判断当前的菜单中是否有该菜单项,如果有直接使用。否则创建新的对象。这里有几个地方需要注意,首先是CommandBarButton 的Tag属性,该属性应该加上一个唯一标志,比如当前时间,或者GUID,然后带上该菜单的名称等信息。加唯一标志的目的是每一次在创建菜单时保证是唯一的,否则会出现菜单只会响应一次按钮点击事件等奇怪的问题。其次设置按钮的Style为MSOffice.MsoButtonStyle.msoButtonIconAndCaption 既带图片又有文字的时候,Picture属性为想要显示在按钮前面的图片,该对象是一个stdole.IPictureDisp类型的对象,您需要进行一下转换。其次直接设置图片会使得图片中的背景色不会透明,背景色为Office的默认风格颜色,如果要将背景色透明,需要设置Mask属性,Mask属性也是一张图片。该图片为带显示图片的蒙版,即原始图片中需要显示的地方,用黑色表示,那么其余地方就会透明显示,具体使用方式您可以参看这篇文章,这里为了简化,不做处理。

添加工具条

工具条其实就是一个大的一级菜单,和创建菜单一样,我们将创建工具条的代码封装到了AddToolBars方法中,该方法代码如下:

public void AddToolBars()
{
try
{
YYToolBar = application.CommandBars["YYToolBar"];
}
catch { }

if (YYToolBar == null)
{
YYToolBar = application.CommandBars.Add("YYToolBar", MSOffice.MsoBarPosition.msoBarTop, false, true);
}
LoginGroup_ToolBar();
FinancialGroup_ToolBar();
MapServiceGroup_ToolBar();
WeatherReportGroup_ToolBar();
AboutGroup_ToolBar();

YYToolBar.Visible = true;
}我们首先需要创建一个大的工具条,和创建菜单类似,在创建工具条之前,我们需要定义好所有的工具条中的按钮,注意,该按钮对象不能和菜单项里面的对象共用,否则会导致事件注册被冲掉的情况。

//歪歪插件工具条
MSOffice.CommandBar YYToolBar;
//实时行情函数工具条
MSOffice.CommandBarButton btnQuoteFunctionToolBarCommand = null;
//Sina实时行情工具条
MSOffice.CommandBarButton btnQuoteSinaFunctionToolBarCommand = null;
//Yahoo实时行情工具条
MSOffice.CommandBarButton btnQuoteYahooFunctionToolBarCommand = null;创建好YYToolBar对象后,在该对象的基础上创建工具条里面的工具项就和创建字菜单类似了,这里就不再赘述了。

现在我们来看在Excel2003下面的效果。由于我们创建的SharedAddin程序,我们在调试的时候,需要设置启动程序,Visual Studio 给我们设置的默认启动程序是Visual Studio本身。这里我们将默认程序指定为Excel 2003 的可执行文件,如下图:

运行程序,Visual Studio就会启动Excel程序,然后就可以看到我们创建的歪歪菜单和工具条了。

三 全版本兼容
前面介绍了在2003以上版本的Ribbon菜单创建和在2003版本下面的传统菜单项的创建。一个良好的Excel应用程序应该会根据版本的不同而展现不同的菜单形式。如果您用VSTO创建的话,那么可能在03版本上就不能很好的支持,因为03版本不支持Ribbon菜单。所以要想兼容所有的Excel版本,可以创建Shared Add-in工程。第二部分已经讲解了如何在SharedAddin中创建传统菜单的方法,要兼容03以上版本,我们只需要在SharedAddin中加载第一部分创建好的RibbonXML即可。

要让SharedAddin能在03以上版本中渲染Ribbon菜单,我们需要让Connect类实现Office.IRibbonExtensibility接口。由于之前生成的Ribbon.cs类已经实现了该接口,所以最简单的方法是:将之前创建好的Ribbon.xml及Ribbon.cs拷贝到SharedAddin工程项目中来。并将Ribbon.xml设置为嵌入的资源。将Ribbon.cs 的命名空间改为和Connect.cs一致的命名空间,然后利用Partial关键字,将Ribbon类名称改为partial Connect类。如下:

[ComVisible(true)]
public partial class Connect : Office.IRibbonExtensibility
{
private Office.IRibbonUI ribbon;
#region IRibbonExtensibility 成员

public string GetCustomUI(string ribbonID)
{
return GetResourceText("YYSharedAddin.RibbonMenu.Ribbon.xml");
}
#endregion

#region 功能区回调
//在此创建回调方法。有关添加回调方法的详细信息,请在解决方案资源管理器中选择功能区 XML 项,然后按 F1

public void Ribbon_Load(Office.IRibbonUI ribbonUI)
{
this.ribbon = ribbonUI;
}

public Image LoadImage(string imageName)
{
Assembly assembly = Assembly.GetExecutingAssembly();
//String[] all =assembly.GetManifestResourceNames();//GetResourceName
Stream stream = assembly.GetManifestResourceStream("YYSharedAddin.Resources." + imageName);
return Image.FromStream(stream);
}

public void GeneralButton_Click(Office.IRibbonControl control)
{
try
{
MessageBox.Show("you clicked the button id is " + control.Id);
}
catch (Exception ex)
{

}
}
#endregion

#region 帮助器

private static string GetResourceText(string resourceName)
{
Assembly asm = Assembly.GetExecutingAssembly();
string[] resourceNames = asm.GetManifestResourceNames();
for (int i = 0; i

浅谈Excel开发:二 Excel 菜单系统(转)的更多相关文章

  1. 浅谈WebService开发二(同步与异步调用)转

    上文 <http://www.dotnetgeek.cn/xuexiwebservice1.html>已经跟大家说了,如果创建一个webservice和简单的调用,本文将注重webserv ...

  2. 浅谈WebService开发三(动态调用WebService)转

    在前两讲里,我已经向大家演示了如何使用WebService.同步, 异步调用WebService,而在实际开发过程中,可能会有多个WebService接口供你选择,而在程序执行过程中才决定使用哪一个 ...

  3. 浅谈Kotlin(二):基本类型、基本语法、代码风格

    浅谈Kotlin(一):简介及Android Studio中配置 浅谈Kotlin(二):基本类型.基本语法.代码风格 浅谈Kotlin(三):类 浅谈Kotlin(四):控制流 通过上面的文章,在A ...

  4. 浅谈Java代理二:Cglib动态代理-MethodInterceptor

    浅谈Java代理二:Cglib动态代理-MethodInterceptor CGLib动态代理特点: 使用CGLib实现动态代理,完全不受代理类必须实现接口的限制,而且CGLib底层采用ASM字节码生 ...

  5. 浅谈 Android 开发文化

    Hello,亲爱的读者朋友们(希望你们是 Android 开发者,或者正在成为 Androider 的路上-)! 质量从用户反馈很清凉然后我们就只能看 CPU 原来的想法是但是事实上不是这些但是我们可 ...

  6. 浅谈iOS开发中多语言的字符串排序

    一.前言 在iOS开发中,一个经常的场景是利用tableview展示一组数据,以很多首歌曲为例子.为了便于查找,一般会把这些歌曲按照一定的顺序排列,还会加上索引条以便于快速定位. 由于歌曲名可能有数字 ...

  7. "浅谈Android"第一篇:Android系统简介

    近来,看了一本书,名字叫做<第一行代码>,是CSDN一名博主写的,一本Android入门级的书,比较适合新手.看了书之后,有感而发,想来进行Android开发已经有一年多了,但欠缺系统化的 ...

  8. 浅谈iOS开发的协议(protocol)和代理(delegate)

    协议和代理对于一个新手来说确实不讨好理解,也有很多的iOS开发的老手对此是懂非懂的.网上的很多博文只是讲了怎么使用,并没有说的很明白.下面我谈一下我的理解. 1.你要先搞明白,协议和代理为什么会出现, ...

  9. 浅谈Web开发中的定时任务

    曾经做过Windows server下的定时任务的业务,最近又做了一些Linux下使用Crontab做的定时任务的业务,觉得有必要进行一次小结,于是有了如下这篇文章. Windows Server下 ...

  10. 浅谈教你如何掌握Linux系统

    linux能做什么?相信绝大数人都有这样的疑问.可以玩吃鸡吗?可以玩lol吗? 如果你是以娱乐的名义来评价linux的可用性,对不起,linux可能不适合你,因为linux是一个工具,他是教你聪明的, ...

随机推荐

  1. TP5 中的redis 队列

    首先我们看一下自己的TP5的框架中的  TP5\vendor\topthink ,这个文件中有没有think-queue这个文件夹,如果没有请安装, 安装这个是要用到Composer的如果没有安装co ...

  2. 提取包含QQ的文本为QQ邮箱

    # -*- coding: utf-8 -*- """ Created on Sun Dec 15 14:08:03 2019 @author: Dell 提取包含QQ号 ...

  3. vue - router + iView 的使用(简单例子)

    所使用的工具:谷歌浏览器.Nodejs(自带npm).HBuilder 0.要先安装Nodejs,下载安装即可 0-1.安装vue-cli,打开cmd 输入 npm install -g @vue/c ...

  4. DOM添加

    ㈠添加元素的步骤 ⑴创建空元素 ⑵设置关键属性 ⑶将元素添加到DOM树   ㈡创建空元素 var elem = document.createElement('table');   示例: var t ...

  5. 多版本python的pip 升级后, pip2 pip3 与python版本失配

    mint19.2   本来pip 和 pip2 对应 python2.7   pip3对应python3.6 用源码安装了python3.7之后. 这样 版本也没问题. 但是,  用pip3.7 安装 ...

  6. fiddler(一)、下载及安装

    fiddler 官网地址:https://www.telerik.com/fiddler 进入页面后点击 Free download 进入下载页面,填写用途,邮箱和国家等信息后,点击Download ...

  7. Linux命令-磁盘管理(一)

    Linux命令-磁盘管理(一) Linux cd命令 Linux cd命令用于切换当前工作目录至 dirName(目录参数). 其中 dirName 表示法可为绝对路径或相对路径.若目录名称省略,则变 ...

  8. HDU 2829 [Lawrence] DP斜率优化

    解题思路 首先肯定是考虑如何快速求出一段铁路的价值. \[ \sum_{i=1}^k \sum_{j=1, j\neq i}^kA[i]A[j]=(\sum_{i=1}^kA[i])^2-\sum_{ ...

  9. Understand RNN with TensorFlow in 7 Steps

    待翻译 https://medium.com/@erikhallstrm/hello-world-rnn-83cd7105b767

  10. 完美解决前端跨域之 easyXDM 的使用和解析

    前端跨域问题在大型网站中是比较常见的问题.本文详细介绍了利用 easyXDM 解决前端跨域的原理细节和使用细节,具体使用时可以在文中代码实例的基础上扩展完成. 0.背景 因个别网络运营商存在 HTTP ...