IntelliJ IDE 插件开发 | (二)UI 界面与数据持久化

系列文章

  • IntelliJ IDE 插件开发 |(一)快速入门

前言

在上一篇文章中介绍了在IDEA下开发、运行和安装插件的基本步骤,因此创建项目等基础步骤不再赘述,本文则开始介绍如何进行 UI 界面的开发以及相关数据的持久化存储,本文涉及到的的完整代码已上传到Github。

UI 界面开发

在开发插件的过程中,我们或多或少都需要进行 UI 界面的开发,但是IntelliJ IDE插件需要使用Swing进行 UI 的开发,相信大部分人都不太了解,因此本文及后续文章都选择使用UI Designer这款插件(IDEA 默认安装,可自行检查一下)通过可视化工具拖拽的方式来实现基本的界面设计。

image-20231205165021976

UI Designer 使用步骤

在上一篇文章中提到过,后续 UI 相关的开发使用 Java,其他则使用 Kolin,由于默认创建的工程目录如下,没有 Java 模块:

image-20231206094935959

所有我们首先需要创建 Java 模块:

image-20231206095044404

然后按照引导创建 UI 文件:

Clip_20231206_095314

image-20231206095502253

创建完成后,会出现类似下图的界面:

image-20231206100144787

可以看到,默认会创建一个 Java 类和一个 form 布局文件,其中 Java 文件主要用于后续控制字段的初始化及获取等操作,form 文件则用于界面布局,点击 form 文件会出现上图所示的三个栏目:组件属性栏、UI 效果栏和组件栏,其中先选中右侧组件然后就可以拖拽到中间的 UI 效果栏展示。

下面我们用一个简单的登录表单来讲解使用方式,首先以一个 GIF 演示拖拽功能开始:

修改 Label 的内容可以通过左侧工具栏或者直接在 UI 效果栏双击标签进行:

image-20231206104111547

输入框对应的字段名则通过左侧组件属性栏进行修改:

image-20231206104321338

这时候我们查看 UIDemo.java 文件会发现以下内容(注释随自己的配置变化):

import javax.swing.*;/*** UI 界面** @author butterfly* @date 2023-12-06*/
public class UIDemo {private JTextField username;private JTextField password;
}

然后通过预览功能,我们也可以先查看表单效果:

动画

简单的使用步骤就到这里,这里就不挨个讲解组件的效果和使用方式了,后续会在使用的过程和实战应用中再进行讲解,大家也可以先自行探索。

使用平台自带组件

在上一小节中我们讲解了如何通过UI Designer插件来创建我们的 UI 界面,可以发现默认提供的 Swing UI 组件并没有办法满足我们的日常使用,比如文件下拉树选择组件就不存在。而我们对 Swing 的开发又不熟悉,那该怎么办呢?还好,我们还可以使用 IntelliJ 平台自带的组件,下面就来讲解使用方法:

首先在空白处右键创建一个分组:

image-20231206110825049

image-20231206110838272

然后右键分组选择第一项添加组件:

image-20231206110928930

选择类名的方式,然后点击...

image-20231206111101478

这里输入TextFieldWithBrowseButton即可找到带有文件下拉树选择输入框:

image-20231206111329419

然后经过两次确认就可以发现组件已经添加到了右侧组件栏中:

image-20231206111601608

由于 UI Designer 的预览功能不支持原生组件的预览,需要运行插件才可以,这里先知道是类似下图选择文件夹的效果即可:

image-20231206144400519

平台自带的组件大多都可以在com.intellij.openapi.ui包下找到,根据组件名TextFieldWithBrowseButton我们也可以发现相关组件的命名也很规范,因此当需要某个组件时就可以先在该包下或者通过关键字进行搜索,除此之外,我们还可以参考开源插件来找到和学习原生组件的使用方式。

以 Git 插件为例,布局如下:

image-20231206150121611

可以在官方仓库找到源码(这里选择的是 192 版本这个分支,之后的版本布局开始使用 Kotlin 进行了重构):

image-20231206152416294

image-20231206150819587

根据插件界面可以发现第一行就是使用带有文件树选择的输入框,我们在代码中也可以找到对应实现:

image-20231206151233997

image-20231206151309499

由于 192 版本之后使用 Kotlin 进行 UI 的编写,因此初学建议可以下载一个 192 的 IDEA 社区版进行界面的参考,这样通过参考布局及相应源码也是快速学习 UI 界面开发的一种方法。

