When I run my program I get this error nullPointerException: null.
import model.*;
import java.awt.*;
import java.awt.event.*;
import java.text.*;
import javax.swing.*;
public class ButtonPanel extends JPanel implements View
{
private Prison prison;
private LeftInputPanel leftInput;
private DaysPanel days;
private MonthsPanel months;
private YearsPanel years;
private CrimePanel crime;
private AllocateListener aListener;
public ButtonPanel()
{
setup();
build();
}
public void setup()
{
}
public void build()
{
JButton button = new JButton("Allocate Cell");
Dimension size = new Dimension(240, 70);
button.setPreferredSize(size);
button.setMinimumSize(size);
button.setMaximumSize(size);
button.addActionListener(aListener);
add(button);
update();
}
public void update()
{
leftInput.update(); //ERROR ON THIS LINE
}
private class AllocateListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
Criminal criminal = new Criminal(leftInput.name());
Period period = new Period(days.days(), months.months(), years.years());
criminal.set(new Crime(crime.getCrime()));
prison.add(criminal);
}
}
}
My LeftInputPanel - where I call the update method from.
import model.*;
import java.awt.*;
import java.text.*;
import javax.swing.*;
public class LeftInputPanel extends JPanel
{
public JTextField field = new JTextField();
public LeftInputPanel()
{
setup();
build();
}
public void setup()
{
//setLayout(new GridLayout());
Dimension size = new Dimension(100, 190);
setPreferredSize(size);
setMinimumSize(size);
setMaximumSize(size);
}
public void build()
{
setLayout(new FlowLayout(FlowLayout.LEFT));
JLabel label = new JLabel(" Name");
field.setPreferredSize(new Dimension(90, 20));
add(label);
add(field);
add(new DaysPanel());
add(new MonthsPanel());
add(new YearsPanel());
}
public String name()
{
return field.getText();
}
public void update()
{
field.setText("");
}
}
Errors
java.lang.NullPointerException
at ButtonPanel.update(ButtonPanel.java:43)
at ButtonPanel.build(ButtonPanel.java:38)
at ButtonPanel.<init>(ButtonPanel.java:21)
at RightInputPanel.build(RightInputPanel.java:30)
at RightInputPanel.<init>(RightInputPanel.java:14)
at InputPanel.build(InputPanel.java:24)
at InputPanel.<init>(InputPanel.java:13)
at Panel.build(Panel.java:30)
at Panel.<init>(Panel.java:13)
at Window.build(Window.java:31)
at Window.<init>(Window.java:11)
at Root.main(Root.java:9)
aListener hasn't been initialized (ie it is still null) and you're trying to add it as an action listener. I suspect all that's required is:
private AllocateListener aListener = new AllocateListener();
When you get an exception, you generally get a stack trace, including the full call sequence - that's an invaluable help in tracking down the problem.
If you cannot figure out the problem from that stack trace, you need to supply it to us along with the relevant code, with line numbers.
Then we'll be better able to help you out by finding the problem and, more importantly, showing you how it's done.
Related
Here is the code I currently have:
public String getLength()
{
return lengthEntry.getText();
}
And in another class:
public class Main {
public static void main(String[] args) {
GUI userInterface = new GUI();
System.out.print(userInterface.getLength());
}
}
This is just a single print statement though, so it only prints the initial value of whatever is in the text field, nothing after. Is there a way I could write a loop in the main method that, while the program is running, prints the value in the text field when the user hits enter? I know I could put the print statement in the actionPerformed method, but then what's the point of the getLength() method if I can't use an object in another class to call it and get relevant information at any point when the program is running? I'm just looking for the pseudocode, it doesn't have to compile or anything.
At a very basic level, you're operating in an event driven environment. That is, something happens and you react to it.
Swing utilises the "observer pattern" to allow interested parties to be notified when something happens. This is a pretty common pattern.
In your case, I would "suggest" that you add a DocumentListener to the JTextField's Document and when it's changed, you trigger a notification to the interested parties that the text count has changed, for example...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.util.EventListener;
import java.util.EventObject;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public class Test extends JFrame {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
TextPane textPane = new TextPane();
StatusPane statusPane = new StatusPane();
textPane.addTextLengthListener(new TextLengthListener() {
#Override
public void textLengthDidChange(TextLengthEvent event) {
statusPane.setCount(event.getLength());
}
});
JFrame frame = new JFrame();
frame.add(textPane);
frame.add(statusPane, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TextLengthEvent extends EventObject {
private int length;
public TextLengthEvent(Object source, int length) {
super(source);
this.length = length;
}
public int getLength() {
return length;
}
}
public interface TextLengthListener extends EventListener {
public void textLengthDidChange(TextLengthEvent event);
}
public class TextPane extends JPanel {
private JTextField field;
public TextPane() {
setLayout(new GridBagLayout());
setBorder(new EmptyBorder(8, 8, 8, 8));
field = new JTextField(40);
add(field);
field.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) {
fireTextLengthDidChange();
}
#Override
public void removeUpdate(DocumentEvent e) {
fireTextLengthDidChange();
}
#Override
public void changedUpdate(DocumentEvent e) {
fireTextLengthDidChange();
}
});
}
public JTextField getField() {
return field;
}
public void addTextLengthListener(TextLengthListener listener) {
listenerList.add(TextLengthListener.class, listener);
}
public void removeTextLengthListener(TextLengthListener listener) {
listenerList.remove(TextLengthListener.class, listener);
}
protected void fireTextLengthDidChange() {
TextLengthListener[] listeners = listenerList.getListeners(TextLengthListener.class);
if (listeners.length == 0) {
return;
}
TextLengthEvent evt = new TextLengthEvent(this, getField().getText().length());
for (TextLengthListener listener : listeners) {
listener.textLengthDidChange(evt);
}
}
}
protected class StatusPane extends JPanel {
private JLabel label;
public StatusPane() {
setLayout(new GridBagLayout());
setBorder(new EmptyBorder(8, 8, 8, 8));
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.EAST;
gbc.weightx = 1;
label = new JLabel("0");
add(label, gbc);
}
public JLabel getLabel() {
return label;
}
public void setCount(int count) {
getLabel().setText(Integer.toString(count));
}
}
}
This is a pretty basic example, which demonstrates
Decoupling of the code
Separation of responsibilities
Observer pattern (implement via the "listener" mechanism in Swing)
Madprogrammer posted a very fine example of reacting to every document change.
If instead you are just interested in the field value (length) when the user hits enter, attach an ActionListener. Of course you can make use of other objects or the content of your TextField in ActionListeners.
Use the ActionEvent.getSource() (inherited from EventObject) method. And be aware if you are using an ActionListener for other stuff already, there is no problem in attaching several listeners for the same event.
I am working on a MVC based off of the code that I will be providing. I am having issues because I am fairly new to the subject. I am able to make the view, but when it comes to making the model it is a little more complicated for me. I need some guidance on how to turn the following code into a MVC so I can practice and learn. I been at this for several hours and I decided to come here for help.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
class SayHi extends JFrame implements MouseListener{
// components
protected JLabel helloLabel = new JLabel("Hello");
protected JTextField userInputTextField = new JTextField(20);
private JButton sayHiBtn = new JButton("Say Hi");
/** Constructor */
SayHi() {
//... Layout the components.
JPanel content = new JPanel();
content.setLayout(new FlowLayout());
content.add(new JLabel("Enter your name"));
content.add(userInputTextField);
content.add(sayHiBtn);
content.add(helloLabel);
// Add a mouse listener to the button
sayHiBtn.addMouseListener(this);
//... finalize layout
this.setContentPane(content);
this.pack();
this.setTitle("Simple App - Not MVC");
// The window closing event should probably be passed to the
// Controller in a real program, but this is a short example.
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
// Methods I am forced to implement because of the MouseListener
public void mouseClicked(MouseEvent e) {
helloLabel.setText("Hello " + userInputTextField.getText());
}
public void mouseEntered(MouseEvent e){
}
public void mouseExited(MouseEvent e){
}
public void mousePressed(MouseEvent e){
}
public void mouseReleased(MouseEvent e){
}
public static void main(String[] args){
SayHi s = new SayHi();
s.setVisible(true);
}
}
The View only controls the visuals, The Model only controls the data access and the Controller is in charge of the logic that glues the two.
You could split that class into 3 classes in order to make it a MVC.
All the Jpanel would be located in a View, in the Model you would have all your values, like setting a string to hello and such, while the controller needs to interact with both the Model and View.
private SayHiModel model;
private SayHiView view;
SayHiController(SayHiModel model, SayHiView view) {
this.model = model;
this.view = view;
this.model.setValue(model.INITIAL_VALUE);
view.totalTextField.setText(model.getValue());
//... Add listeners to the view.
view.addMultiplyListener(new MultiplyListener());
view.addClearListener(new ClearListener());
}
Just a little hint to get you going.
There isn't much of a model to work with.
Here's your example code, with one view class, one model class, and one controller class. The SayHi class is the view class. The SayHiModel class is the model class. The SayHiListener class is the controller class.
package com.ggl.testing;
import java.awt.FlowLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class SayHi implements Runnable {
private JFrame frame;
private JLabel helloLabel;
private JTextField userInputTextField;
private SayHiModel model;
public static void main(String[] args) {
SwingUtilities.invokeLater(new SayHi());
}
public SayHi() {
this.model = new SayHiModel();
}
#Override
public void run() {
// ... Layout the components.
JPanel content = new JPanel();
content.setLayout(new FlowLayout());
content.add(new JLabel("Enter your name: "));
userInputTextField = new JTextField(20);
content.add(userInputTextField);
JButton sayHiBtn = new JButton("Say Hi");
// Add a mouse listener to the button
sayHiBtn.addMouseListener(new SayHiListener(this, model));
content.add(sayHiBtn);
helloLabel = new JLabel("Hello");
content.add(helloLabel);
// ... finalize layout
frame = new JFrame("MVC App");
// The window closing event should probably be passed to the
// Controller in a real program, but this is a short example.
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(content);
frame.pack();
frame.setVisible(true);
}
public JFrame getFrame() {
return frame;
}
public void setHelloLabel(String name) {
helloLabel.setText("Hello " + name);
}
public String getName() {
return userInputTextField.getText().trim();
}
public class SayHiModel {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class SayHiListener extends MouseAdapter {
private SayHi sayHi;
private SayHiModel sayHiModel;
public SayHiListener(SayHi sayHi, SayHiModel sayHiModel) {
this.sayHi = sayHi;
this.sayHiModel = sayHiModel;
}
#Override
public void mouseClicked(MouseEvent e) {
sayHiModel.setName(sayHi.getName());
sayHi.setHelloLabel(sayHiModel.getName());
JFrame frame = sayHi.getFrame();
frame.setVisible(false);
frame.pack();
frame.setVisible(true);
}
}
}
I am trying to make a Login Form with Java. I Cant get it working.
I have looked all over then internet for how to fix this, I can't find anything.
Code:
LoginFrame.java:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class LoginFrame extends JFrame
{
JPanel pane = new JPanel();
static JFormattedTextField username = new JFormattedTextField(16);
static JFormattedTextField password = new JFormattedTextField(16);
static JButton loginButton = new JButton("Login!");
static String input[];
public LoginFrame() throws IOException
{
super("Login");
setSize(300,150);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container con = this.getContentPane();
con.add(pane);
pane.add(new JLabel("Username"));
pane.add(username);
pane.add(new JLabel("Password"));
pane.add(password);
pane.add(loginButton);
#Override
IEventHandler eHandler = new IEventHandler();
#Override
loginButton.addActionListener(eHandler);
setVisible(true);
}
static String[] getInput()
{
return input;
}
}
IEventHandler.java:
import java.awt.event.*;
class IEventHandler implements ActionListener
{
public void actionPreformed(ActionEvent e)
{
if(e.getSource() == LoginFrame.loginButton){
LoginFrame.loginButton.setEnabled(false);
new AuthLIB().authenticate(LoginFrame.getInput());
}
}
public IEventHandler()
{
System.out.println("Event Handler Hooked");
}
}
You aren't overriding anything with-in the method body. These
#Override
IEventHandler eHandler = new IEventHandler();
#Override
loginButton.addActionListener(eHandler);
should just be
IEventHandler eHandler = new IEventHandler();
loginButton.addActionListener(eHandler);
and assuming you want ActionListener.actionPerformed(ActionEvent)
public void actionPreformed(ActionEvent e)
should use that annotation. You'd see the spelling mistake quicker anyway.
#Override
public void actionPerformed(ActionEvent e)
a basic problem that i can't figure out, tried a lot of things and can't get it to work, i need to be able to get the value/text of the variable
String input;
so that i can use it again in a different class in order to do an if statement based upon the result
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
public class pInterface extends JFrame {
String input;
private JTextField item1;
public pInterface() {
super("PAnnalyser");
setLayout(new FlowLayout());
item1 = new JTextField("enter text here", 10);
add(item1);
myhandler handler = new myhandler();
item1.addActionListener(handler);
System.out.println();
}
public class myhandler implements ActionListener {
// class that is going to handle the events
public void actionPerformed(ActionEvent event) {
// set the variable equal to empty
if (event.getSource() == item1)// find value in box number 1
input = String.format("%s", event.getActionCommand());
}
public String userValue(String input) {
return input;
}
}
}
You could display the window as a modal JDialog, not a JFrame and place the obtained String into a private field that can be accessed via a getter method. Then the calling code can easily obtain the String and use it. Note that there's no need for a separate String field, which you've called "input", since we can easily and simply extract a String directly from the JTextField (in our "getter" method).
For example:
import java.awt.Dialog.ModalityType;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import javax.swing.*;
import javax.swing.text.JTextComponent;
public class TestPInterface {
#SuppressWarnings("serial")
private static void createAndShowGui() {
final JFrame frame = new JFrame("TestPInterface");
// JDialog to hold our JPanel
final JDialog pInterestDialog = new JDialog(frame, "PInterest",
ModalityType.APPLICATION_MODAL);
final MyPInterface myPInterface = new MyPInterface();
// add JPanel to dialog
pInterestDialog.add(myPInterface);
pInterestDialog.pack();
pInterestDialog.setLocationByPlatform(true);
final JTextField textField = new JTextField(10);
textField.setEditable(false);
textField.setFocusable(false);
JPanel mainPanel = new JPanel();
mainPanel.add(textField);
mainPanel.add(new JButton(new AbstractAction("Get Input") {
#Override
public void actionPerformed(ActionEvent e) {
// show dialog
pInterestDialog.setVisible(true);
// dialog has returned, and so now extract Text
textField.setText(myPInterface.getText());
}
}));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
// by making the class a JPanel, you can put it anywhere you want
// in a JFrame, a JDialog, a JOptionPane, another JPanel
#SuppressWarnings("serial")
class MyPInterface extends JPanel {
// no need for a String field since we can
// get our Strings directly from the JTextField
private JTextField textField = new JTextField(10);
public MyPInterface() {
textField.addFocusListener(new FocusAdapter() {
#Override
public void focusGained(FocusEvent e) {
JTextComponent textComp = (JTextComponent) e.getSource();
textComp.selectAll();
}
});
add(new JLabel("Enter Text Here:"));
add(textField);
textField.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Window win = (Window) SwingUtilities.getWindowAncestor(MyPInterface.this);
win.dispose();
}
});
}
public String getText() {
return textField.getText();
}
}
A Good way of doing this is use Callback mechanism.
I have already posted an answer in the same context.
Please find it here JFrame in separate class, what about the ActionListener?.
Your method is a bit confusing:
public String userValue(String input) {
return input;
}
I guess you want to do something like this:
public String getInput() {
return input;
}
public void setInput(String input) {
this.input = input;
}
Also your JFrame is not visible yet. Set the visibility like this setVisible(true)
Description of the problem: I have a JFrame, inside this JFrame there is a JPanel with a button, when I press the button an action listener change the current JPanel with a new JPanel, which contains other two JPanels, those two have an inputMap that when the user press the key "up" make something on both of them. The problem is: when I change the JPanel with the new one the "up" key won't do anything.
Here is the code: is a SSCCE, so you just have to copy and paste to see what it does.
This modified code comes from another question that I "solved" sometimes ago. How to make two JPanels listen to the same event?
(the code is in the answer that I selected).
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.Arrays;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
public class TwoPanelsTest extends JFrame {
private static MyPanel one = new MyPanel("One");
private static MyPanel two = new MyPanel("Two");
private static List<MyPanel> list = Arrays.asList(one, two);
private PanelsController panelsController;
public TwoPanelsTest() {
super("TwoPanelsTest");
panelsController= new PanelsController(this);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(400,400);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
private static class MyPanel extends JPanel {
private String string = " will be updated though its action.";
private Action action = new UpdateAction(this);
private String name;
private JLabel label;
public MyPanel(String name) {
this.name = name;
this.label = new JLabel(name + string, JLabel.CENTER);
this.setLayout(new GridLayout());
this.setFocusable(true);
this.add(label);
}
public Action getAction() {
return action;
}
private void update() {
label.setText(name + ": " + System.nanoTime());
}
private static class UpdateAction extends AbstractAction {
private MyPanel panel;
public UpdateAction(MyPanel panel) {
this.panel = panel;
}
#Override
public void actionPerformed(ActionEvent ae) {
panel.update();
}
}
}//MyPanel
private static class ButtonPanel extends JPanel{
private JButton button ;
private PanelsController panelsController;
public ButtonPanel(PanelsController panelsController){
this.panelsController=panelsController;
button = new JButton("Button");
button.setActionCommand("buttonPressed");
button.addActionListener(this.panelsController);
this.setFocusable(true);
add(button);
}
}//ButtonPanel
private static class PanelsController implements ActionListener {
private TwoPanelsTest twoPanelsTest;
public PanelsController(TwoPanelsTest twoPanelsTest){
this.twoPanelsTest=twoPanelsTest;
this.twoPanelsTest.getContentPane().add(new ButtonPanel(this));
}
#Override
public void actionPerformed(ActionEvent ae) {
if (ae.getActionCommand().equals("buttonPressed")){
twoPanelsTest.getContentPane().removeAll();
twoPanelsTest.getContentPane().invalidate();
JPanel panel = new JPanel(new GridLayout(0, 1, 10, 10));
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
panel.add(one);
panel.add(two);
panel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "up");
panel.getActionMap().put("up", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
for (MyPanel panel : list) {
panel.getAction().actionPerformed(e);
}
}
});
twoPanelsTest.getContentPane().add(panel);
twoPanelsTest.validate();
twoPanelsTest.repaint();
}
}//ActionPerformed
}//PanelsController
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
TwoPanelsTest t = new TwoPanelsTest();
}
});
}
}
Well, its pretty simple - if you have those two panels without any components inside and want them to listen the hotkey use:
panel.getInputMap ( JComponent.WHEN_IN_FOCUSED_WINDOW )
.put ( KeyStroke.getKeyStroke ( KeyEvent.VK_UP, 0 ), "up" );
JComponent.WHEN_IN_FOCUSED_WINDOW instead of JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT.
Otherwise you need to have somthing focused inside the panel so it could catch the key events.
By the way, there is also another way to listen global hotkeys inside Java application windows:
Toolkit.getDefaultToolkit ().addAWTEventListener ( new AWTEventListener ()
{
public void eventDispatched ( AWTEvent event )
{
// All application key events will be passed here
}
}, AWTEvent.KEY_EVENT_MASK );