[JAVA] Ich habe ein Plug-In für IntelliJ IDEA erstellt

Dieser Beitrag "DeNA IP Platform Division Adventskalender 2017" Dies ist der Artikel am 19. Tag.

In meinem Team codieren alle serverseitigen Ingenieure mit IntelliJ IDEA. Kürzlich habe ich mich plötzlich gefragt: "Wie erstelle ich ein IntelliJ IDEA-Plug-In?". Während des Studiums habe ich versucht, so etwas wie ein Desktop-Maskottchen zu erstellen, das auf der IDE angezeigt wird. Daher möchte ich den Ablauf zusammenfassen.

Was ich gemacht habe

Wenn Sie die IDE starten, erscheinen seltsame Kreaturen. Während Sie codieren, werden Erfahrungswerte (Exp) akkumuliert. (Ich wollte eine Funktion hinzufügen, die das Codieren etwas mehr unterstützt, aber das ist okay) movie.gif

Umgebung

IntelliJ IDEA ist erforderlich, um ein Plug-In zu erstellen. (Community Edition ist ebenfalls akzeptabel) Es scheint, dass es einfacher ist, während der Plug-Entwicklung zu debuggen, wenn der Quellcode von IntelliJ IDEA Community Edition ebenfalls gelöscht wird, aber ich habe ihn diesmal nicht verwendet. Das detaillierte Verfahren ist im offiziellen Dokument beschrieben, daher werde ich es weglassen.

Ich werde versuchen, es vorerst zu schaffen

Neues Projekt

[Datei> Neues Projekt> IntelliJ Platform Plugin> Weiter] auf IntelliJ IDEA Geben Sie dem Projektnamen einen geeigneten Namen. (Diesmal ist Nunyu) new_project1.png

Machen Sie eine Komponente

Die Basis des Plug-Ins sind die folgenden drei Arten von Komponenten.

Dieses Mal möchte ich, dass das Maskottchen beim Start der IDE projektübergreifend angezeigt wird, daher erstelle ich es mit der Komponente auf Anwendungsebene. Sie können eine neue erstellen, indem Sie mit der rechten Maustaste auf das Projektfenster klicken und [Neu> Plugin DevKit> Anwendungskomponente] auswählen. Der Komponentenname lautet "Nunyu". new_component.png

Stellen Sie sicher, dass es funktioniert

Tatsächlich läuft das Plug-In jetzt auf der IDE! Komponente initialisieren Lassen Sie uns abmelden und mit initComponent ausführen.

src/Nunyu.java


import com.intellij.openapi.diagnostic.Logger;
    ...
    @Override
    public void initComponent() {
        Logger.getInstance(Nunyu.class).info("Nunyu");
    }
    ...

Um es auszuführen, wählen Sie [Ausführen> Debuggen] aus dem Menü. Dann wird eine weitere IntelliJ IDEA gestartet und das Plug-In ausgeführt. Und Sie können sehen, dass in der Debug-Konsole eine Meldung angezeigt wird. debug.png

Versuchen Sie, das Maskottchen anzuzeigen

Rufen Sie JWindow auf

Lassen Sie die Komponente "JWindow" erben, um das Fenster bei der Initialisierung anzuzeigen und das Bild zu rendern. Hier geht es um "Swing".

src/Nunyu.java


import com.intellij.openapi.components.ApplicationComponent;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Nunyu extends JWindow implements ApplicationComponent {
    private Image image;
    private ImagePanel imagePanel;

    public Nunyu() {
    }

    @Override
    public void initComponent() {
        initWindow();
        makeDraggable();
    }

    public void initWindow() {
        image = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/images/nunyu-alpha.png "));

        setSize(100, 100);
        setAlwaysOnTop(true);
        setBackground(new Color(1, 0, 0, 0));

        imagePanel = new ImagePanel();
        add(imagePanel);

        setVisible(true);
    }
    
    public void makeDraggable() {
        final Point startPos = new Point();
        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                startPos.setLocation(e.getPoint());
            }
        });
        addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                setLocation(e.getXOnScreen() - startPos.x, e.getYOnScreen() - startPos.y);
            }
        }); 
    }

    public class ImagePanel extends JPanel {
        public ImagePanel() {
            setOpaque(false);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(image, 0, 0, this);
        }

    }

    @Override
    public void disposeComponent() {
        // TODO: insert component disposal logic here
    }

    @Override
    @NotNull
    public String getComponentName() {
        return "Nunyu";
    }
}