至于如何快速找到插件的某个组件实现,这里建议在下载源码后,就可以根据界面上的提示文字进行代码的全局搜索即可。

在配置界面和侧边栏中展示 UI 界面

通过上述两步,我们可以了解到如何实现开发一个简单的 UI 界面,下面就开始讲解如何将设计好的界面展示在配置页面或者侧边栏中。

准备工作

在正式开始之前我们需要对上文中创建的界面进行一些修改,布局外层的 Panel 需要先设置一下字段名:

image-20231206155142916

然后增加相应的 Get 方法:

import javax.swing.*;/*** UI 界面** @author butterfly* @date 2023-12-06*/
public class UIDemo {private JTextField username;private JTextField password;private JPanel mainPanel;public JPanel getMainPanel() {return mainPanel;}}

准备工作到此结束。

配置界面 UI

接下来就是将 UI 展示在配置界面,我们先创建一个UISettingsConfig.kt文件:

import cn.butterfly.ui.UIDemo
import com.intellij.openapi.options.Configurable
import javax.swing.JComponent/*** UI 配置界面配置类** @author butterfly* @date 2023-12-06*/
class UISettingsConfig: Configurable {private val form = UIDemo()private val component: JComponentinit {component = form.mainPanel}override fun createComponent() = componentoverride fun isModified() = trueoverride fun apply() {}override fun getDisplayName() = "UISettingsConfig"}

然后在plugin.xml文件中进行如下的配置,这里的applicationConfigurable代表使用应用级别的配置,相应地,还有projectConfigurable代表项目级别的配置,具体区别在下文的数据持久化中进行介绍:

<extensions defaultExtensionNs="com.intellij"><applicationConfigurableinstance="cn.butterfly.ui.config.UISettingsConfig"id="cn.butterfly.ui.config.UISettingsConfig"displayName="UISettingsConfig"/>
</extensions>

这里我们运行插件,打开配置界面就可以发现我们的界面效果了:

image-20231206160442085

如果想要修改其显示位置,比如显示在Tools菜单下:

image-20231206160426698

只需要在配置中增加parentId="tools"即可:

<applicationConfigurableinstance="cn.butterfly.ui.config.UISettingsConfig"id="cn.butterfly.ui.config.UISettingsConfig"parentId="tools"displayName="UISettingsConfig"/>

applicationConfigurable中完整的配置项可查看官网文档。

侧边栏界面 UI

最后再来说明如何在侧边栏中显示界面,首先创建一个UISidebarConfig.kt

import cn.butterfly.ui.UIDemo
import com.intellij.openapi.project.Project
import com.intellij.openapi.wm.ToolWindow
import com.intellij.openapi.wm.ToolWindowFactory
import com.intellij.ui.content.ContentFactory
import javax.swing.JComponent/*** UI 侧边栏界面配置类** @author butterfly* @date 2023-12-06*/
class UISidebarConfig: ToolWindowFactory {private val form = UIDemo()private val component: JComponentinit {component = form.mainPanel}override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {toolWindow.contentManager.addContent(ContentFactory.getInstance().createContent(component, "", false))}}

然后我们可以准备一个 svg 图标文件用于后续在侧边栏展示:

image-20231206162613699

同时需要创建对应的文件加载接口:

image-20231206163645276

import com.intellij.openapi.util.IconLoader;
import javax.swing.*;/*** 插件图标** @author butterfly* @date 2023-12-06*/
public interface PluginIcons {Icon BUTTERFLY = IconLoader.getIcon("/icons/butterfly.svg", PluginIcons.class);}

然后在plugin.xml配置文件中进行如下设置即可,anchor可设置默认位置,icon用于设置上文的图标:

<extensions defaultExtensionNs="com.intellij"><toolWindow id="UISettingsConfig" anchor="right"factoryClass="cn.butterfly.ui.config.UISidebarConfig"icon="cn.butterfly.ui.icons.PluginIcons.BUTTERFLY"/>
</extensions>

运行插件,即可在右侧的侧边栏看到我们设置的界面:

image-20231206164451821

数据持久化

讲完了界面开发的相关内容,下面就开始介绍如何进行配置数据的持久化,首先是创建一个存储数据信息的UIDemoState.kt文件:

