IntellijIDEA插件开发京东云技术团队

如有疏漏欢迎指正,如想深入了解欢迎探讨。

IntelliJIDEA与IntelliJPlatform

IntelliJIDEA简称IDEA,是Jetbrains公司旗下的一款JAVA开发工具,支持Java、Scala、Groovy等语言的开发,同时具备支持目前主流的技术和框架,擅长于企业应用、移动应用和Web应用的开发,提供了丰富的功能,智能代码助手、代码自动提示、重构、J2EE支持、各类版本工具(git、svn等)、JUnit、CVS整合、代码分析、创新的GUI设计等。

IntelliJPlatform是一个构建IDE的开源平台,基于它构建的IDE有IntelliJIDEA、WebStorm、DataGrip、以及AndroidStudio等等。IDEA插件也是基于IntelliJPlatform开发的。

注意各软件版本要对应

PluginDevKit是IntelliJ的一个插件,它使用IntelliJIDEA自己的构建系统来为开发IDEA插件提供支持。开发IDEA插件之前需要安装并启用PluginDevKit。\打开IDEA,导航到Settings|Plugins,若插件列表中没有PluginDevKit,点击InstallJetBrainsplugin,搜索并安装。

IntelliJPlatformPluginSDK就是开发IntelliJ平台插件的SDK,是基于JDK之上运行的,类似于开发Android应用需要AndroidSDK。\3.1导航到File|ProjectStructure,选择对话框左侧栏PlatformSettings下的SDKs

3.2点击+按钮,先选择JDK,指定JDK的路径;再创建IntelliJPlatformPluginSDK,指定homepath为IDEA的安装路径,如图

创建好IntelliJPlatformPluginSDK后,选择左侧栏ProjectSettings下的Projects,在ProjectSDK下选择刚创建的IntelliJPlatformPluginSDK。

4.1查看build号:打开IDEA,Help|About,查看版本号及build号

4.3选择工程结构设置后选择SDKs->选中之前在第3步添加的sdk点击SourcePath后按如下1点击添加一个sourcePath,选择上面下载额源码后点击OK、点击Applay

4.4未安装源码时点击某一个action(NewModuleAction)会看到如下所示阅读起来会比较晦涩难懂。

IntelliJIDEA插件以Debug/Run模式运行时是在SandBox中进行的,不会影响当前的IntelliJIDEA;但是同一台机器同时开发多个插件时默认使用的同一个sandbox,即在创建IntelliJPlatformSDK时默认指定的SandboxHome

如果需要每个插件的开发环境是相互独立的,可以创建多个IntelliJPlatformSDK,为SandboxHome指定不同的目录。

插件的创建、配置、运行、打包流程,以及action

选择File|New|Project,左侧栏中选择IntelliJPlatformPlugin工程类型

点击Next,设置工程名称及位置,点击Finish完成创建。可以到File|ProjectStructure来自定义工程设置。

插件工程内容:

PluginDemo/resources/META-INF/plugin.xmlsrc/com/foo/.........

下面示例描述了可在plugin.xml文件配置的主要元素:

Action是实现插件功能的类,一个Action类需要继承AnAction并且实现actionPerformed方法。当用户点击菜单或者工具栏按钮,按快捷键,或者通过Help|FindAction点击时,IntelliJPlatform系统会回调对应Action的actionPerformed方法。\一个Action表示IDEA菜单里的一个menuitem或工具栏上的一个按钮,通过继承AnActionclass实现,当选择一个menuitem或点击工具栏上的按钮时,就会调用AnAction类的actionPerformed方法。\实现自定义Action分两步:

定义一个Javaclass,继承AnAction类,并重写actionPerformed方法,如

publicclassActionDemoextendsAnAction{publicvoidactionPerformed(AnActionEventevent){Projectproject=event.getData(PlatformDataKeys.PROJECT);Messages.showInputDialog(project,"Whatisyourname","Inputyourname",Messages.getQuestionIcon());}}

在plugin.xml文件的元素内注册

上面示例会定义一个被添加到IDEA主菜单的最后面的“SampleMenu”的菜单,点击该菜单将弹出一个“TextBoxes”item,如图

IntelliJPlatform提供了NewAction向导,它会帮助我们创建actionclass并配置plugin.xml文件:

在目标package上右键,选择New|PluginDevKit|Action:

