Use KeyListener in a loop - java

I don't have a lot of experience with KeyListeners but I used one in my application and it works fine except I need to wait for input before my program can continue. For this I made a while loop that loops until the String temp is not null (which would mean there would be input).
The problem is there is no way to type in the JTextField (called input). Below is code from my two methods that are supposed to work together so that the text in my JTextField (input) can be returned (as temp). I'm not sure why this doesn't work or how to fix it.
The keyPressed method for my KeyListener:
public void keyPressed(KeyEvent e)
{
//only sends text if the enter key is pressed
if (e.getKeyCode()==KeyEvent.VK_ENTER)
{
//if there really is text
if (!input.getText().equals(""))
{
//String temp is changed from null to input
temp=input.getText();
//text sent to another JTextField
output.append(temp+"\n");
//input no longer has text
input.setText("");
}
}
}
The method thats trying to get text, also in my KeyListener class
public String getTemp()
{
booleans isNull=temp==null;
//loops until temp is not null
while (isNull)
{
//unnecessary line of code, only used so the loop not empty
isNull=checkTemp();
}
return temp;
}
public boolean checkTemp()
{
return temp==null;
}

Your while loop is a common console program construct, but understand that you're not creating a console program here but rather an event-driven GUI, and in this situation, the while loop fights against the Swing GUI library, and you need to get rid of it. Instead of a while loop with continual polling you now want to respond to events, and if you're listening for user input into a JTextField do not use a KeyListener as this low-level listener can cause unwanted side effects. Instead add a DocumentListener to the JTextField's Document.
Edit: You're listening for the enter key, and so the solution is even easier: add an ActionListener to the JTextField!
e.g.,
input.addActionListener(e -> {
String text = input.getText().trim();
if (text.isEmpty()) {
return;
}
output.append(text + "\n");
input.setText("");
});
More complete example:
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import javax.swing.*;
public class ChatBox extends JPanel {
private static final int COLS = 40;
private JTextField input = new JTextField(COLS);
private JTextArea output = new JTextArea(20, COLS);
private JButton submitButton = new JButton("Submit");
public ChatBox() {
output.setFocusable(false); // user can't get into output
JScrollPane scrollPane = new JScrollPane(output);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
ActionListener inputListener = e -> {
String text = input.getText().trim();
if (text.isEmpty()) {
return;
}
output.append(text + "\n");
input.setText("");
input.requestFocusInWindow();
};
input.addActionListener(inputListener);
submitButton.addActionListener(inputListener);
JPanel bottomPanel = new JPanel();
bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.LINE_AXIS));
bottomPanel.add(input);
bottomPanel.add(submitButton);
setLayout(new BorderLayout());
add(scrollPane, BorderLayout.CENTER);
add(bottomPanel, BorderLayout.PAGE_END);
}
private static void createAndShowGui() {
ChatBox mainPanel = new ChatBox();
JFrame frame = new JFrame("Chat Box");
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(() -> createAndShowGui());
}
}

Related

How to Add text to JTextArea