import com.intellij.openapi.components.PersistentStateComponent
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.State
import com.intellij.openapi.components.Storage
import com.intellij.util.xmlb.XmlSerializerUtil/*** 数据持久化存储** @author butterfly* @date 2023-12-06*/
@Service
@State(name = "UIDemoState", storages = [Storage("ui-demo-state.xml")])
class UIDemoState: PersistentStateComponent<UIDemoState> {var username = ""var password = ""override fun getState(): UIDemoState {return this}override fun loadState(state: UIDemoState) {XmlSerializerUtil.copyBean(state, this)}}

其中usernamepassword对应表单中我们设置的两个字段,这里设置了默认值为空字符串,ui-demo-state.xml用于设置数据持久化存储的文件名。

然后我们需要对前文中创建的布局文件进行些许的修改,增加字段的 Get 方法:

import javax.swing.*;/*** UI 界面** @author butterfly* @date 2023-12-06*/
public class UIDemo {/*** 用户名*/private JTextField username;/*** 密码*/private JTextField password;private JPanel mainPanel;public JTextField getUsername() {return username;}public JTextField getPassword() {return password;}public JPanel getMainPanel() {return mainPanel;}}

最后我们就需要对前文中创建的UISettingsConfig.kt文件进行修改,用于处理界面上保存数据的操作:

import cn.butterfly.ui.UIDemo
import cn.butterfly.ui.state.UIDemoState
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.options.Configurable
import javax.swing.JComponent/*** UI 配置界面配置类** @author butterfly* @date 2023-12-06*/
class UISettingsConfig: Configurable {private val form = UIDemo()private val component: JComponentprivate val state = ApplicationManager.getApplication().getService(UIDemoState::class.java)init {component = form.mainPanelreset()}override fun createComponent() = componentoverride fun isModified(): Boolean {return state.username != form.username.text || state.password != form.password.text}override fun apply() {state.username = form.username.textstate.password = form.password.text}override fun reset() {form.username.text = state.usernameform.password.text = state.password}override fun getDisplayName() = "UISettingsConfig"}

其中reset用于重置表单内容为修改前设置的值,apply用于保存当前修改,isModified用于判断当前数据和上次数据之间是否存在不同,用于Apply按钮的禁用/激活状态的切换,这三个操作对应界面上的效果如下:

image-20231206180134340

image-20231206180129318

那我们的配置文件存储位置是在哪里呢?

由于在前文中我们使用applicationConfigurable选择了应用级别的存储,因此文件就存储在 IDEA 默认的配置文件存储地址:C:\Users\用户名\AppData\Roaming\JetBrains\IntelliJIdea2023.2\options,其中IntelliJIdea2023.2对应自己使用的 IDEA 名称。不过,由于我们当前是通过沙盒环境运行,所以位置并不是全局设置的位置,而是在build/idea-sandbox/config/options下:

image-20231206181847391

当我们将插件安装到我们正式的 IDEA 中,也就可以在上述的位置下发现配置文件了:

image-20231206182446451

如果我们将配置设为projectConfigurable选择项目级别,那么首先需要对配置文件进行如下修改:

<extensions defaultExtensionNs="com.intellij"><projectConfigurableinstance="cn.butterfly.ui.config.UISettingsConfig"id="cn.butterfly.ui.config.UISettingsConfig"parentId="tools"displayName="UISettingsConfig"/>
</extensions>

同时修改UIDemoState.kt文件上的注解配置:

import com.intellij.openapi.components.PersistentStateComponent
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.State
import com.intellij.openapi.components.Storage
import com.intellij.util.xmlb.XmlSerializerUtil/*** 数据持久化存储** @author butterfly* @date 2023-12-06*/
@Service(Service.Level.PROJECT) // 只修改该行
@State(name = "UIDemoState", storages = [Storage("ui-demo-state.xml")])
class UIDemoState: PersistentStateComponent<UIDemoState> {var username = ""var password = ""override fun getState(): UIDemoState {return this}override fun loadState(state: UIDemoState) {XmlSerializerUtil.copyBean(state, this)}}

最后还需要修改UISettingsConfig.kt文件,增加一个 project 的构造参数并修改 state 的初始化:

