Variable sized array of JTextFields and other widgets - java

public class Creator extends JFrame {
JLabel[] pos;
JTextField[] monInitFi;
JPanel panel, statusP, inputP;
JTextField numMonsFi;
JButton goB, initRollB;
int numMons;
public Creator() {
panel = new JPanel();
createInputP();
panel.add(inputP);
add(panel);
}
//The Input board
public JPanel createInputP() {
inputP = new JPanel();
numMonsFi = new JTextField(3);
inputP.add(numMonsFi);
goB = new JButton("Go");
goB.addActionListener(new goBListener());
inputP.add(goB);
return inputP;
}
//Creates the initiative input board.
public JPanel createStatusP() {
statusP = new JPanel();
monInitFi = new JTextField[numMons];
for (int i = 0; i < numMons; i++) {
monInitFi[i] = new JTextField(3);
statusP.add(monInitFi[i]);
}
initRollB = new JButton("Roll");
statusP.add(initRollB);
return statusP;
}
//The button listener, should update numMons, and create and add the initiative panel.
public class goBListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
numMons = Integer.parseInt(numMonsFi.getText());
createStatusP();
panel.add(statusP);
}
}
public static void main(String[] args) {
Creator c = new Creator();
c.setVisible(true);
c.setSize(1000, 600);
c.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
c.setTitle("D&D 4e Encounter Tracker");
}
}
So this is only a sample of what I'm trying to do, but I cant even get the basics to work. When I run this the statusP(JPanel) does not show up, and I'm not sure if it's because its not running, or because it won't work.
I've tried putting the createStatusP() method in the GUI constructor but only the JButton will appear as if the for loop doesn't run.
Any help would be much appreciated.

In your goBListener's actionPerformed method, you should be calling panel.revalidate() to force the panel to be relaid out which will trigger a repaint, after you have added the statusP panel.
You should also try and follow Java naming conventions, the goBListener should start with an uppercase, GoBListener, it will make it easier for others to read (but will also make it easier for you to read other peoples code)
Instead of arrays, you might consider using some of List, this is a personal thing, but List is generally more flexible. Take a look at Collections for more details

This is because you call createInputP() as it's a procedure , but it's not ! it's a function it will return something that is in this case inputP panel ! so what's actually happening is overridable method call in constructor ! so the solution is add final keyword before createInputP() method !!
// final keyword after public keyword!
public final JPanel createInputP(){ ..... }
And modify goBListener like below :
public class goBListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
numMons = Integer.parseInt(numMonsFi.getText());
panel.revalidate();
panel.add(createStatusP());
}
}
Dang !! That's it !!

Related

How can I pass a JPanel as a parameter to a method?

Let me ask.
I´m working in a java project in Netbeans. I've created a JFrameForm (Design mode), inside the JFrameForm, there is five (5) JPanel.
I've found a method por enable/disable all components inside a Jpanel. Works.
private void changeState(){
for(Component c : mypanel.getComponents()){
c.setEnabled(false);
}
}
//mypanel it's one of a five panels in JFrameForm.
//I would like pass all the JPanel as parameters
I'm try writing a method where I can pass like parameter, just, the JPanel that I need when I invoced the method. Can you help me?
I'm try this,but don't work:
private void changeState(JPanel p){
for(Component c : p.getComponents()){
c.setEnabled(false);
}
}
I'm sorry if the answer it's very easy. I'm beginner in JAVA and in this community. I hope you can help me.
But it does work! When I run the following code (with your method included) it gives me 2 x true, and then 2 x false. So the method is fine.
public class Panelik extends JFrame {
JPanel panel;
JLabel label1, label2;
public Panelik() {
panel = new JPanel();
label1 = new JLabel();
label2 = new JLabel();
panel.add(label1);
panel.add(label2);
System.out.println(label1.isEnabled());
System.out.println(label2.isEnabled());
changeState(panel);
System.out.println(label1.isEnabled());
System.out.println(label2.isEnabled());
}
public void changeState(JPanel p) {
for(Component c : p.getComponents()) {
c.setEnabled(false);
}
}
public static void main(String[] args) {
Panelik panelik = new Panelik();
}
}