Im creating a programme using java. I want the user to enter some text, then push the button so the text entered shows in the label. However, I have 2 problems. First, the text are isn´t displaying when I execute the app. Second, I don´t know how to allow the user to type in the area. Im new in java so that´s why Im asking. Here is the code. Thank you.
import javax.swing.*;
import java.awt.event.*;
class Boton extends JFrame implements ActionListener {
JButton boton;
JTextArea textArea = new JTextArea();
JLabel etiqueta = new JLabel();
public Boton() {
setLayout(null);
boton = new JButton("Escribir");
boton.setBounds(100, 150, 100, 30);
boton.addActionListener(this);
add(boton);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == boton) {
try {
String texto = textArea.getText();
etiqueta.setText(texto);
Thread.sleep(3000);
System.exit(0);
} catch (Exception excep) {
System.exit(0);
}
}
}
}
public class Main{
public static void main(String[] ar) {
Boton boton1 =new Boton();
boton1.setBounds(0,0,450,350);
boton1.setVisible(true);
boton1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Problems:
You never add the JTextArea into your GUI, and if it doesn't show, a user cannot directly interact with it.
You are calling Thread.sleep on the Swing event thread, and this will put the entire application to sleep, meaning the text that you added will not show.
Other issues include use of null layouts and setBounds -- avoid doing this.
Solutions:
Set the JTextArea's column and row properties so that it sizes well.
Since your JTextArea's text is going into a JLabel, a component that only allows a single line of text, I wonder if you should be using a JTextArea at all. Perhaps a JTextField would work better since it allows user input but only one line of text.
Add the JTextArea to a JScrollPane (its viewport actually) and add that to your GUI. Then the user can interact directly with it. This is most easily done by passing the JTextArea into a JScrollPane's constructor.
Get rid of the Thread.sleep and instead, if you want to use a delay, use a Swing Timer. check out the tutorial here
For example:
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Window;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class Main2 {
public static void main(String[] args) {
// create GUI in a thread-safe manner
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
BotonExample mainPanel = new BotonExample();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
class BotonExample extends JPanel {
private JLabel etiqueta = new JLabel(" ");
private JButton boton = new JButton("Escribir");
// jtext area rows and column properties
private int rows = 5;
private int columns = 30;
private JTextArea textArea = new JTextArea(rows, columns);
public BotonExample() {
// alt-e will activate button
boton.setMnemonic(KeyEvent.VK_E);
boton.addActionListener(e -> {
boton.setEnabled(false); // prevent button from re-activating
String text = textArea.getText();
etiqueta.setText(text);
// delay for timer
int delay = 3000;
Timer timer = new Timer(delay, e2 -> {
// get current window and dispose ofit
Window window = SwingUtilities.getWindowAncestor(boton);
window.dispose();
});
timer.setRepeats(false);
timer.start(); // start timer
});
// create JPanels to add to GUI
JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 5, 5));
topPanel.add(new JLabel("Etiqueta:"));
topPanel.add(etiqueta);
JPanel bottomPanel = new JPanel();
bottomPanel.add(boton);
JScrollPane scrollPane = new JScrollPane(textArea);
// use layout manager and add components
setLayout(new BorderLayout());
add(topPanel, BorderLayout.PAGE_START);
add(scrollPane, BorderLayout.CENTER);
add(bottomPanel, BorderLayout.PAGE_END);
}
}
textarea.setText("Text"); // this will insert text into the text area
textarea.setVisable(true); // this will display the text area so you can type in it
textarea.setSize(500,500); // set size of the textarea so it actually shows
The user should be able to type in the TA when it is displayed and just do a getText to pull the text

How do I wait for the input from the GUI back to main?

I want to be able to pass user input from my GUI to one of my classes. However, the input is not passed over and immediately checks the if statement.
How do I get program to wait for the input and only checks after the button is clicked?
Main class
public class MainTest {
public static void main(String[] args) {
String weaponCategory;
//Create Java GUI
GUITest window = new GUITest();
if(window.getCategory() != "")
{
System.out.println("test");
}
}
}
GUITest class
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class GUITest implements ActionListener{
private JFrame frmInventorysystem;
private JPanel frameBottom;
private JComboBox equipList;
private String category = "";
private JButton confirmBtn, cancelBtn;
/**
* Create the application.
*/
public GUITest()
{
frmInventorysystem = new JFrame();
frmInventorysystem.setTitle("InventorySystem");
frmInventorysystem.setBounds(100, 100, 450, 300);
frmInventorysystem.getContentPane().setLayout(new BorderLayout(0, 0));
frmInventorysystem.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
/*JFrame inside another JFrame is not recommended. JPanels are used instead.
* Creating a flow layout for the bottom frame
*/
frameBottom = new JPanel();
frameBottom.setLayout(new FlowLayout());
//creates comboBox to find out which of the three items player is looking to insert
String[] weaponCategories = {"Weapon", "Armor", "Mod"};
equipList = new JComboBox(weaponCategories);
frmInventorysystem.getContentPane().add(equipList, BorderLayout.NORTH);
//Converting BorderLayout.south into a flow layout
frmInventorysystem.getContentPane().add(frameBottom, BorderLayout.SOUTH);
confirmBtn = new JButton("Confirm");
confirmBtn.addActionListener(this);
frameBottom.add(confirmBtn);
cancelBtn = new JButton("Cancel");
cancelBtn.addActionListener(this);
frameBottom.add(cancelBtn);
frmInventorysystem.setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
//creates new windows to sort equipment when confirmBtn is clicked
if(e.getSource() == confirmBtn)
{
if(equipList.getSelectedItem().equals("Weapon"))
{
//GUIWeaponCategory weapon = new GUIWeaponCategory();
category = equipList.getSelectedItem().toString();
}
}
//Exits when cancelBtn is clicked
if(e.getSource() == cancelBtn)
{
System.exit(0);
}
}
public String getCategory()
{
return category;
}
public void setCategory(String a)
{
category = a;
}
}
GUITest launches as expected.
However, the first println is missing.
How would I go about doing this?
What concepts or pieces of code am I missing?
EDIT1: Added a couple more details to make the program reproducible and complete.
EDIT2: Making the code more readable for easy understanding.
There are some changes to make on your program
Remove extends JFrame as stated in my comments above, see Extends JFrame vs. creating it inside the program
Place your program on the EDT, see point #3 on this answer and the main method for an example on how to do that.
You're confused about how the ActionListeners work, they wait until you perform certain action in your program (i.e. you press Confirm button) and then do something. "Something" in your program means: Print the selected item and check if it's a weapon then, do something else.
So, in this case, you don't need to return back to main to continue with your program, main only serves to initialize your application and nothing else. You need to think in the events and not in a sequential way. That's the tricky and most important part.
You need to change your programming paradigm from console applications and do-while that everything happens in a sequential manner rather than events that are triggered when the user does something with your application.
For example:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class GUITest implements ActionListener {
private JFrame frmInventorysystem;
private JPanel frameBottom;
private JComboBox equipList;
private JButton confirmBtn, cancelBtn;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new GUITest()); //Java 8+ if using an earlier version check the point #2 in this answer and modify the code accordingly.
}
/**
* Create the application.
*/
public GUITest() {
frmInventorysystem = new JFrame();
frmInventorysystem.setTitle("InventorySystem");
frmInventorysystem.setBounds(100, 100, 450, 300);
frmInventorysystem.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmInventorysystem.getContentPane().setLayout(new BorderLayout(0, 0));
/*
* JFrame inside another JFrame is not recommended. JPanels are used instead
* Creating a flow layout for the bottom frame
*/
frameBottom = new JPanel();
frameBottom.setLayout(new FlowLayout());
// creates comboBox to find out which of the three items player is looking to
// insert
String[] weaponCategories = { "Weapon", "Armor", "Mod" };
equipList = new JComboBox(weaponCategories);
frmInventorysystem.getContentPane().add(equipList, BorderLayout.NORTH);
// Converting BorderLayout.south into a flow layout
frmInventorysystem.getContentPane().add(frameBottom, BorderLayout.SOUTH);
confirmBtn = new JButton("Confirm");
confirmBtn.addActionListener(this);
frameBottom.add(confirmBtn);
cancelBtn = new JButton("Cancel");
cancelBtn.addActionListener(this);
frameBottom.add(cancelBtn);
frmInventorysystem.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
// creates new windows to sort equipment when confirmBtn is clicked
if (e.getSource() == confirmBtn) {
String category = equipList.getSelectedItem().toString(); //Get the selected category
doSomething(category); //Pass it as a parameter
}
// Exits when cancelBtn is clicked
if (e.getSource() == cancelBtn) {
frmInventorysystem.dispose();
}
}
// Do something with the category
private void doSomething(String selectedEquipment) {
System.out.println(selectedEquipment);
if (selectedEquipment.equals("Weapon")) {
System.out.println("It's a weapon!"); //You can open dialogs or do whatever you need here, not necessarily a print.
} else {
System.out.println("Not a weapon");
}
}
}
Notice that I removed inheritance, I'm not returning back to main and still printing the selected item and checking if it's a weapon or not.
I also exit the application in a safer way.
This is a sample output:
Weapon
It's a weapon!
Armor
Not a weapon

