美文网首页
IDEA 用户界面组件(二)

IDEA 用户界面组件(二)

作者: 鱼蛮子9527 | 来源:发表于2022-08-14 14:49 被阅读0次

这篇接着 IDEA 用户界面组件(一) 继续介绍下其他的一些组件。

Popups

Popups 是 IntelliJ 平台中广泛使用弹出窗口 - 没有显式的关闭按钮并在失去焦点时自动消失。个人感觉跟 Action 类似。

IntelliJ 平台提供了 JBPopupFactory 接口,来创建显示不同类型组件的弹出窗口。

createComponentPopupBuilder()

通用的创建方式,允许显示任何 Swing 组件,也就是可以在弹出的窗口中嵌套前面介绍过的 JComponent,而 JComponent 中就可以自定义任何我们想要显示的内容。

public class PopupComponentAction extends AnAction {
    @Override
    public void actionPerformed(@NotNull AnActionEvent e) {
        Project project = e.getProject();
        if (Objects.isNull(project)) {
            return;
        }

        JPanel panel = new JPanel(new BorderLayout());
        panel.add(new JLabel("这是一个ComponentPopup"), BorderLayout.CENTER);
        panel.add(new JButton("上一个"), BorderLayout.NORTH);
        panel.add(new JButton("下一个"), BorderLayout.SOUTH);

        JBPopup jbPopup = JBPopupFactory.getInstance().createComponentPopupBuilder(panel, null).createPopup();
        jbPopup.showCenteredInCurrentWindow(project);
    }
}

ComponentPopup 示例

createPopupChooserBuilder()

可以传入一个普通的 java.util.List,根据传入的内容自动生成一个列表项。

public class PopupChooserAction extends AnAction {
    @Override
    public void actionPerformed(@NotNull AnActionEvent e) {
        Project project = e.getProject();
        if (Objects.isNull(project)) {
            return;
        }

        JBPopup chooser = JBPopupFactory.getInstance()
                .createPopupChooserBuilder(Lists.newArrayList("abc", "def")).createPopup();
        chooser.showCenteredInCurrentWindow(project);
    }
}
PopupChooser 示例

createConfirmation()

创建一个两个选项的选择弹窗,并可以根据选择的内容执行不同的操作。

public class PopupConfirmationAction extends AnAction {
    @Override
    public void actionPerformed(@NotNull AnActionEvent e) {
        Project project = e.getProject();
        if (Objects.isNull(project)) {
            return;
        }

        ListPopup popup = JBPopupFactory.getInstance()
                .createConfirmation("这是个确认创建", ()-> System.out.println("选择了YES"), 1);
        popup.showCenteredInCurrentWindow(project);
    }
}
Confirmation 示例

createActionGroupPopup()

用于展示 Action Group 中的 actions,并执行用户选择的 action。官方文档中给的示例是: Edit / Find Usages / Recent Find Usages 中显示最近的的查询记录,应该就是下面这个。

搜索历史
public class PopupActionGroupAction extends AnAction {

    public static final int NUM_10 = 10;

    @Override
    public void actionPerformed(@NotNull AnActionEvent e) {
        new PopupGroupAction().actionPerformed(e);
    }

    public static class PopupGroupAction extends DefaultActionGroup {
        @Override
        public void actionPerformed(@NotNull AnActionEvent e) {
            Project project = e.getProject();
            if (Objects.isNull(project)) {
                return;
            }
            ListPopup popup = JBPopupFactory.getInstance()
                    .createActionGroupPopup("CreateActionGroupPopup", this, e.getDataContext(),
                            JBPopupFactory.ActionSelectionAid.SPEEDSEARCH, false);
            popup.showCenteredInCurrentWindow(project);
        }

        @Override
        public AnAction @NotNull [] getChildren(@Nullable AnActionEvent e) {
            AnAction[] actions = new AnAction[NUM_10];
            for (int i = 0; i < NUM_10; i++) {
                actions[i] = new AnAction("index:" + i) {
                    @Override
                    public void actionPerformed(@NotNull AnActionEvent e) {
                        System.out.println(e.getPresentation().getText());
                    }
                };
            }
            return actions;
        }
    }
}
PopupActionGroup 示例

Action Group 中除了可以使用箭头键进行选择外,还可以通过传递 JBPopupFactory.ActionSelectionAid 枚举中的常量之一,来选择通过输入序号或者输入部分文本来快速选择 action。

其他说明

创建 Popup 后,您需要通过调用 show() 方法来显示它。您可以通过调用 showInBestPositionFor() 让 IntelliJ 平台根据上下文自动选择位置,或者通过 showUnderneathOf() 和 showInCenterOf() 等方法显式指定位置。