Add listener to JPanel

I have a custom class CustomField that extends JPanel. As I often have to reuse the same pattern, my custom class is made of 2 JLabels and 2 JComboBox.
It's quite simple; the first JComboBox has ON/OFF choices and the second JComboBox is only visible if the first is set to "ON". I can manage this part.
The part that I however don't know who to design it well is that CustomField instances are in another class that is the main JFrame and in this JFrame, some parts will be visible only if the JComboBox from the CustomField class is set to "ON". I thought about using a MouseAdapter, but I don't know it is good practice.
Here is my CustomField class:
public class CustomField extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
JLabel text, portText;
JComboBox<String> testCB, option;
public CustomField(String text, String opt, String tst) {
this.text = new JLabel(text);
String[] onOffOpt= {"OFF", "ON"};
this.option = new JComboBox<String>(onOffOpt);
this.option.setSelectedItem(opt);
this.option.addItemListener(new ItemListener(){
#Override
public void itemStateChanged(ItemEvent ie) {
portText.setVisible(option.getSelectedIndex() == 1);
testCB.setVisible(option.getSelectedIndex() == 1);
}
});
this.portText = new JLabel("Test:");
String[] testChoices = {"Test", "Test2"};
this.testCB = new JComboBox<String>(testChoices);
this.testCB.setSelectedItem(tst);
this.setLayout(new FlowLayout());
add(this.text);
add(this.option);
add(this.portText);
add(this.testCB);
}
}
And here is the main JFrame:
public class Main {
CustomField cf = new CustomField("test", "ON, "Test2");
public static void main(String s[]) {
JFrame frame = new JFrame("Application");
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(cf);
JLabel labelTest = new JLabel("Label that should be visible or not");
panel.add(labelTest);
frame.add(panel);
frame.setSize(300, 300);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Basically, I want that the labelTest visibily changes according to the CustomField settings. In the way that it is made, I can not put the labelTest in the CustomField class.
Is there a clean way to do what I want? Should I redesign the actual thing and put all the fields in the same class?
Thanks!
First, you want to expose the combobox's state with a method in CustomField:
public boolean isOn() {
return testCB.getSelectedIndex() == 1;
}
You can get an idea for how listening for state is done by looking at the method signatures in the documentation for various Swing components, which use the standard JavaBean listener pattern: You’ll want to add three public methods, and one protected method:
public void addChangeListener(ChangeListener listener) {
listenerList.add(ChangeListener.class, listener);
}
public void removeChangeListener(ChangeListener listener) {
listenerList.remove(ChangeListener.class, listener);
}
public ChangeListener[] getChangeListeners() {
return listenerList.getListeners(ChangeListener.class);
}
protected void fireChangeListeners() {
ChangeEvent event = new ChangeEvent(this);
for (ChangeListener listener : getChangeListeners()) {
listener.stateChanged(event);
}
}
(The listenerList field is inherited from JComponent.)
Now, you can simply add a call to fireChangeListeners(); whenever you detect that the user has changed the value of the On/Off combobox—that is, you’ll want to call it in your ItemListener.
As you can probably guess, your Main class can now call cf.addChangeListener, and inside that listener adjust the visibility of your label based on the value returned by cf.isOn().
You can learn a lot more by reading these.

Java Method Call Expected

This is a java program with two buttons used to change an integer value and display it.
However in IntelliJIDEA the two lines with
increase.addActionListener(incListener());
decrease.addActionListener(decListener());
keep displaying errors 'Method call expected'.
I am not sure what to do to fix this.
Any help will be greatly appreciated
Thanks
Note: the full code is attached below.
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Main extends JDialog {
public JPanel contentPane;
public JButton decrease;
public JButton increase;
public JLabel label;
public int number;
public Main() {
setContentPane(contentPane);
setModal(true);
increase = new JButton();
decrease = new JButton();
increase.addActionListener(incListener());
decrease.addActionListener(decListener());
number = 50;
label = new JLabel();
}
public class incListener implements ActionListener {
public void actionPerformed (ActionEvent event) {
number++;
label.setText("" + number);
}
}
public class decListener implements ActionListener {
public void actionPerformed (ActionEvent event) {
number--;
label.setText("" + number);
}
}
public static void main(String[] args) {
Main dialog = new Main();
dialog.pack();
dialog.setVisible(true);
System.exit(0);
}
}
incListener and declListener are classes, not methods.
Try
increase.addActionListener(new incListener());
btw, rename your classes names to make them start with an uppercase
It's simple: use new incListener() instead of incListener(). The later is trying to call a method named incListener, the former creates an object from the class incListener, which is what we want.
incListener and decListener are a classes but not a methods, so you must call new to use them, try this:
increase.addActionListener(new incListener());
decrease.addActionListener(new decListener());
sorry for my bad english
substitute the lines with
increase.addActionListener( new incListener());
decrease.addActionListener( new decListener());
Make these changes:
public Main() {
contentPane = new JPanel();
setContentPane(contentPane);
setModal(true);
increase = new JButton("inc");
decrease = new JButton("dec");
contentPane.add(increase);
contentPane.add(decrease);
increase.addActionListener(new incListener());
decrease.addActionListener(new decListener());
number = 50;
label = new JLabel(number+"");
contentPane.add(label);
}
It's sad but I had to Google this same error... I was staring at a method that returned a class. I left off the new operator.
return <class>(<parameters>)
vs
return new <class>(<parameters>)
Whenever a string object is created using new operator a new object is created which is what your program is looking for.
The following link is useful in learning about the difference between a string and a new string.
What is the difference between "text" and new String("text")?

Java getter not working?

Ok so i have a comboBox, and a JTextField, whenever i chose the quantity, it would be displayed on the textfield. I have another class, which will retrieve the whatever inside the textfield, but the order class doesn't retrieve the information from catalogue class.
class Catalogue extends JPanel {
String[] h1Quantity = {"0","1","2","3","4","5","6","7","8","9","10"};
h1CBox = new JComboBox <String> (h1Quantity);
h1CBox.setSelectedIndex(0);
h1CBox.addActionListener (new Listener());
h1CBox.setPreferredSize ( new Dimension (50,30));
JLabel noBooks = new JLabel ("Quantity");
booksF = new JTextField(8);
public class Listener implements ActionListener {
public void actionPerformed (ActionEvent event) {
int total = h1CBox.getSelectedIndex();
booksF.setText(Integer.toString(total));
}
}
public String booksFText() {
return booksF.getText();
}
}
class Order extends JPanel {
Catalogue catalogue ;
public Order (Catalogue catalogue)
{
this.catalogue = catalogue;
JPanel panel = new JPanel ();
String text2= catalogue.booksFText();
textArea1 = new JTextArea (text2, 20, 35);
add(textArea1);
add(panel);
}
}
I'm new to java so please keep it simple. thanks alot.
You have 2 constructors in the Order class and catalogue is only set in the first one. Set this in the second contructor as well and the NPE should go away (although hard to know for sure without the stacktrace!)
Always try to post complete code. and stack trace too.
See your order class.
class Order extends JPanel {
public Order (Catalogue catalogue)
{
add(textArea);
}
}
If you use the second constructor , then the class variable catalogue will not be given memory. Thus NULL POINTER EXCEPTION . The code inside the second constructor has been moved to the first one.
The other reason may be that the variable being passed in order constructor is not defined properly. Should be done something like this.
Catalogue catalogue = new Catalogue();
Order order = new Order(catalogue);
See Updated Catalogue class.
class Catalogue extends JPanel {
String[] h1Quantity = {"0","1","2","3","4","5","6","7","8","9","10"};
JComboBox<String> h1CBox ; //Assuming you forgot to define it.
JLabel noBooks ;
JTextField booksF ;
//Define a new constructor
public Catalogue () {
//set jlabel
noBooks = new JLabel ("Quantity");
//set combobox
h1CBox = new JComboBox <String> (h1Quantity);
h1CBox.setSelectedIndex(0);
h1CBox.addActionListener (new Listener());
h1CBox.setPreferredSize ( new Dimension (50,30));
//set textfield
booksF = new JTextField(8);
//add UI items to your panel class
add(h1CBox); //combobox
add(noBooks); // label
add(booksF); // textfield
}
public class Listener implements ActionListener {
public void actionPerformed (ActionEvent event) {
int total = h1CBox.getSelectedIndex();
booksF.setText(Integer.toString(total));
}
}
public String booksFText() {
return booksF.getText();
}
}
Always define your UI like this . Of course , there are better ways . Thus code looks clean and you understand things. Learn to put comments to remind you what you tried to do somewhere.
The MAIN Class
public class Main {
static JTextArea textArea = new JTextArea(40,40);
static class Order extends JPanel{
public Order(){
add(textArea);
}
}
static class Catalogue extends JPanel{
....
private ActionListener listener = new ActionListener(){
public void actionPerformed(ActionEvent event){
textArea.setText(h1CBox.getSelectedIndex()+"");
}
};
}
public static void main(String args[]){
//Construct a frame and add panels and you are good to go.
}
}
One last suggestion, if you plan on NOT changing the data of textarea yourself , use textfield or label instead of textarea. Sometimes the text inside textarea is set , but user is unable to see because of improper bounds . So , to be sure just replace the textarea with label or textfield. Cheers :)

Using AWT Buttons and detecting if clicked

I just joined, and am glad to be here~ So, this morning (at like 2am, but thats besides the point :P ) I was doing a little bit of Java tests with JFrame and other GUI stuff. This is my first time working with GUIs. I was trying to make a little java app that would act as a dream journaller. However, my progress was frozen when I encountered a problem i could not solve. My code is as follows.
import java.awt.*;
import javax.swing.*;
import java.applet.*;
public class Display extends Canvas
{
static final int WIDTH = 600;
static final int HEIGHT = 400;
public static String defaultEntry = "Dreams...";
public static final String TITLE = "Dream Journal Testing";
Button erase;
public static void main(String[] args)
{
Display d = new Display();
d.create();
}
public void create()
{
JFrame frame = new JFrame();
System.out.println("Running");
Panel cardOne = new Panel();
Panel p1 = new Panel();
Panel p2 = new Panel();
Panel p3 = new Panel();
Panel grid = new Panel();
cardOne.setLayout(new BorderLayout());
p1.setLayout(new GridLayout(2,1,3,6));
TextArea textArea1 = new TextArea(defaultEntry);
/*Font f1 = new Font("Courier", Font.PLAIN, 16);
setFont(f1);*/
Label l1 = new Label("Welcome to the Dream Journal! :)");
Label l2 = new Label("Type your dream below:");
p1.add(l1);
p1.add(l2);
p2.add(textArea1);
p3.setLayout(new FlowLayout(FlowLayout.CENTER));
Button ok = new Button("Save");
erase = new Button("Erase");
p3.add(erase);
p3.add(ok);
cardOne.add("North",p1);
cardOne.add("Center",p2);
cardOne.add("South",p3);
frame.add(cardOne);
//frame.add(cardOne);
//frame.setLocationRelativeTo(null);
frame.pack();
frame.setTitle(TITLE);
frame.setSize(WIDTH, HEIGHT);
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
System.out.println(textArea1.getText());
}
/*public boolean handleEvent(Event evt)
{
if(evt.target == erase)
{
System.out.println("it works");
return true;
}
else return super.handleEvent(evt);
}
*/
public boolean action(Event evt, Object arg)
{
if("Erase".equals(arg))
{
System.out.println("hello");
//textArea1.setText("");
}
return true;
}
}
The problem i have is I am not able to figure out how to make it so if the "Erase" AWT button is pushed, the system will print a line (as a test). I have tried
public boolean action(Event evt, Object arg)
And
public boolean handleEvent, but neither worked. Anyone have any suggestions for the Java noob that is me? Thanks!! :)
One way is to add an action listener to the button (e.g. for Save). Another way is to create an Action (e.g. for Erase).
Don't mix Swing with AWT components unless it is necessary. It is not worth even learning how to use AWT components at this point in time, use Swing only for best results and best help.
Here is a version of the app. using all Swing components.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Display
{
static final int WIDTH = 600;
static final int HEIGHT = 400;
public static String defaultEntry = "Dreams...";
public static final String TITLE = "Dream Journal Testing";
JButton erase;
public static void main(String[] args)
{
Display d = new Display();
d.create();
}
public void create()
{
JFrame frame = new JFrame();
System.out.println("Running");
JPanel cardOne = new JPanel();
JPanel p1 = new JPanel();
JPanel p2 = new JPanel();
JPanel p3 = new JPanel();
cardOne.setLayout(new BorderLayout());
p1.setLayout(new GridLayout(2,1,3,6));
JTextArea textArea1 = new JTextArea(defaultEntry);
JLabel l1 = new JLabel("Welcome to the Dream Journal! :)");
JLabel l2 = new JLabel("Type your dream below:");
p1.add(l1);
p1.add(l2);
p2.add(textArea1);
p3.setLayout(new FlowLayout(FlowLayout.CENTER));
JButton ok = new JButton("Save");
ok.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
System.out.println("Do " + ae.getActionCommand());
}
});
erase = new JButton(new EraseAction());
p3.add(erase);
p3.add(ok);
// Use the constants
cardOne.add(BorderLayout.PAGE_START,p1);
cardOne.add(BorderLayout.CENTER,p2);
cardOne.add(BorderLayout.PAGE_END,p3);
frame.add(cardOne);
frame.pack();
frame.setTitle(TITLE);
frame.setSize(WIDTH, HEIGHT);
frame.setResizable(false);
frame.setLocationByPlatform(true);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
System.out.println(textArea1.getText());
}
}
class EraseAction extends AbstractAction {
EraseAction() {
super("Erase");
}
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("Do " + arg0.getActionCommand());
}
}
First let me explain you the Funda of Event Handler....
- First of all there are Event Source, when any action take place on the Event Source, an Event Object is thrown to the call back method.
- Call Back method is the method inside the Listener (Interface) which is needed to be implemented by the Class that implements this Listener.
- The statements inside this call back method will dictate whats needed to be done, when the action is done on the Event Source.
Eg:
Assume
Event Source - Button
When Clicked - Event object is thrown at the call back method
Call back method - actionPerformed(ActionEvent e) inside ActionListener.
Now your case :
Now this can be done in 2 ways.....
1. Let you Display class implements the ActionListener, then Register the button with
the ActionListener, and finally implement the abstract method actionPerformed() of ActionListener.
Eg:
public class Display extends Canvas implements ActionListener{
public Display(){
// Your code....
setComponent(); // Initializing the state of Components
}
public void setComponent(){
// Your code.........
Button b = new Button("Click");
b.addActionListener(this); // Registering the button.
// Your code..........
}
public void actionPerformed(ActionEvent event) {
// Do here whatever you want on the Button Click
}
}
2. Use Anonymous class.
- Anonymous class are declared and initialized simultaneously.
- Anonymous class must implement or extend to only one interface or class resp.
Your Display class will NOT implement ActionListener here....
public class Display extends Canvas {
public Display(){
// Your code....
setComponent(); // Initializing the state of Components
}
public void setComponent(){
// Your code.........
Button b = new Button("Click");
// Registering the button and Implementing it
b.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event) {
// Do here whatever you want on the Button Click
}
});
// Your code..........
}
}
You need to implement ActionListner :
public class Display extends Canvas implements ActionListener
and add yourself to your button as such:
erase.addActionListener(this);
and then implement the required method:
public void actionPerformed(ActionEvent event) {
//do stuff
}
For more info, check out this tutorial on creating ActionListeners.
You'll find that this observable pattern is widely used the in Java GUI.
A couple high level critiques:
You are using many older AWT components (ie Button) when there are similar, but newer (read: more flexible) Swing components available (ie JButton). Take a look at this for a quick explanation on the difference.
The event model that you have implemented was revamped in 1997 to the observable pattern that I suggested above. If you would like to learn more, you can read this.

Categories

Resources