nunyu-alpha.png

Wenn Sie es jetzt ausführen, sehen Sie die Maskottchen, die Sie ziehen können! show1.png

Maskottchen ausblenden, wenn IDE inaktiv ist

Selbst wenn die IDE den Fokus verliert, bleibt das Maskottchen bei dieser Geschwindigkeit oben angezeigt und verschwindet nicht. Es ist nervig. Wenn die IDE den Fokus verliert, füge ich einen Prozess hinzu, um das Maskottchen gleichzeitig zu löschen.

src/Nunyu.java


    @Override
    public void initComponent() {
        initWindow();
        setupFocusEvent();
    }
    ...
    public void setupFocusEvent() {
        WindowManager.getInstance().addListener(new WindowManagerListener() {
            @Override
            public void frameCreated(IdeFrame frame) {
                WindowManager.getInstance().getFrame(frame.getProject()).addWindowFocusListener(new WindowFocusListener() {
                    @Override
                    public void windowGainedFocus(WindowEvent e) {
                        setVisible(true);
                    }

                    @Override
                    public void windowLostFocus(WindowEvent e) {
                        if (e.getOppositeWindow() == null) {
                            setVisible(false);
                        }
                    }
                });
            }

            @Override
            public void beforeFrameReleased(IdeFrame frame) {
            }
        });
    }