Make program "pause" until the user enters something in a JTextField

I'm tying to make a program that acts similar to the Windows Command Prompt, or a terminal. It's basically just a JFrame with a JTextArea as output, and a JTextField as input. It looks like this:
I want to be able to get input from the JTextField whenever my program calls a method that returns a String, something like:
public static String getInput() {
//Wait for user to enter something, then press the enter key
}
I added an AbstractAction so I can do stuff when the enter key is pressed, but I still could figure out how to return the input as a String whenever I call the method.
Action action = new AbstractAction(){
#Override
public void actionPerformed(ActionEvent e) {
//Clears the JTextField
input.setText("");
}
};
I could put something like userInput = input.getText() in public void actionPerformed(), so it would just set a variable to whatever has been entered every time, and use userInput whenever I want to, but I want the user to have time to read whats on the screen, then have the program wait for a response, instead of just using the last thing they entered right away.
I tried to use a userInput variable and a boolean variable like this:
private static String userInput = "";
private static boolean enterPressed = false;
Action action = new AbstractAction(){
#Override
public void actionPerformed(ActionEvent e) {
userInput = input.getText()
enterPressed = true;
input.setText("");
}
};
...
public static String getInput() {
enterPressed = false;
while(!enterPressed){
//Do Nothing
}
enterPressed = false;
return userInput;
}
When I called output.setText(getInput());, it worked like I wanted to, except that the while(!enterPressed){} made my processor work a lot harder than it should need to. I'm pretty sure there's probably a lot better way of doing this.
Here's my whole code right now:
public class ConsoleFrame {
//Objects for Console Frame
JFrame frame = new JFrame();
JTextArea output = new JTextArea();
JTextField input = new JTextField();
BoxLayout boxLayout = new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS);
JScrollPane scrollPane = new JScrollPane(output);
DefaultCaret caret = (DefaultCaret)output.getCaret();
Action action = new AbstractAction(){
#Override
public void actionPerformed(ActionEvent e) {
input.setText("");
}
};
ConsoleFrame(){
input.addActionListener(action);
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
frame.setLayout(boxLayout);
frame.add(scrollPane);
frame.add(input);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 250);
frame.setLocationRelativeTo(null);
input.setMaximumSize(new Dimension(Integer.MAX_VALUE, 10));
output.setEditable(false);
output.setAutoscrolls(true);
}
public static String getInput() {
return null;
}
}
So, how could I stop the program until the user presses enter, every time I call getInput();?
I want to be able to get input from the JTextField whenever my program
calls a method that returns a String, something like:
I added an AbstractAction so I can do stuff when the enter key is
pressed, but I still could figure out how to return the input as a
String whenever I call the method.
public String getInput() {
return input.getText();
}
So, how could I stop the program until the user presses enter, every time I call getInput();?
You don't. Swing, like most UI frame works is event driven, that is, something happens and your respond to it.
So, with that in mind you should consider using some kind Observer Pattern, where you use a call back to be notified of some kind of change which you are interested in, like your ActionListener for example.
Instead, you could provide some kind of listener, which interested parties would register with and when the field changes you would notify them, for example...
import java.util.EventListener;
import java.util.EventObject;
public class InputEvent extends EventObject {
private final String text;
public InputEvent(Object source, String text) {
super(source);
this.text = text;
}
public String getText() {
return text;
}
}
public interface InputObsever extends EventListener {
public void inputChanged(InputEvent evt);
}
So, we now have an observer who will be notified when ever the input is changed/updated.
Then we simply need a way to un/register and fire the event...
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.event.EventListenerList;
import javax.swing.text.DefaultCaret;
public class ConsoleFrame {
//Objects for Console Frame
JFrame frame = new JFrame();
JTextArea output = new JTextArea();
JTextField input = new JTextField();
BoxLayout boxLayout = new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS);
JScrollPane scrollPane = new JScrollPane(output);
DefaultCaret caret = (DefaultCaret) output.getCaret();
Action action = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
fireInputChanged(input.getText());
input.selectAll();
}
};
private EventListenerList listenerList = new EventListenerList();
ConsoleFrame() {
input.addActionListener(action);
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
frame.setLayout(boxLayout);
frame.add(scrollPane);
frame.add(input);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 250);
frame.setLocationRelativeTo(null);
input.setMaximumSize(new Dimension(Integer.MAX_VALUE, 10));
output.setEditable(false);
output.setAutoscrolls(true);
}
public String getInput() {
return input.getText();
}
public void addInputObsever(InputObsever obsever) {
listenerList.add(InputObsever.class, obsever);
}
public void removeInputObsever(InputObsever obsever) {
listenerList.remove(InputObsever.class, obsever);
}
protected void fireInputChanged(String text) {
InputObsever[] listeners = listenerList.getListeners(InputObsever.class);
if (listeners.length > 0) {
InputEvent evt = new InputEvent(this, text);
for (InputObsever obsever : listeners) {
obsever.inputChanged(evt);
}
}
}
}
Now, the point here is, when you want to know when the text has been input/changed, you register an observer to the instance of the ConsoleFrame
console.addInputObsever(new InputObsever() {
#Override
public void inputChanged(InputEvent evt) {
// Do what ever you need to do...
}
});
EDIT: First half removed. It was brought to my attention that it was erroneous.
The best option is to enclose a call to whatever you need your computer to execute after the user inputs text inside your actionPerformed method. So when the user inputs text and presses enter, the program automatically continues from there.
Action action = new AbstractAction(){
#Override
public void actionPerformed(ActionEvent e) {
userInput = input.getText()
enterPressed = true;
input.setText("");
//call next method;
}
};
This requires some more formatting work on your behalf, but it could be helpful depending on your project. This link has more information on this strategy.
Hope this helped.
jTextField1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
yourFunction(jTextField1.getText());
jTextField1.setText("");
}
});
Btw just a tip, you may append the JTextArea to get the feel of a console window

