IntelliJ IDE 插件开发 | (三)消息通知与事件监听

系列文章

  • IntelliJ IDE 插件开发 |(一)快速入门
  • IntelliJ IDE 插件开发 |(二)UI 界面与数据持久化
  • IntelliJ IDE 插件开发 |(三)消息通知与事件监听

前言

在前两篇文章中讲解了关于插件开发的基础知识,本文将介绍关于消息通知和事件监听方面的内容,关于 IntelliJ IDE 插件开发的基本内容也就到此为止,在下一篇文章中将开发一个简单的插件对这部分内容做一个总结,后续再介绍关于虚拟文件和PSI相关的知识,最后以一个代码生成插件作为结尾。话不多说,下面就开始本文的主题,同时本文涉及到的的完整代码已上传到Github。

消息通知

在 IntelliJ IDE 中用于展示消息提示的方式有很多种,例如侧边栏的消息通知、对话框、鼠标悬浮代码时出现的弹框等等,下面就一一进行介绍。

侧边栏通知

这种通知是在 IDE 内的右下角进行显示,同时这类消息会集中收集在消息通知中可进行查看(如下图所示),并且还可以让用户在Settings | Appearance & Behavior | Notifications中设置。

image-20231210171737691

这种通知可使用Notifications.Bus.notify()方法或NotificationGroupManager类来进行实现,例如上面的例子如果使用Notifications.Bus.notify()方法就是:

val notification = Notification("listener", "Hello, world!", NotificationType.INFORMATION)
Notifications.Bus.notify(notification, e.project)

可以看到需要传递两个参数,一个是通知对象,一个是项目对象(可选)。不过核心还是Notification这个通知类,其中推荐使用的构造方式有两种:

  • Notification(String groupId, String content, NotificationType type)
  • Notification(String groupId, String title, String content, NotificationType type)

在上述例子里使用的则是第一个构造参数方式,其中第一个参数是分组 id,可以使用系统的已有的分组,也可以选择自己创建分组,这里还是推荐自行创建,只要在 plugin.xml 中加入如下配置即可:

<extensions defaultExtensionNs="com.intellij"><notificationGroup id="listener" displayType="BALLOON"/>
</extensions>

其中配置的 id 就可以使用了。

对于第二参数则是我们要显示的内容,如果选择的是第二个构造函数,则可以设置消息的标题,效果如下:

image-20231210190316090

这里的内容也支持使用 HTML 标签:

val content = """<h4>四级标题<h1><p>第一段原色字体</p><p style="color: blue;">第二段蓝色字体</p>
""".trimIndent()
val notification = Notification("listener", "Title", content, NotificationType.INFORMATION)
Notifications.Bus.notify(notification, e.project)

对应的效果如下:

image-20231210192232537

最后一个参数则是消息的类型,总共有四种IDE_UPDATEINFORMATIONWARNINGERROR,效果如下图所示:

image-20231210190759222

同样地,如果使用NotificationGroupManager类,则按照以下方式使用即可,其中 Title 参数也是可选项:

NotificationGroupManager.getInstance().getNotificationGroup("listener").createNotification("Title", "Hello, world!", NotificationType.INFORMATION).notify(e.project)

除了以上设置内容之外,相信你也经常可以看到类似如下包含可点击内容的消息通知:

timed_toast@2x

可以通过 Notification 类的addAction方法(可添加多个 Action )实现类似的效果:

val notification = Notification("listener", "Title", "Hello, world!", NotificationType.INFORMATION)
notification.addAction(object : NotificationAction("ShowProjectStructureSettings") {override fun actionPerformed(e: AnActionEvent, notification: Notification) {// 用于打开设置界面, 这里的 ShowSettings 是 IDEA 定义的常量值ActionManager.getInstance().getAction("ShowSettings").actionPerformed(e)}
})
Notifications.Bus.notify(notification, e.project)

最终效果如下:

动画

如果设置了多个 Action 无法在一行显示,则默认会进行折叠,通过点击 More 可以进行查看并操作:

image-20231210195547319

ActionManager.getInstance().getAction(actionName).actionPerformed(e) 可根据 Action 的 id 调用自行创建的或者平台已定义的 Action,例如打开设置界面,这里的 ShowSettings 就是已经定义好的:

image-20231211093004675

也就是说,只要我们知道内部定义的 Action 对应的 id,我们也就可以自由地使用平台已有的功能,同时如果有类似功能需求的时候还可以根据相应的类找到对应源码,然后我们再进行修改即可。哪有没有快速知道一个操作对应 Action 的方法呢?还好,平台内部也给我们准备了内部工具,打开和使用方式参考开启内部工具部分进行查看。

对话框通知

对话框通知的一般效果如下:

image-20231212150057692

官方推荐使用DialogWrapper抽象类来创建,上面效果对应的代码如下:

class DialogDemo(private val project: Project): DialogWrapper(project) {init {// 设置标题并初始化title = "Title"init()}// 创建布局面板override fun createCenterPanel(): JComponent {return panel {row {label("Hello, world!")}}}}

其中 title 用于设置对话框左上角的标题,createCenterPanel()则用于创建布局内容,这里的布局对象同样支持我们在第二篇文章中的创建方式,也就是说除了基本的文本信息,各种表单输入框也都是支持的。而这里为了方便,就使用了Koltin UI DSL,也很好理解,可以参考官方文档进行学习,后续会再写一篇文章进行讲解,这里就不再展开说了。

当然除了以上基本的对话框内容,DialogWrapper还支持自定义按钮事件,并且可以显示帮助按钮以及不再展示的提示:

动画

上述效果对应的代码如下:

class DialogDemo(private val project: Project): DialogWrapper(project) {private lateinit var checkBox: Cell<JBCheckBox>init {// 设置标题并初始化title = "Title"init()}// 创建 Don't show again 选择框override fun createDoNotAskCheckbox(): JComponent {return panel { row { checkBox = checkBox("Do not show again")}}}// 设置帮助按钮 idoverride fun getHelpId(): String {return "ListenerHelp"}// 设置帮助按钮的 Tooltipoverride fun setHelpTooltip(helpButton: JButton) {helpButton.toolTipText = "Tip"}// 处理帮助按钮事件override fun doHelpAction() {showInfo("Help")}// 处理 OK 按钮事件override fun doOKAction() {super.doOKAction()showInfo("OK, value: ${checkBox.selected()}")}// 处理取消按钮事件override fun doCancelAction() {super.doCancelAction()showInfo("Cancel")}// 展示消息private fun showInfo(msg: String) {Notifications.Bus.notify(Notification("listener", msg, NotificationType.INFORMATION), project)}// 创建布局面板override fun createCenterPanel(): JComponent {return panel {row {label("Hello, world!")}}}}

如果还有其它定制化需求,重写DialogWrapper内的相应方法即可。如果我们只是为了显示简单的文本信息,类似下述效果:

image-20231218123328330

也可以选择平台已经封装好的com.intellij.openapi.ui.Messages类,使用其中的工具方法即可,上述效果只需要一行代码即可:

Messages.showInfoMessage("Hello, world!", "Title")

Messages类中已经封装好了很多基础对话框,这里就不再一一展示。

编辑器提示

正如标题,这种信息的展示方式是在编辑器中通过悬浮框展示的,类似下述效果:

image-20231218102537826

使用方式也很简单,只需要一行代码即可:

e.getData(PlatformDataKeys.EDITOR)?.let { HintManager.getInstance().showInformationHint(it, "Information")
}

同时除了showInformationHint还支持showErrorHint展示错误提示信息:

image-20231218102825834

不过还有一个showQuestionHint使用较为复杂,在 IDEA 中提示我们导包就是通过这种方式:

image-20231218103235567

这种通知方式除了包含提示外还会对指定单词增加下划线,这里就不复现完整的效果了,只展示下基础的使用方式:

e.getData(PlatformDataKeys.EDITOR)?.let {HintManager.getInstance().showQuestionHint(it, "Question", it.caretModel.offset, it.caretModel.offset + 6) {true}
}

效果如下:

image-20231218103521566

编辑器横幅

当我们新建一个 Java 项目缺没有配置 JDK,通常会在编辑器内出现类似下图的提示:

image-20231218124413132

这个提示配置 JDK 的提示就是编辑器横幅的效果。

实现这个效果也很简单,只需要继承EditorNotificationProvider并重写其中的方法即可:

class EditorBanner: EditorNotificationProvider {override fun collectNotificationData(project: Project, virtualFile: VirtualFile): Function<in FileEditor, out JComponent?> {return Function {val banner = EditorNotificationPanel()banner.text = "EditorBanner"banner.toolTipText = "ShowSettings"banner.createActionLabel("ShowSettings") {ShowSettingsUtil.getInstance().showSettingsDialog(project, "Editor")}banner}}}

然后在plugin.xml中增加如下配置:

<extensions defaultExtensionNs="com.intellij"><editorNotificationProvider implementation="cn.butterfly.listener.ui.EditorBanner"/>
</extensions>

最终效果如下:

动画

这里展示编辑器横幅一般是先获取本地时候是否缺少指定配置,如果判断已经包含某个配置,则 collectNotificationData 需要返回 null,否则才需要创建 banner 进行展示。

“Got It” 提示

在更新 IDEA 后我们通常能看到类似下图中介绍新功能的提示:

img

这种效果也很容易实现,只需要使用GotItTooltip这个类即可,在这里我们结合前文对话框通知中创建的帮助按钮来使用(只展示变更部分):

private lateinit var helpButton: JButton// 设置帮助按钮的 Tooltip
override fun setHelpTooltip(helpButton: JButton) {helpButton.toolTipText = "Tip"this.helpButton = helpButton
}// 处理帮助按钮事件
override fun doHelpAction() {showInfo("Help")GotItTooltip("listener.tip.id", "GotItTooltip").show(helpButton, GotItTooltip.BOTTOM_MIDDLE)
}

可以得到如下效果(点击帮助按钮后出现):

image-20231218145718929

GotItTooltip 使用了建造者模式,因此配置项可通过链式调用,可自行选择配置项:

image-20231218150150400

弹出框

除了以上常见的消息展示方式外,还有一种弹出框选项的方式,当我们使用Ctrl + Shift + Alt + /快捷键的时候会出现以下弹出框:

image-20231218154906724

这种弹出框则需要使用JBPopupFactory进行创建,使用方式也很简单:

class PopupAction:AnAction() {override fun actionPerformed(e: AnActionEvent) {JBPopupFactory.getInstance().createListPopup(MyListPopupStep("Title", arrayOf("Option 1", "Option 2", "Option 3"))).showInFocusCenter()}}class MyListPopupStep constructor(title: String?, values: Array<String?>) : BaseListPopupStep<String>(title, *values) {override fun onChosen(selectedValue: String, finalChoice: Boolean): PopupStep<*> {// 选中事件return FINAL_CHOICE}override fun getIconFor(value: String): Icon? {// 设置图标return null}override fun isMnemonicsNavigationEnabled(): Boolean = false}

以上代码可以实现如下的效果:

image-20231218155019025

除了使用createListPopup,还可以直接选择使用createMessage直接展示信息,或者使用createConfirmation展示只有 yes 和 no 的弹出框:

image-20231218155156931

使用createMessage("Hello, world!")的效果:

image-20231218155349883

使用createConfirmation("Title", {}, 0)的效果:

image-20231218155431263

事件监听

在开发插件的过程中,我们有时候需要在项目打开或关闭的时候去完成一些操作,而 IntelliJ 平台也为我们提供了相应的监听器类,当然除了项目监听,平台包含插件还自带了很多其它类型的监听器,这里就不逐一介绍了,以项目监听为例,然后再说明如何自定义一个事件监听器。

项目监听器

对项目打开和关闭的监听方式很简单,只需要继承ProjectManagerListener类即可,然后既可以在相应方法中处理对应操作:

class MyProjectManagerListener: ProjectManagerListener {init {// 项目启动处理val notification = Notification("listener", "Title", "Open", NotificationType.INFORMATION)Notifications.Bus.notify(notification, null)}override fun projectClosing(project: Project) {// 项目即将关闭println("Closing")}}

同时在plugin.xml中增加如下配置:

<projectListeners><listener class="cn.butterfly.listener.listener.MyProjectManagerListener"topic="com.intellij.openapi.project.ProjectManagerListener"/>
</projectListeners>

在新版本中平台建议我们继承ProjectActivity类并通过postStartupActivity扩展点来实现,这里也展示一下使用方法:

class MyProjectActivity: ProjectActivity {override suspend fun execute(project: Project) {val notification = Notification("listener", "Title", "Open", NotificationType.INFORMATION)Notifications.Bus.notify(notification, null)}}

然后也需要在plugin.xml中增加配置:

<extensions defaultExtensionNs="com.intellij"><postStartupActivity implementation="cn.butterfly.listener.listener.MyProjectActivity"/>
</extensions>

自定义事件监听器

在 IntelliJ 平台中的事件可以看作是发布订阅的模式,我们需要先定义一个主题,然后发布者发布相应的事件,订阅者实现对应的监听器事件即可。继续使用前文中的帮助按钮的例子,如果点击了帮助按钮,我们就在界面中显示帮助按钮被点击,下面介绍如何实现这个功能。

首先自定义一个监听器:

interface MyListener {companion object {var MY_TOPIC: Topic<MyListener> = Topic.create("listener", MyListener::class.java)}fun afterHelpBtnClicked(msg: String)}

然后定义实现类:

class MyListenerA: MyListener {override fun afterHelpBtnClicked(msg: String) {Messages.showInfoMessage(msg, "Title")}}

之后在plugin.xml中注册:

<projectListeners><listener class="cn.butterfly.listener.listener.MyListenerA"topic="cn.butterfly.listener.listener.MyListener"/>
</projectListeners>

最后在点击了帮助按钮后发布事件用于测试:

// 处理帮助按钮事件
override fun doHelpAction() {showInfo("Help")// 发布事件project.messageBus.syncPublisher(MyListener.MY_TOPIC).afterHelpBtnClicked("点击了帮助按钮")GotItTooltip("listener.tip.id", "GotItTooltip").show(helpButton, GotItTooltip.BOTTOM_MIDDLE)
}

效果如下:

动画

其它平台自带监听器

除了上文提到的项目监听器,平台还提供了很多其它监听器(还可以使用其它插件内定义的监听器,比如 Git 插件的一些事件),参考上述自定义监听器的实现和使用方式即可,完整列表可参考官方文档。

开启内部工具

选择Help | Edit Custom Properties...,然后在文件内加上idea.is.internal=true的配置,最后保存文件并重启 IDEA 即可。

重启后我们就可以使用了,例如上文提到的查看某个操作对应 Action 的 id,参考下述动图步骤即可,可以看到在打开设置界面后里面出现了我们前文使用的ShowSettings这个 id:

动画

内部工具的使用先到此为止,由于其中实用功能挺多的,就在后续专门用一篇文章进行讲解。

总结

本文讲解了关于消息通知和事件监听相关的内容,在下一篇文章将会实战开发一个类似 VSCode 中 Timer Master 的插件(如下图所示)来对这一部分的内容做一个小结。

image-20231210162740533

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/220816.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言:前缀和

【模板】前缀和_牛客题霸_牛客网 (nowcoder.com) 前缀和&#xff1a;将数组小于该前缀的数加起来的新数组。 例&#xff1a; 该数组为1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5。前缀和为1&#xff0c;3&#xff0c;6&#xff0c;10&#xff0c;15 。 如果要求…

1-完全理解以太坊智能合约

了解区块链 区块链技术的核心概念是分布式账本&#xff0c;它是许多参与者共享的特定类型的数据库。 这个特殊的数据库只是一个交易列表&#xff0c;记录着网络中发生的每笔交易。每个人都可以拥有自己的交易列表备份&#xff0c;再加上强有力的货币激励措施消除各方之间信任…

比 style gan 更好的 style gan2

上一篇博客介绍了style gan 原理&#xff0c;但是 style gan 的结果会有水珠伪影&#xff0c;作者实验后发现是 Adain 导致的&#xff0c;AdaIN对每一个feature map的通道进行归一化&#xff0c;这样可能破坏掉feature之间的信息。当然实验证明发现&#xff0c;去除AdaIN的归一…

广州华锐互动VRAR:利用VR开展新能源汽车触电安全演练,降低培训成本和风险

随着新能源汽车行业的快速发展&#xff0c;相关的安全培训也变得越来越重要。其中&#xff0c;触电急救培训对于保障驾驶员和乘客的安全具有重要意义。传统培训方式存在一些不足&#xff0c;而利用VR技术进行培训则具有很多优势。 利用VR技术开展新能源汽车触电安全演练可以在模…

2023 英特尔On技术创新大会直播 | 窥探未来科技的边界

2023 英特尔On技术创新大会直播 | 窥探未来科技的边界 写在最前面观后感其他有趣的专题课程 写在最前面 嘿&#xff0c;你是不是对科技和创新充满好奇&#xff1f;2023 英特尔 On 技术创新大会线上活动邀请你一起探索最前沿的科技世界&#xff01; 这不仅是一场普通的聚会&…

AWS Linux安装桌面并远程访问

文章目录 小结问题及解决参考 小结 在AWS Linux安装了桌面并进行远程访问。 问题及解决 需要使用过程桌面访问AWS Linux&#xff0c;这里在AWS服务器安装并使用Amazon Linux 2 MATE desktop。 检查OS版本&#xff1a; [ec2-userip-10-0-3-241 ~]$ grep PRETTY_NAME /etc/o…

WordCloud—— 词云

【说明】文章内容来自《机器学习入门——基于sklearn》&#xff0c;用于学习记录。若有争议联系删除。 wordcloud 是python的第三方库&#xff0c;称为词云&#xff0c;也成文字云&#xff0c;可以根据文本中的词频以直观和艺术化的形式展示文本中词语的重要性。 依赖于pillow …

Windows本地搭建开源企业管理套件Odoo并实现公网访问

文章目录 前言1. 下载安装Odoo&#xff1a;2. 实现公网访问Odoo本地系统&#xff1a;3. 固定域名访问Odoo本地系统 前言 Odoo是全球流行的开源企业管理套件&#xff0c;是一个一站式全功能ERP及电商平台。 开源性质&#xff1a;Odoo是一个开源的ERP软件&#xff0c;这意味着企…

零刻EQ12 N100 2.5G双网口 All In One新手教程

零刻EQ12 N100 2.5G双网口 All In One新手教程 前言1.硬件配置2.准备工作2.1. ESXI8.0U2镜像2.2. Rufus磁盘工具下载2.3. ikuai镜像下载2.4. StarWindConverter虚拟磁盘格式转换工具下载2.5. OpenWrt镜像下载2.6. 黑群晖RR引导镜像下载(DSM7.2)2.7. 需要准备的硬件2.8. 格式化需…

《每天一分钟学习C语言·二》

1、当使用const关键字变量就无法修改可当常量来用。常量指针不能通过指针来改变变量的值&#xff0c;但可以通过其他引用来改变变量的值常量指针也可以指向其他变量地址&#xff0c;如 int a5,b6; const int *pt &a; *pt6; //错误 a6; //正确 pt&b; //正确指针常量指…

Databend 开源周报第 124 期

Databend 是一款现代云数仓。专为弹性和高效设计&#xff0c;为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务&#xff1a;https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend 。 新增对 Delta 和…

使用下载代替物理串口输出-STM32 Debug (printf) Viewer

使用下载代替物理串口输出-STM32 Debug 硬件要求配置方法代码要求打印输出结果 硬件要求 STM32的PB9、PB10引脚的串口1通常用作其他功能使用后&#xff0c;无法通过printf()函数打印输出想要调试输出查看变量或调试信息。现已使用另外一种方法实现printf()函数打印输出。 ST…

R语言采集获取58商铺出租转让信息

前两篇文章给我一个朋友分析出店铺商品以及地址房源信息&#xff0c;后来去看了下店铺房租有点贵&#xff0c;还是毛坯房&#xff0c;要自己装修&#xff0c;本着节约成本的原则。熬了个通宵&#xff0c;给他采集了一些转租商铺数据&#xff0c;因为数据比较多&#xff0c;过于…

virtualbox 虚拟机ubuntu22 识别不了CH340串口

首先启用USB设备&#xff0c;CH340识别为QinHengXXXXX USB Serial. 设置以后发现还是无法识别到/dev/ttyUSB0&#xff0c;但是cp2102按照相同的设置能够正确识别到&#xff0c;查看tty系统日志 sudo dmesg | grep tty 发现串口被brltty占用了 将其卸载试试 sudo apt remove …

Pytorch深度强化学习案例:基于Q-Learning的机器人走迷宫

目录 0 专栏介绍1 Q-Learning算法原理2 强化学习基本框架3 机器人走迷宫算法3.1 迷宫环境3.2 状态、动作和奖励3.3 Q-Learning算法实现3.4 完成训练 4 算法分析4.1 Q-Table4.2 奖励曲线 0 专栏介绍 本专栏重点介绍强化学习技术的数学原理&#xff0c;并且采用Pytorch框架对常见…

C# WPF上位机开发(利用tcp/ip网络访问plc)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 c# wpf如果是用来开发非标上位机的&#xff0c;那么和plc的通信肯定是少不了的。而且&#xff0c;大部分plc都支持modbus协议&#xff0c;所以这个…

lv12 linux 内核移植 10

目录 1 内核概述 1.1 内核与操作系统 1.2 Linux层次结构 1.3 Linux内核特点 2 Linux内核源码结构 2.1 Linux内核源码获取 2.2 源码结构 3 Linux内核移植 3.1 在 Linux 官网下载 Linux 内核源码&#xff08;这里我们下载 linux-3.14.tar.xz&#xff09; 3.2 拷贝内核源…

Gitee:远程仓库步骤

第一步&#xff1a;新建仓库 第二步&#xff1a;初始化本地仓库&#xff0c;git init 创建分支 git branch 新分支名 第三步&#xff1a;git add . &#xff1a;添加到暂存区 第四步&#xff1a;git config –global user.email关联邮箱&#xff0c;user.name用户名 第…

C++模板进阶

文章目录 前言反向迭代器反向迭代器和正向迭代器的区别stl反向迭代器源码反向迭代器模拟实现测试 模板进阶非类型模板参数Array 模板的特化模板的分离编译 前言 模板进阶也没有到一些特别的东西&#xff0c;就是讲比较偏的一些特性。 在这里我们先来讲一下反向迭代器。 反向迭…

Linux常用网络指令

网络参数设定使用的指令 手动/自动设定与启动/关闭 IP 参数&#xff1a;ifconfig, ifup, ifdown ifconfig ifconfig常用于修改网络配置以及查看网络参数的指令 [rootwww ~]# ifconfig {interface} {up|down} < 观察与启动接口 [rootwww ~]# ifconfig interface {options…