从jar运行我的应用程序时,UI设计器抛出的NPE生成了JPanel

时间:2019-05-03 12:18:22

标签: java swing intellij-idea

我已经使用Intellij-IDEA的UI设计器构建了一个GUI应用程序,当我从IDE中运行它时,它可以正常工作。当我将应用程序打包到jar中并尝试使用Intelli-IDEA jar运行器运行它时,就会出现问题,它会抛出NPE。

我去看代码,发现这可能是初始化问题,因为用于我的应用程序的JPanel实际上是由UI Designer本身初始化的。问题出在初始化axUI的try块上。

package com.negassagisila.axeereraa;

import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class Axeereraa {
  private final String lookAndFeel;
  private final String appHome;
  private static final List<Note> notes = new ArrayList<>();
  private static File APP_HOME_FILE = null;
  private static AxeereraaUI axUI;
  private static String theSystem;

  private static String theFileSeparator;
  private static String theUserHome;

  private static String getTheSystem() {
    return theSystem;
  }

  private static String getTheFileSeparator() {
    return theFileSeparator;
  }

  private static String getTheUserHome() {
    return theUserHome;
  }

  String getLookAndFeel() {
      return lookAndFeel;
  }

  private String getAppHome() {
      return appHome;
  }

  public Axeereraa(String appHome, String lookAndFeel) {
    this.appHome = appHome;
    this.lookAndFeel = lookAndFeel;
  }

  public static void main(String[] args) {
    //TODO: create and instantiate a new concrete Note object for every UI instance
    //TODO: perhaps using a builder for the UI instance that will call a factory method for the Note object
    theSystem = System.getProperty("os.name");
    theFileSeparator = System.getProperty("file.separator");
    theUserHome = System.getProperty("user.home");

    String theLookAndFeel = UIManager.getSystemLookAndFeelClassName();

    String theAppHome = getAxEnvironment(getTheSystem(), getTheFileSeparator(), getTheUserHome());

    Axeereraa axRunner = new Axeereraa(theAppHome, theLookAndFeel);

    try {
      axUI = new AxeereraaUI(axRunner);
    } catch (IllegalAccessException |
            InstantiationException |
            ClassNotFoundException |
            UnsupportedLookAndFeelException |
            FontFormatException |
            NullPointerException|
            IOException e) {
      e.printStackTrace();
    }

    APP_HOME_FILE = new File(axRunner.getAppHome());

    /**
     * checks if the folder exists or not & if it's empty or not,
     * and creates it if it doesn't exist.
     */

    if (!APP_HOME_FILE.exists() || !APP_HOME_FILE.isDirectory()) {
      APP_HOME_FILE.mkdir();
      axUI.setNote(new Note("")).showAx();
    } else {
      displayExistingNotes(axRunner, theFileSeparator);
    }

  }

  /**
   * used to save a single Note instance
   */

  static void saveNote(Note n) {
    try {
      final String noteName = "Axeereraa".concat(String.valueOf(n.hashCode())).concat(".ser");
      new NoteSaver(new FileOutputStream(APP_HOME_FILE + theFileSeparator + noteName)).save(n);
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    }
  }

  /**
   * This method is used to load and display the
   * pre-existing notes that were already saved.
   * @param runner the Axeereraa object needed to set it up.
   */
  private static void displayExistingNotes(Axeereraa runner, String theFileSeparator) {
    List<Note> result;
    try {
      result = runner.getExistingNotes(theFileSeparator);
      for (Note n : result) {
        new AxeereraaUI(runner).setNote(n)
                .showAx();
      }
      if (result.isEmpty()) {
        axUI.setNote(new Note("")).showAx();
      }
    } catch (IllegalAccessException |
            InstantiationException |
            UnsupportedLookAndFeelException |
            ClassNotFoundException |
            NullPointerException |
            FontFormatException |
            IOException e) {
      e.printStackTrace();
    }
  }

  /**
   * This method is responsible for getting the system environment in which the applications
   * runs in.
   * @param theSystem name of the OS the application runs in
   * @param theFileSeparator the specific file separator of the OS
   * @param theUserHome the user folder in which the data will be saved in
   * @return a String that's comprised of the user home, the file separator,
   * application name & the file separator.
   */
  private static String getAxEnvironment(String theSystem, String theFileSeparator, String theUserHome) {
    String output;
    if (theSystem.startsWith("win")) {
      if (theSystem.contains("xp")) {
        output = System.getenv("APPDATA") + "\\.Axeereraa\\";
      } else {
        output = theUserHome + theFileSeparator + ".Axeereraa" + theFileSeparator;
      }
    } else {
      output = theUserHome + theFileSeparator + ".Axeereraa" + theFileSeparator;
    }

    return output;
  }

  /**
   * This method is responsible for getting the saved Notes from the file system.
   * It calls the read() from the NoteReader class.
   * @return a List\<Note\> populated with the saved Notes.
   * @throws FileNotFoundException if it can't find the folder in which the files are saved in.
   */
  private List<Note> getExistingNotes(String theFileSeparator) throws FileNotFoundException {
    File savedNotesLocation = new File(APP_HOME_FILE + theFileSeparator);
    for (File f: Objects.requireNonNull(savedNotesLocation.listFiles())) {
      NoteReader noteReader = new NoteReader(new FileInputStream(f));
      synchronized (notes) {
        try {
          notes.add(noteReader.read());
        } catch (IOException | ClassNotFoundException e) {
          e.printStackTrace();
        }
      }
    }

    return notes;
  }
}

下面将说明AxeereraaUI类,并在调用getContentPane().add(axRootPanel)时引发NPE;

package com.negassagisila.axeereraa;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;

//TODO: 7. run & test (currently no other option, sorry)

/**
 * The actual user interface for the Axeereraa application.
 */

