动作初始化的区别
Difference in Action initialization
我尝试创建程序,其中 Action 的 class 是一个 class 的内部 class,但其对象的初始化发生在另一个 class ,但是我总是遇到异常。下面我展示了我的问题的简化模型:
有一个 class 构建 GUI 并包含 Action 的内部 class:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
public class SomeClass {
JTextArea area;
public static void main(String[] args){
SomeClass outerAction = new SomeClass();
outerAction.go();
}
public void go(){
JFrame frame = new JFrame();
area = new JTextArea(5,10);
JToolBar toolBar = new JToolBar(SwingConstants.HORIZONTAL);
CreateAction createAction = new CreateAction();
JButton button1 = new JButton(innerGetAction());
JButton button2 = new JButton(createAction.otherGetAction());
toolBar.add(button1);
toolBar.add(button2);
frame.getContentPane().add(BorderLayout.PAGE_START,toolBar);
frame.getContentPane().add(BorderLayout.CENTER,area);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public Action innerGetAction(){
Action action = new SomeAction("DO","Do sth",KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_MASK));
return action;
}
public class SomeAction extends AbstractAction{
public SomeAction(String name, String desc, KeyStroke key){
super(name);
putValue(SHORT_DESCRIPTION,desc);
putValue(ACCELERATOR_KEY,key);
}
public void actionPerformed(ActionEvent e) {
area.setText("Done");
}
}
}
有两个具有相同 Action 的 JButton,但是首先初始化出现在 SomeClass 中,另一个出现在单独的 CreateActionClass 中:
import javax.swing.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
public class CreateAction {
public static Action otherGetAction(){
Action action = new SomeClass().new SomeAction("DO","Do sth",KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_MASK));
return action;
}
}
一个按钮工作正常,另一个按钮出现异常。我不明白为什么。
你能告诉我吗:
- 为什么在 class CreateAction 中初始化的 Action 无法访问 SomeClass 的字段?
如果getAction是SomeClass的一个方法,一切都ok,可以修改JTextArea,但是当是CreateAction的一个方法时,就有一个java.lang.NullPointerException。有什么区别?
- 在不同于 class 的 Action class 中初始化 Action 对象并放置构造函数是否有意义?
请原谅我这个可悲的例子。
堆栈跟踪:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at SomeClass$SomeAction.actionPerformed(SomeClass.java:40)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2346)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:289)
at java.awt.Component.processMouseEvent(Component.java:6525)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3321)
at java.awt.Component.processEvent(Component.java:6290)
at java.awt.Container.processEvent(Container.java:2234)
at java.awt.Component.dispatchEventImpl(Component.java:4881)
at java.awt.Container.dispatchEventImpl(Container.java:2292)
at java.awt.Component.dispatchEvent(Component.java:4703)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4898)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4533)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4462)
at java.awt.Container.dispatchEventImpl(Container.java:2278)
at java.awt.Window.dispatchEventImpl(Window.java:2739)
at java.awt.Component.dispatchEvent(Component.java:4703)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:746)
at java.awt.EventQueue.access0(EventQueue.java:97)
at java.awt.EventQueue.run(EventQueue.java:697)
at java.awt.EventQueue.run(EventQueue.java:691)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain.doIntersectionPrivilege(ProtectionDomain.java:75)
at java.security.ProtectionDomain.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.awt.EventQueue.run(EventQueue.java:719)
at java.awt.EventQueue.run(EventQueue.java:717)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain.doIntersectionPrivilege(ProtectionDomain.java:75)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:716)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
您收到 NullPointerException,因为您在此处使用错误的 SomeClass 来创建操作:
Action action = new SomeClass().new SomeAction("DO", "Do sth",
KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_MASK));
这个new SomeClass()
不是显示的SomeClass!
而是考虑传入可视化对象。
public static Action otherGetAction(SomeClass someClass) {
return someClass.new SomeAction("DO", "Do sth",
KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_MASK));
}
如果您打算在 GUI 之外设置操作,请考虑将其从 GUI 中分离出来。例如:
import java.awt.event.ActionEvent;
import javax.swing.*;
public class Test2 extends JPanel implements Fooable {
private JTextField field = new JTextField(10);
private JTextArea textarea = new JTextArea(20, 30);
private JButton button = new JButton();
public Test2() {
textarea.setFocusable(false);
JScrollPane scrollPane = new JScrollPane(textarea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
add(field);
add(scrollPane);
add(button);
}
public void setActions(Action action) {
button.setAction(action);
field.setAction(action);
}
@Override
public String getFieldText() {
field.selectAll();
return field.getText();
}
@Override
public void appendText(String text) {
textarea.append(text + "\n");
}
private static void createAndShowGui() {
Test2 mainPanel = new Test2();
Action myAction = new MyAction("Press Me", KeyEvent.VK_P, mainPanel);
mainPanel.setActions(myAction);
JFrame frame = new JFrame("Test2");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
interface Fooable {
String getFieldText();
void appendText(String text);
}
class MyAction extends AbstractAction {
private Fooable fooable;
public MyAction(String name, int mnemonic, Fooable fooable) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
this.fooable = fooable;
}
@Override
public void actionPerformed(ActionEvent e) {
if (fooable != null) {
fooable.appendText(fooable.getFieldText());
}
}
}
我尝试创建程序,其中 Action 的 class 是一个 class 的内部 class,但其对象的初始化发生在另一个 class ,但是我总是遇到异常。下面我展示了我的问题的简化模型:
有一个 class 构建 GUI 并包含 Action 的内部 class:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
public class SomeClass {
JTextArea area;
public static void main(String[] args){
SomeClass outerAction = new SomeClass();
outerAction.go();
}
public void go(){
JFrame frame = new JFrame();
area = new JTextArea(5,10);
JToolBar toolBar = new JToolBar(SwingConstants.HORIZONTAL);
CreateAction createAction = new CreateAction();
JButton button1 = new JButton(innerGetAction());
JButton button2 = new JButton(createAction.otherGetAction());
toolBar.add(button1);
toolBar.add(button2);
frame.getContentPane().add(BorderLayout.PAGE_START,toolBar);
frame.getContentPane().add(BorderLayout.CENTER,area);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public Action innerGetAction(){
Action action = new SomeAction("DO","Do sth",KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_MASK));
return action;
}
public class SomeAction extends AbstractAction{
public SomeAction(String name, String desc, KeyStroke key){
super(name);
putValue(SHORT_DESCRIPTION,desc);
putValue(ACCELERATOR_KEY,key);
}
public void actionPerformed(ActionEvent e) {
area.setText("Done");
}
}
}
有两个具有相同 Action 的 JButton,但是首先初始化出现在 SomeClass 中,另一个出现在单独的 CreateActionClass 中:
import javax.swing.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
public class CreateAction {
public static Action otherGetAction(){
Action action = new SomeClass().new SomeAction("DO","Do sth",KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_MASK));
return action;
}
}
一个按钮工作正常,另一个按钮出现异常。我不明白为什么。
你能告诉我吗:
- 为什么在 class CreateAction 中初始化的 Action 无法访问 SomeClass 的字段? 如果getAction是SomeClass的一个方法,一切都ok,可以修改JTextArea,但是当是CreateAction的一个方法时,就有一个java.lang.NullPointerException。有什么区别?
- 在不同于 class 的 Action class 中初始化 Action 对象并放置构造函数是否有意义?
请原谅我这个可悲的例子。
堆栈跟踪:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException at SomeClass$SomeAction.actionPerformed(SomeClass.java:40) at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022) at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2346) at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402) at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259) at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252) at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:289) at java.awt.Component.processMouseEvent(Component.java:6525) at javax.swing.JComponent.processMouseEvent(JComponent.java:3321) at java.awt.Component.processEvent(Component.java:6290) at java.awt.Container.processEvent(Container.java:2234) at java.awt.Component.dispatchEventImpl(Component.java:4881) at java.awt.Container.dispatchEventImpl(Container.java:2292) at java.awt.Component.dispatchEvent(Component.java:4703) at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4898) at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4533) at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4462) at java.awt.Container.dispatchEventImpl(Container.java:2278) at java.awt.Window.dispatchEventImpl(Window.java:2739) at java.awt.Component.dispatchEvent(Component.java:4703) at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:746) at java.awt.EventQueue.access0(EventQueue.java:97) at java.awt.EventQueue.run(EventQueue.java:697) at java.awt.EventQueue.run(EventQueue.java:691) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain.doIntersectionPrivilege(ProtectionDomain.java:75) at java.security.ProtectionDomain.doIntersectionPrivilege(ProtectionDomain.java:86) at java.awt.EventQueue.run(EventQueue.java:719) at java.awt.EventQueue.run(EventQueue.java:717) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain.doIntersectionPrivilege(ProtectionDomain.java:75) at java.awt.EventQueue.dispatchEvent(EventQueue.java:716) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93) at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
您收到 NullPointerException,因为您在此处使用错误的 SomeClass 来创建操作:
Action action = new SomeClass().new SomeAction("DO", "Do sth",
KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_MASK));
这个new SomeClass()
不是显示的SomeClass!
而是考虑传入可视化对象。
public static Action otherGetAction(SomeClass someClass) {
return someClass.new SomeAction("DO", "Do sth",
KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_MASK));
}
如果您打算在 GUI 之外设置操作,请考虑将其从 GUI 中分离出来。例如:
import java.awt.event.ActionEvent;
import javax.swing.*;
public class Test2 extends JPanel implements Fooable {
private JTextField field = new JTextField(10);
private JTextArea textarea = new JTextArea(20, 30);
private JButton button = new JButton();
public Test2() {
textarea.setFocusable(false);
JScrollPane scrollPane = new JScrollPane(textarea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
add(field);
add(scrollPane);
add(button);
}
public void setActions(Action action) {
button.setAction(action);
field.setAction(action);
}
@Override
public String getFieldText() {
field.selectAll();
return field.getText();
}
@Override
public void appendText(String text) {
textarea.append(text + "\n");
}
private static void createAndShowGui() {
Test2 mainPanel = new Test2();
Action myAction = new MyAction("Press Me", KeyEvent.VK_P, mainPanel);
mainPanel.setActions(myAction);
JFrame frame = new JFrame("Test2");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
interface Fooable {
String getFieldText();
void appendText(String text);
}
class MyAction extends AbstractAction {
private Fooable fooable;
public MyAction(String name, int mnemonic, Fooable fooable) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
this.fooable = fooable;
}
@Override
public void actionPerformed(ActionEvent e) {
if (fooable != null) {
fooable.appendText(fooable.getFieldText());
}
}
}