import cn.butterfly.ui.UIDemo
import cn.butterfly.ui.state.UIDemoState
import com.intellij.openapi.options.Configurable
import com.intellij.openapi.project.Project
import javax.swing.JComponent/*** UI 配置界面配置类** @author butterfly* @date 2023-12-06*/
// 增加 project: Project 构造参数
class UISettingsConfig(project: Project): Configurable {private val form = UIDemo()private val component: JComponent// 修改该行private val state = project.getService(UIDemoState::class.java)init {component = form.mainPanelreset()}override fun createComponent() = componentoverride fun isModified(): Boolean {return state.username != form.username.text || state.password != form.password.text}override fun apply() {state.username = form.username.textstate.password = form.password.text}override fun reset() {form.username.text = state.usernameform.password.text = state.password}override fun getDisplayName() = "UISettingsConfig"}

然后我们就可以在项目下的.idea文件夹中找到我们针对项目级别的配置了:

image-20231206185943881

至于读取配置文件,则通过private val state = project.getService(UIDemoState::class.java)或者private val state = ApplicationManager.getApplication().getService(UIDemoState::class.java)分别换取项目或应用级别的 state 对象,然后读取其中的字段即可。

总结

本文讲解了关于 UI 界面开发和数据持久化相关的内容,如果有错误或不足之处,欢迎一起交流讨论。

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

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

相关文章

unity 2d 入门 飞翔小鸟 飞翔脚本(五)

新建c#脚本 using System.Collections; using System.Collections.Generic; using UnityEngine;public class Fly : MonoBehaviour {//获取小鸟&#xff08;刚体&#xff09;private Rigidbody2D bird;//速度public float speed;// Start is called before the first frame up…

强敌环伺:金融业信息安全威胁分析——钓鱼和恶意软件

门口的敌人&#xff1a;分析对金融服务的攻击 Akamai会定期针对不同行业发布互联网状态报告&#xff08;SOTI&#xff09;&#xff0c;介绍相关领域最新的安全趋势和见解。最新的第8卷第3期报告主要以金融服务业为主&#xff0c;分析了该行业所面临的威胁和Akamai的见解。我们发…

SQL server 根据已有数据库创建相同的数据库

文章目录 用导出的脚本创建相同的数据库导出建表脚本再次建表 一些sql语句 用导出的脚本创建相同的数据库 导出建表脚本 首先&#xff0c;右击要导出的数据库名&#xff0c;依次选择任务-生成脚本。 简介&#xff08;第一页&#xff09;处选择下一步&#xff0c;然后来到选择…

反序列化 [网鼎杯 2020 朱雀组]phpweb 1

打开题目 我们发现这个页面一直在不断的刷新 我们bp抓包一下看看 我们发现index.php用post方式传了两个参数上去&#xff0c;func和p 我们需要猜测func和p两个参数之间的关系&#xff0c;可以用php函数MD5测一下看看 我们在响应处得到了一串密文&#xff0c;md5解密一下看看 发…

HBase-架构与设计

HBase架构与设计 一、背景二、HBase概述1.设计特点2.适用场景2.1 海量数据2.2 稀疏数据2.3 多版本数据2.4 半结构或者非结构化数据 三、数据模型1.RowKey2.Column Family3.TimeStamp 四、HBase架构图1.Client2.Zookeeper3.HMaster4.HRegionServer5.HRegion6.Store7.StoreFile8.…

10_企业架构NOSQL数据库之MongoDB

企业架构NOSQL数据库之MongoDB 学习目标和内容 1、能够简单描述MongoDB的使用特点 2、能够安装配置启动MongoDB 3、能够使用命令行客户端简单操作MongoDB 4、能够实现基本的数据操作 5、能够实现MongoDB基本安全设置 6、能够操作安装php的MongoDB扩展 一、背景描述及其方案设计…

PlantUML语法(全)及使用教程-类图

目录 1. 类图1.1、什么是类图1.2、元素声明1.3、类之间的关系1.4、关系上的标签1.5、在元素名称和关系标签中使用非字母1.6、添加方法 1. 类图 类图的设计语法与编程语言的传统语法相似。这种相似性为开发人员提供了一个熟悉的环境&#xff0c;从而使创建图表的过程更简单、更直…

接口获取数据控制台打印有值但是展开又没有了

谷歌浏览器只会展现响应式数据最后的结果&#xff0c;证明原来接口是有值的&#xff0c;后面对这个数据进行操作后&#xff0c;最终没有值了。所以对数据进行操作时最好对数据进行一次深拷贝 JSON.parse(JSON.stringify(data))

Apache Flink(七):Apache Flink快速入门 - DataStream BATCH模式

🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你大数据的个人空间-豹哥教你大数据个人主页-哔哩哔哩视频 下面使用Java代码使用DataStream…

【9】PyQt对话框

目录 1. QMessageBox 2. QIputDialog 对话框是为了更好地实现人与程序的交互 对话框主要是完成特定场景下的功能,比如删除确认等 QDialog的子类有QMessageBox、QFileDialog、QFontDialog、QInputDialog等 1. QMessageBox QMessageBox是普通的对话框 代码示例&#xff1a; …

操作系统的特征

一、并发 并发&#xff1a;指两个或多个事件在同一时间间隔内发生。这些事件宏观上是同时发生的&#xff0c;但微观上是交替发生的。 并行 &#xff1a;是指两个或多个事件同一事件发生。 操作系统的并发性指计算机系统中“同时”运行着多个程序&#xff0c;这些程序宏观上看…

CleanMyMac X4.15.0最新官方和谐版下载

Mac系统进行文件清理&#xff0c;一般是直接将文件拖动入“废纸篓”回收站中&#xff0c;然后通过清理回收站&#xff0c;就完成了一次文件清理的操作&#xff0c;但是这么做并无法保证文件被彻底删除了&#xff0c;有些文件通过一些安全恢复手段依旧是可以恢复的&#xff0c;那…

【PyTorch】权重衰减

文章目录 1. 理论介绍2. 实例解析2.1. 实例描述2.2. 代码实现 1. 理论介绍 通过对模型过拟合的思考&#xff0c;人们希望能通过某种工具调整模型复杂度&#xff0c;使其达到一个合适的平衡位置。权重衰减&#xff08;又称 L 2 L_2 L2​正则化&#xff09;通过为损失函数添加惩…

【ArcGIS微课1000例】0078:创建点、线、面数据的最小几何边界

本实例为专栏系统文章:讲述在ArcMap10.6中创建点数据最小几何边界(范围),配套案例数据,持续同步更新! 文章目录 一、工具介绍二、实战演练三、注意事项一、工具介绍 创建包含若干面的要素类,用以表示封闭单个输入要素或成组的输入要素指定的最小边界几何。 工具位于:数…

HarmonyOS开发(十):通知

1、通知概述 1.1、简介 应用可以通过通知接口发送通知消息&#xff0c;终端用户可以通过通知栏查看通知内容&#xff0c;也可以点击通知来打开应用。 通知使用的的常见场景&#xff1a; 显示接收到的短消息、即使消息...显示应用推送消息显示当前正在进行的事件&#xff0c…

聚观早报 |东方甄选将上架文旅产品;IBM首台模块化量子计算机

【聚观365】12月6日消息 东方甄选将上架文旅产品 IBM首台模块化量子计算机 新思科技携手三星上新兴领域 英伟达与软银推动人工智能研发 苹果对Vision Pro供应商做出调整 东方甄选将上架文旅产品 东方甄选宣布12月10日将在东方甄选APP上线文旅产品&#xff0c;受这一消息影…

软件工程之需求分析

一、对需求的基本认识 1.需求分析简介 (1)什么是需求 用户需求&#xff1a;由用户提出。原始的用户需求通常是不能直接做成产品的&#xff0c;需要对其进行分析提炼&#xff0c;最终形成产品需求。 产品需求&#xff1a;产品经理针对用户需求提出的解决方案。 (2)为什么要…

Web前端JS如何获取 Video/Audio 视音频声道(左右声道|多声道)、视音频轨道、音频流数据

写在前面&#xff1a; 根据Web项目开发需求&#xff0c;需要在H5页面中&#xff0c;通过点击视频列表页中的任意视频进入视频详情页&#xff0c;然后根据视频的链接地址&#xff0c;主要是 .mp4 文件格式&#xff0c;在进行播放时实时的显示该视频的音频轨道情况&#xff0c;并…

短视频购物系统源码:构建创新购物体验的技术深度解析

短视频购物系统作为电商领域的新宠&#xff0c;其背后的源码实现是其成功的关键。本文将深入探讨短视频购物系统的核心技术和源码设计&#xff0c;以揭示其如何构建创新购物体验的技术奥秘。 1. 技术架构与框架选择 短视频购物系统的源码首先考虑的是其技术架构。常见的选择…

多传感器融合SLAM在自动驾驶方向的初步探索的记录

1. VIO的不可观问题 现有的VIO都是解决的六自由度的问题, 但是对于行驶在路面上的车来说, 通常情况下不会有roll与z方向的自由度, 而且车体模型限制了不可能有纯yaw的变换. 同时由于IMU在Z轴上与roll, pitch上激励不足, 会导致IMU在初始化过程中尺度不准以及重力方向估计错误,…