public class AxeereraaUI extends JFrame {
  private JPanel axRootPanel;
  private JScrollPane axRootScrollPane;
  private JTextArea axRootTextArea;
  private JMenuBar axMenuBar;
  private Axeereraa axRunner;
  private static int COUNTER;
  private JPopupMenu rightClickOptions;

  /**
   * A constructor that runs every time a new Axeereraa note is needed or built
   */

  //TODO: find a way to create a new Note object whenever this constructor runs
  //especially if it's run from a saved file location

  public AxeereraaUI(Axeereraa axRunner) throws ClassNotFoundException, UnsupportedLookAndFeelException, InstantiationException, IllegalAccessException, IOException, FontFormatException {

    this.axRunner = axRunner;
    UIManager.setLookAndFeel(axRunner.getLookAndFeel());

    AxeereraaUI.this.setFont(
            Font.createFont(
                    Font.TRUETYPE_FONT,
                    Axeereraa.class.getResourceAsStream(
                            "/font/Roboto-Medium.ttf"
                    )
            )
    );

    setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

    getContentPane().add(axRootPanel);
    setSize(300, 250);
    setTitle("Axeereraa");

    buildUI();
    setJMenuBar(axMenuBar);

    AxeereraaUI.COUNTER++;
  }

  /**
   * This method is responsible for building the components of the UI like
   * the menu bar, the menu and it's options.
   */

  //TODO: how about adding a Note parameter to this method that builds the UI
  //it can get the existing notes as it builds the UI or
  //create a new Note object if there aren't any saved notes
  private void buildUI() throws IOException {
    axMenuBar = new JMenuBar();

    rightClickOptions = new JPopupMenu();

    axRootScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
    axRootScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

    axRootTextArea.addMouseListener(new RightClickOptions());

    axRootScrollPane.getVerticalScrollBar().setPreferredSize(
            new Dimension(3, Integer.MAX_VALUE));

    /**
     * as the name suggests this sets up the JMenus and their corresponding JMenuItems
     */
    SetUpMenuAndMenuItems setUpMenuAndMenuItems = new SetUpMenuAndMenuItems().invoke();
    JMenu fileMenu = setUpMenuAndMenuItems.getFileMenu();
    JMenu editMenu = setUpMenuAndMenuItems.getEditMenu();
    JMenu viewMenu = setUpMenuAndMenuItems.getViewMenu();
    JMenu helpMenu = setUpMenuAndMenuItems.getHelpMenu();

    /**
     * this adds all the above JMenus to the JMenuBar
     */

    axMenuBar.add(fileMenu);
    axMenuBar.add(editMenu);
    axMenuBar.add(viewMenu);
    axMenuBar.add(helpMenu);

    axRootTextArea.setLineWrap(true);
    axRootTextArea.setWrapStyleWord(true);

    /**
     * As the name suggests this sets up the right click options for the text area.
     */

    SetupRightClickOptions setupRightClickOptions = new SetupRightClickOptions().setup();
    JMenuItem selectAllRightClickMenuItem = setupRightClickOptions.getSelectAllRightClickMenuItem();
    JMenuItem copyRightClickMenuItem = setupRightClickOptions.getCopyRightClickMenuItem();
    JMenuItem pasteRightClickMenuItem = setupRightClickOptions.getPasteRightClickMenuItem();
    JMenuItem cutRightClickMenuItem = setupRightClickOptions.getCutRightClickMenuItem();
    JMenuItem markdownOption = setupRightClickOptions.getMarkdownOption();
    JMenu changeNoteColorMenu = setupRightClickOptions.getChangeNoteColorMenu();

    /**
     * adds all the declared JMenuItems to the right click popup menu.
     */

    rightClickOptions.add(selectAllRightClickMenuItem);
    rightClickOptions.add(copyRightClickMenuItem);
    rightClickOptions.add(pasteRightClickMenuItem);
    rightClickOptions.add(cutRightClickMenuItem);
    rightClickOptions.add(markdownOption);
    rightClickOptions.add(changeNoteColorMenu);

    AxeereraaUI.this.setIconImage(
            ImageIO.read(
                    this.getClass().getResource(
                            "/images/icon.png"
                    )
            )
    );
  }

  /**
   * This method is responsible for setting the Note to the UI when the previous Notes are loaded.
   * @param note the Note object that will be set to the UI.
   * @return the UI object that will be displayed.
   */

  AxeereraaUI setNote(Note note) {
    setAxRootTextAreaText(note.getWrittenText());
    setAxRootTexAreaColor(note.getNoteColor());
    return this;
  }

  /**
   * This method is responsible for setting the written text from the saved Note object.
   * @param text written text from the saved Note
   */

  private void setAxRootTextAreaText(String text) {
    axRootTextArea.setText(text);
  }

  /**
   * This method is responsible for setting the background color of the running instance
   * of the application from the saved Note object.
   * @param color the color from the saved Note
   */

  private void setAxRootTexAreaColor(Color color) {
    //axRootPanel.setBackground(color);
    axRootTextArea.setBackground(color);
  }

  /**
   * This method displays the GUI to the user on the Event Dispatcher Thread (EDT).
   */

  void showAx() {

    /**
     * This calls the EventQueue.invokeLater() method from the EventQueue class so as to run the
     * AxeereraaUI on the EDT.
     */

    EventQueue.invokeLater(() -> {
      try {
        buildUI();
        setLocationByPlatform(true);
        setVisible(true);
      } catch (IOException e) {
        e.printStackTrace();
      }
      }
    );
}

  /**
   * This method is used to get a single instance of the Note object from the UI
   * @return new Note(written text, NoteColor)
   */

  private Note getNote() {
    return new Note(this.axRootTextArea.getText(), this.getAxRooTextAreaColor(this.axRootTextArea.getBackground()));
  }

  /**
   * this method gets the note color from the TextArea background and returns it's equivalent
   * to the calling method as a NoteColor enum object.
   * @param axRootTextAreaBackgroundColor contains the color of the TextArea.
   * @return outputNoteColor is the NoteColor enum object.
   */