如果您需要在弹出窗口关闭时执行某些操作,您可以使用 addListener() 方法为其附加监听器。

如果只是想简单的创建一个通知内容,可以通过 JBPopupFactory.getInstance().createMessage("这是一个消息").showInFocusCenter(); 来创建一个很简单的消息。

Notifications

要显示一些通知信息,可以使用 Dialogs、Popup,但通常来说显示非模态通知的方法是使用 Notifications 类。

它有两个主要优点:

  • 用户可以控制每种通知类型的显示方式,通过 Settings/Preferences | Appearance & Behavior | Notifications
  • 所有显示的通知都收集在事件日志工具窗口中,供以后查看

通知的文本支持 HTML 标记。

使用 Notification.addAction(AnAction) 可以在内容下方添加链接,通过 NotificationAction 可以更方便的使用。

可以通过 Notification 构造函数的 groupId 参数指定通知类型。用户可以在 Settings/Preferences | Appearance & Behavior | Notifications 中选择每种通知类型对应的显示类型。

普通 Notification

要通过首选项指定显示类型,需要使用 NotificationGroup 创建通知,下面是使用 NotificationGroup 方式来创建 Notification。

 <extensions defaultExtensionNs="com.intellij">
    <notificationGroup id="Custom Notification Group INFORMATION" displayType="BALLOON" />
    <notificationGroup id="Custom Notification Group WARNING" displayType="BALLOON" />
    <notificationGroup id="Custom Notification Group ERROR" displayType="BALLOON" />
  </extensions>
public class Notification extends AnAction {
    @Override
    public void actionPerformed(@NotNull AnActionEvent e) {
        Project project = e.getProject();
        if (Objects.isNull(project)) {
            return;
        }

        NotificationGroupManager.getInstance().getNotificationGroup("Custom Notification Group INFORMATION")
                .createNotification("这是一个 Notification INFORMATION", NotificationType.INFORMATION)
                .notify(project);

        NotificationGroupManager.getInstance().getNotificationGroup("Custom Notification Group WARNING")
                .createNotification("这是一个 Notification WARNING", NotificationType.WARNING)
                .notify(project);

        NotificationGroupManager.getInstance().getNotificationGroup("Custom Notification Group ERROR")
                .createNotification("这是一个 Notification ERROR", NotificationType.ERROR)
                .notify(project);
    }
}

执行后在 IDEA 的右下角就可以看到通知出现,应该是同时最多能展示 2 个 Notification,创建的 INFORMATION 并没有同时展示出来。同时在 Event Log 里面可以看到通知记录。

Notification Event Log

带 HTML 标记的 Notification

下面创建了一个带有 HTML 标签的通知消息,不过貌似对 HTML 标签的支持不是特别好。

public class BalloonHtmlText extends AnAction {
    @Override
    public void actionPerformed(@NotNull AnActionEvent e) {
        Project project = e.getProject();
        if (Objects.isNull(project)) {
            return;
        }

        // 创建一个消息
        final JFrame jFrame = WindowManager.getInstance().getFrame(project);
        Balloon balloon = JBPopupFactory.getInstance().createHtmlTextBalloonBuilder("<form>姓名:<input type=\"text\" name=\"name\"/>住址:<input type=\"text\" name=\"address\"/><button type=\"submit\">提交</button></form>", MessageType.INFO, e1 -> {
        }).createBalloon();
        balloon.showInCenterOf(Objects.requireNonNull(jFrame).getRootPane());
    }
}
HTML Balloon

File and Class Choosers

通过 Dialog

要让用户选择一个文件、目录或多个文件,可以使用 FileChooser.chooseFiles() 方法。这个有多个重载方法。最好用的方式选择返回 void 的方法,并传入一个接收所选文件列表作为参数的回调。类似下面的方法:

  public static void chooseFiles(@NotNull final FileChooserDescriptor descriptor,
                                 @Nullable final Project project,
                                 @Nullable final VirtualFile toSelect,
                                 @NotNull final Consumer<? super List<VirtualFile>> callback) {
    chooseFiles(descriptor, project, null, toSelect, callback);
  }

FileChooserDescriptor 类控制可以选择哪些文件。构造函数参数指定是否可以选择文件和(或)目录,以及是否允许多选(详细说明请参见 FileChooserDescriptorFactory)。

要对允许的选择进行更细粒度的控制,可以覆写 isFileSelectable() 方法。还可以通过覆写 getIcon()、getName() 和 getComment() 方法来自定义文件的呈现方式。需要注意的是,macOS 系统对大多数的自定义都不支持。如果确实想要修改,则需要使用重载的 chooseFiles() 来显示标准的 IntelliJ 平台对话框。

通过 Textfield