Fügen Sie einen "WindowManagerListener" -Listener hinzu und fügen Sie diesem Fenster jedes Mal einen "WindowFocusListener" hinzu, wenn ein Frame in der IDE erstellt wird. Implementieren Sie in diesem Listener "windowGainedFocus", das ausgelöst wird, wenn das Fenster den Fokus erhält, und "windowLostFocus", das ausgelöst wird, wenn das Fenster den Fokus verliert. Ich möchte das Maskottchen anzeigen, wenn das Fenster auf der IDE den Fokus erhält, damit ich "setVisible (true)" aufrufen kann. Wenn Sie dagegen den Fokus verlieren, können Sie "e.getOppositeWindow ()" verwenden, um das Fenster abzurufen, das der nächste Fokus sein wird. Wenn dies jedoch "null" ist, hat die IDE keinen Fokus, also "setVisible" Call (false) `.

Geben Sie Maskottchen Erfahrung

Hook-Editor-Tastenanschläge

Wenn ich das nächste Mal im Editor codiere, werde ich versuchen, dem Maskottchen einen Erfahrungswert zu geben. Dies erfordert das Verknüpfen von Editor-Tastenanschlägen. Erweitern Sie jedoch "editorTypedHandler", um dies zu erreichen.

src/MyTypedHandler.java


import com.intellij.codeInsight.editorActions.AutoFormatTypedHandler;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actionSystem.TypedActionHandler;
import org.jetbrains.annotations.NotNull;

public class MyTypedHandler extends AutoFormatTypedHandler {
    public MyTypedHandler(TypedActionHandler originalHandler) {
        super(originalHandler);
    }

    @Override
    public void execute(@NotNull Editor editor, char charTyped, @NotNull DataContext dataContext) {
        super.execute(editor, charTyped, dataContext);
        Logger.getInstance(Nunyu.class).info("Typed: " + charTyped);
    }
}

resources/META-INF/plugin.xml


  ...
  <extensions defaultExtensionNs="com.intellij">
    <editorTypedHandler implementationClass="MyTypedHandler"/>
  </extensions>
  ...

Wenn ein Zeichen in den Editor eingegeben wird, wird "execute ()" aufgerufen. Versuchen Sie, die gedrückte Taste im Protokoll auszugeben, während Sie "super.execute ()" aufrufen, um das Standardverhalten nicht zu ändern. Versuchen Sie es jetzt auszuführen und bearbeiten Sie etwas in der IDE, die gestartet wird. Sie können sehen, dass der eingegebene Schlüssel im Infoprotokoll angezeigt wird. So haken Sie diesen Schlüssel ein, aber es scheint Es gibt auch eine Möglichkeit, TypedHandlerDelegate zu verwenden, aber als ich es versuchte, war es in der IDE Als das AutoCompletion-Popup herauskam, schien das Ereignis nicht zu kommen, also funktionierte es nicht. (Ehrlich gesagt, ich weiß nicht, was die richtige Antwort ist.)

Daten beibehalten

Selbst wenn ich das Maskottchen erleben kann, ist es traurig, dass es zurückgesetzt wird, wenn die IDE neu gestartet wird. Machen wir es also möglich, den als nächstes angegebenen Erfahrungswert dauerhaft zu machen. Verwenden Sie "PersistentStateComponent", um Daten im Plug-In beizubehalten.

src/MyService.java


import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;

@State(
        name = "MyService",
        storages = {
                @Storage("nunyu.xml"),
        }
)

class MyService implements PersistentStateComponent<MyService.State> {
    static class State {
        public Integer exp = 0;
    }

    State myState;

    public MyService() {
        this.myState = new State();
    }

    public State getState() {
        return myState;
    }

    public void loadState(State state) {
        myState = state;
    }

    public static MyService getInstance() {
        return ServiceManager.getService(MyService.class);
    }
}

Ich habe eine Box implementiert, die einfach die Ganzzahl "exp" hat. Sie können das Ziel so festlegen, dass es mit der Annotation "@ State" beibehalten wird.

Vergessen Sie auch nicht, in plugin.xml zu erwähnen, um diesen Service zu nutzen.

resources/META-INF/plugin.xml


  ...
  <extensions defaultExtensionNs="com.intellij">
    <applicationService serviceInterface="MyService" serviceImplementation="MyService"/>
  </extensions>
  ...

Registrieren Sie sich als applicationService, da dieser von Komponenten auf Anwendungsebene verwendet wird. Beachten Sie, dass es andere projectService usw. gibt.

Verbinden

Beginnen wir zunächst mit der Anzeige des Erfahrungswerts auf dem Bildschirm. Schreiben Sie die paintComponent () -Methode der ImagePanel-Klasse neu, um die exp des MyService anzuzeigen. Bereiten Sie außerdem die Methode repaint () vor, damit Sie jedes Mal neu zeichnen können, wenn sich der Erfahrungswert erhöht.

src/Nunyu.java


    ...
    public void repaint() {
        imagePanel.repaint();
    }
    ...
    public class ImagePanel extends JPanel {
        ...
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(image, 0, 0, this);

            g.drawString("Exp. " + MyService.getInstance().myState.exp, 0, 10);
        }
    }
    ...

Schreiben Sie als Nächstes einen Prozess, um den Erfahrungswert zum Zeitpunkt der Tasteneingabe zu erhöhen und neu zu zeichnen.

src/MyService.java


    ...
    public void increment() {
        myState.exp++;
    }
    ...

src/MyTypedHandler.java


    ...
    @Override
    public void execute(@NotNull Editor editor, char charTyped, @NotNull DataContext dataContext) {
        super.execute(editor, charTyped, dataContext);
        ServiceManager.getService(MyService.class).increment();
        ApplicationManager.getApplication().getComponent(Nunyu.class).repaint();
    }
    ...

Das ist es. Während Sie programmieren, wird Ihre Erfahrung stetig zunehmen!

Schließlich

Übrigens habe ich ein Plug-In erstellt, das keinen Nutzen hatte (lacht), aber durch Ausprobieren habe ich irgendwie verstanden, wie man ein Plug-In erstellt. Es war ziemlich schwierig, Informationen aus den Dokumenten zu finden, und ich konnte nichts wie "Was soll ich tun, wenn ich so etwas tun möchte ?!" Finden, und selbst ein so einfaches war sehr schwierig. Es gibt viele Plugins auf dem Markt, sodass Sie nach nützlichem Code oder In der Community suchen suchen können. community & topic = 20036979 & utf8 =% E2% 9C% 93) Möglicherweise finden Sie die gesuchten Informationen oder nicht! Dieser Artikel war das Ende eines Kampfes, aber wenn Sie Vorschläge haben, kommentieren Sie bitte.

Recommended Posts

Ich habe ein Plug-In für IntelliJ IDEA erstellt
Ich hatte Probleme bei der Arbeit und habe ein IntelliJ-Plug-In erstellt
Ich habe ein Diff-Tool für Java-Dateien erstellt
Ich habe ein Docker-Image für die japanische Version von SDAPS erstellt
Ich habe ein Check-Tool für das Release-Modul erstellt
Ich habe eine Methode entwickelt, um nach Premium Friday zu fragen
Ich habe einen THETA API-Client erstellt, der für die Plug-Entwicklung verwendet werden kann
Ich habe eine Chat-App erstellt.
Ich habe eine Bibliothek zum Anzeigen von Tutorials auf Android erstellt.
Ich habe ein Plug-In erstellt, das Jextract mit Gradle-Aufgaben ausführt
Ich habe eine shopify App @java erstellt
Ich habe mit Swing eine GUI erstellt
Ich habe eine einfache Empfehlungsfunktion erstellt.
Ich habe eine passende App erstellt (Android App)
Ich habe ein Tool zur Generierung von package.xml erstellt.
[Android] Ich habe eine Schrittzähler-App erstellt.
Ich habe mit JD-Core eine Befehlszeilenschnittstelle mit dem WinMerge Plugin erstellt
Erstellt eine Methode zum Anfordern von Premium Friday (Java 8-Version)
Ich habe eine Antwortfunktion für die Rails Tutorial-Erweiterung (Teil 5) erstellt:
[Ruby] Ich habe einen einfachen Ping-Client erstellt
IntelliJ IDEA Praktische Funktion für Anfänger (Wichtigkeit ★ 4)
Ich habe eine Methode für den Premium-Freitag mit einem Liner erstellt
Ich habe mit Ruby einen riskanten Würfel gemacht
Ich habe eine Janken App mit Kotlin gemacht
Ich habe eine Taschenrechner-App für Android erstellt
Ich habe ein neues Java-Bereitstellungstool erstellt
IntelliJ IDEA Praktische Funktion für Anfänger (Wichtigkeit ★ 5)
Ich habe eine Janken App mit Android gemacht
Über den Stream Debugger des IntelliJ IDEA Plugins
Ich habe eine Antwortfunktion für die Rails Tutorial-Erweiterung (Teil 2) erstellt: Modell ändern
Ich habe ein Programm zur Beurteilung von Primzahlen in Java erstellt
04. Ich habe mit SpringBoot + Thymeleaf ein Frontend gemacht
Ich habe Mosaikkunst mit Pokemon-Bildern gemacht
Ich habe selbst eine App gemacht! (Leseverwaltungs-App)
Ich habe eine Android-App für den MiRm-Dienst erstellt
Ich habe ein Janken-Spiel in Java (CLI) gemacht.
Ich habe eine Viewer-App erstellt, die PDF anzeigt
Ich habe einen Docker-Container erstellt, um Maven auszuführen
Ich habe eine Ruby-Erweiterungsbibliothek in C erstellt
Ich habe einen API-Client für Nature Remo erstellt
Ich habe eine einfache Grafikbibliothek für Smartphone-Apps erstellt [MP Android Chart Kai]
Ich habe einen LINE Bot mit Rails + Heroku gemacht
IntelliJ IDEA-Einstellungen
Ich habe versucht, den Profiler von IntelliJ IDEA zu verwenden
Ich habe mit Ruby On Rails ein Portfolio erstellt
Beachten Sie, dass ich von den Einstellungen des Android-Projekts von IntelliJ IDEA abhängig war
Ich habe ein einfaches Berechnungsproblemspiel in Java gemacht
[Ruby] Ich habe einen Crawler mit Anemone und Nokogiri gemacht.
Ich habe den neuen Feature-Profiler von IntelliJ IDEA 2019.2 ausprobiert.
Ich habe mit WebAssembly einen Zeichnungschat "8bit Paint Chat" erstellt
Ich habe versucht, das Docker Integration-Plug-In in IntelliJ zu installieren
Ich habe im Frühjahr einen Restful-Server und -Client erstellt.
Ich habe eine Bibliothek erstellt, die in Safari wie ein Tab funktioniert !!
Ich habe einen Wrapper erstellt, der KNP von Java aus aufruft
Ich möchte eine generische Anmerkung für einen Typ erstellen
[Java] Eine Technik zum Schreiben von Konstruktoren, Gettern und Setzern auf einmal mit IntelliJ IDEA.
Ich habe eine Antwortfunktion für die Erweiterung Rails Tutorial (Teil 4) erstellt: Eine Funktion, die den Benutzer einzigartig macht