一时兴起,自己动手开发了个IDEA插件!

开发 前端
一个插件的开发、调试、安装就完成了,理论上通过这个简单的例子就可以实现一些实际的功能了,因为其完整展示了数据输入到数据获取整个过程。

[[407214]]

前言

最近工作比较闲,自己琢磨点东西,一时兴起想自己做个IDEA插件玩玩,说不定还能卖钱,哈哈。

版本工具

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

达到什么目标?

本实例实现一个Idea的插件,弹出一个表单Dialog,然后点击按钮,获取表单里输入的内容,然后将内容打印在表单的上方。

成品图展示:

项目初始化

新建一个gradle项目,修改其build.gradle文件:

  1. plugins { 
  2.     id 'java' 
  3.     id 'org.jetbrains.intellij' version '0.4.14' //引入intellij的gradle插件 
  4.   
  5. group 'org.example' 
  6. version '1.0' //定义jar包/zip包的版本号 
  7.   
  8. sourceCompatibility = 1.8 //限制jdk的使用版本号,这里限制到8,表示生成的idea插件只能运行在jdk8以上的环境中 
  9.   
  10. repositories { 
  11.     mavenCentral() //远程仓库 
  12.   
  13. dependencies { 
  14.     //这里引别的依赖包 
  15.     testCompile group'junit'name'junit', version: '4.12' 
  16.   
  17. // See https://github.com/JetBrains/gradle-intellij-plugin/ 
  18. intellij { 
  19.     // 这里是指打插件包的时候用idea什么版本的依赖包打 
  20.     // 比如这里用2019.3打包,如果你的插件实现源码里用了2019.3不存在的依赖包或类,就会报错 
  21.     // 一般就填当前IDEA的版本号即可 
  22.     version "2019.3" 
  23.   
  24. patchPluginXml { 
  25.   
  26.     //changeNotes里的内容展示位置参考图14 
  27.     changeNotes ""
  28.       1.0版本. 
  29.  
  30.       第1.0版本:初始化这个测试插件项目""
  31.   
  32.     // 这个意思是说当前定义的这个插件最早支持到什么版本的IDEA 
  33.     // 这里配置sinceBuild=191,表示插件只能被版本号大于等于2019.1版本的IDEA安装,低于这个版本的将抛无法兼容的错误 
  34.     // ↑上方参考这篇问答:https://intellij-support.jetbrains.com/hc/en-us/community/posts/360003338799-Build-compatible-plugin 
  35.     sinceBuild "191" 

然后Idea的右边栏gradle将会多出intellij选项:

“这里说下runIde,它用来调试插件,运行它会再次启动一个Idea,这个Idea会自动安装上你当前定义的插件包,让你用来调试。

新增plugin.xml

这个文件非常重要,它可以指定你定义的插件出现在IDEA的哪个位置,可以指定具体的处理逻辑,还可以定义插件名称、子名称等等。

这个文件位于MATE-INF下:

配置内容为:

  1. <idea-plugin> 
  2.     <!--插件的id,注意不要跟其他插件重复,这个id全局唯一,尽可能复杂些--> 
  3.     <id>plugin.test</id> 
  4.     <!--插件的名称--> 
  5.     <name>PluginTest</name
  6.     <vendor email="xxxx@qq.com" url="http://www.bilibili.com">你公司的名字</vendor> 
  7.  
  8.     <!--插件的描述信息,支持html,展示的位置参考图14--> 
  9.     <description><![CDATA[ 
  10.     Plugin Test<br> 
  11.     第一行:单纯只是个测试<br> 
  12.     第二行:都说了只是个测试(● ̄(エ) ̄●)<br> 
  13.     <a href='https://www.bilibili.com'>你猜猜这是哪个网站?</a> 
  14.     <em>v1.0</em> 
  15.     ]]></description> 
  16.      
  17.     <extensions defaultExtensionNs="com.intellij"
  18.         <!-- Add your extensions here --> 
  19.     </extensions> 
  20.  
  21.     <!--跟build.gradle里的sinceBuild一致即可,意义相同,必须配置--> 
  22.     <idea-version since-build="191"/> 
  23.  
  24.     <actions> 
  25.         <!--下面的group是分组,分组需要有一个唯一的id标识,text用来控制分组出现在IDEA时呈现的文案,description是描述,不会展现出来,简单描述下分组就行--> 
  26.         <group id="PluginTest" text="插件测试组" description="插件测试描述"
  27.             <!--add-to-group控制把该分组加到IDEA里,group-id用来描述加在哪个位置,MainMenu表示加在IDEA上方的主菜单栏里, 
  28.             anchor表示顺序,last表示最后一个,所以下面的配置可以描述为:将该插件加到IDEA上方主菜单栏的最后一位--> 
  29.             <add-to-group group-id="MainMenu" anchor="last"/> 
  30.             <!--这个用来指定一个分组下的触发动作,同样的需要一个id,自定义;class就是用来处理这个动作的逻辑类,具体的插件逻辑都会写到对应的action类里,text用来控制文案,description为描述--> 
  31.             <action id="Plugin.Test.Action" 
  32.                     class="plugin.test.FromAction" 
  33.                     text="表单测试" description="表单测试描述"/> 
  34.         </group
  35.     </actions> 
  36. </idea-plugin> 

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

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

启动

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

来看下调试IDEA的界面运行效果:

定义Action

1. 定义会话框类

经过上面三步的配置,插件的基本样式已经展示出来,但是点击下方“表单测试”的action,并没有什么用,因为其绑定的FormAction类里没有任何有意义的实现。现在来实现开始的目标,点击“表单测试”后,弹出一个自定义的表单会话框,然后点击按钮,获取表单内容后打印在会话框内。

会话框(Dialog)需要定义一个继承了IDEA的DialogWrapper抽象类的子类,这个子类就是自定义的会话框实现,所有的样式定义、功能触发都是放到这个子类里的,现定于如下子类:

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

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

找个实际的会话框为例,针对上述中几个方法所控制的会话框里的元素如下:

3. 会话框方法重定义

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

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

4. 自定义swing样式

下面是放置swing样式的类:

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

现在点击下runIde按钮,同样的,在调试IDE里点击“表单测试”,然后就会弹出如下表单框:

“除非有特殊情况需要自定义swing样式,否则建议不加任何swing样式,这样自定义的swing界面是会随着IDEA的主题改变而去自适应的,比如将图7中的调试IDE的主题设置成Darcula,自定义的表单也会自适应的变成黑色背景:

5. 事件绑定

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

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

现在再来点击下“提交”按钮,就可以输出表单内容了:

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.     } 

7. 插件的打包&安装

截止到第四步,都只是在调试IDE里查看效果,如果一个插件开发完成后,需要被实际的IDEA安装,这个时候就需要借助打包选项来打包你的插件,点击下面的选项构建插件:

构建完成后,查看build包下的distributions目录,里面的zip包就可以直接安装进你的IDEA:

然后选择IDEA的Preferences下的plugins选项,弹出如下框,按照图里的指示选择zip包安装即可:

然后安装完成,重启IDEA即可:

各个展示模块对应插件项目里配置的来源参考下图:

重启后出现了跟调试IDEA里一样的菜单栏,选中后运行成功:

总结

截止到这里,一个插件的开发、调试、安装就完成了,理论上通过这个简单的例子就可以实现一些实际的功能了,因为其完整展示了数据输入到数据获取整个过程。

因为工作当中需要写一个代码生成器,想要以一个IDEA插件的方式提供服务,所以在这里做个记录,防止以后再次用到时从零开始。

要有一定的swing基础,我在开发代码生成器的时候,就是因为swing基础太差,布局花了非常多的时间。

 

责任编辑:姜华 来源: 无聊学Java
相关推荐

2011-08-25 09:30:22

2021-04-26 07:31:22

SpringMVCweb框架

2015-09-01 09:49:28

2017-03-02 13:31:02

监控系统

2010-07-23 10:23:05

Google机房

2023-07-10 09:53:59

console开发插件

2020-10-10 06:32:43

IDEA插件环境

2017-02-14 10:20:43

Java Class解析器

2015-06-02 10:24:43

iOS网络请求降低耦合

2016-07-25 18:09:29

2023-02-13 00:18:22

前端库框架集合

2015-06-02 09:51:40

iOS网络请求封装接口

2020-10-12 10:58:15

IDEA插件监听

2011-10-31 10:17:05

插件

2016-09-21 12:34:10

Chrome浏览器插件

2023-11-13 18:01:15

开发工具Java

2022-04-18 19:02:53

chrome扩展浏览器

2023-09-21 22:56:32

插件开发

2022-11-10 09:28:40

框架开发

2024-03-08 12:45:00

C#Web服务器
点赞
收藏

51CTO技术栈公众号