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

IT牧场

共 7995字,需浏览 16分钟

 · 2021-11-18

点击下方“IT牧场”,选择“设为星标”

今天无聊带你们撩一下IDEA插件

前言

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

版本工具说明

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

达到什么目标?

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

成品图展示:

项目初始化

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

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 {
 
    //changeNotes里的内容展示位置参考图14
    changeNotes """
      1.0版本.

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

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

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

新增plugin.xml

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

这个文件位于MATE-INF下:

配置内容为:

<idea-plugin>
    
    <id>plugin.testid>
    
    <name>PluginTestname>
    <vendor email="xxxx@qq.com" url="http://www.bilibili.com">你公司的名字vendor>

    
    <description>    Plugin Test

    第一行:单纯只是个测试

    第二行:都说了只是个测试(● ̄(エ) ̄●)

    你猜猜这是哪个网站?
    v1.0
    ]]>description>
    
    <extensions defaultExtensionNs="com.intellij">
        
    extensions>

    
    <idea-version since-build="191"/>

    <actions>
        
        <group id="PluginTest" text="插件测试组" description="插件测试描述">
            
            <add-to-group group-id="MainMenu" anchor="last"/>
            
            <action id="Plugin.Test.Action"
                    class="plugin.test.FromAction"
                    text="表单测试" description="表单测试描述"/>

        group>
    actions>
idea-plugin>

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

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

启动

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

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

定义Action

1. 定义会话框类

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

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

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

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

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

3. 会话框方法重定义

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

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

4. 自定义swing样式

下面是放置swing样式的类:

public class FormTestSwing {
 
    private JPanel north = new JPanel();
 
    private JPanel center = new JPanel();
 
    private JPanel south = new JPanel();
 
    //为了让位于底部的按钮可以拿到组件内容,这里把表单组件做成类属性
    private JLabel r1 = new JLabel("输出:");
    private JLabel r2 = new JLabel("NULL");
 
    private JLabel name = new JLabel("姓名:");
    private JTextField nameContent = new JTextField();
 
    private JLabel age = new JLabel("年龄:");
    private JTextField ageContent = new JTextField();
 
    public JPanel initNorth() {
 
        //定义表单的标题部分,放置到IDEA会话框的顶部位置
 
        JLabel title = new JLabel("表单标题");
        title.setFont(new Font("微软雅黑", Font.PLAIN, 26)); //字体样式
        title.setHorizontalAlignment(SwingConstants.CENTER); //水平居中
        title.setVerticalAlignment(SwingConstants.CENTER); //垂直居中
        north.add(title);
 
        return north;
    }
 
    public JPanel initCenter() {
 
        //定义表单的主体部分,放置到IDEA会话框的中央位置
 
        //一个简单的3行2列的表格布局
        center.setLayout(new GridLayout(32));
 
        //row1:按钮事件触发后将结果打印在这里
        r1.setForeground(new Color(2554793)); //设置字体颜色
        center.add(r1);
        r2.setForeground(new Color(13918120)); //设置字体颜色
        center.add(r2);
 
        //row2:姓名+文本框
        center.add(name);
        center.add(nameContent);
 
        //row3:年龄+文本框
        center.add(age);
        center.add(ageContent);
 
        return center;
    }
 
    public JPanel initSouth() {
 
        //定义表单的提交按钮,放置到IDEA会话框的底部位置
 
        JButton submit = new JButton("提交");
        submit.setHorizontalAlignment(SwingConstants.CENTER); //水平居中
        submit.setVerticalAlignment(SwingConstants.CENTER); //垂直居中
        south.add(submit);
 
        return south;
    }
}

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

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

5. 事件绑定

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

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

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

6. 插件绑定类:FormAction

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

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

7. 插件的打包&安装

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

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

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

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

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

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

总结

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

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

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

更多细节请看IDEA官方文档:https://plugins.jetbrains.com/docs/intellij/welcome.html?from=jetbrains.org

参考文档

  • http://www.jetbrains.org/intellij/sdk/docs/tutorials/build_system/prerequisites.html

  • http://www.jetbrains.org/intellij/sdk/docs/user_interface_components/tool_windows.html

  • http://www.jetbrains.org/intellij/sdk/docs/user_interface_components/dialog_wrapper.html

  • https://intellij-support.jetbrains.com/hc/en-us/community/posts/360003338799-Build-compatible-plugin

干货分享

最近将个人学习笔记整理成册,使用PDF分享。关注我,回复如下代码,即可获得百度盘地址,无套路领取!

001:《Java并发与高并发解决方案》学习笔记;002:《深入JVM内核——原理、诊断与优化》学习笔记;003:《Java面试宝典》004:《Docker开源书》005:《Kubernetes开源书》006:《DDD速成(领域驱动设计速成)》007:全部008:加技术群讨论

加个关注不迷路

喜欢就点个"在看"呗^_^

浏览 103
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报