使用文件选择器的一种非常常见的方法是使用文本字段输入路径,并使用省略号按钮 (...) 来显示文件选择器。要创建这样的控件,请使用 TextFieldWithBrowseButton 组件,并对其调用 addBrowseFolderListener() 方法来设置文件选择器。

通过 Tree

通过 TreeFileChooserFactory 类可以使用另一种选择文件的 UI。当使用输入文件名来搜索选择文件时,这种 UI 的效果是最好的。

这个 API 显示的对话框有两个选项卡:

  • 一个是显示项目结构
  • 另一个是显示类似于 Navigate | File 的文件列表。

要显示对话框,请在 createFileChooser() 返回的选择器上调用 showDialog() 方法。通过调用 getSelectedFile() 来获得用户的选择。

Class 文件选择

如果想提供选择 Java 类的功能,可以使用 TreeClassChooserFactory 类。其不同的方法允许指定获取类的范围,可以将选择限制为特定类的子类或接口的实现,以及包含或排除内部类等。

UI 的效果与 TreeFileChooserFactory 非常类似。

Package 选择

如果要选择 Java 包,可以使用 PackageChooserDialog 类。这个类继承自 DialogWrapper,使用起来与前面介绍的 DialogWrapper 一致。

下面是一个简单的示例,集合了上面介绍的 5 种文件选择器。

public class FileChooseAction extends AnAction {
    @Override
    public void actionPerformed(@NotNull AnActionEvent e) {
       new CustomDialog(e).show();
    }

    public static class CustomDialog extends DialogWrapper{

        AnActionEvent anActionEvent;

        public CustomDialog(AnActionEvent anActionEvent) {
            super(true);
            this.anActionEvent = anActionEvent;
            init();
        }

        @Override
        protected @Nullable JComponent createCenterPanel() {

            Project project = anActionEvent.getProject();
            if (Objects.isNull(project)) {
                return null;
            }
            PsiFile psiFile = anActionEvent.getData(CommonDataKeys.PSI_FILE);
            if (psiFile == null) {
                return null;
            }

            JPanel panel = new JPanel(new FlowLayout());
            panel.setVisible(true);

            // 添加普通文件选择
            JButton fileChooseBtn = new JButton("普通文件选择");
            fileChooseBtn.addActionListener(event ->
                    FileChooser.chooseFiles(FileChooserDescriptorFactory.createSingleFileDescriptor(),
                            project, null, (s) -> s.forEach(f -> System.out.println(f.getName()))));
            panel.add(fileChooseBtn);

            // 添加带浏览按钮的文本框控件
            TextFieldWithBrowseButton browseButton = new TextFieldWithBrowseButton();
            browseButton.addBrowseFolderListener(new TextBrowseFolderListener(FileChooserDescriptorFactory.createSingleFileDescriptor()));
            panel.add(browseButton);

            // 添加 Tree 文件选择
            JButton treeFileChooseBtn = new JButton("Tree 文件选择");
            treeFileChooseBtn.addActionListener(event -> {
                TreeFileChooser chooser = TreeFileChooserFactory.getInstance(project)
                        .createFileChooser("Tree 文件选择", psiFile, FileTypes.PLAIN_TEXT, null);
                chooser.showDialog();
                System.out.println(chooser.getSelectedFile());
            });
            panel.add(treeFileChooseBtn);

            // 添加 Class 文件选择
            JButton treeClassChooseBtn = new JButton("Class 文件选择");
            treeClassChooseBtn.addActionListener(event -> {
                TreeClassChooser chooser = TreeClassChooserFactory.getInstance(project).createProjectScopeChooser("Class 文件选择");
                chooser.showDialog();
                System.out.println(chooser.getSelected());
            });
            panel.add(treeClassChooseBtn);

            // 添加 Java 包选择
            JButton packageChooseBtn = new JButton("Java 包选择");
            packageChooseBtn.addActionListener(event -> {
                PackageChooserDialog chooser = new PackageChooserDialog("Java 包选择", project);
                if (chooser.showAndGet()) {
                    PsiPackage aPackage = chooser.getSelectedPackage();
                    System.out.println(aPackage.getName());
                }
            });
            panel.add(packageChooseBtn);

            return panel;
        }
    }
}

这是整个 Dialog 的显示样式。

5 种文件选择器

下面是分别使用 5 种文件选择器的文件选择 UI 效果。

普通文件选择

普通文件选择

Textfield 文件选择

Textfield 文件选择

Tree 文件选择

Tree 文件选择 Tree 文件选择

Class 文件选择

Class 文件选择 Class 文件选择

Package 选择

Package 选择

相关文章

网友评论

      本文标题:IDEA 用户界面组件(二)

      本文链接:https://www.haomeiwen.com/subject/dmdkwrtx.html