如何将Mindjet的宏放到自定义功能区
虽然很早就接触了思维软件Mindjet Manager,但最近才用得比较频繁。现在软件已发布到Mindjet15版,官方原版终于支持中文了,但我还是比较习惯11版,原因很简单,15版还没有破解。大家可以很轻松地在网上下载到Mindjet 11破解版,也可以直接在我的百度网盘下载。
网盘链接: http://pan.baidu.com/s/18XRv4 密码: b9nj
我先总结一下使用感受:
- 比较容易上手
- 内置甘特图,与任务板配合使用,非常适合作计划
- 支持表格、数据库,图片、备注、附件自然也支持
- 可以自定义宏,可惜不能录制宏
- 文件格式从11版到15版没有变化,即用15版制作的用11版也能打开
一、Mindjet Macro使用经历
平时用Excel VBA的时间比较多,发现Mindjet也支持宏后,我就把Excel VBA的那一套照搬过去,发现它们使用完全一样的语言,只是对象不一样。比如,Excel里用得最多的是Range对象,Mindjet里则是Topic对象。不过,Excel VBA要流行得多,至少可以在网上找到很多的教程,而且其自带的帮助文档也很详细,有说明有实例。相比之下,Mindjet Macro就麻烦多了,想找点中文教程真是难,只好硬着头皮去Google。好在找到一些例子,不然,我可能现在连Topic对象都还不会用。CSDN里必定有牛人会Mindjet宏,但我找了半天也没有找到教程。也许是用的人少,讨论少了点,所以我在此抛砖引玉,希望大家来交流交流经验。
摸索出一些简单对象的用法后,我先编写了几个宏,增强一下mindjet任务模块的功能,比如批量添加进度、查找当天的任务等。后来发现在组织宏时,可以把宏添加到一些下拉菜单、右键弹出菜单,确实方便了不少。但还是不能和excel的相比,人家可以把任意sub放在自定义功能区的任何位置。于是我琢磨着,能不能让mindjet也做到这样?折腾了两天,总算弄出来了。先上一个效果图:
二、使用的软件及文件
Mindjet Manager用的是11.1.353专业版,此版为英文版,须使用汉化补丁。
你如果用过11版,一定注意到了新建界面有些不一样。没错,这里面是15版的导图模板。文章开头的时候我说过,11版和15版的文件格式是一样的,他们的模板可以通用。只需把15版的模板复制到11版就行了,大概是在这个位置:
C:\Users\Administrator\AppData\Local\Mindjet\MindManager\11\Library\ENU\Templates
另外还需要VS2010,其他版本应该也可以,但我没试过。
1.处理思路
首先说说思想来源。我在www.Activeityowner.com上找到一篇文章,作者提供了一个Addin,可以把某文件夹下的宏全部添加到一个主选项卡。效果如图:
这个mymapmacros插件有3个版本,最新的是2012版,即10版。安装后发现,我的11版不能用。顺便说一下,我之前说的例子,有些就是从这里来的,有兴趣的可以去看看——MindManager Macro Library,另外还有这里——
于是,我继续找,从Yahoo Group里找到这个How to Create a MindManager 7 Add-in Using Visual Basic .NET (VB)
看了一下,好像看懂了(我之前从没写过插件,所以知道的不多)。于是,我决定自己写一个Addin。
在写的过程中,查看了一下注册表,发现mymapmacros把注册信息写到了Mindjet/10/Addins/下面,果断把它导出来,把10改成11再导回去。居然可以用了!其他版本应该也可以这样弄。
我本想就此停住,但我关闭软件时,突然弹了个网页出来,是作者的网站。于是我又继续研究写插件。
2.用VS2010写一个HelloWorld
这似乎是程序员惯例吧,先用HelloWorld试下水。
其实,基本就照网上说的就行了。可能有的人不习惯看英文,所以我大致翻译一下。
(1).下载注册表文件,给vs2010添加Mindjet 插件向导
原文件里,只有mindjet7、8、9,需要增加mindjet11及其他版本的注册信息。这是原版,点击下载。修改后的,下载。
主要修改2个地方:一个是”RegistryRoot”,可以在注册表搜索mindjet(项,全字匹配),找到Addins项,看看是不是和Mindjet选项里一样的。因为我装的64位系统,用的32位Mindjet,所以它在Software\Wow6432Node\
另一个地方是Microsoft\Shared Tools\AddinWizard的位置,还是用查找的方法,看你的vs2010的插件向导在哪里。
修改完后,导入注册表即可。
(2).新建工程
我用的也是英文版VS2010,就直接用原图说明了。
文件->新建工程->其他工程->扩展->共享插件(应该是这样吧),在取名时最好一次取好,以后改麻烦。这里仍用Mm7HelloWorld_VB。
选择VB语言。
如果在这里看到了Mindjet的选项,讲明第1步成功了。若没看到,就再改注册表。
填插件名字、说明。
勾选随程序启动和所有用户都可用。
新建完成。
(3).添加/删除引用
在solution面板,右键工程,Add Reference添加引用。
在com选项里选择Mindmanager 11 Type Library,其他版本类推。
再到工程属性里,把名字改成插件名,不然生成的dll名字会是默认值。然后到Reference里把office的引用删了。
(4).添加代码
网站上说明很详细,把高亮的代码添加进去即可。但有个更简单的方法,把你工程中的GuidAttribute那串数字,替换掉下面代码中的GuidAttribute。如果插件名不一样的话,也可以直接替换。然后把代码全部复制进工程即可。
imports Extensibility
Imports System.Runtime.InteropServices
Imports Mindjet.MindManager.Interop
#Region " Read me for Add-in installation and setup information. "
' When run, the Add-in wizard prepared the registry for the Add- in.
' At a later time, if the Add-in becomes unavailable for reasons such as:
' 1) You moved this project to a computer other than which is was originally created on.
' 2) You chose 'Yes' when presented with a message asking if you wish to remove the Add- in.
' 3) Registry corruption.
' you will need to re-register the Add-in by building the MM7HelloWorldSetup project
' by right clicking the project in the Solution Explorer, then choosing install.
#End Region
<GuidAttribute("69A3AD57-AA91-4D9E-A1B3- 3CFF65100030"), ProgIdAttribute("Mm7HelloWorld_VB.Connect")> _
Public Class Connect
Implements Extensibility.IDTExtensibility2
Dim applicationObject As Mindjet.MindManager.Interop.Application
Dim addInInstance As Object
Dim WithEvents mmCommand As Mindjet.MindManager.Interop.Command
Public Sub OnBeginShutdown(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnBeginShutdown
MsgBox("OnBeginShutdown")
End Sub
Public Sub OnAddInsUpdate(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnAddInsUpdate
MsgBox("OnAddInsUpdate")
End Sub
Public Sub OnStartupComplete(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnStartupComplete
MsgBox("OnStartupComplete")
End Sub
Public Sub OnDisconnection(ByVal RemoveMode As Extensibility.ext_DisconnectMode, ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnDisconnection
MsgBox("OnDisconnection")
' Release all objects
'
' Use ReleaseComObject() for event-handled objects
' or else the application will not shut down
System.Runtime.InteropServices.Marshal.ReleaseComObject(mmCommand)
applicationObject = Nothing
addInInstance = Nothing
' Make sure "garbage collection" is done, otherwise cached
' objects might cause the application not to shut down.
System.GC.Collect()
End Sub
Public Sub OnConnection(ByVal application As Object, ByVal connectMode As Extensibility.ext_ConnectMode, ByVal addInInst As Object, ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnConnection
applicationObject = application
addInInstance = addInInst
mmCommand = applicationObject.Commands.Add("Mm7HelloWorld_VB.Connect", "ID_HelloWorld")
mmCommand.Caption = "Hello World (VB)"
mmCommand.SetDynamicMenu(Mindjet.MindManager.Interop.MmDynamicMenu.mmDynamicMenuTools)
End Sub
Private Sub mmCommand_UpdateState(ByRef enabled As Boolean, ByRef checked As Boolean) _
Handles mmCommand.UpdateState
' Only enable command if a document is open
enabled = applicationObject.Documents.Count > 0
checked = False
End Sub
Private Sub mmCommand_Click() Handles mmCommand.Click
' Process the MindManager command and say hello
MsgBox("Hello, world! (VB)")
End Sub
End Class
(5).编译测试
然后Build 插件,以及插件的setup工程。网站上说Build之后就能在注册表mindjet下看到有Mm7HelloWorld_VB,而且能在mindjet里出现helloworld按钮。但我的好像没有出现,我把setup编译好后,安装了一遍,才有的。Hello World插件就是在插件启动、更新、断开时用对话框进行提示。
然后,在VS2010里改代码,关掉mindjet再build,重开mindjet就能看到变化。如果你已到了这一步,相信如果你会一些mindjet macro的话,就能进行自己的插件开发了。主要就是用ribbon对象、command对象。
3.MacroToRibbon插件
以下是将宏放到自定义功能区的MacroToRibbon插件代码
Imports Extensibility
Imports System.Runtime.InteropServices
Imports Mindjet.MindManager.Interop
#Region " Read me for Add-in installation and setup information. "
' When run, the Add-in wizard prepared the registry for the Add-in.
' At a later time, if the Add-in becomes unavailable for reasons such as:
' 1) You moved this project to a computer other than which is was originally created on.
' 2) You chose 'Yes' when presented with a message asking if you wish to remove the Add-in.
' 3) Registry corruption.
' you will need to re-register the Add-in by building the MacroToRibbonSetup project,
' right click the project in the Solution Explorer, then choose install.
#End Region
<GuidAttribute("C7BCF9F4-2ACB-4F6E-AF7E-7D748B811C1C"), ProgIdAttribute("MacroToRibbon.Connect")> _
Public Class Connect
Implements Extensibility.IDTExtensibility2
Public Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As String, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Integer, ByVal lpFileName As String) As Integer
Public Declare Function WritePrivateProfileString Lib "kernel32" Alias "WritePrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As String, ByVal lpString As String, ByVal lpFileName As String) As Long
Dim applicationObject As Mindjet.MindManager.Interop.Application
Private addInInstance As Object
Dim WithEvents mmCommand As Mindjet.MindManager.Interop.Command
Dim mycmd() As Mindjet.MindManager.Interop.Command
Dim ribtb() As ribbonTab
Dim ribgp As RibbonGroup
Dim ctl As Control
Dim ctn() As CmdBtn
Private m_filename As String = "F:\backup\loadmacro.ini"
Public Function GetiniValue(ByVal lpKeyName As String, ByVal strName As String) As String
Dim strTmp As String
strTmp = New String(" ", 256)
Call GetPrivateProfileString(lpKeyName, strName, "", strTmp, Len(strTmp), m_filename)
GetiniValue = Left$(strTmp, InStr(strTmp, vbNullChar) - 1)
End Function
Public Sub OnBeginShutdown(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnBeginShutdown
End Sub
Public Sub OnAddInsUpdate(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnAddInsUpdate
MsgBox("OnAddInsUpdate")
End Sub
Public Sub OnStartupComplete(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnStartupComplete
End Sub
Public Sub OnDisconnection(ByVal RemoveMode As Extensibility.ext_DisconnectMode, ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnDisconnection
' MsgBox("OnDisconnection")
' Release all objects
'
' Use ReleaseComObject() for event-handled objects
' or else the application will not shut down
Dim i As Integer
For i = 1 To UBound(mycmd)
System.Runtime.InteropServices.Marshal.ReleaseComObject(mycmd(i))
Next
For i = 1 To UBound(ribtb)
ribtb(i).Delete()
Next
applicationObject = Nothing
addInInstance = Nothing
' Make sure "garbage collection" is done, otherwise cached
' objects might cause the application not to shut down.
System.GC.Collect()
End Sub
Public Sub OnConnection(ByVal application As Object, ByVal connectMode As Extensibility.ext_ConnectMode, ByVal addInInst As Object, ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnConnection
applicationObject = CType(application, Mindjet.MindManager.Interop.Application)
addInInstance = addInInst
ReadSet()
End Sub
Private Sub mmCommand_UpdateState(ByRef enabled As Boolean, ByRef checked As Boolean) _
Handles mmCommand.UpdateState
' Only enable command if a document is open
enabled = applicationObject.Documents.Count > 0
checked = False
End Sub
Private Sub mmCommand_Click() Handles mmCommand.Click
' Process the MindManager command and say hello
' applicationObject.RunMacro("F:\backup\其他\全部添加完成度.mmbas")
End Sub
Private Sub ReadSet()
'下面是读取INI文件中的数据()
Dim ret As Integer
Dim n As Integer
Dim i As Integer
Dim j As Integer
Dim filename As String
Dim section As String
Dim name As String
Dim image As String
Dim bigimage As String
Dim mtab() As String
Dim ntab As Integer
Dim group As String
Dim mgroup As Integer
Dim whenever As Boolean
ret = CInt(GetiniValue("set", "tabcount"))
ReDim ribtb(ret), mtab(ret)
For j = 1 To UBound(ribtb)
mtab(j) = GetiniValue("tab" & j, "tabname")
ribtb(j) = applicationObject.Ribbon.Tabs.Add(6, mtab(j), "DIYBYNIGHTMOON" & j)
ret = CInt(GetiniValue("tab" & j, "groupcount"))
For i = 1 To ret
group = GetiniValue("tab" & j, CStr(i))
ribgp = ribtb(j).Groups.Add(0, group, "DIYTAB" & j & "GROUP" & i, "")
Next
Next
n = CInt(GetiniValue("set", "count"))
ReDim ctn(n), mycmd(n)
section = "macro"
For i = 1 To n
section = "macro" & i
name = GetiniValue(section, "name")
filename = GetiniValue(section, "filename")
image = GetiniValue(section, "image")
bigimage = GetiniValue(section, "bigimage")
ntab = CInt(GetiniValue(section, "tab"))
mgroup = CInt(GetiniValue(section, "group"))
whenever = CBool(GetiniValue(section, "whenever"))
mmCommand = applicationObject.Commands.Add("MacroToRibbon.Connect", "DIY_" & section)
mmCommand.Caption = name
If image <> "" Then mmCommand.ImagePath = image
If bigimage <> "" Then mmCommand.LargeImagePath = bigimage
'If ribgp.GroupControls.Count > mindex Then mindex = 0
If GetiniValue(section, "onribbon") = "1" Then
ctl = ribtb(ntab).Groups.Item(mgroup).GroupControls.AddButton(mmCommand)
End If
mycmd(i) = mmCommand
ctn(i) = New CmdBtn
ctn(i).Init(applicationObject, mmCommand, filename, whenever)
Next
End Sub
End Class
Public Class CmdBtn
Dim WithEvents mcmd As Mindjet.MindManager.Interop.Command
Dim appObject As Mindjet.MindManager.Interop.Application
Dim ss As String
Dim documentcount As Integer
Public Sub Init(ByRef app As Mindjet.MindManager.Interop.Application, ByVal mmcommand As Mindjet.MindManager.Interop.Command, ByVal filename As String, Optional ByVal whenever As Boolean = True)
appObject = app
mcmd = mmcommand
ss = filename
If whenever = True Then
documentcount = -1
Else
documentcount = 0
End If
End Sub
Private Sub mcmd_Click() Handles mcmd.Click
'MsgBox("I am here")
'MsgBox(ss)
appObject.RunMacro(ss)
End Sub
Private Sub mcmd_UpdateState(ByRef enabled As Boolean, ByRef checked As Boolean) Handles mcmd.UpdateState
enabled = appObject.Documents.Count > documentcount
checked = False
End Sub
Protected Overrides Sub finalize()
mcmd = Nothing
End Sub
Public Sub New()
End Sub
End Class
对应的ini文件内容为:
[set]
count=3
tabcount=2
[tab1]
tabname=自定义
groupcount=2
1=MyMacro
2=Trial
[tab2]
tabname=自定义2
groupcount=2
1=MyMacro
2=Trial
[macro1]
name="全部添加完成度"
filename=F:\backup\其他\全部添加完成度.mmbas
image=F:\backup\其他\b.ico
bigimage=F:\backup\其他\b.ico
onribbon=1
tab=1
group=1
whenever=1
[macro2]
name="刷新完成情况"
filename=F:\backup\其他\刷新完成情况.mmbas
image=F:\backup\其他\b.ico
bigimage=
onribbon=1
tab=1
group=2
whenever=0
插件启动时,会按照ini文件里的配置将宏加载成插件命令,放到功能区。
ini文件的路径为:F:\backup\loadmacro.ini
可以自己改,但注意路径不要有中文,这然会出问题。
set下的count表示宏的数量,tabcount表示主选项卡的数量,对应tab1、tab2……
tab1下的name表示选项卡的名称,groupcount表示分组数,1、2等对应组名。
macro1下的name表示按钮名称,filename表示宏文件位置,image为小图标位置,bigimage为大图标位置,onribbon为是否在功能区显示,tab表示选项卡号,group表示组号,whenever表示是否没打开map也有效。
支持mindjet 10、11、14、15,工程文件到这里下载。
时间仓促,有些难免有误,请各位不吝指教!
抛砖引玉,望大家多多交流,将Mindjet VBA也开拓一下!