注意:该向导只能向主菜单中已存在的actiongroup或工具栏上添加action,若要创建新的actiongroup,请参考前面的内容。

运行/调试插件可直接在IntelliJIDEA进行,选择Run|EditConfigurations...,若左侧栏没有Plugin类型的Configuration,点击右上角+按钮,选择Plugin类型,如图

Useclasspathofmodule选择要调试的module,其余配置一般默认即可;切换到Logs选项卡,如果勾选了idea.log,运行插件时idea.log文件的内容将输出到idea.logconsole。

运行插件点击工具栏上运行按钮Run

\

选择Build|PreparePluginModule‘modulename’forDeployment来打包插件:

jar类型的插件包:

PluginDemo.jar/com/xxx/.........META-INF/plugin.xml

zip类型的插件包:

PluginDemo.zip/lib/libxxx.jarlibbar.jarPluginDemo.jar/com/xxx/.........META-INF/plugin.xml

导航到File|Settings|Plugins页面,点击Installpluginfromdisk...

这个时候我们了解的都比较浅显还停留在demo层面,如何进行深入的了解呢?

eg:我们怎么知道都有哪些action或actiongroup可以被我们添加呢?

1、我们可以点击配置group-id="MainMenu"下的MainMenu

2、进入PlatformActions.xml如下图,这个时候不难看出这里就是主菜单的第一列子菜单

3.这个时候如果我们想新建个类似与File-->New和Open的菜单该怎么做呢?

3.1我们应该先实现布局,添加主菜单MainMenu

3.2实现自定义的打开文件

其实是通过下面的action配置的OpenFileAction找到源码

在将源码拷贝出来粘贴到自己的action内。这样就可以实现自己的主菜单File下的Open子菜单

3.3这个时候有人会有疑问我不知道去哪找New对应的action呀?

这个时候我们通过界面可以看到ProjectfromExistingSources...,这里我们就可以去搜这个文本呀。既然显示在页面上。必然有地方定义了它。ActionBundle.properties

这个时候我们在根据对应的action定义的文本在去搜索对应的action,com.intellij.ide.actions.ImportProjectAction

3.4这个时候我们将对应的action拷贝到自己的插件定义的配置上也就形成了3.1的一级和二级菜单

1.筛选后查找要添加的group\2.选择对应的action\3.选择要添加到这个action的某个位置

IntelliJIDEA的组件模型是基于PicoContainer的,组件都包含在这些容器中,但容器有三种级别:applicationcontainer,projectcontainer以及modulecontainer。applicationcontainer可以包含多个projectcontainer,而projectcontainer可以包含多个modulecontainer。

Components是插件开发的基础,Components有三种类型:

components需要配置在plugin.xml中,并指定interface和implementation,interface类用于从其他组件中检索组件,implementation类用于实例化组件。示例:

//创建一个applicationlevelcomponentpublicinterfaceComponent1extendsApplicationComponent{}publicclassComponent1ImplimplementsComponent1{@OverridepublicStringgetComponentName(){return"PluginDemo.Component1";}}

plugin.xml

com.example.test.Component1com.example.test.Component1Impl

注意:一个interface-class不能有多个implementation-class,如下图:

ApplicationComponent的生命周期方法:

//构造方法publicconstructor(){}//初始化publicvoidinitComponent(){}publicvoiddisposeComponent(){}

ProjectComponent的生命周期方法:

//构造方法publicconstructor(){}//通知一个project已经完成加载publicvoidprojectOpened(){}publicvoidprojectClosed(){}//执行初始化操作以及与其他components的通信publicvoidinitComponent(){}//释放系统资源或执行其他清理publicvoiddisposeComponent(){}

ModuleComponent的生命周期方法:

ModuleComponent的生命周期方法中比ProjectComponent多一个moduleAdded(),用于通知module已经被添加到project中。

Application级别的components在IDEA启动时加载,Project和Module级别的components在项目启动时共同加载。

一个组件加载过程:

示例:

publicclassMyComponentimplementsApplicationComponent{privatefinalMyOtherComponentotherComponent;publicMyComponent(MyOtherComponentotherComponent){this.otherComponent=otherComponent;}...}

一个组件卸载过程:

前面我们提到有三种不同的容器,applicationcontainer实现Application接口;projectcontainer实现Project接口;