  private NoteColor getAxRooTextAreaColor(Color axRootTextAreaBackgroundColor) {
    NoteColor outputNoteColor;
    if (axRootTextAreaBackgroundColor.equals(NoteColor.getTheColorOfTheNote(NoteColor.lightGreen))) {
      outputNoteColor = NoteColor.lightGreen;
    } else if (axRootTextAreaBackgroundColor.equals(NoteColor.getTheColorOfTheNote(NoteColor.lightRed))) {
      outputNoteColor = NoteColor.lightRed;
    } else {
      outputNoteColor = NoteColor.lightYellow;
    }
    return outputNoteColor;
  }

  /**
   * This method is responsible for setting the application always on top
   * @param status boolean value to be passed to the instance of the UI.
   */

  private void stayOnTop(boolean status) {

    /**
     * called on every instance of the UI, method from the JFrame class.
     */

    this.setAlwaysOnTop(status);

    /**
     * changes the icon to lock to show that the result
     */

    displayLockIcon(status);
  }

  /**
   * changes the icon to lock to show that the result
   * @param status boolean value of that checks if the always on top has been set
   */

  private void displayLockIcon(boolean status) {
    //todo: find a way to display the lock.png image on the axRootPanel or axRootTextArea
    if (status) {
      try {
        Image lockIcon = ImageIO.read(this.getClass().getResource("/images/lock.png"));

      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }

  /**
   * This method is responsible for removing the deleted note from the UI
   */

  private void removeNote() {
    this.setVisible(false);
    AxeereraaUI.COUNTER--;
    //TODO: delete the Note file
    if (AxeereraaUI.COUNTER == 0) {
      System.exit(0);
    }
    //NoteDeleter.deleteNote();
  }

  /**
   * This method is responsible for displaying the markdown containing JEditorPane.
   * It calls the remove() method from the root scroll pane to remove the currently displayed
   * axRootTextArea and instead calls the add() method to insert the jEditorPane.
   * @param jEditorPane the editor pane that contains the markdown that will be displayed
   */
  private void showMarkdown(JEditorPane jEditorPane) {
    jEditorPane.addMouseListener(new RightClickOptions());
    this.axRootScrollPane.getViewport().remove(axRootTextArea);
    this.axRootScrollPane.getViewport().add(jEditorPane);
  }

  /**
   * This method is responsible for showing the raw text instead of the markdown.
   */
  private void showRawText() {
    this.axRootScrollPane.getViewport().add(axRootTextArea);
  }

  /**
   * This method creates and displays a JDialog that
   * contains the necessary info about the application.
   * @param titleOfDialog that will be passed to the JDialog setTitle() method.
   */
  private void displayDialog(String titleOfDialog) {
    String messageText = null;
    if (titleOfDialog.equals("About")) {
      messageText = "Axeereraa version 1.0.0\n" +
              "For more info \ngo to the github repo:\n" +
              "github.com/NegassaB/Axeereraa";
    } else if(titleOfDialog.equals("Contact")){
      messageText = "You can reach the developer via\n" +
              "email or using github.\n" +
              "negassab16@gmail.com\n" +
              "and github.com/NegassaB";
    }

    JOptionPane.showMessageDialog(
            AxeereraaUI.this,
            messageText,
            titleOfDialog,
            JOptionPane.INFORMATION_MESSAGE
    );
  }

  /**
   * This inner class is responsible for setting up the Menus and their items.
   * the entire text found in the
   * any selected text in the Axeereraa text area.
   */

  private class SetUpMenuAndMenuItems {
    private JMenu fileMenu;
    private JMenu editMenu;
    private JMenu viewMenu;
    private JMenu helpMenu;

    JMenu getFileMenu() {
      return fileMenu;
    }

    JMenu getEditMenu() {
      return editMenu;
    }

    JMenu getViewMenu() {
      return viewMenu;
    }

    JMenu getHelpMenu() {
      return helpMenu;
    }

    SetUpMenuAndMenuItems invoke() {
      fileMenu = new JMenu("file");
      editMenu = new JMenu("edit");
      viewMenu = new JMenu("view");
      helpMenu = new JMenu("help");

      JMenuItem[] fileMenuItems = new JMenuItem[3];
      fileMenuItems[0] = new JMenuItem("New Note");
      fileMenuItems[1] = new JMenuItem("Delete Note");
      fileMenuItems[2] = new JMenuItem("Save");

      fileMenuItems[0].addActionListener(e -> {
                try {
                  new AxeereraaUI(axRunner)
                          .setNote(new Note(""))
                          .showAx();
                } catch (UnsupportedLookAndFeelException |
                        IllegalAccessException |
                        ClassNotFoundException |
                        InstantiationException |
                        FontFormatException |
                        IOException ex) {
                  ex.printStackTrace();
                }
              }
      );
      fileMenuItems[1].addActionListener(e -> removeNote());
      fileMenuItems[2].addActionListener(e -> Axeereraa.saveNote(AxeereraaUI.this.getNote()));

      for(JMenuItem m : fileMenuItems) {
        fileMenu.add(m);
      }

      JMenuItem[] editMenuItems = new JMenuItem[4];
      editMenuItems[0] = new JMenuItem("Select All");
      editMenuItems[1] = new JMenuItem("Cut");
      editMenuItems[2] = new JMenuItem("Copy");
      editMenuItems[3] = new JMenuItem("Paste");

      editMenuItems[0].setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_MASK));
      editMenuItems[0].addActionListener(e -> axRootTextArea.selectAll());

      editMenuItems[1].setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_MASK));
      editMenuItems[1].addActionListener(e -> axRootTextArea.cut());

