IntelliJ IDE 插件开发 | (三)消息通知与事件监听
系列文章
- IntelliJ IDE 插件开发 |(一)快速入门
- IntelliJ IDE 插件开发 |(二)UI 界面与数据持久化
- IntelliJ IDE 插件开发 |(三)消息通知与事件监听
前言
在前两篇文章中讲解了关于插件开发的基础知识,本文将介绍关于消息通知和事件监听方面的内容,关于 IntelliJ IDE 插件开发的基本内容也就到此为止,在下一篇文章中将开发一个简单的插件对这部分内容做一个总结,后续再介绍关于虚拟文件和PSI相关的知识,最后以一个代码生成插件作为结尾。话不多说,下面就开始本文的主题,同时本文涉及到的的完整代码已上传到Github。
消息通知
在 IntelliJ IDE 中用于展示消息提示的方式有很多种,例如侧边栏的消息通知、对话框、鼠标悬浮代码时出现的弹框等等,下面就一一进行介绍。
侧边栏通知
这种通知是在 IDE 内的右下角进行显示,同时这类消息会集中收集在消息通知中可进行查看(如下图所示),并且还可以让用户在Settings | Appearance & Behavior | Notifications中设置。

这种通知可使用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 就可以使用了。
对于第二参数则是我们要显示的内容,如果选择的是第二个构造函数,则可以设置消息的标题,效果如下:

这里的内容也支持使用 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)
对应的效果如下:

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

同样地,如果使用NotificationGroupManager类,则按照以下方式使用即可,其中 Title 参数也是可选项:
NotificationGroupManager.getInstance().getNotificationGroup("listener").createNotification("Title", "Hello, world!", NotificationType.INFORMATION).notify(e.project)
除了以上设置内容之外,相信你也经常可以看到类似如下包含可点击内容的消息通知:

可以通过 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 可以进行查看并操作:

ActionManager.getInstance().getAction(actionName).actionPerformed(e) 可根据 Action 的 id 调用自行创建的或者平台已定义的 Action,例如打开设置界面,这里的 ShowSettings 就是已经定义好的:
也就是说,只要我们知道内部定义的 Action 对应的 id,我们也就可以自由地使用平台已有的功能,同时如果有类似功能需求的时候还可以根据相应的类找到对应源码,然后我们再进行修改即可。哪有没有快速知道一个操作对应 Action 的方法呢?还好,平台内部也给我们准备了内部工具,打开和使用方式参考开启内部工具部分进行查看。
对话框通知
对话框通知的一般效果如下:

官方推荐使用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内的相应方法即可。如果我们只是为了显示简单的文本信息,类似下述效果:

也可以选择平台已经封装好的com.intellij.openapi.ui.Messages类,使用其中的工具方法即可,上述效果只需要一行代码即可:
Messages.showInfoMessage("Hello, world!", "Title")
在Messages类中已经封装好了很多基础对话框,这里就不再一一展示。
编辑器提示
正如标题,这种信息的展示方式是在编辑器中通过悬浮框展示的,类似下述效果:

使用方式也很简单,只需要一行代码即可:
e.getData(PlatformDataKeys.EDITOR)?.let { HintManager.getInstance().showInformationHint(it, "Information")
}
同时除了showInformationHint还支持showErrorHint展示错误提示信息:

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

这种通知方式除了包含提示外还会对指定单词增加下划线,这里就不复现完整的效果了,只展示下基础的使用方式:
e.getData(PlatformDataKeys.EDITOR)?.let {HintManager.getInstance().showQuestionHint(it, "Question", it.caretModel.offset, it.caretModel.offset + 6) {true}
}
效果如下:

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

这个提示配置 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 后我们通常能看到类似下图中介绍新功能的提示:

这种效果也很容易实现,只需要使用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)
}
可以得到如下效果(点击帮助按钮后出现):

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

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

这种弹出框则需要使用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}
以上代码可以实现如下的效果:

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

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

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

事件监听
在开发插件的过程中,我们有时候需要在项目打开或关闭的时候去完成一些操作,而 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 的插件(如下图所示)来对这一部分的内容做一个小结。

