IDEA Plugins

版本工具说明

  • JDK1.8
  • IDEA2020.1
  • 插件项目基于gradle构建。
  • 知识背景:swing

    目标

    本实例实现一个Idea的插件,弹出一个表单Dialog,然后点击按钮,获取表单里输入的内容,然后将内容打印在表单的上方。
    成品图展示:
    IDEA插件开发 - 图1

    项目初始化

    新建一个gradle项目,修改其build.gradle文件: ```groovy plugins { id ‘java’ id ‘org.jetbrains.intellij’ version ‘0.4.14’ //引入intellij的gradle插件 }

group ‘org.example’ version ‘1.0’ //定义jar包/zip包的版本号

sourceCompatibility = 1.8 //限制jdk的使用版本号,这里限制到8,表示生成的idea插件只能运行在jdk8以上的环境中

repositories { mavenCentral() //远程仓库 }

dependencies { //这里引别的依赖包 testCompile group: ‘junit’, name: ‘junit’, version: ‘4.12’ }

// See https://github.com/JetBrains/gradle-intellij-plugin/ intellij { // 这里是指打插件包的时候用idea什么版本的依赖包打 // 比如这里用2019.3打包,如果你的插件实现源码里用了2019.3不存在的依赖包或类,就会报错 // 一般就填当前IDEA的版本号即可 version “2019.3” }

patchPluginXml {

  1. //changeNotes里的内容展示位置参考图14
  2. changeNotes """
  3. 1.0版本.
  4. 第1.0版本:初始化这个测试插件项目"""
  5. // 这个意思是说当前定义的这个插件最早支持到什么版本的IDEA
  6. // 这里配置sinceBuild=191,表示插件只能被版本号大于等于2019.1版本的IDEA安装,低于这个版本的将抛无法兼容的错误
  7. // ↑上方参考这篇问答:https://intellij-support.jetbrains.com/hc/en-us/community/posts/360003338799-Build-compatible-plugin
  8. sinceBuild "191"

}

  1. 然后Idea的右边栏gradle将会多出intellij选项:<br />![](https://cdn.nlark.com/yuque/0/2021/webp/396745/1636965114078-09190434-5eed-4fa1-a74e-51a31c25b140.webp#clientId=uc932fb85-3596-4&from=paste&id=ua6666b5b&margin=%5Bobject%20Object%5D&originHeight=419&originWidth=361&originalType=url&ratio=1&status=done&style=none&taskId=u5c009b30-5713-40a8-a925-f44787204d1)<br />这里说下runIde,它用来调试插件,运行它会再次启动一个Idea,这个Idea会自动安装上当前定义的插件包,用来调试。
  2. <a name="zlqdS"></a>
  3. ## 新增plugin.xml
  4. 这个文件非常重要,它可以指定定义的插件出现在IDEA的哪个位置,可以指定具体的处理逻辑,还可以定义插件名称、子名称等等。<br />这个文件位于MATE-INF下:<br />![](https://cdn.nlark.com/yuque/0/2021/webp/396745/1636965114058-c06dfaed-39b6-44d9-bd0e-a4d169f20abb.webp#clientId=uc932fb85-3596-4&from=paste&id=ufb408ce8&margin=%5Bobject%20Object%5D&originHeight=365&originWidth=332&originalType=url&ratio=1&status=done&style=none&taskId=uc10997dc-a5c5-4751-bf87-5fbced0337b)<br />配置内容为:
  5. ```xml
  6. <idea-plugin>
  7. <!--插件的id,注意不要跟其他插件重复,这个id全局唯一,尽可能复杂些-->
  8. <id>plugin.test</id>
  9. <!--插件的名称-->
  10. <name>PluginTest</name>
  11. <vendor email="xxxx@qq.com" url="http://www.bilibili.com">你公司的名字</vendor>
  12. <!--插件的描述信息,支持html,展示的位置参考图14-->
  13. <description><![CDATA[
  14. Plugin Test<br>
  15. 第一行:单纯只是个测试<br>
  16. 第二行:都说了只是个测试(● ̄(エ) ̄●)<br>
  17. <a href='https://www.bilibili.com'>你猜猜这是哪个网站?</a>
  18. <em>v1.0</em>
  19. ]]></description>
  20. <extensions defaultExtensionNs="com.intellij">
  21. <!-- Add your extensions here -->
  22. </extensions>
  23. <!--跟build.gradle里的sinceBuild一致即可,意义相同,必须配置-->
  24. <idea-version since-build="191"/>
  25. <actions>
  26. <!--下面的group是分组,分组需要有一个唯一的id标识,text用来控制分组出现在IDEA时呈现的文案,description是描述,不会展现出来,简单描述下分组就行-->
  27. <group id="PluginTest" text="插件测试组" description="插件测试描述">
  28. <!--add-to-group控制把该分组加到IDEA里,group-id用来描述加在哪个位置,MainMenu表示加在IDEA上方的主菜单栏里,
  29. anchor表示顺序,last表示最后一个,所以下面的配置可以描述为:将该插件加到IDEA上方主菜单栏的最后一位-->
  30. <add-to-group group-id="MainMenu" anchor="last"/>
  31. <!--这个用来指定一个分组下的触发动作,同样的需要一个id,自定义;class就是用来处理这个动作的逻辑类,具体的插件逻辑都会写到对应的action类里,text用来控制文案,description为描述-->
  32. <action id="Plugin.Test.Action"
  33. class="plugin.test.FromAction"
  34. text="表单测试" description="表单测试描述"/>
  35. </group>
  36. </actions>
  37. </idea-plugin>