      editMenuItems[2].setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_MASK));
      editMenuItems[2].addActionListener(e -> axRootTextArea.copy());

      editMenuItems[3].setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_MASK));
      editMenuItems[3].addActionListener(e -> axRootTextArea.paste());

      for (JMenuItem m : editMenuItems) {
        editMenu.add(m);
      }

      JMenu previewMenu = new JMenu("preview");
      JMenuItem[] previewMenuItems = new JMenuItem[2];
      previewMenuItems[0] = new JMenuItem("show markdown");
      previewMenuItems[0].addActionListener(e -> showMarkdown(DisplayMarkdown.displayMarkdown(axRootTextArea.getText())));
      previewMenuItems[1] = new JMenuItem("show raw text");
      previewMenuItems[1].addActionListener(e -> showRawText());

      for (JMenuItem m : previewMenuItems) {
        previewMenu.add(m);
      }

      JMenu stayOnTopMenu = new JMenu("stay on top");
      JMenuItem alwaysOnTopItem = new JMenuItem("Always");
      JMenuItem neverOnTopItem = new JMenuItem("Never");

      alwaysOnTopItem.addActionListener(e -> stayOnTop(true));
      neverOnTopItem.addActionListener(e -> stayOnTop(false));

      stayOnTopMenu.add(alwaysOnTopItem);
      stayOnTopMenu.add(neverOnTopItem);

      viewMenu.add(previewMenu);
      viewMenu.add(stayOnTopMenu);

      JMenuItem[] helpMenuItems = new JMenuItem[2];
      helpMenuItems[0] = new JMenuItem("About");
      helpMenuItems[0].addActionListener(e -> displayDialog("About"));

      helpMenuItems[1] = new JMenuItem("Contact Developer");
      helpMenuItems[1].addActionListener(e -> displayDialog("Contact"));

      for (JMenuItem m : helpMenuItems) {
        helpMenu.add(m);
      }

      return this;
    }

  }

  /**
   * This class displays the right click options when the axRootTextArea is right clicked.
   */

  private class RightClickOptions extends MouseAdapter {

    @Override
    public void mousePressed(MouseEvent e) {
      showRightClickOptions(e);
    }

    private void showRightClickOptions(MouseEvent e) {
      if (e.isPopupTrigger()) {
        rightClickOptions.show(e.getComponent(), e.getX(), e.getY());
      }
    }
  }

  /**
   * This inner class is responsible for setting up all the necessary right click options
   * by using JPopupMenu. It's method @method setup() will conduct the necessary steps and
   * package it in the SetupRightClickOptions instance object.
   */

  private class SetupRightClickOptions {
    JMenuItem selectAllRightClickMenuItem;
    JMenuItem copyRightClickMenuItem;
    JMenuItem pasteRightClickMenuItem;
    JMenuItem cutRightClickMenuItem;
    JMenu markdownOption;
    JMenu changeNoteColorMenu;

    /**
     * This method is responsible for wiring up the necessary functionality of the JPopupMenu with
     * it's JMenuItems instantiated above. It will set the keyboard accelerators and the
     * ActionListeners for all the MenuItems.
     * @return this running instance of SetupRightClickOptions class
     */

    SetupRightClickOptions setup() {
      selectAllRightClickMenuItem = new JMenuItem("select all");
      copyRightClickMenuItem = new JMenuItem("copy");
      pasteRightClickMenuItem = new JMenuItem("paste");
      cutRightClickMenuItem = new JMenuItem("cut");
      markdownOption = new JMenu("preview");
      changeNoteColorMenu = new JMenu("change Color");

      selectAllRightClickMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_MASK));
      selectAllRightClickMenuItem.addActionListener(e -> axRootTextArea.selectAll());

      copyRightClickMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_MASK));
      copyRightClickMenuItem.addActionListener(e -> axRootTextArea.copy());

      pasteRightClickMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_MASK));
      pasteRightClickMenuItem.addActionListener(e -> axRootTextArea.paste());

      cutRightClickMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_MASK));
      cutRightClickMenuItem.addActionListener(e -> axRootTextArea.cut());

      JMenuItem[] noteColorMenuItems = new JMenuItem[3];
      noteColorMenuItems[0] = new JMenuItem("light green");
      noteColorMenuItems[1] = new JMenuItem("light yellow");
      noteColorMenuItems[2] = new JMenuItem("light red");

      noteColorMenuItems[0].addActionListener(e -> axRootTextArea.setBackground(
              NoteColor.getTheColorOfTheNote(NoteColor.lightGreen)
      ));

      noteColorMenuItems[1].addActionListener(e -> axRootTextArea.setBackground(
              NoteColor.getTheColorOfTheNote(NoteColor.lightYellow)
      ));

      noteColorMenuItems[2].addActionListener(e -> axRootTextArea.setBackground(
              NoteColor.getTheColorOfTheNote(NoteColor.lightRed)
      ));

      for (JMenuItem m : noteColorMenuItems) {
        changeNoteColorMenu.add(m);
      }

      JMenuItem[] markdownOptions = new JMenuItem[2];
      markdownOptions[0] = new JMenuItem("show markdown");
      markdownOptions[0].addActionListener(e -> showMarkdown(DisplayMarkdown.displayMarkdown(axRootTextArea.getText())));
      markdownOptions[1] = new JMenuItem("back to raw text");
      markdownOptions[1].addActionListener(e -> showRawText());

      for (JMenuItem m : markdownOptions) {
        markdownOption.add(m);
      }

      return this;
    }

    /**
     * Method used to get the selectAllRightClickMenuItem
     * @return selectAllRightClickMenuItem
     */

    JMenuItem getSelectAllRightClickMenuItem() {
      return selectAllRightClickMenuItem;
    }

    /**
     * Method used to get the copyRightClickMenuItem
     * @return copyRightClickMenuItem
     */

    JMenuItem getCopyRightClickMenuItem() {
      return copyRightClickMenuItem;
    }

    /**
     * Method used to get the pasteRightClickMenuItem
     * @return pasteRightClickMenuItem
     */

    JMenuItem getPasteRightClickMenuItem() {
      return pasteRightClickMenuItem;
    }

    /**
     * Method used to get the cutRightClickMenuItem
     * @return cutRightClickMenuItem
     */

    JMenuItem getCutRightClickMenuItem() {
      return cutRightClickMenuItem;
    }

    /**
     * Method used to get the markdownOption
     * @return markdownOption
     */

    JMenuItem getMarkdownOption() {
      return markdownOption;
    }

    /**
     * Method used to get the changeNoteColorMenu
     * @return changeNoteColorMenu
     */
    JMenu getChangeNoteColorMenu() {
      return changeNoteColorMenu;
    }
  }
}
/usr/local/java/jdk1.8.0_191/bin/java -Dfile.encoding=UTF-8 -jar /home/gadd/IntelliJIDEAProjects/Axeereraa/build/libs/Axeereraa-1.0-SNAPSHOT.jar
java.lang.NullPointerException
    at java.awt.Container.addImpl(Container.java:1095)
    at java.awt.Container.add(Container.java:419)
    at com.negassagisila.axeereraa.AxeereraaUI.<init>(AxeereraaUI.java:50)
    at com.negassagisila.axeereraa.Axeereraa.main(Axeereraa.java:60)