modulecontainer实现Module接口。每一个容器都有自己的方法去获取容器内的component。

获取application容器及其内部的组件:

/获取application容器Applicationapplication=ApplicationManager.getApplication();//获取application容器中的组件MyComponentmyComponent=application.getComponent(MyComponent.class);

获取project/module容器及其内部的组件:

publicclassMyComponentimplementsProjectComponent{Projectproject;publicMyComponent(Projectproject){this.project=project;}publicvoidinitComponent(){OtherComponentotherComponent=project.getComponent(OtherComponent.class);}}

在这个例子中,组件在构造方法中获取了容器对象,将其保存,然后在component其他地方进行引用。

7.1创建一个ApplicationComponent

packagecom.plugin.demo.component;importcom.intellij.openapi.components.ApplicationComponent;//创建一个applicationlevelcomponentpublicinterfaceApplicationComponentDemoextendsApplicationComponent{}packagecom.plugin.demo.component;importcom.intellij.openapi.application.Application;importcom.intellij.openapi.application.ApplicationManager;publicclassApplicationComponentDemoImplimplementsApplicationComponentDemo{@OverridepublicStringgetComponentName(){System.out.println("ApplicationComponentDemoImpl="+this.getClass().getName());returnthis.getClass().getName();}//初始化publicvoidinitComponent(){System.out.println("ApplicationComponentDemoImplinitComponent");}publicvoiddisposeComponent(){//获取application容器Applicationapplication=ApplicationManager.getApplication();//获取application容器中的组件ApplicationComponentDemoImplmyComponent=application.getComponent(ApplicationComponentDemoImpl.class);System.out.println("disposeComponent="+myComponent.getComponentName());}}

7.2创建一个ProjectComponent

7.3创建一个ModuleComponent

7.4注册配置Component

com.plugin.demo.component.ApplicationComponentDemocom.plugin.demo.component.ApplicationComponentDemoImplcom.plugin.demo.component.ProjectComponentDemocom.plugin.demo.component.ProjectComponentDemocom.plugin.demo.component.ModuleComponentDemocom.plugin.demo.component.ModuleComponentDemo

7.5运行后的预期是先执行应用层组件,在执行工程级组件,在执行模块级组件

如果插件需要扩展IDEAPlatform或其他插件的功能,或为其他插件提供可以扩展自己的接口,那么就要用到extensions和extensionpoints,用于与IDEA和其他插件交互。

示例上述代码中的MyExtensionPoint1的beanClass:

publicclassMyBeanClassextendsAbstractExtensionPointBean{@Attribute("key")publicStringkey;@Attribute("implementationClass")publicStringimplementationClass;...}

插件的service的实现就是扩展IDEAPlatform的applicationService或projectService两个extensionpoints

IntelliJPlatform的部分extensionpoints

Service也是一种按需加载的component,在调用ServiceManager.getService(Class)时才会加载,且程序中只有一个实例。

Service是插件的一个组件,是为了把公共的逻辑放到一起,Service的实例是单例的。

Serivce在IntelliJIDEA中是以extensionpoint形式提供的,实现自己的service需要扩展相应extensionpoint。

在需要放置service的package上右键,New|PluginDevKit|xxxxService,如图

选择相应service,弹出如下对话框,填写interface类和implementation类,若不勾选Separateinterfacefromimplementation,只需填写implementation类。

\IntelliJIDEA会自动创建相应类并配置plugin.xml文件。\

示例:plugin.xml:

生成的service类:

publicinterfaceApplicationServiceDemo{staticApplicationServiceDemogetInstance(){returnServiceManager.getService(ApplicationServiceDemo.class);}}publicinterfaceProjectServiceDemo{staticProjectServiceDemogetInstance(@NotNullProjectproject){returnServiceManager.getService(project,ProjectServiceDemo.class);}}publicinterfaceModuleServiceDemo{staticModuleServiceDemogetInstance(@NotNullModulemodule){returnmodule.getService(ModuleServiceDemo.class);}}

publicclassApplicationServiceDemoImplimplementsApplicationServiceDemo{publicApplicationServiceDemoImpl(){System.out.println("ApplicationServiceDemoImpl=");}}publicclassProjectServiceDemoImplimplementsProjectServiceDemo{publicProjectServiceDemoImpl(Projectproject){System.out.println("ProjectServiceDemoImpl="+project);}}publicclassModuleServiceDemoImplimplementsModuleServiceDemo{publicModuleServiceDemoImpl(Moduleproject){System.out.println("ModuleServiceDemoImpl="+project);}}

