我已经使用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'
谢谢。
答案 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'