Process finished with exit code 1

我希望它像打包到罐子之前一样运行,即添加JPanel而不出现任何问题。我怎样才能做到这一点?或者,如何初始化UI设计师的Jpanel,即private JPanel axRootPanel,使其有效。哦,由于某种原因,我正在使用gradle脚本而不是Intellij自己的b / c来生成jar。如果有帮助,我将build.gralde文件放在下面。

plugins {
    id 'java'
}

jar {
    manifest {
        attributes 'Main-Class': 'com.negassagisila.axeereraa.Axeereraa'
    }

    from {
        configurations.compile.collect {it.isDirectory() ? it : zipTree(it)}
    }
}

version '1.0.0-SNAPSHOT'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
    jcenter()
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')

//    compile files("libs/annotations-16.0.2.jar")

    testImplementation 'org.mockito:mockito-core:2.1.0'
    testImplementation 'junit:junit:4.12'
    testImplementation 'org.hamcrest:hamcrest-all:1.3'

    compile 'com.vladsch.flexmark:flexmark-all:0.40.32'

}

apply plugin: 'java'

谢谢。

1 个答案:

答案 0 :(得分:1)

向其他可能遇到此问题的人,this is the solution。因此,如该答案所述,我更改了AxeereraaUI.java类,而不是将Dependecy设置为flatDir并指向rootDir,而是将文件复制到了自己的libs目录中,并在构建的dependencies部分中进行了说明。 .gradle。 AxeereraaUI类

package com.negassagisila.axeereraa;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;

//TODO: 7. run & test (currently no other option, sorry)

/**
 * The actual user interface for the Axeereraa application.
 */

public class AxeereraaUI extends JFrame {
  private JPanel axRootPanel;
  private JScrollPane axRootScrollPane;
  private JTextArea axRootTextArea;
  private JMenuBar axMenuBar;
  private Axeereraa axRunner;
  private static int COUNTER;
  private JPopupMenu rightClickOptions;

  /**
   * A constructor that runs every time a new Axeereraa note is needed or built
   */

  //TODO: find a way to create a new Note object whenever this constructor runs
  //especially if it's run from a saved file location
  public AxeereraaUI(Axeereraa axRunner) throws ClassNotFoundException, UnsupportedLookAndFeelException, InstantiationException, IllegalAccessException, IOException, FontFormatException {

    this.axRunner = axRunner;
    UIManager.setLookAndFeel(axRunner.getLookAndFeel());

    AxeereraaUI.this.setFont(
            Font.createFont(
                    Font.TRUETYPE_FONT,
                    Axeereraa.class.getResourceAsStream(
                            "/font/Roboto-Medium.ttf"
                    )
            )
    );

    setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

    getContentPane().add(axRootPanel);
    setSize(300, 250);
    setTitle("Axeereraa");

    buildUI();
    setJMenuBar(axMenuBar);

    AxeereraaUI.COUNTER++;
  }

  /**
   * This method is responsible for building the components of the UI like
   * the menu bar, the menu and it's options.
   */

  //TODO: how about adding a Note parameter to this method that builds the UI
  //it can get the existing notes as it builds the UI or
  //create a new Note object if there aren't any saved notes
  private void buildUI() throws IOException {
    axMenuBar = new JMenuBar();

    rightClickOptions = new JPopupMenu();

    axRootScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
    axRootScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

    axRootTextArea.addMouseListener(new RightClickOptions());

    axRootScrollPane.getVerticalScrollBar().setPreferredSize(
            new Dimension(3, Integer.MAX_VALUE));

    /**
     * as the name suggests this sets up the JMenus and their corresponding JMenuItems
     */
    SetUpMenuAndMenuItems setUpMenuAndMenuItems = new SetUpMenuAndMenuItems().invoke();
    JMenu fileMenu = setUpMenuAndMenuItems.getFileMenu();
    JMenu editMenu = setUpMenuAndMenuItems.getEditMenu();
    JMenu viewMenu = setUpMenuAndMenuItems.getViewMenu();
    JMenu helpMenu = setUpMenuAndMenuItems.getHelpMenu();

    /**
     * this adds all the above JMenus to the JMenuBar
     */

    axMenuBar.add(fileMenu);
    axMenuBar.add(editMenu);
    axMenuBar.add(viewMenu);
    axMenuBar.add(helpMenu);

    axRootTextArea.setLineWrap(true);
    axRootTextArea.setWrapStyleWord(true);

    /**
     * As the name suggests this sets up the right click options for the text area.
     */

    SetupRightClickOptions setupRightClickOptions = new SetupRightClickOptions().setup();
    JMenuItem selectAllRightClickMenuItem = setupRightClickOptions.getSelectAllRightClickMenuItem();
    JMenuItem copyRightClickMenuItem = setupRightClickOptions.getCopyRightClickMenuItem();
    JMenuItem pasteRightClickMenuItem = setupRightClickOptions.getPasteRightClickMenuItem();
    JMenuItem cutRightClickMenuItem = setupRightClickOptions.getCutRightClickMenuItem();
    JMenuItem markdownOption = setupRightClickOptions.getMarkdownOption();
    JMenu changeNoteColorMenu = setupRightClickOptions.getChangeNoteColorMenu();

    /**
     * adds all the declared JMenuItems to the right click popup menu.
     */

    rightClickOptions.add(selectAllRightClickMenuItem);
    rightClickOptions.add(copyRightClickMenuItem);
    rightClickOptions.add(pasteRightClickMenuItem);
    rightClickOptions.add(cutRightClickMenuItem);
    rightClickOptions.add(markdownOption);
    rightClickOptions.add(changeNoteColorMenu);

    AxeereraaUI.this.setIconImage(
            ImageIO.read(
                    this.getClass().getResource(
                            "/images/icon.png"
                    )
            )
    );
  }