Trying to create a character counter, but my button is not updating the while loop boolean to do so

so I am trying to make a small java program to count the number of characters in a given string.
Right now, my code works in the console output, but it is not updating the text field I have created in a JFrame and I am unsure why. Can someone please explain this to me?
BTW: I have set "onPress" to true, so the button doesn't really have an effect right now, I'm just trying to test the functionality of the program before I implement button functionality.
Thank you :)! Here is my code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class characterCounterTwov2 extends JFrame {
static boolean onPress = true;
public characterCounterTwov2(){
/*******************/
/* Local Variables */
/*******************/
//creates a new Jframe to put our frame objets in
JFrame frame = new JFrame();
//creates a text field frame object
JTextField txtField = new JTextField("Enter your text here", 25);
//stores the string of the the jtextfield into a variable text
String text = txtField.getText();
//creates a text field that is uneditable with the word "characters"
String charString = "Characters: ";
JTextField charField = new JTextField(charString, 25);
charField.setEditable(false);
//integer to count the characters
int charCounter = 0;
//string that will be used in a text field to display the # of chars
String charCount = Integer.toString(charCounter);
//Text field that displays charCount
JTextField charFieldTwo = new JTextField(charCount, 10);
//calculate button
JButton calcButton = new JButton("Calculate");
calcButton.addActionListener(new calcButtonFunc());
/*******************/
/* Frame Setup */
/*******************/
//sets the layout of the frame
frame.setLayout(new BorderLayout());
//add's elements to the frame
frame.add(txtField, BorderLayout.NORTH);
frame.add(charField, BorderLayout.CENTER);
frame.add(charFieldTwo, BorderLayout.SOUTH);
frame.add(calcButton, BorderLayout.EAST);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
//begin while loop
//infinite while loop
System.out.println("Entering main while loop");
while(true)
{
while(onPress == true)
{
System.out.println("text length is:" + charCount);
for(int i = 0; i < text.length(); i++)
{
charCounter++;
System.out.println("Number of characters:" + charCounter);
}
//charCount = Integer.toString(charCounter);
onPress = false;
}
}
}
static class calcButtonFunc implements ActionListener
{
public void actionPerformed(java.awt.event.ActionEvent event)
{
onPress = true;
}
}
public static void main(String[] args){
new characterCounterTwov2();
System.out.println("End of program. Should not get here");
}
}
~~~~~~~~~
EDIT
I was given a lot of helpful tips by Hovercraft Full of Eels, and cleaned up my code. I am still having a problem with calculating the character count on button press, and having it reflect in the GUI. I am thinking my bug lies within the line "text = txtField.getText();" inside my button listener class.
Here is my updated code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class characterCounterTwov4{
//creates a new Jframe to put our frame objets in
JFrame frame = new JFrame();
//creates a text field frame object
JTextField txtField = new JTextField(25);
//stores the string of the the jtextfield into a variable text
String text = txtField.getText();
//creates a text field that is uneditable with the word "characters"
String charString = "Characters: ";
JTextField charField = new JTextField(charString, 25);
public characterCounterTwov4(){
charField.setEditable(false);
//integer to count the characters
int charCounter = 0;
//string that will be used in a text field to display the # of chars
String charCount = Integer.toString(text.length());
//Text field that displays charCount
JTextField charFieldTwo = new JTextField(charCount, 10);
//calculate button
JButton calcButton = new JButton("Calculate");
calcButton.addActionListener(new ActionListener(){
public void actionPerformed(java.awt.event.ActionEvent event)
{
System.out.println("button pressed");
//stores the string of the the jtextfield into a variable text
text = txtField.getText();
//string that will be used in a text field to display the # of chars
String charCount = Integer.toString(text.length());
//Text field that displays charCount
JTextField charFieldTwo = new JTextField(charCount, 10);
}
});
/*******************/
/* Frame Setup */
/*******************/
//sets the layout of the frame
frame.setLayout(new BorderLayout());
//add's elements to the frame
frame.add(txtField, BorderLayout.NORTH);
frame.add(charField, BorderLayout.CENTER);
frame.add(charFieldTwo, BorderLayout.SOUTH);
frame.add(calcButton, BorderLayout.EAST);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args){
new characterCounterTwov4();
System.out.println("End of program. Should not get here");
}
}
Your code is not structured for correct Swing GUI event-driven programming but rather looks like a linear console program that is being shoe-horned into a GUI. Get rid of that while loop, get rid of that static boolean variable. Instead give your class a non-static (instance) int counter variable and a JTextField non-static variable and simply increment your counter in the actionPerformed method and display the results in the JTextField (or JLabel if you prefer).
So the actionPerformed could look something like:
public void actionPerformed(ActionEVent e) {
counter++; // increment the counter variable
charCount.setText("Count: " + counter); // display the results
}
and again, counter and charCount are non-static and are declared and initialized in the class, not inside of the constructor or any method.
Edit
Additional notes:
Why does your class extend JFrame when you don't use it as a JFrame?
In general, it's a good idea to start all Swing proggrams on the Swing Event Dispatch Thread or EDT. This can be done by passing a Runnable with your start-up code in it to the SwingUtilities static method invokeLater(...).
For example:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
// create and display your GUI from in here
MainGui mainGui = new MainGui();
JFrame mainFrame = new JFrame("Main GUI");
mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
mainFrame.add(mainGui);
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
}
Edit 2
Oops, I read your requirements wrong. You need to count the chars in a String, and so you will need another class instance JTextField, one to hold the user's String, get rid of the counter instance field since it no longer will be needed, and then in the actionPerformed method, simply get the String from the JTextField, get its length, and display the length in another JTextField or in a JLabel, again your choice.
Edit 3
Your code is now almost there!
Problems:
The charFieldTwo variable is a non-final local variable. To be able to use it in your anonymous inner class, either make it final, and note that doing this won't harm its ability to work since it is a reference variable, not a primite,
Or you could move its declaration out of the constructor, like you do the other variables.
Once you've done this, it is easy to call charFieldTwo.setText(charCount); on it at the bottom of your ActionListener, and you're pretty much done.