相关文章:
IntelliJ IDE 插件开发 | (三)消息通知与事件监听
系列文章 IntelliJ IDE 插件开发 |(一)快速入门IntelliJ IDE 插件开发 |(二)UI 界面与数据持久化IntelliJ IDE 插件开发 |(三)消息通知与事件监听 前言 在前两篇文章中讲解了关于插件开发的基础知识&…...
VUE小知识点
Vue 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。 Vue 的主要作用是帮助开发者构建现代 Web 应用程序。它允许前端开发人员专注于应用程序…...
深入了解常见的应用层网络协议
目录 1. HTTP协议 1.1. 工作原理 1.2. 应用场景 1.3. 安全性考虑 2. SMTP协议 2.1. 工作原理 2.2. 应用场景 2.3. 安全性考虑 3. FTP协议 3.1. 工作原理 3.2. 应用场景 3.3. 安全性考虑 4. DNS协议 4.1. 工作原理 4.2. 应用场景 4.3. 安全性考虑 5. 安全性考虑…...
网络爬虫 多任务采集
一、JSON文件存储 JSON,全称为 JavaScript 0bject Notation,也就是JavaSript 对象标记,它通过对象和数组的组合来表示数据,构造简洁但是结构化程度非常高,是一种轻量级的数据交换格式。本节中,我们就来了解如何利用 P…...
真实并发编程问题-1.钉钉面试题
👏作者简介:大家好,我是爱吃芝士的土豆倪,24届校招生Java选手,很高兴认识大家📕系列专栏:Spring源码、JUC源码、Kafka原理、分布式技术原理、数据库技术🔥如果感觉博主的文章还不错的…...
基于vue+element-plus+echarts制作动态绘图页面(柱状图,饼图和折线图)
前言 我们知道echarts是一个非常强大的绘图库,基于这个库,我们可以绘制出精美的图表。对于一张图来说,其实比较重要的就是配置项,填入不同的配置内容就可以呈现出不同的效果。 当然配置项中除了样式之外,最重要的就是…...
2312llvm,02前端
前端 编译器前端,在生成目标相关代码前,把源码变换为编译器的中间表示.因为语言有独特语法和语义,所以一般,前端只处理一个语言或一组类似语言. 比如Clang,处理C,C,objective-C源码. 介绍Clang Clang项目是C,C,Objective-C官方的LLVM前端.Clang的官方网站在此. 实际编译器(…...
【MATLAB源码-第101期】基于matlab的蝙蝠优化算BA)机器人栅格路径规划,输出做短路径图和适应度曲线。
操作环境: MATLAB 2022a 1、算法描述 蝙蝠算法(BA)是一种基于群体智能的优化算法,灵感来源于蝙蝠捕食时的回声定位行为。这种算法模拟蝙蝠使用回声定位来探测猎物、避开障碍物的能力。在蝙蝠算法中,每只虚拟蝙蝠代表…...
【数据结构】二叉树的模拟实现
前言:前面我们学习了堆的模拟实现,今天我们来进一步学习二叉树,当然了内容肯定是越来越难的,各位我们一起努力! 💖 博主CSDN主页:卫卫卫的个人主页 💞 👉 专栏分类:数据结构 👈 &…...
open3d bug:pcd转txt前后位姿发生改变
1、open3d bug:pcd转txt前后位姿发生改变 open3d会对原有结果进行一个微小位姿变换 import open3d as o3d import numpy as np# 读取PCD点云文件 pcd o3d.io.read_point_cloud(/newdisk/darren_pty/zoom_centered_s2.pcd)# 获取点云坐标 points pcd.points# 指定…...
持续集成交付CICD:Jenkins使用GitLab共享库实现基于Ansible的CD流水线部署前后端应用
目录 一、实验 1.部署Ansible自动化运维工具 2.K8S 节点安装nginx 3.Jenkins使用GitLab共享库实现基于Ansible的CD流水线部署前后端应用 二、问题 1.ansible安装报错 2.ansible远程ping失败 3. Jenkins流水线通过ansible命令直接ping多台机器的网络状态报错 一、实验 …...
OpenAI 疑似正在进行 GPT-4.5 灰度测试!
大家好,我是二狗。 今天,有网友爆料OpenAI疑似正在进行GPT-4.5灰度测试! 当网友询问ChatGPT API调用查询模型的确切名称是什么时? ChatGPT的回答竟然是 gpt-4.5-turbo。 也有网友测试之后发现仍然是GPT-4模型。 这是有网友指…...
DC-6靶场
DC-6靶场下载: https://www.five86.com/downloads/DC-6.zip 下载后解压会有一个DC-3.ova文件,直接在vm虚拟机点击左上角打开-->文件-->选中这个.ova文件就能创建靶场,kali和靶机都调整至NAT模式,即可开始渗透 首先进行主…...
单片机应用实例:LED显示电脑电子钟
本例介绍一种用LED制作的电脑电子钟(电脑万年历)。其制作完成装潢后的照片如下图: 上图中,年、月、日及时间选用的是1.2寸共阳数码管,星期选用的是2.3寸数码管,温度选用的是0.5寸数码管,也可根据…...
会议剪影 | 思腾合力受邀出席首届CCF数字医学学术年会
首届CCF数字医学学术年会(CCF Digital Medicine Symposium,DMS)于2023年12月15日-17日在苏州CCF业务总部召开。这次会议的成功召开,标志着数字医学领域进入了一个新的时代,计算机技术和人工智能在医学领域的应用和发展…...
node.js mongoose中间件(middleware)
目录 简介 定义模型 注册中间件 创建doc实例,并进行增删改查 方法名和注册的中间件名相匹配 执行结果 分析 错误处理中间件 手动抛出错误 注意点 简介 在mongoose中,中间件是一种允许在执行数据库操作前(pre)或后&…...
[Toolschain cpp ros cmakelist python vscode] 记录写每次项目重复的设置和配置 不断更新
写在前面 用以前的设置,快速配置项目,以防长久不用忘记,部分资料在资源文件里还没有整理 outline cmakelist 复用vscode 找到头文件vscode debug现有代码直接关联远端gitros杂记repo 杂记glog杂记 cmakelist 复用 包含了根据系统路径找库…...
【每日OJ—有效的括号(栈)】
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 1、有效的括号题目: 1.1方法讲解: 1.2代码实现: 总结 前言 世上有两种耀眼的光芒,一种是正在升起的太阳&#…...
.gitignore和git lfs学习
The ninth day——12.18 1. .gitignore 忽略规则优先级 从命令行中读取可用的忽略规则当前目录定义的规则父级目录定义的规则,依次递推$GIT_DIR/info/exclude 文件中定义的规则core.excludesfile中定义的全局规则 忽略规则匹配语法 空格不匹配任意文件ÿ…...
2023-12-18 C语言实现一个最简陋的B-Tree
点击 <C 语言编程核心突破> 快速C语言入门 C语言实现一个最简陋的B-Tree 前言要解决问题:想到的思路:其它的补充: 一、C语言B-Tree基本架构: 二、可视化总结 前言 要解决问题: 实现一个最简陋的B-Tree, 研究B-Tree的性质. 对于B树, 我是心向往之, 因为他是数据库的基…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
SQL Server 触发器调用存储过程实现发送 HTTP 请求
文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...
【大模型】RankRAG:基于大模型的上下文排序与检索增强生成的统一框架
文章目录 A 论文出处B 背景B.1 背景介绍B.2 问题提出B.3 创新点 C 模型结构C.1 指令微调阶段C.2 排名与生成的总和指令微调阶段C.3 RankRAG推理:检索-重排-生成 D 实验设计E 个人总结 A 论文出处 论文题目:RankRAG:Unifying Context Ranking…...
js 设置3秒后执行
如何在JavaScript中延迟3秒执行操作 在JavaScript中,要设置一个操作在指定延迟后(例如3秒)执行,可以使用 setTimeout 函数。setTimeout 是JavaScript的核心计时器方法,它接受两个参数: 要执行的函数&…...
qt+vs Generated File下的moc_和ui_文件丢失导致 error LNK2001
qt 5.9.7 vs2013 qt add-in 2.3.2 起因是添加一个新的控件类,直接把源文件拖进VS的项目里,然后VS卡住十秒,然后编译就报一堆 error LNK2001 一看项目的Generated Files下的moc_和ui_文件丢失了一部分,导致编译的时候找不到了。因…...