  /**
   * This method is responsible for setting the Note to the UI when the previous Notes are loaded.
   *
   * @param note the Note object that will be set to the UI.
   * @return the UI object that will be displayed.
   */

  AxeereraaUI setNote(Note note) {
    setAxRootTextAreaText(note.getWrittenText());
    setAxRootTexAreaColor(note.getNoteColor());
    return this;
  }

  /**
   * This method is responsible for setting the written text from the saved Note object.
   *
   * @param text written text from the saved Note
   */

  private void setAxRootTextAreaText(String text) {
    axRootTextArea.setText(text);
  }

  /**
   * This method is responsible for setting the background color of the running instance
   * of the application from the saved Note object.
   *
   * @param color the color from the saved Note
   */

  private void setAxRootTexAreaColor(Color color) {
    //axRootPanel.setBackground(color);
    axRootTextArea.setBackground(color);
  }

  /**
   * This method displays the GUI to the user on the Event Dispatcher Thread (EDT).
   */

  void showAx() {

    /**
     * This calls the EventQueue.invokeLater() method from the EventQueue class so as to run the
     * AxeereraaUI on the EDT.
     */

    EventQueue.invokeLater(() -> {
              try {
                buildUI();
                setLocationByPlatform(true);
                setVisible(true);
              } catch (IOException e) {
                e.printStackTrace();
              }
            }
    );
  }

  /**
   * This method is used to get a single instance of the Note object from the UI
   *
   * @return new Note(written text, NoteColor)
   */

  private Note getNote() {
    return new Note(this.axRootTextArea.getText(), this.getAxRooTextAreaColor(this.axRootTextArea.getBackground()));
  }

  /**
   * this method gets the note color from the TextArea background and returns it's equivalent
   * to the calling method as a NoteColor enum object.
   *
   * @param axRootTextAreaBackgroundColor contains the color of the TextArea.
   * @return outputNoteColor is the NoteColor enum object.
   */

  private NoteColor getAxRooTextAreaColor(Color axRootTextAreaBackgroundColor) {
    NoteColor outputNoteColor;
    if (axRootTextAreaBackgroundColor.equals(NoteColor.getTheColorOfTheNote(NoteColor.lightGreen))) {
      outputNoteColor = NoteColor.lightGreen;
    } else if (axRootTextAreaBackgroundColor.equals(NoteColor.getTheColorOfTheNote(NoteColor.lightRed))) {
      outputNoteColor = NoteColor.lightRed;
    } else {
      outputNoteColor = NoteColor.lightYellow;
    }
    return outputNoteColor;
  }

  /**
   * This method is responsible for setting the application always on top
   *
   * @param status boolean value to be passed to the instance of the UI.
   */

  private void stayOnTop(boolean status) {

    /**
     * called on every instance of the UI, method from the JFrame class.
     */

    this.setAlwaysOnTop(status);

    /**
     * changes the icon to lock to show that the result
     */

    displayLockIcon(status);
  }

  /**
   * changes the icon to lock to show that the result
   *
   * @param status boolean value of that checks if the always on top has been set
   */

