I do not understand what is happening in my code, when I fire a button with attached action listener, reading the JTextField getText() value shows as null, even though all fields contain text. Furthermore when I debugged the code and stopped just before this line the JTextField object showed as null as well, like it was never initialised in the first place.
I'm not sure whether I can keep all these JLabel and JTextField as class members and then just freely read from them.
public class EditPartGUI extends JFrame {
private JLabel manufacturerLabel;
private JTextField manufacturerTextField;
private JButton submit;
private ActionListener submitListener;
public EditPartGUI(Part part) {
JPanel panel = new JPanel();
this.setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
panel.add(initialiseField("Manufacturer: ", manufacturerLabel, part.getManufacturer(), manufacturerTextField));
JPanel sub = new JPanel();
submit = new JButton("Submit");
submitListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println(submit().toString());
}
};
submit.addActionListener(submitListener);
sub.add(submit);
panel.add(sub);
this.add(panel);
}
public JPanel initialiseField(String label, JLabel contentLabel, String value, JTextField contentTextField) {
JPanel contentPanel = new JPanel();
contentLabel = new JLabel(label, JLabel.TRAILING);
contentTextField = new JTextField(10);
contentTextField.setText(value);
contentLabel.setLabelFor(contentTextField);
contentPanel.add(contentLabel);
contentPanel.add(contentTextField);
return contentPanel;
}
public Part submit() {
Part p = new Part();
p.setManufacturer(this.manufacturerTextField.getText()); // <---- this is where NullPointerException shows
return p;
}
}
I'm not sure whether I can keep all these JLabel and JTextField as class members and then just freely read from them.
Yes you can and that is the solution to your problem.
Just use the following when you
//private JTextField manufacturerTextField;
private JTextField manufacturerTextField = new JTextField();
and don't try to create the text field in your initialiseField() method. Of course you will need to do the same with the label.
so I could avoid repeating the same code for each field (there are a lot more of them in my actual code).
If you want to have many panels with those fields, then you need to create a custom class to create the panel and then the text fields and labels will be part of that class, not your main class.
The problem is, that you assume that the method initialiseField is assigning the argument contentTextField to manufactererTextField. This won't work in Java as David Wallace already stated.
If you want to avoid repeating the same code, try to create a method that returns the initialised TextField and assign it in the constructor.
Related
Apparently my Google-fu skills are bit lacklustre and I can't figure out how to get JTextField when pressing a JButton.
Please note that I've removed some parts of the code for ease of reading.
If you see some variable that's not defined assume that it was part of that code.
As it stands, the code works fine.
public final class Main {
// Some removed code was here
private void prepareGUI() {
// Top right stuff
JPanel topRightPanel = new JPanel();
topRightPanel.setLayout(new FlowLayout());
JLabel topRightLabel = new JLabel("Address");
JTextField topRightTextField = new JTextField("", 15);
topRightTextField.setName("add_address");
JButton topRightButton = new JButton("Add");
topRightButton.setName("add_btn");
topRightPanel.add(topRightLabel);
topRightPanel.add(topRightTextField);
topRightPanel.add(topRightButton);
mainFrame.add(topRightPanel);
// The button in question. Very suggestive name, I know.
topRightButton.addActionListener(new GenericButtonListener());
genericButtonListener.setKernel(kernel);
// some other non relevant stuff here
mainFrame.setVisible(true);
}
}
public class GenericButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
JButton btn = (JButton) e.getSource();
String btnName = btn.getName();
if(btnName.toLowerCase().contains("add_btn")) {
addBtn(btn);
}
}
public void addBtn(JButton button){
SshFileIO sshFileIO = kernel.getFileIO();
// Get field text here
}
}
My current dilemma is how to get said textfield value inside GenericButtonListener.
I realize that I can use getText to get the text field value, however I don't have access to that variable inside the actionPerformed function.
I suppose this is more of a scoping problem rather than anything else.
I just need some pointing in the right direction, no hand holding required.
It's painfully obvious that I'm very new to Java.
Please try to get a reference of topRightTextField with the constructor of GenericButtonListener. Store as property of the class and use it inside actionPerformed.
Change this one:
topRightButton.addActionListener(new GenericButtonListener());
To this:
topRightButton.addActionListener(new GenericButtonListener(topRightTextField));
And inside class GenericButtonListener add field:
private JTextField topRightTextField;// set it in the constructor
And then use it inside of your method actionPerformed.
Have a nice coding and good luck!
I have a JPanel which consists of a dropdown and a text field inside my JFrame. There is a button in my JFrame, when user clicks on that button, application adds new JPanel with the same components i.e. drop down and a text field. So, for this I have created a function which gets called on clicking on the button using ActionListener.
Everything works fine from GUI side but the problem is when user is done with adding JPanels and entering the values in these drop downs and text fields, it will click on Submit button. Upon clicking on Submit button, I should be able to fetch the values from all drop downs and text fields. This is a challenge, since I am using the same functions to create JPanels, I can't call its name to get the values since that will give me the last JPanel values.
Any suggestion how I should go about this? I have added the screenshot of my JFrame and the function to create the JPanel. Any help is appreciated. Thanks.
public static void AddPanel(final Container pane) {
panel1 = new JPanel();
String text = "<html><b>Property" + nooftimes + " :</b></html>";
JLabel label = new JLabel(text);
label.setPreferredSize(new Dimension(80, 30));
panel1.add(label);
panel1.add(new JLabel("Please enter the property"));
DefaultComboBoxModel<String> model = new DefaultComboBoxModel<String>();
model.addElement("value1");
model.addElement("value2");
model.addElement("value3");
model.addElement("value4");
model.addElement("value5");
final JComboBox<String> comboBox1 = new JComboBox<String>(model);
AutoCompleteDecorator.decorate(comboBox1);
comboBox1.setPreferredSize(new Dimension(120, 22));
panel1.add(comboBox1);
final JTextField txtfield1 = new JTextField(
"Please enter your value here");
txtfield1.setPreferredSize(new Dimension(200, 22));
panel1.add(txtfield1);
txtfield1.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
txtfield1.setText("");
}
public void focusLost(FocusEvent e) {
// nothing
}
});
container.add(panel1);
nooftimes++;
frame.revalidate();
frame.validate();
frame.repaint();
}
Screenshot:
}
You could return the JPanel and store it in a List<JPanel>. When you click your submit-Button you are able to iterate through the JPanels and its Components.
public class Application {
private static List<JPanel> panels = new ArrayList<>();
private static Container someContainer = new Container();
public static void main(String[] args) {
panels.add(addPanel(someContainer));
panels.add(addPanel(someContainer));
panels.add(addPanel(someContainer));
submit();
}
public static JPanel addPanel(final Container pane) {
JPanel panel1 = new JPanel();
// shortened code
final JComboBox<String> comboBox1 = new JComboBox<String>();
panel1.add(comboBox1);
final JTextField txtfield1 = new JTextField("Please enter your value here");
txtfield1.setText(String.valueOf(Math.random()));
panel1.add(txtfield1);
return panel1;
}
private static void submit() {
for (JPanel panel : panels) {
Component[] components = panel.getComponents();
for (Component comp : components) {
// Cast comp to JComboBox / JTextField to get the values
if (comp instanceof JTextField) {
JTextField textField = (JTextField) comp;
System.out.println(textField.getText());
}
}
}
}
}
You could simply have a class (extending JPanel) with specific methods to add your components , and to get inputs from user (i.e. get the combo box selected index and text from textfield ).
Every time you add a panel, you don't call a static method, but you create an instance of this class, keeping the reference somewhere (for example adding it to an arraylist).
But you could consider a different scenario: personally i don't like to add components "on fly", you could have a component (for example another JComboBox), where user can select the number of values he needs.
You decide a default value (for example 4), so at the beginning you create 4 panels of your class, and you can use a simple array containing them.
If the user changes the number of panels, you could dispose frame and create a new one.
Of course this solution does not woork good if you want to keep inputs inserted, or if the frame construction takes a lot of time.
Here there is a screenshot of a gui i created: user can select the number of partials, when the choice changes i just recreate the panels below,containing the textfields (which are memorized in a two-dimensional array).
I am trying since 1 hour but I can't access my jtextField from JPanel to Jpanel1.
I am working on a course project in which I have to show the name of the log in user in the JPanel using jlabel but I can't access the jTextField in JPanel from jpanel1.
I make my JTextField1 public Static using this Answer but still unable to catch the values
I am using this code to fetch the values from JPanel in JPanel1. What I am doing is creating a object of JPanel in JPanel1 and then try to fetch the value.
LoginPanel s = new LoginPanel();
String sc=s.jTextField1.getText();
this.jLabel3.setText(sc);
Don't make a variable static for this purpose as you're breaking OOPs rules for no good reason.
Don't create a completely new object if you want to get the state of another object of the same type, since the two objects will be completely different instances.
If you need to have one object query the state of another (here the state being the text held within the JTextField), then give the the object with the JTextField a public getter field that will return the text in its JTextField and have the first object call this method when needed.
The first object will of course need a valid reference to the displayed object with the text field. How this is done will depend on the structure of your program, something we have no idea of at the moment.
Often the problem is when to obtain the text, since if you try to obtain the text before the user has had a chance to enter anything, then your code won't work. To avoid this, this is usually done in an event listener, and again the details will depend on the structure of your program and on code not shown.
Sometimes the timing is achieved by displaying the 2nd JPanel within a modal dialog window such as a JDialog or JOptionPane. This method is used most often when trying to get log on information from a user.
For better and more specific help, please make your question more informative. Show actual code, not an image of code. How much code? best would be if you could create and show us a minimal code example program.
For example, using a JOptionPane to display one JPanel and obtain text in a modal fashion:
import java.awt.Component;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class TwoPanels extends JPanel {
private MyPanel1 panel1 = new MyPanel1();
private MyPanel2 panel2 = new MyPanel2();
public TwoPanels() {
add(panel2);
add(new JButton(new AbstractAction("Get Name") {
#Override
public void actionPerformed(ActionEvent arg0) {
Component parent = TwoPanels.this;
String title = "Enter Name";
int messageType = JOptionPane.PLAIN_MESSAGE;
int optionType = JOptionPane.OK_CANCEL_OPTION;
int result = JOptionPane.showConfirmDialog(parent, panel1, title, optionType, messageType);
if (result == JOptionPane.OK_OPTION) {
String name = panel1.getNameText();
panel2.setNameText(name);
}
}
}));
}
private static void createAndShowGui() {
TwoPanels mainPanel = new TwoPanels();
JFrame frame = new JFrame("TwoPanels");
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();
}
});
}
}
class MyPanel1 extends JPanel {
private JTextField nameField = new JTextField(10);
public MyPanel1() {
add(new JLabel("Name:"));
add(nameField);
}
public String getNameText() {
return nameField.getText();
}
}
class MyPanel2 extends JPanel {
private JTextField nameField = new JTextField(10);
public MyPanel2() {
nameField.setFocusable(false);
nameField.setEditable(false);
add(new JLabel("Name:"));
add(nameField);
}
public void setNameText(String text) {
nameField.setText(text);
}
}
I'm very new to Java and I'm trying to create a small program that reverses text (That part I've figured out).
Where I'm getting stuck on is my GUI, my envisioned plan for the gui is a window with a centered text field for user input then under it in the directly middle of the window a button that reverses the text from the above text box and outputs it in a text box below the button.
Right now I'm using JTextField boxes and after trying to make them look the way I want I'm getting the feeling that there's an easier way to do it, but I don't know it.
Here's my GUI class:
public class ReverseTextGUI extends ReverseRun implements ActionListener {
public static JFrame frame;
private JPanel northFlowLayoutPanel;
private JPanel centerFlowLayoutPanel;
private JPanel southFlowLayoutPanel;
private final JButton reverse = new JButton("Reverse");
private final JTextField userInput = new JTextField(50);
private final JTextField reverseOutput = new JTextField(50);
public void actionPerformed(ActionEvent e) {
reverse.addActionListener((ActionListener) reverse);
reverse.setActionCommand("Reverse");
if ("algorithm".equals(e.getActionCommand())) {
System.out.println("test");
}
}
public void initUI() {
northFlowLayoutPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
northFlowLayoutPanel.add(userInput);
userInput.setPreferredSize(new Dimension(150,100));
centerFlowLayoutPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
centerFlowLayoutPanel.add(reverse);
southFlowLayoutPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
southFlowLayoutPanel.setBorder(BorderFactory.createTitledBorder("Output text"));
southFlowLayoutPanel.add(reverseOutput);
reverseOutput.setPreferredSize(new Dimension(150,100));
JFrame frame = new JFrame("Backwardizer");
frame.setLayout(new BorderLayout()); // This is the default layout
frame.add(northFlowLayoutPanel, BorderLayout.PAGE_START);
frame.add(centerFlowLayoutPanel, BorderLayout.CENTER);
frame.add(southFlowLayoutPanel, BorderLayout.PAGE_END);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setSize(750, 500);
}
Any ideas how to either move the cursor to the start of the box (it shows up in the middle as of now) or a better way to accomplish what I'm trying to do?
For the reversing aspect, you can add the text from the first box to a string builder
StringBuilder rev = new StringBuilder(firstBox.getText());
String reversedText = rev.reverse().toString();
secondBox.setText(reversedText);
Something along those line should get the desired result if you nest it in the button action.
Any ideas how to either move the cursor to the start of the box (it shows up in the middle as of now) or a better way to accomplish what I'm trying to do?
JTextField#setCaretPosition, call this AFTER you've updated the text of the field
Make the field readonly, JTextField#setEditable and pass it false
Additionally, you could use a JList or JTextArea if you want to store multiple rows/lines of text
You should also avoid using setPreferredSize, see Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing? for more details
Why can't I shift focus to an unshown JPanel card in a CardLayout?
I'm implementing a CardLayout-based interface that needs to be keyboard navigation friendly. When a user finishes tabbing through all the fields on one card, the user needs to be able to tab to the next card.
I've already implemented a FocusTraversalPolicy that produces the right Component at each point in the process, and a FocusAdapter to pop up any cards newly tabbed to, but something is eating the messages and preventing focus change.
I can uncleanly pass the CardLayout to the FocusTraversalPolicy to change the card— though any of its functions are called several times in Swing's many threads and leads to strange behavior. Besides, that way's just dirty.
I do not want to use key bindings b/c that would require reimplementing all of the focus work Java already does for me, and is also really unclean.
Basically: Java dislikes shifting focus to unshown cards in CardLayouts— how can I override this?
I want to keep the program compartmentalized, as it runs in distinct steps.
This does not prevent you from creating a long scrolling form?
You can still create individual panels the way you are doing now. Then instead of adding these panels to a CardLayout where you need to swap panels, you can add the panels to a panel using a BoxLayout (or GridBagLayout).
This would even give more flexibility since each panel can be of a different size without impacting the size of every individual panel.
However, forms do not currently scroll automatically in a JScrollPane, so you may want to check out Scrolling a Form for a class this will do this for you.
It sounds like you have a wizard-like UI. If so, add a "Next" button as the last field on each card.
The action of the Next button would be to flip to the next card as set focus to the first entry field.
The last entry field on each card would transfer focus to the Next button, who could then be "pressed" with a strike of the spacebar when it receives focus (which is the default behavior of a JButton), keeping it keyboard-friendly.
This would alleviate the need for special KeyBindings or FocusTraversalPolicies.
EDIT:
Try this, using FocusListeners for the JTextFields. Tab thorugh the fields and the cards will flip to the next one automatically once you tab out of the last field. You could use ActionListeners instead if you wish:
EDIT 2: Added hack for panels that only have 1 field.
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import javax.swing.*;
public class CardLayoutDemo2 implements Runnable
{
final static String CARD1 = "One";
final static String CARD2 = "Two";
final static String CARD3 = "Three";
JPanel cards;
CardLayout cardLayout;
JTextField tf1, tf2, tf3, tf4, tf5;
JButton dummy;
public static void main(String[] args)
{
SwingUtilities.invokeLater(new CardLayoutDemo2());
}
public void run()
{
tf1 = new JTextField(10);
tf2 = new JTextField(10);
tf2.addFocusListener(new CardFlipper(CARD2));
tf3 = new JTextField(10);
tf4 = new JTextField(10);
tf4.addFocusListener(new CardFlipper(CARD3));
tf5 = new JTextField(10);
tf5.addFocusListener(new CardFlipper(CARD1));
dummy = new JButton()
{
#Override
public Dimension getPreferredSize()
{
return new Dimension(0,0);
}
};
dummy.addFocusListener(new FocusAdapter()
{
#Override
public void focusGained(FocusEvent e)
{
dummy.transferFocus();
}
});
JPanel card1 = new JPanel();
card1.add(new JLabel("One"));
card1.add(tf1);
card1.add(new JLabel("Two"));
card1.add(tf2);
JPanel card2 = new JPanel();
card2.add(new JLabel("Three"));
card2.add(tf3);
card2.add(new JLabel("Four"));
card2.add(tf4);
JPanel card3 = new JPanel();
card3.add(dummy);
card3.add(new JLabel("Five"));
card3.add(tf5);
cardLayout = new CardLayout();
cards = new JPanel(cardLayout);
cards.add(card1, CARD1);
cards.add(card2, CARD2);
cards.add(card3, CARD3);
JFrame f = new JFrame("CardLayout Demo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(cards, BorderLayout.CENTER);
f.setSize(180, 200);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private class CardFlipper extends FocusAdapter
{
private String nextCard;
CardFlipper(String cardName)
{
this.nextCard = cardName;
}
#Override
public void focusLost(FocusEvent e)
{
cardLayout.show(cards, nextCard);
}
}
}