然后定义一个Action类,记为FormAction,继承AnAction,实现其抽象方法actionPerformed即可:

  1. public class FromAction extends AnAction {
  2. @Override
  3. public void actionPerformed(@NotNull AnActionEvent e) {
  4. //TODO 这里放插件逻辑
  5. }
  6. }

启动

现在双击runIde即可调出另外一个安装了这个插件的IDEA界面,然后可以看运行结果进行调试。runIde还支持debug模式,不过运行时要右击选择:
IDEA插件开发 - 图2
来看下调试IDEA的界面运行效果:
IDEA插件开发 - 图3

定义Action

1. 定义会话框类

经过上面三步的配置,插件的基本样式已经展示出来,但是点击下方“表单测试”的action,并没有什么用,因为其绑定的FormAction类里没有任何有意义的实现。现在来实现开始的目标,点击“表单测试”后,弹出一个自定义的表单会话框,然后点击按钮,获取表单内容后打印在会话框内。
会话框(Dialog)需要定义一个继承了IDEA的DialogWrapper抽象类的子类,这个子类就是自定义的会话框实现,所有的样式定义、功能触发都是放到这个子类里的,现定于如下子类:

  1. public class FormTestDialog extends DialogWrapper {
  2. private String projectName; //假如需要获取到项目名,作为该类的属性放进来
  3. // DialogWrapper没有默认的无参构造方法,所以需要重写构造方法,它提供了很多重载构造方法,
  4. // 这里使用传project类型参数的那个,通过Project对象可以获取当前IDEA内打开的项目的一些属性,
  5. // 比如项目名,项目路径等
  6. public FormTestDialog(@Nullable Project project) {
  7. super(project);
  8. setTitle("表单测试~~"); // 设置会话框标题
  9. this.projectName = project.getName();
  10. }
  11. // 重写下面的方法,返回一个自定义的swing样式,该样式会展示在会话框的最上方的位置
  12. @Override
  13. protected JComponent createNorthPanel() {
  14. return null;
  15. }
  16. // 重写下面的方法,返回一个自定义的swing样式,该样式会展示在会话框的最下方的位置
  17. @Override
  18. protected JComponent createSouthPanel() {
  19. return null;
  20. }
  21. // 重写下面的方法,返回一个自定义的swing样式,该样式会展示在会话框的中央位置
  22. @Override
  23. protected JComponent createCenterPanel() {
  24. return null;
  25. }
  26. }

2. 会话框模块&类元素对照

找个实际的会话框为例,针对上述中几个方法所控制的会话框里的元素如下:
IDEA插件开发 - 图4

3. 会话框方法重定义

按照本文的实现目标,自定义的表单主体部分可以位于createCenterPanel里,然后表单的大标题可以放到createNorthPanel里,提交按钮可以放到createSouthPanel里,现在改写如下:

  1. public class FormTestDialog extends DialogWrapper {
  2. private String projectName;
  3. //swing样式类,定义在4.3.2
  4. private FormTestSwing formTestSwing = new FormTestSwing();
  5. public FormTestDialog(@Nullable Project project) {
  6. super(true);
  7. setTitle("表单测试~~"); //设置会话框标题
  8. this.projectName = project.getName(); //获取到当前项目的名称
  9. init(); //触发一下init方法,否则swing样式将无法展示在会话框
  10. }
  11. @Override
  12. protected JComponent createNorthPanel() {
  13. return formTestSwing.initNorth(); //返回位于会话框north位置的swing样式
  14. }
  15. // 特别说明:不需要展示SouthPanel要重写返回null,否则IDEA将展示默认的"Cancel"和"OK"按钮
  16. @Override
  17. protected JComponent createSouthPanel() {
  18. return formTestSwing.initSouth();
  19. }
  20. @Override
  21. protected JComponent createCenterPanel() {
  22. //定义表单的主题,放置到IDEA会话框的中央位置
  23. return formTestSwing.initCenter();
  24. }
  25. }

4. 自定义swing样式