MyApplicationServiceapplicationService=ServiceManager.getService(MyApplicationService.class);//获取project级别的service,需要提供project对象MyProjectServiceprojectService=ServiceManager.getService(project,MyProjectService.class);//获取module级别的service,需要提供module对象MyModuleServicemoduleService=ModuleServiceManager.getService(module,MyModuleService.class);

我们在使用IDE开始开发工作之前,总是要先在settings页面进行一些设置,且每次重新打开IDE后这些设置仍然保留着,那么这些设置是如何保存下来的呢?

IntelliJPlatform提供了一些API,可以使components或services在每次打开IDE时仍然使用之前的数据,即持久化其状态。

对于一些简单少量的值,我们可以使用PropertiesComponent,它可以保存application级别和project级别的值。

下面方法用于获取PropertiesComponent对象:

//获取application级别的PropertiesComponentPropertiesComponent.getInstance()//获取project级别的PropertiesComponent,指定相应的projectPropertiesComponent.getInstance(Project)propertiesComponent.setValue(name,value)propertiesComponent.getValue(name)

PropertiesComponent保存的是键值对,由于所有插件使用的是同一个namespace,强烈建议使用前缀来命名name,比如使用pluginid。

PersistentStateComponent用于持久化比较复杂的components或services,可以指定需要持久化的值、值的格式以及存储位置。

要使用PersistentStateComponent持久化状态:

下面通过两个例子进行说明:

classMyServiceimplementsPersistentStateComponent{//这里state是一个beanclassstaticclassState{publicStringvalue;...}//用于保存当前的状态StatemyState;//从当前对象里获取状态publicStategetState(){returnmyState;}//从外部加载状态,设置给当前对象的相应字段publicvoidloadState(Statestate){myState=state;}}

//这里的state就是实现类本身classMyServiceimplementsPersistentStateComponent{publicStringstateValue;...publicMyServicegetState(){returnthis;}publicvoidloadState(MyServicestate){XmlSerializerUtil.copyBean(state,this);}}

a、字段要求

state类中可能有多个字段,但不是所有字段都可以被持久化,可以被持久化的字段:

这些字段也有类型要求:

如果不希望某个字段被持久化,可以使用@com.intellij.util.xmlb.annotations.Transient注解。

b、构造器要求

state类必须有一个默认构造器,这个构造器返回的state对象被认为是默认状态,只有当当前状态与默认状态不同时,状态才会被持久化。

我们可以使用@State注解来定义存储位置

@State(name="PersistentDemo",storages={@Storage(value="PluginDemo.xml")})publicclassPersistentDemoimplementsPersistentStateComponent{...}

name:定义xml文件根标签的名称

storages:一个或多个@Storage,定义存储的位置

代码中获取状态与获取service的方式一样:

PersistentDemopersistDemo=ServiceManager.getService(PersistentDemo.class);PersistentDemo2persistDemo2=ServiceManager.getService(project,PersistentDemo.class);

获取状态与获取component的方式一样:

publicstaticPersistentComponentgetInstance(){returnApplicationManager.getApplication().getComponent(PersistentComponent.class);}publicstaticPersistentComponentgetInstance(Projectproject){returnproject.getComponent(PersistentComponent.class);}

开发插件时可能会用到其他插件,可能是IDEA绑定的,也可能是第三方的插件。

配置插件依赖需要将插件包添加到SDK的classpath中,并在plugin.xml配置。

配置plugin.xml在plugin.xml的部分添加所依赖插件的id。

org.jetbrains.kotlin

pluginid可以从插件包的plugin.xml文件查看。

GUI是IntelliJIDEA提供的一个自动生成java布局代码的工具,它使用JDK中的Swing控件来实现UI界面。

使用步骤:

配置GUI首先打开Settings对话框,选择Editor|GUIDesigner,如图,在GenerateGUIinto:有两个选项,生成class文件或java代码,我们选择生成java代码,因为建好布局后可能需要修改代码。其他默认即可。

创建form文件form文件用于记录界面布局。在相应的package上右键,选择New|GUIForm,如图,输入form文件名,一般与java文件名相同,点击OK创建form与java文件。

编辑界面打开form文件,如图,通过拖拽控件来搭建布局。每个form文件布局的root控件都是一个JPanel,可将该root对象传给需要该布局的类。注意:左下角的属性面板,只有当填写了fieldname属性时该控件的对象才会被当成成员变量,否则为局部变量。

生成java代码搭建好布局后,点击build

编译按钮,即可生成java的源码文件。

SmartConverter--POJOObjectConverter

在分层开发中,我们总是面临着各种POJO(DTO,DO,JO,VO)对象之间的相互转换。当对象比较复杂时,编写转换代码耗时较多,且非常容易出错。以至于可能会出现写一天代码,半天在写各种convert的囧境。

为了实现自动转换,出现了BeanUtil和ModelMapper等解决方案。这些方案,在少量对象转换时,性能损耗可以忽略,但是当转换数量达到一定量级时,这种损耗会对性能产生影响。

本插件可以自动生成POJO之间的转换代码,省去手工转换的麻烦,也不会损失性能。

下载SmartConverter.zip,并在IntellijIdea中安装;

publicstaticListtoDTOList(ListuserDTOList){}

插件自动从转换函数的参数和返回值推断出转换POJO;

支持List之间的转换。

如果存在单个转换的函数,则直接使用

如果不存在单个转换的函数,创建单个转换函数

支持嵌套转换

因为使用SmartConvert是使用alt+insert弹出或者右键点击Generate显示SmartConvertAction,所以根据前文的添加位置不难推断添加在弹出菜单EditorPopupMenu下,这个时候我们可以从两个方向找他添加的位置。

首先从项目的配置文件进入找到plugin.xml下配置的action。由此不难看出它实际是添加在了GenerateGroup这个组上的

这个时候我们不难看出并没有地方引用这个组,这个时候我们不防从使用的地方入手,我们是右键点击Generate或者alt+insert弹出的EditorLangPopupMenu下的Generate的组。这个时候我们去全局搜索EditorPopupMenu

发现这里有一个添加到右键菜单下的

点击后跳转的是

GenerateAction的点击方法actionPerformed内动态生成了ActionGroup

JBPopupFactory.getInstance().createActionGroupPopup(CodeInsightBundle.message("generate.list.popup.title"),wrapGroup(getGroup(),dataContext,project),dataContext,JBPopupFactory.ActionSelectionAid.SPEEDSEARCH,false);

而getGroup()通过指定groupid获取到GenerateGroup的Action组

return(DefaultActionGroup)ActionManager.getInstance().getAction(IdeActions.GROUP_GENERATE);

2.1ProgramStructureInterface(PSI)

程序结构接口,通常简称为PSI,负责解析文件并创建语法和语义代码模型,为平台的众多功能提供支持。

PSI文件是结构的根,将文件内容表示为特定编程语言中元素的层次结构

PsiFile是所有PSI文件的公共基类,而特定语言的文件通常由其子类表示。例如PsiJavaFile类代表一个Java文件,类XmlFile代表一个XML文件。

2.2查看某一个文件的PSI结构

参考文档:PSIViewer

未配置开启查看PIS结构时如下图

开启查看PIS结构找到idea安装路径下的bin目录下的idea.properties配置如下

idea.is.internal=true

开启后显示了ViewPSIStructure和ViewPSIStructureofCurrentFile

进入要查看结构的文件后点击ViewPSIStructureofCurrentFile\查看某一个文件的psi结构

2.3查看插件源码

进入ConvertGeneratorAction的点击事件方法不难看到如下的根据PSI获取当前类和方法的代码

2.4继续跟踪生成方法转换代码

这里主要是根据返回类型获取到了一个MethodGenerator并执行对应的generateCode方法

2.5MethodGenerator下的generateCode

MethodGenerator下的generateCode主要获取了当前方法的入参fromClass与toClass,并进行了字符串的组装和生成代码块。

\PsiCodeBlockcodeBlock=elementFactory.\

createCodeBlockFromText("{"+String.join("\n",statementList)+"}",psiClass);\源码分析就到这里,如果有兴趣的同学可以自行深入分析并欢迎补充。

想编写一个什么样的插件(功能)

插件要实现的能力是什么,eg:进行方法入参快速转为出参、获取选择的文本添加为笔记、idea激活弹出框、数据库Database...等。

实现插件需要具备哪些能力(功能拆解)

需要页面操作交互能力(javaswing)

需要添加action的能力(插件需要放在哪里,插件的生命周期是什么等级的等。)

需要读写文件的能里(newBufferedWriter(newOutputStreamWriter(newFileOutputStream(file),"utf-8"));)

创建一个action并继承AnAction

packagecom.test.action;importcom.intellij.openapi.actionSystem.AnAction;importcom.intellij.openapi.actionSystem.AnActionEvent;publicclasstestActionextendsAnAction{@OverridepublicvoidactionPerformed(AnActionEvente){//TODO:insertactionlogichereSystem.out.println("action点击触发方法="+e);}

}

使用spring-web下的RestTemplate创建网络请求工具(也可以直接使用RestTemplate)

在需的地方触发网络请求获取数据

触发验证

首先创建一个回显显示的界面

packagecom.test.view;importcom.intellij.openapi.ui.DialogWrapper;importorg.jetbrains.annotations.Nullable;importjavax.swing.*;importjava.awt.*;publicclasstestDialogextendsDialogWrapper{JLabellabel;publictestDialog(booleancanBeParent){super(canBeParent);init();//初始化dialogsetTitle("标题");}@Overrideprotected@NullableJComponentcreateCenterPanel(){/*创建一个面板,设置其布局为边界布局*/JPanelcenterPanel=newJPanel(newBorderLayout());/*创建一个文字标签,来承载内容*/Stringtext="aaa11111测试回显内容";label=newJLabel(text);/*设置首先大小*/label.setPreferredSize(newDimension(100,100));/*将文字标签添加的面板的正中间*/centerPanel.add(label,BorderLayout.CENTER);returncenterPanel;}publicvoidsetLabelText(Stringtext){label.setText(text);}}

在action内触发请求网络获取内容并设置到显示的面板上。

像上图的标题等直接赋值汉字时会有乱码,重新编码进行处理(这种方式简单的汉字和汉字较少时可以)

StringencodeTitle=newString("标题".getBytes("gbk"),"UTF-8");title=newEditorTextField(encodeTitle);

我们从action中获取editor对象,在通过editor获取SelectionModel,在获取选中的文本。

弹窗提供一个重新设置选择文本的方法testDialog.setContent(selectedText);

@OverridepublicvoidactionPerformed(AnActionEvente){//TODO:insertactionlogicheretestDialogtestDialog=newtestDialog(true);//获取当前编辑器对象Editoreditor=e.getRequiredData(CommonDataKeys.EDITOR);//获取选择的数据模型SelectionModelselectionModel=editor.getSelectionModel();//获取当前选择的文本StringselectedText=selectionModel.getSelectedText();System.out.println(selectedText);testDialog.setContent(selectedText);testDialog.show();}

测试选中内容和回显内容如下图

可以使用java本身的流进行读写,也可以使用模板引擎进行,这里使用freemarker模版引擎\3.8.1获取按钮点击事件后弹出目录选择框选择要保存的文件夹,首先需要改造弹窗的构造器传入当前action的事件Event,从event获取当前的工程

3.8.2按钮点击事件创建文件选择器

有人会有疑问,为什么这样就弹出了文件选择器,其实最后是一个FileChooser->FileChooserDialog

finalFileChooserDialogchooser=FileChooserFactory.getInstance().createFileChooser(descriptor,project,parent);returnchooser.choose(project,toSelect);

3.8.3引入freemarker模版引擎依赖并进行文件创建保存

组织数据、获取模版、创建文件、执行创建文件

模版代码创建并获取上图中的组织数据model下的内容

NotificationGroupnotificationGroup=newNotificationGroup("testId",NotificationDisplayType.BALLOON,true);/***content:通知内容*type:通知的类型,warning,info,error*/Notificationnotification=notificationGroup.createNotification("测试通知保存成功",MessageType.INFO);Notifications.Bus.notify(notification);

添加一个自定义ToolWindow\3.10.1创建一个toolwindow

packagecom.test.view;importcom.intellij.openapi.wm.ToolWindow;importjavax.swing.*;importjava.text.SimpleDateFormat;importjava.util.Date;publicclassMyToolWindow{privateJButtonhideButton;privateJLabeldatetimeLabel;privateJPanelmyToolWindowContent;publicMyToolWindow(ToolWindowtoolWindow){init();hideButton.addActionListener(e->toolWindow.hide(null));}privatevoidinit(){datetimeLabel=newJLabel();datetimeLabel.setText(newSimpleDateFormat("yyyy-MM-ddHH:mm:ss").format(newDate()));hideButton=newJButton("取消");myToolWindowContent=newJPanel();myToolWindowContent.add(datetimeLabel);myToolWindowContent.add(hideButton);}publicJPanelgetContent(){returnmyToolWindowContent;}}

3.10.2创建ToolWindowFactory的实现类

packagecom.test.view;importcom.intellij.openapi.project.Project;importcom.intellij.openapi.wm.ToolWindow;importcom.intellij.openapi.wm.ToolWindowFactory;importcom.intellij.ui.content.Content;importcom.intellij.ui.content.ContentFactory;importorg.jetbrains.annotations.NotNull;publicclasstoolWindowExtimplementsToolWindowFactory{@OverridepublicvoidcreateToolWindowContent(@NotNullProjectproject,@NotNullToolWindowtoolWindow){MyToolWindowmyToolWindow=newMyToolWindow(toolWindow);//获取内容工厂的实例ContentFactorycontentFactory=ContentFactory.SERVICE.getInstance();//获取用于toolWindow显示的内容Contentcontent=contentFactory.createContent(myToolWindow.getContent(),"自定义toolwindow",false);//给toolWindow设置内容toolWindow.getContentManager().addContent(content);}}

idea插件开发经验总结(一):环境搭建

IDEA插件开发简明教程

【IDEA插件开发】快速入门系列01开发一个简单的Idea插件

IDEAPlugin插件怎么开发?

作者:京东健康马仁喜

上一篇:

下一篇:

在云环境中,你如何保证数据一致性

你对云计算中的计费模式有什么理解?能否详细解释一下按需付费和预留实例的区别?

描述一下云计算的几种服务模式(IaaS、PaaS、SaaS)以及它们之间的区别

介绍一下云计算中的冷启动、热迁移和容灾,以及它们的优缺点

解释一下什么是无服务器计算,以及它在云环境中的应用

介绍一下云计算中的多租户技术,以及它在云环境中的应用

请解释一下什么是Docker,以及它在云环境中的应用

2024-06-03

2024-05-13

2024-05-11

2024-06-18

公司地址:长沙高新开发区麓谷街道东方红中路23号神汉商业广场3004

THE END
1.github操作学习笔记这是一个学习github高级操作的笔记本 创建新仓库 1、先在github上建一个新仓库 2、打开vscode终端 git init 初始化仓库 git add README.md 保存新文件 git commit -m "first commit" 提交新文件 git branch -M main 更名为main分支 git remote add origin https://github.com/ZJR-FZD/experiment1.git 添加https://blog.csdn.net/2302_79795489/article/details/144332325
2.github下载的东西怎么运行?Worktile社区要运行从GitHub下载的东西,你需要遵循一些基本的步骤。下面是一个简单的指南,告诉你如何运行从GitHub下载的项目。 1. 首先,确认你的计算机上是否已安装了所需的运行环境。通常,从GitHub下载的项目会有一个说明文件,其中包含了必要的依赖项和环境要求。你需要确保你的计算机上已经安装了这些依赖项和环境。 https://worktile.com/kb/ask/515877.html
3.github上下载的python程序如何运行git上下载项目下载完成,点击.exe文件打开运行,然后点击Next 按需选择安装组件与配置,我这里使用的是默认选项。然后点击Next。 选择Git默认编辑器 注意:选择默认编辑器的时候,只能选择电脑里已经安装了的编辑器,没有安装的,需要先安装。 Git安装程序中有10种编辑器和1个其他项可以选择,比如:the Nano、Vim、Notepad++、Visual Studiohttps://blog.51cto.com/u_16213624/9144116
4.GitHub加速器GitHub加速工具下载下载电脑V1.60以管理员运行exe,也可打开exe文件属性->兼容性->以管理员运行 最后的话 如何有不对的地方或者更好的办法,欢迎讨论 如果还是访问不了网站,这是正常现象,因为只是加速,不能保证100%访问 GitHub加速工具下载 电脑V1.60 普通下载地址: 本地普通下载 本地电信下载 http://www.kkx.net/soft/85527.html
5.HelperWiki·publishhelper/publish打开本仓库Releases,下载最新的zip文件。 如果中国大陆GitHub下载缓慢,可访问Gitee仓库Releases,内容会同步更新。 2. 解压软件 解压下载后的zip压缩包,获取解压后的文件夹,并且储存到你想要存的地方。 3. 运行软件 打开解压后的Publish Helper文件夹,双击运行Publish Helper.exe应用程序,耐心等待软件启动。 至此,软件https://github.com/publish-helper/publish-helper/wiki/Publish-Helper-Wiki
6.Deskreen它可能与这个错误有关: https://github.com/pavlobu/deskreen/discussions/68#discussioncomment-330357 在我的操作系统上,Deskreen 应用程序无法运行/安装。防病毒软件会阻止它,并提示它可能有病毒。它有病毒吗?我该怎么办? Deskreen 安装文件中没有病毒,您可以使用防病毒软件进行检查。你看到这些警告的原因是这个应用https://deskreen.com/
7.Github如何下载文件或源代码这篇文章教大家如何下载GitHub上面的代码或者单个文件,以及已经编译好的可执行软件文件,网上很多地方都没有把这个事情讲明白,连一张图都没有配,简直让人无法接受,本站将简单明了的教你怎么下载GitHub上面的东西。 我们告诉你最简单的方法下载,方便你快速入门,GitHub也支持使用客户端clone,也支持命令复制代码,不过那对https://get.qiaobuqiao.com/post-7907
8.Mac如何安装FaceFusion视频AI换脸软件张洪Heo这篇文章介绍了如何在Mac上安装和使用AI视频换脸软件的步骤。首先,它提供了安装所需环境(Python、PIP、GIT、FFmpeg)的命令。接着,介绍了如何下载源文件和设置Python环境。文章详细说明了如何运行安装脚本,包括选择Torch变体和处理器类型。最后,它指导用户如何运行软件、下载模型,并使用浏览器访问软件的主界面,以及如何选https://blog.zhheo.com/p/a856617c.html
9.如何解决百度云下载大文件限速问题ps:百度云下载不保证是最新版,最新版请自行到github下载 3.下载好插件以后,打开谷歌浏览器->更多工具->扩展程序 ->将下载好的文件(chrome.crx)直接拖到扩展程序界面 这样扩展程序就安装好了。 打开百度云的分享界面,我们可以看到多了一个按钮。 测试链接:https://pan.baidu.com/s/1dECWsdN https://www.jianshu.com/p/cc25189db4a1
10.简易教程NLPIR汉语分词系统2.下载-解压后,得到2.3GB的文件夹,点击该文件夹。 3.点击【NLPIR-Parser】。 4.根据系统情况(32/64),选择相应文件夹。 5.点击【NLPIR-Parser】。 注意:如果弹出【授权文件无效】,需要重新下载授权文件。 GitHub上的授权文件页面:https://github.com/NLPIR-team/NLPIR/tree/master/License https://www.douban.com/note/715867867/
11.Git--distributed-is-the-new-centralized Git is afree and open sourcedistributed version control system designed to handle everything from small to very large projects with speed and efficiency. Git iseasy to learnand has atiny footprint with lightning fast performance. It outclasses SCM tools like https://git-scm.com/
12.智算平台模型训练相关问题智算平台常见问题在Jupyter文件浏览器双击打开ipynb文件,并在导航栏选择:File-Save and Export Notebook As-Executable Script 10. 如何在预置kernel的Notebook文件中运行py文件,且确保能引用到预置kernel的包? 在Notebook里执行pip,查看当前使用的kernel对应的环境,并在运行py文件时,使用绝对路径的python,例如,使用预置kernel时,可在Nohttps://ecloud.10086.cn/op-help-center/doc/article/51475
13.2019年5月,如何解决百度云限速问题?Morix(WIN / IOS / Lunix)下载:https://motrix.app/ ? Windows推荐使用IDM,Mac上推荐使用Morix 下面阿虚讲一下IDM的安装使用注意事项等。 IDM安装说明 解压后,右键解压出来的文件「点我绿化卸载.bat」,选择管理员模式运行,安装软件。 打开Chrome浏览器的更多工具——扩展程序——打开右上角的开发者模式——https://weibo.com/ttarticle/p/show?id=2309404367596328747071