  private void displayLockIcon(boolean status) {
    //todo: find a way to display the lock.png image on the axRootPanel or axRootTextArea
    if (status) {
      try {
        Image lockIcon = ImageIO.read(this.getClass().getResource("/images/lock.png"));

      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }

  /**
   * This method is responsible for removing the deleted note from the UI
   */

  private void removeNote() {
    this.setVisible(false);
    AxeereraaUI.COUNTER--;
    //TODO: delete the Note file
    if (AxeereraaUI.COUNTER == 0) {
      System.exit(0);
    }
    //NoteDeleter.deleteNote();
  }

  /**
   * This method is responsible for displaying the markdown containing JEditorPane.
   * It calls the remove() method from the root scroll pane to remove the currently displayed
   * axRootTextArea and instead calls the add() method to insert the jEditorPane.
   *
   * @param jEditorPane the editor pane that contains the markdown that will be displayed
   */
  private void showMarkdown(JEditorPane jEditorPane) {
    jEditorPane.addMouseListener(new RightClickOptions());
    this.axRootScrollPane.getViewport().remove(axRootTextArea);
    this.axRootScrollPane.getViewport().add(jEditorPane);
  }

  /**
   * This method is responsible for showing the raw text instead of the markdown.
   */
  private void showRawText() {
    this.axRootScrollPane.getViewport().add(axRootTextArea);
  }

  /**
   * This method creates and displays a JDialog that
   * contains the necessary info about the application.
   *
   * @param titleOfDialog that will be passed to the JDialog setTitle() method.
   */
  private void displayDialog(String titleOfDialog) {
    String messageText = null;
    if (titleOfDialog.equals("About")) {
      messageText = "Axeereraa version 1.0.0\n" +
              "For more info \ngo to the github repo:\n" +
              "github.com/NegassaB/Axeereraa";
    } else if (titleOfDialog.equals("Contact")) {
      messageText = "You can reach the developer via\n" +
              "email or using github.\n" +
              "negassab16@gmail.com\n" +
              "and github.com/NegassaB";
    }

    JOptionPane.showMessageDialog(
            AxeereraaUI.this,
            messageText,
            titleOfDialog,
            JOptionPane.INFORMATION_MESSAGE
    );
  }

  {
// GUI initializer generated by IntelliJ IDEA GUI Designer
// >>> IMPORTANT!! <<<
// DO NOT EDIT OR ADD ANY CODE HERE!
    $$$setupUI$$$();
  }

  /**
   * Method generated by IntelliJ IDEA GUI Designer
   * >>> IMPORTANT!! <<<
   * DO NOT edit this method OR call it in your code!
   *
   * @noinspection ALL
   */
  private void $$$setupUI$$$() {
    axRootPanel = new JPanel();
    axRootPanel.setLayout(new com.intellij.uiDesigner.core.GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1));
    axRootScrollPane = new JScrollPane();
    axRootScrollPane.setEnabled(true);
    axRootScrollPane.setVisible(true);
    axRootPanel.add(axRootScrollPane, new com.intellij.uiDesigner.core.GridConstraints(0, 0, 1, 1, com.intellij.uiDesigner.core.GridConstraints.ANCHOR_CENTER, com.intellij.uiDesigner.core.GridConstraints.FILL_BOTH, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_SHRINK | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_WANT_GROW, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_SHRINK | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
    axRootTextArea = new JTextArea();
    axRootTextArea.setLineWrap(true);
    axRootTextArea.setVisible(true);
    axRootScrollPane.setViewportView(axRootTextArea);
  }

  /**
   * @noinspection ALL
   */
  public JComponent $$$getRootComponent$$$() {
    return axRootPanel;
  }

  /**
   * This inner class is responsible for setting up the Menus and their items.
   * the entire text found in the
   * any selected text in the Axeereraa text area.
   */

  private class SetUpMenuAndMenuItems {
    private JMenu fileMenu;
    private JMenu editMenu;
    private JMenu viewMenu;
    private JMenu helpMenu;

    JMenu getFileMenu() {
      return fileMenu;
    }

    JMenu getEditMenu() {
      return editMenu;
    }

    JMenu getViewMenu() {
      return viewMenu;
    }

    JMenu getHelpMenu() {
      return helpMenu;
    }

    SetUpMenuAndMenuItems invoke() {
      fileMenu = new JMenu("file");
      editMenu = new JMenu("edit");
      viewMenu = new JMenu("view");
      helpMenu = new JMenu("help");

      JMenuItem[] fileMenuItems = new JMenuItem[3];
      fileMenuItems[0] = new JMenuItem("New Note");
      fileMenuItems[1] = new JMenuItem("Delete Note");
      fileMenuItems[2] = new JMenuItem("Save");

      fileMenuItems[0].addActionListener(e -> {
                try {
                  new AxeereraaUI(axRunner)
                          .setNote(new Note(""))
                          .showAx();
                } catch (UnsupportedLookAndFeelException |
                        IllegalAccessException |
                        ClassNotFoundException |
                        InstantiationException |
                        FontFormatException |
                        IOException ex) {
                  ex.printStackTrace();
                }
              }
      );
      fileMenuItems[1].addActionListener(e -> removeNote());
      fileMenuItems[2].addActionListener(e -> Axeereraa.saveNote(AxeereraaUI.this.getNote()));

      for (JMenuItem m : fileMenuItems) {
        fileMenu.add(m);
      }

      JMenuItem[] editMenuItems = new JMenuItem[4];
      editMenuItems[0] = new JMenuItem("Select All");
      editMenuItems[1] = new JMenuItem("Cut");
      editMenuItems[2] = new JMenuItem("Copy");
      editMenuItems[3] = new JMenuItem("Paste");

      editMenuItems[0].setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_MASK));
      editMenuItems[0].addActionListener(e -> axRootTextArea.selectAll());

      editMenuItems[1].setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_MASK));
      editMenuItems[1].addActionListener(e -> axRootTextArea.cut());

      editMenuItems[2].setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_MASK));
      editMenuItems[2].addActionListener(e -> axRootTextArea.copy());

      editMenuItems[3].setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_MASK));
      editMenuItems[3].addActionListener(e -> axRootTextArea.paste());

      for (JMenuItem m : editMenuItems) {
        editMenu.add(m);
      }

      JMenu previewMenu = new JMenu("preview");
      JMenuItem[] previewMenuItems = new JMenuItem[2];
      previewMenuItems[0] = new JMenuItem("show markdown");
      previewMenuItems[0].addActionListener(e -> showMarkdown(DisplayMarkdown.displayMarkdown(axRootTextArea.getText())));
      previewMenuItems[1] = new JMenuItem("show raw text");
      previewMenuItems[1].addActionListener(e -> showRawText());

      for (JMenuItem m : previewMenuItems) {
        previewMenu.add(m);
      }

      JMenu stayOnTopMenu = new JMenu("stay on top");
      JMenuItem alwaysOnTopItem = new JMenuItem("Always");
      JMenuItem neverOnTopItem = new JMenuItem("Never");

      alwaysOnTopItem.addActionListener(e -> stayOnTop(true));
      neverOnTopItem.addActionListener(e -> stayOnTop(false));

      stayOnTopMenu.add(alwaysOnTopItem);
      stayOnTopMenu.add(neverOnTopItem);

      viewMenu.add(previewMenu);
      viewMenu.add(stayOnTopMenu);

      JMenuItem[] helpMenuItems = new JMenuItem[2];
      helpMenuItems[0] = new JMenuItem("About");
      helpMenuItems[0].addActionListener(e -> displayDialog("About"));

      helpMenuItems[1] = new JMenuItem("Contact Developer");
      helpMenuItems[1].addActionListener(e -> displayDialog("Contact"));

      for (JMenuItem m : helpMenuItems) {
        helpMenu.add(m);
      }

      return this;
    }

  }

  /**
   * This class displays the right click options when the axRootTextArea is right clicked.
   */

  private class RightClickOptions extends MouseAdapter {

    @Override
    public void mousePressed(MouseEvent e) {
      showRightClickOptions(e);
    }

    private void showRightClickOptions(MouseEvent e) {
      if (e.isPopupTrigger()) {
        rightClickOptions.show(e.getComponent(), e.getX(), e.getY());
      }
    }
  }

  /**
   * This inner class is responsible for setting up all the necessary right click options
   * by using JPopupMenu. It's method @method setup() will conduct the necessary steps and
   * package it in the SetupRightClickOptions instance object.
   */

  private class SetupRightClickOptions {
    JMenuItem selectAllRightClickMenuItem;
    JMenuItem copyRightClickMenuItem;
    JMenuItem pasteRightClickMenuItem;
    JMenuItem cutRightClickMenuItem;
    JMenu markdownOption;
    JMenu changeNoteColorMenu;

    /**
     * This method is responsible for wiring up the necessary functionality of the JPopupMenu with
     * it's JMenuItems instantiated above. It will set the keyboard accelerators and the
     * ActionListeners for all the MenuItems.
     *
     * @return this running instance of SetupRightClickOptions class
     */

    SetupRightClickOptions setup() {
      selectAllRightClickMenuItem = new JMenuItem("select all");
      copyRightClickMenuItem = new JMenuItem("copy");
      pasteRightClickMenuItem = new JMenuItem("paste");
      cutRightClickMenuItem = new JMenuItem("cut");
      markdownOption = new JMenu("preview");
      changeNoteColorMenu = new JMenu("change Color");

      selectAllRightClickMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_MASK));
      selectAllRightClickMenuItem.addActionListener(e -> axRootTextArea.selectAll());

      copyRightClickMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_MASK));
      copyRightClickMenuItem.addActionListener(e -> axRootTextArea.copy());

      pasteRightClickMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_MASK));
      pasteRightClickMenuItem.addActionListener(e -> axRootTextArea.paste());

      cutRightClickMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_MASK));
      cutRightClickMenuItem.addActionListener(e -> axRootTextArea.cut());

      JMenuItem[] noteColorMenuItems = new JMenuItem[3];
      noteColorMenuItems[0] = new JMenuItem("light green");
      noteColorMenuItems[1] = new JMenuItem("light yellow");
      noteColorMenuItems[2] = new JMenuItem("light red");

      noteColorMenuItems[0].addActionListener(e -> axRootTextArea.setBackground(
              NoteColor.getTheColorOfTheNote(NoteColor.lightGreen)
      ));

      noteColorMenuItems[1].addActionListener(e -> axRootTextArea.setBackground(
              NoteColor.getTheColorOfTheNote(NoteColor.lightYellow)
      ));

      noteColorMenuItems[2].addActionListener(e -> axRootTextArea.setBackground(
              NoteColor.getTheColorOfTheNote(NoteColor.lightRed)
      ));

      for (JMenuItem m : noteColorMenuItems) {
        changeNoteColorMenu.add(m);
      }

      JMenuItem[] markdownOptions = new JMenuItem[2];
      markdownOptions[0] = new JMenuItem("show markdown");
      markdownOptions[0].addActionListener(e -> showMarkdown(DisplayMarkdown.displayMarkdown(axRootTextArea.getText())));
      markdownOptions[1] = new JMenuItem("back to raw text");
      markdownOptions[1].addActionListener(e -> showRawText());

      for (JMenuItem m : markdownOptions) {
        markdownOption.add(m);
      }

      return this;
    }

    /**
     * Method used to get the selectAllRightClickMenuItem
     * @return selectAllRightClickMenuItem
     */

    JMenuItem getSelectAllRightClickMenuItem() {
      return selectAllRightClickMenuItem;
    }

    /**
     * Method used to get the copyRightClickMenuItem
     * @return copyRightClickMenuItem
     */

    JMenuItem getCopyRightClickMenuItem() {
      return copyRightClickMenuItem;
    }

    /**
     * Method used to get the pasteRightClickMenuItem
     * @return pasteRightClickMenuItem
     */

    JMenuItem getPasteRightClickMenuItem() {
      return pasteRightClickMenuItem;
    }

    /**
     * Method used to get the cutRightClickMenuItem
     * @return cutRightClickMenuItem
     */

    JMenuItem getCutRightClickMenuItem() {
      return cutRightClickMenuItem;
    }

    /**
     * Method used to get the markdownOption
     * @return markdownOption
     */

    JMenuItem getMarkdownOption() {
      return markdownOption;
    }

    /**
     * Method used to get the changeNoteColorMenu
     * @return changeNoteColorMenu
     */
    JMenu getChangeNoteColorMenu() {
      return changeNoteColorMenu;
    }
  }

}

和build.gradle文件

plugins {
    id 'java'
}

jar {
    manifest {
        attributes 'Main-Class': 'com.negassagisila.axeereraa.Axeereraa'
    }

    from {
        configurations.compile.collect {it.isDirectory() ? it : zipTree(it)}
    }
}

version '1.0.0-SNAPSHOT'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
    jcenter()
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')

    compile files("libs/forms_rt.jar")

    testImplementation 'org.mockito:mockito-core:2.1.0'
    testImplementation 'junit:junit:4.12'
    testImplementation 'org.hamcrest:hamcrest-all:1.3'

    compile 'com.vladsch.flexmark:flexmark-all:0.40.32'
}

apply plugin: 'java'