一篇學會開發摸魚看書的側邊欄窗體
一、說明
方向不對,努力白費!
總有人拿到產品的需求,就著急開干,反正也懶的想開發中會發生啥,上線后多少人使用,管它三七二十一先堆起來代碼看一看,反正能跑就行,無論代碼還是你!
其實很多時候在編寫代碼前,所需要做的技術調研、架構設計、模塊分層、數據結構、詳細分析、方案評審等,與三七二十一那家伙對比起來,好像都會顯得有點慢。但這個看上去慢的過程,卻能解決以后很多常見和麻煩的問題,比如產品需求迭代、業務流程變更、代碼邏輯更改、線上異常排查。雖然看著慢,但這個積基樹本的過程就像打地基一樣,總得有一個穩定的根基,才能蓋好整棟大樓。萬丈高樓平地起,勿在浮沙筑高臺
二、需求目的
如果你需要開發一個自定義功能的插件,無論是處理代碼、輔助ORM生成、日志信息記錄等,都會需要進行一個插件的功能配置進行初始化操作以及把對應功能展示到整個 IDEA 窗體中的右邊欄或者下邊欄中,這樣才能滿足一個插件的基本需求。
那么這樣就需要在 IDEA 窗體 File -> Settings 中擴展自己的配置窗體,以及開發自己需要的 ToolWindow 嵌入到 IDEA 中(左側、右側、下側),這里窗體的開發需要用到 Swing 但目前在 IDEA 中開發這樣的功能只需要拖拽窗體就可以,還是蠻容易的。
那么接下來我們以一個在 IDEA 中摸魚看書的場景為案例,學習配置窗體和閱讀窗體的功能實現。
三、案例開發
1. 工程結構
- guide-idea-plugin-tool-window
- ├── .gradle
- └── src
- ├── main
- │ └── java
- │ └── cn.bugstack.guide.idea.plugin
- │ └── factory
- │ │ ├── ReadFactory.java
- │ │ └── SettingFactory.java
- │ └── ui
- │ │ ├── ReadUI.java
- │ │ ├── ReadUI.form
- │ │ ├── SettingUI.java
- │ │ └── SettingUI.form
- │ └── Config
- ├── resources
- │ └── META-INF
- │ └── plugin.xml
- ├── build.gradle
- └── gradle.properties
此工程主要涉及兩部分,在factory中一個是配置窗體、一個是閱讀窗體,與之對應的兩組UI的實現。最后 factory 類的實現都會配置到 plugin.xml 中進行使用,同時也是在 plugin.xml 中控制窗體位置和圖標。
2. 創建 UI 窗體
2.1 創建方式
New -> Swing UI Designer -> GUI Form
- 在 Java 中創建窗體的方式主要有 AWT、Swing、JavaFx,由于 IDEA 使用 Swing 開發,所以這里創建 Swing 窗體的兼容性會更好。
- 那么這里 Swing 窗體的創建可以是自己手寫窗體結構,也可以使用可視化拖拽的 GUI Form 如果你的窗體不復雜,其實拖拽的方式就可以滿足使用。
2.2 配置頁窗體
- public class SettingUI {
- private JPanel mainPanel;
- private JPanel settingPanel;
- private JLabel urlLabel;
- private JTextField urlTextField;
- private JButton urlBtn;
- public SettingUI() {
- // 給按鈕添加一個選擇文件的事件
- urlBtn.addActionListener(e -> {
- JFileChooser fileChooser = new JFileChooser();
- fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
- fileChooser.showOpenDialog(settingPanel);
- File file = fileChooser.getSelectedFile();
- urlTextField.setText(file.getPath());
- });
- }
- public JComponent getComponent() {
- return mainPanel;
- }
- public JTextField getUrlTextField() {
- return urlTextField;
- }
- }
- 配置頁窗體主要提供文章路徑的選擇,這里需要用到的標簽包括:JLabel、JTextField、JButton
- 在使用 GUI Form 創建完窗體后,就會出現這樣一個可視化的頁面,右側可以把各類標簽拖到中間的面板中,左側進行設置展示名稱和屬性名稱。
- 最終這里的代碼標簽代碼會展示到 SettingUI.java 中,而渲染內容會被隱藏,這樣的方式也比較方便控制一些自定義內容的添加,例如事件和新窗體等
- 另外在 SettingUI.java 中,還需要在構造函數添加一個按鈕事件,用于打開文件選擇器,把我們需要打開的文件,設置到 urlTextField 中。
2.3 閱讀頁窗體
- public class ReadUI {
- private JPanel mainPanel;
- private JTextPane textContent;
- public JComponent getComponent() {
- return mainPanel;
- }
- public JTextPane getTextContent() {
- return textContent;
- }
- }
在窗體創建和配置頁窗體是一樣的,也是通過拖拽到面板中,用于展示路徑文件內容。
你可以適當的添加一些其他按鈕進去,比如翻頁閱讀、滾動條、字數展示等。
3. ToolWindow 工具框
為了把我們自己實現的閱讀窗體放到整個 IDEA 右側側邊欄中,我們需要創建一個實現了 ToolWindowFactory 的接口,并把實現類配置到 plugin.xml 中
- public class ReadFactory implements ToolWindowFactory {
- private ReadUI readUI = new ReadUI();
- @Override
- public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
- // 獲取內容工廠的實例
- ContentFactory contentFactory = ContentFactory.SERVICE.getInstance();
- // 獲取 ToolWindow 顯示的內容
- Content content = contentFactory.createContent(readUI.getComponent(), "", false);
- // 設置 ToolWindow 顯示的內容
- toolWindow.getContentManager().addContent(content);
- // 全局使用
- Config.readUI = readUI;
- }
- }
接口方法 ToolWindowFactory#createToolWindowContent 是需要自己工具框類實現的方法,在這個 createToolWindowContent 方法中把自己的窗體 ReadUI 實例化后填充進去即可。
添加窗體的補助主要依賴于 ContentFactory.SERVICE.getInstance() 創建出 ContentFactory 并最終使用 toolWindow 添加窗體顯示 UI 即可。
這里我們額外的還添加了一個全局屬性 Config.readUI 這是為了后續可以在配置窗體中使用這個 UI 進行設置文件內容。
4. Configurable 配置框
- public class SettingFactory implements SearchableConfigurable {
- private SettingUI settingUI = new SettingUI();
- @Override
- public @NotNull String getId() {
- return "test.id";
- }
- @Override
- public @Nls(capitalization = Nls.Capitalization.Title) String getDisplayName() {
- return "test-config";
- }
- @Override
- public @Nullable JComponent createComponent() {
- return settingUI.getComponent();
- }
- @Override
- public boolean isModified() {
- return true;
- }
- @Override
- public void apply() throws ConfigurationException {
- String url = settingUI.getUrlTextField().getText();
- // 設置文本信息
- try {
- File file = new File(url);
- RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
- randomAccessFile.seek(0);
- byte[] bytes = new byte[1024 * 1024];
- int readSize = randomAccessFile.read(bytes);
- byte[] copy = new byte[readSize];
- System.arraycopy(bytes, 0, copy, 0, readSize);
- String str = new String(copy, StandardCharsets.UTF_8);
- // 設置內容
- Config.readUI.getTextContent().setText(str);
- } catch (Exception ignore) {
- }
- }
- }
- 實現自 SearchableConfigurable 接口的方法比較多,包括:getId、getDisplayName、createComponent、isModified、apply 這些里面用于寫邏輯實現的主要是 createComponent 和 apply
- createComponent 方法主要是把我們自己創建的 UI 面板提供給 JComponent
- apply 是一個事件,當我們點擊完成配置的 OK、完成,時候就會觸發到這個方法。在這個方法中我們拿到文件的 URL 地址使用 RandomAccessFile 進行讀取解析文件,并最終把文件內容展示到閱讀窗體中 Config.readUI.getTextContent().setText(str);
5. 配置 plugin.xml
- <extensions defaultExtensionNs="com.intellij">
- <!-- Add your extensions here -->
- <!-- 配置 File -> Settings -> Tools -->
- <projectConfigurable groupId="tools" displayName="My Test Config" id="test.id"
- instance="cn.bugstack.guide.idea.plugin.factory.SettingFactory"/>
- <!-- 窗體 (IDEA 界面右側) -->
- <toolWindow id="Read-Book" secondary="false" anchor="right" icon="/icons/logo.png"
- factoryClass="cn.bugstack.guide.idea.plugin.factory.ReadFactory"/>
- </extensions>
本次在 plugin.xml 中的主要配置內容就是 projectConfigurable 和 toolWindow,另外在 toolWindow 中還添加了一個 icon 的 logo,配置完成后就可以在 IDEA 頁面展示出我們的自己添加的窗體了。
四、插件測試
- 通過 Plugin 啟動插件,這個時候會打開一個新的 IDEA 窗體,在這個新窗體中就可以看到我們添加的功能了。
配置文件路徑
- 點擊選擇按鈕,選擇你的文件位置,選擇后點擊 OK
查看展示文件
確認好文件路徑后,就可以再右側欄看到自己的文件展示內容了。是不是在擴展些,就適合你摸魚了!?
五、總結
學習自定義開發UI,把UI填充到需要放置的 IDEA 窗體位置,并在窗體中添加功能的流程步驟,其實主要包括三方面:Swing UI、Factory 實現類、plugin 配置。
在 plugin 配置中,主要包括如窗體ID、位置、icon圖標、對應的實現類,如果不添加這些是不能正常展示窗體信息的。
另外可以以這個案例為基礎,添加自己想完成的功能,比如讓這個摸魚看書的功能更加完善,可以支持不同類型的文件,甚至可以是 PDF 的閱讀,以及你想看的書籍。