CodeBlocks插件开发指南(三)
1. 添加右键弹出菜单
我们在这里,将会在插件中加入右键弹出菜单功能。也就是如下图那样,在文档区内,点击鼠标右键时会弹出的菜单。我们将在这个菜单中加入属于我们插件的菜单项目”testplug”。
加入菜单项目的效果如下图:
让我们看看,咱们创建的插件工程中,给我们提供了什么样的入口代码了吧。
1. 在函数BuildModuleMenu中添加菜单项。
在文档的视图里才加入菜单项的入口函数是BuildModuleMenu,它的初始代码是下面那样:
1 void testplug::BuildModuleMenu(const ModuleType type, wxMenu* menu, const FileTreeData* data)
2 {
3 //Some library module is ready to display a pop-up menu.
4 //Check the parameter \"type\" and see which module it is
5 //and append any items you need in the menu
6 //TIP: for consistency, add a separator as the first item
7 NotImplemented(_T("testplug::BuildModuleMenu()"));
8 }
其实该函数就是一个往日志里打印log而已,里面调用的函数NotImplemented也不起到任何作用,可以无视。
其中函数参数的意义如下:
①type 当前运行的是CodeBlocks的哪个模块
②men 编辑器的右键弹出菜单的实例的指针
③data IDE环境的文件数列表数据的指针
接下来,让我看看应该在这个函数里加入什么样的代码才能加入我们菜单项目
1 void testplug::BuildModuleMenu(const ModuleType type, wxMenu* menu, const FileTreeData* data)
2 {
3 //Some library module is ready to display a pop-up menu.
4 if (!menu || !IsAttached())
5 return;
6 //Check the parameter \"type\" and see which module it is
7 //and append any items you need in the menu
8 if (type == mtEditorManager) {
9 menu->AppendSeparator();
10 menu->Append(idTestPlug, _("TestPlug"), _("hello world"));
11 }
12 //TIP: for consistency, add a separator as the first item
13 NotImplemented(_T("testplug::BuildModuleMenu()"));
14 }
IsAttached函数的意思是检查插件是否已经被载入到CodeBlocks中,没有载入插件的场合返回FALSE.
如果当前运行的模块是CodeBlocks的编辑器的话,我们就可以插入我们的菜单项了。插入菜单项的方法非常简单,就是利用wxMenu的Append接口就可以了。如上面的代码中使用了如下的语句:
menu->Append(idTestPlug, _("TestPlug"), _("hello world"));
该接口的原型声明为:
wxMenu::Append
wxMenuItem* Append(int id, const wxString& item = "", const wxString& helpString = "", wxItemKind kind = wxITEM_NORMAL)
id: 菜单项的ID.
item: 是在右键弹出菜单中显示的字符串
helpString: 是在状态条中显示的字符串
kind: 菜单项的类型
我们在第二个参数item设置成字符串TestPlug,helpString随便传一个字符串,第四个参数kind不用写,使用默认值即可。
注意,上面代码中的menu->AppendSeparator()表示在菜单项中加入一个分割线。AppendSeparator同样也是wxMenu类的一个成员。
2. 给菜单项创建资源ID。
里面最重要的一个参数非id莫数了,因为在GUI中,参单项跟画面上的控件一样都属于插件的资源,所以它也应该有一个资源ID,也就是我们这里的参数id.所以,接下来我们要给菜单项添加一个资源标示。
const int idTestPlug = wxNewId();
如上所示,使用wxNewId函数来创建一个资源id,并赋值给idTestPlug。
因此,把上述的语句加入到源文件的开始处即可. 即把idTestPlug作为一个全局变量来使用.
注:wxNewID实际上是一个返回static的全局引用计数的函数。在C++中允许在全局变量定义时执行某个函数,让函数的返回值赋值给全局变量。这在C中是不允许的。
3. 在事件管理表中加入事件处理函数。
接下来,在插件的event table中加入菜单项被单击后的事件处理函数。如下:
1 // events handling
2 BEGIN_EVENT_TABLE(testplug, cbPlugin)
3 // add any events you want to handle here
4 EVT_MENU(idTestPlug, testplug::OnTestPlug)
5 END_EVENT_TABLE()
注意,我们这里加入的事件处理函数的名字是OnTestPlug, 其实我们就是通过宏EVT_MENU将idTestPlug和该函数关联起来。
4. 声明事件处理函数。
在testplug类中要做一下事件处理函数的声明,如下:
private:
void OnTestPlug(wxCommandEvent &event);
DECLARE_EVENT_TABLE();
OnTestPlug函数的参数event是被传入的是一个事件的实例,它的类名是wxCommandEvent
5. 实现事件处理函数。
这里,我们就可以为所欲为了,在OnTestPlug中添加的代码,在TestPlug菜单项被电击之后就可以被执行了。为了简单起见,函数很简单,仅仅是弹出一个消息框而已。
1 void testplug::OnTestPlug(wxCommandEvent &event)
2 {
3 cbMessageBox(_("This is my first Plugin test program"), _("Info"), wxICON_QUESTION);
4 }
数里面仅仅使用cbMessageBox来弹出一个消息。
OK了,如果上述的代码没有敲错任何字符的话,你就可以没有任何错误的编译通过了。如果编译没有问题,你就按照5-④把你编译好的插件重新载入到CodeBlocks里了。当然在重新载入前,你先得把老版本的插件卸载掉。记住,每次你的插件有什么改动的话,你必须都得这么做。
如果上面的步骤都没有问题,你可以试试在编辑器中点击鼠标右键,是不是可以发现右键菜单上多了一个 TestPlug 的菜单项。
然后你点击这个菜单项,是不是就弹出下面的对话框了吧。
如果没有出来的话,你就应该反复的检查上面的任何一个步骤,看看是否有什么没有照做的地方。
在CodeBlock里添加一个菜单项还是很简单吧。一共就用了不到10行程序就搞定了。接下来,我们将尝试在CodeBlocks的主菜单里添加一个同名的菜单项。
2. 主菜单中添加下拉菜单
假设我们想象下面那样,在CodeBlocks的Tools主菜单中加入一个菜单项,那该如何做呢?
为了方便起见,我们这里加入的菜单项跟上一步的菜单名字是一样,功能也是一样的。也就是使用同一个资源id就行了,就是上一步中的idTestPlug. 如果想设定不同的名字,不同的功能,你可以重复上一步中的2~5的步骤就可以了。
关键是要找到,在系统菜单中加入菜单项的入口函数在哪里。这个函数就是testplug类的成员函数BuildMenu。我们可以看它的初始代码是什么样的。
void testplug::BuildMenu(wxMenuBar* menuBar)
{
//The application is offering its menubar for your plugin,
//to add any menu items you want
//Append any items you need in the menu
//NOTE: Be careful in here The application's menubar is at your disposal.
NotImplemented(_T("testplug::BuildMenu()"));
}
跟BuildModuleMenu函数一样,它的初始化函数基本上也是空的。里面仅仅调用了一个无关紧要的函数NotImplemented。大家注意到,这个函数的参数menBar了吧,它是wmMenuBar的实例的指针,这个实例就是系统菜单条(menuBar)的实例。我们只要利用这个实例的接口函数来加入我们的菜单项了。
下面,我们看看如何修改这个函数。
1 void testplug::BuildMenu(wxMenuBar* menuBar)
2 {
3 //The application is offering its menubar for your plugin,
4 //to add any menu items you want
5 if (!IsAttached())
6 return;
7 //Append any items you need in the menu
8 int pos = menuBar->FindMenu(_("&Tools"));
9 if (pos != wxNOT_FOUND) {
10 m_ToolsMenu = menuBar->GetMenu(pos);
11 m_ToolsMenu->AppendSeparator();
12 m_ToolsMenu->Append(idTestPlug, _("TestPlug\tCtrl-1"));
13 }
14
15 //NOTE: Be careful in here The application's menubar is at your disposal.
16 NotImplemented(_T("testplug::BuildMenu()"));
17 }
① 首先,跟上一节一样,我们在加入我们的任何动作之前,都要判断我们的插件是否已经被载入到CodeBlock中了,这时候使用IsAttached()就可以了。
② 在菜单条menBar中找到Tools主菜单的位置
使用的函数是FindMenu, 参数就是菜单的名字,即一个字符串。该函数的返回值是该菜单的位置索引,如果查找的菜单不在主菜单中的话,它会返回wxNOT_FOUND.
③ 根据这个位置得到Tools菜单的实例
使用函数GetMenu就可以得到菜单的实例了,该函数参数就是菜单的位置索引,也就是上一步FindMenu的返回值。
④ 利用这个实例就可以在Tools菜单中加入TestPlug菜单项了。
有了菜单的实例,就可以跟在右键弹出菜单那样,在里面加入我们自己的菜单项。方法跟1-1是一样的,这里就不重复了。
注意:在Apennd函数的第二个参数是菜单项的名字,我们这里是"TestPlug\tCtrl-1"。这个字符串里有"\tCtrl-1"的字样,表示激活该菜单项的快捷间是Ctrl-1. 也就是你在IDE中按下Ctrl-1键就会执行该菜单项对应消息处理函数,在我们的例子中,则是弹出下面的消息框:
到此为止,在主菜单中添加菜单项的任务就完成了。如果想要为该菜单项添加自己的消息处理函数,则重复上一步中的2~5的步骤就可以了。