using listeners with both list and button

Very new to Java, but I am slowly picking my way through things. So please be kind. I understand most things I've tried so far, and built a version of the following that uses console output, but now I'm trying to make a GUI. I tried the netbeans GUI maker, but it created so much new code that when I tried to pick through it, I got lost. I'm much better at learning by piecing new things together myself, not having an IDE generate a ton of code and then attempt to find where I want to work.
I am trying to build an window that has a list with three choices on the left side, a button in the middle that confirms your choice, and an answer output on the right. Once the button is pressed, the input from the list is read and is converted into a corresponding answer. As of right now, all I get is "We recommend... null" after selecting an option in the list. The button appears to do nothing at the moment.
I have used tutorials, hacked up others' code from online, and referenced a few books, but I'm stuck.
Here is what I have:
package diffguidegui;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class DiffGuideGUI extends JPanel implements ListSelectionListener {
private JList resultsTabList;
private DefaultListModel listModel;
private static final String recommendString = "Recommend a Option";
private JButton recommendButton;
private String recommendOutput;
final JLabel output = new JLabel("We recommend..." + recommendOutput);
//build list
public DiffGuideGUI () {
super(new BorderLayout());
listModel = new DefaultListModel();
listModel.addElement("A");
listModel.addElement("B");
//create the list and put it in the scroll pane
resultsTabList = new JList(listModel);
resultsTabList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
resultsTabList.setSelectedIndex(0);
//listener for user input
resultsTabList.addListSelectionListener(this);
resultsTabList.setVisibleRowCount(2);
JScrollPane listScrollPane = new JScrollPane(resultsTabList);
//build the button at the bottom to fire overall behavior
recommendButton = new JButton(recommendString);
recommendButton.setActionCommand(recommendString);
recommendButton.addActionListener(new RecommendListener());
//create a panel that uses Boxlayout for the button
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
buttonPane.add(recommendButton);
//create a panel that uses Boxlayout for the label
JPanel outputPane = new JPanel();
outputPane.setLayout(new BoxLayout(outputPane, BoxLayout.LINE_AXIS));
outputPane.add(output);
add(listScrollPane, BorderLayout.WEST);
add(buttonPane, BorderLayout.CENTER);
add(outputPane, BorderLayout.EAST);
}
//build listener class
class RecommendListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
//build in logic for choice made here
String resultsTabChoice;
resultsTabChoice = (String)resultsTabList.getSelectedValue();
if( resultsTabChoice.equals("A")) {
recommendOutput = "One";}
else {recommendOutput = "Two";}
}
}
public void valueChanged(ListSelectionEvent e) {
if(e.getValueIsAdjusting() == false) {
if(resultsTabList.getSelectedIndex() == -1) {
recommendButton.setEnabled(false);
} else {
recommendButton.setEnabled(true);
}
}
}
//Create GUI and show it
private static void createAndShowGUI() {
JFrame frame = new JFrame("Recommend Window");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//create and set up content pane
JComponent newContentPane = new DiffGuideGUI();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
//display the window
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
The button appears to do nothing at the moment.
It does something. It calculates the value for your recommendOutput varable. But you never output this value.
try the following:
//build listener class
class RecommendListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
//build in logic for choice made here
String resultsTabChoice;
resultsTabChoice = (String)resultsTabList.getSelectedValue();
if( resultsTabChoice.equals("A")) {
recommendOutput = "One";}
else {recommendOutput = "Two";}
System.out.println(recommendOutput); // <-###################
}
}
This should print the value to stdout
To put the value into your label try this instead:
output.setText(recommendOutput);
where do you set the text for the JLabel? It says "We recommend NULL" because recommenedOutput is null when the object is created. I dont see
output.setText("We recommend "+value) anywhere. You probably need output.invalidate() also. Try putting setText(String text)/invalidate() in the RecommendListener.actionPerformed() method.
output.setText("We recommend A");
output.invalidate();

Categories