下面是放置swing样式的类:

  1. public class FormTestSwing {
  2. private JPanel north = new JPanel();
  3. private JPanel center = new JPanel();
  4. private JPanel south = new JPanel();
  5. //为了让位于底部的按钮可以拿到组件内容,这里把表单组件做成类属性
  6. private JLabel r1 = new JLabel("输出:");
  7. private JLabel r2 = new JLabel("NULL");
  8. private JLabel name = new JLabel("姓名:");
  9. private JTextField nameContent = new JTextField();
  10. private JLabel age = new JLabel("年龄:");
  11. private JTextField ageContent = new JTextField();
  12. public JPanel initNorth() {
  13. //定义表单的标题部分,放置到IDEA会话框的顶部位置
  14. JLabel title = new JLabel("表单标题");
  15. title.setFont(new Font("微软雅黑", Font.PLAIN, 26)); //字体样式
  16. title.setHorizontalAlignment(SwingConstants.CENTER); //水平居中
  17. title.setVerticalAlignment(SwingConstants.CENTER); //垂直居中
  18. north.add(title);
  19. return north;
  20. }
  21. public JPanel initCenter() {
  22. //定义表单的主体部分,放置到IDEA会话框的中央位置
  23. //一个简单的3行2列的表格布局
  24. center.setLayout(new GridLayout(3, 2));
  25. //row1:按钮事件触发后将结果打印在这里
  26. r1.setForeground(new Color(255, 47, 93)); //设置字体颜色
  27. center.add(r1);
  28. r2.setForeground(new Color(139, 181, 20)); //设置字体颜色
  29. center.add(r2);
  30. //row2:姓名+文本框
  31. center.add(name);
  32. center.add(nameContent);
  33. //row3:年龄+文本框
  34. center.add(age);
  35. center.add(ageContent);
  36. return center;
  37. }
  38. public JPanel initSouth() {
  39. //定义表单的提交按钮,放置到IDEA会话框的底部位置
  40. JButton submit = new JButton("提交");
  41. submit.setHorizontalAlignment(SwingConstants.CENTER); //水平居中
  42. submit.setVerticalAlignment(SwingConstants.CENTER); //垂直居中
  43. south.add(submit);
  44. return south;
  45. }
  46. }

现在点击下runIde按钮,同样的,在调试IDE里点击“表单测试”,然后就会弹出如下表单框:
IDEA插件开发 - 图5
除非有特殊情况需要自定义swing样式,否则建议不加任何swing样式,这样自定义的swing界面是会随着IDEA的主题改变而去自适应的,比如将图7中的调试IDE的主题设置成Darcula,自定义的表单也会自适应的变成黑色背景:
IDEA插件开发 - 图6

5. 事件绑定

定义好了样式,现在给“提交”按钮绑定一个事件,现在改写下FormTestSwing.initSouth方法:

  1. public JPanel initSouth() {
  2. //定义表单的提交按钮,放置到IDEA会话框的底部位置
  3. JButton submit = new JButton("提交");
  4. submit.setHorizontalAlignment(SwingConstants.CENTER); //水平居中
  5. submit.setVerticalAlignment(SwingConstants.CENTER); //垂直居中
  6. south.add(submit);
  7. //按钮事件绑定
  8. submit.addActionListener(e -> {
  9. //获取到name和age
  10. String name = nameContent.getText();
  11. String age = ageContent.getText();
  12. //刷新r2标签里的内容,替换为name和age
  13. r2.setText(String.format("name:%s, age:%s", name, age));
  14. });
  15. return south;
  16. }

现在再来点击下“提交”按钮,就可以输出表单内容了:
IDEA插件开发 - 图7

6. 插件绑定类:FormAction

之前讲过,这个类是插件的入口,结合上面定义好的表单Dialog,来看下它是怎么写的:

  1. public class FromAction extends AnAction {
  2. @Override
  3. public void actionPerformed(@NotNull AnActionEvent e) {
  4. FormTestDialog formTestDialog = new FormTestDialog(e.getProject());
  5. formTestDialog.setResizable(true); //是否允许用户通过拖拽的方式扩大或缩小你的表单框,我这里定义为true,表示允许
  6. formTestDialog.show();
  7. }
  8. }

7. 插件的打包&安装

截止到第四步,都只是在调试IDE里查看效果,如果一个插件开发完成后,需要被实际的IDEA安装,这个时候就需要借助打包选项来打包插件,点击下面的选项构建插件:
IDEA插件开发 - 图8
构建完成后,查看build包下的distributions目录,里面的zip包就可以直接安装进IDEA:
IDEA插件开发 - 图9
然后选择IDEA的Preferences下的plugins选项,弹出如下框,按照图里的指示选择zip包安装即可:
IDEA插件开发 - 图10
然后安装完成,重启IDEA即可:
IDEA插件开发 - 图11
各个展示模块对应插件项目里配置的来源参考下图:
IDEA插件开发 - 图12
重启后出现了跟调试IDEA里一样的菜单栏,选中后运行成功:
IDEA插件开发 - 图13
更多细节请看IDEA官方文档:https://plugins.jetbrains.com/docs/intellij/welcome.html?from=jetbrains.org

参考文档