How to pass user input from GUI to main class - java

I'm just starting to work with Java Swing again and I have the same problem as last time.
I want to write a program which reads some user input, executes an algorithm and displays the result. The program has to work with two different user interfaces (console and GUI with Java Swing).
Currently I have a packet of classes with the algorithm (i can just pass in the user input and fetch the result), a class which contains the main class, a class for the console interface and a class for the GUI (which extends from JFrame).
Some code:
public class Algorithm {
//a lot of code
}
public class MainClass {
public static void main(...) {
Algorithm algorithm = new Algorithm();
//use either console or GUI and read user input
algorithm.execute(user input);
algorithm.getResult();
//display result on console/GUI
}
}
public class GUI extends JFrame implements ActionListener {
}
My Problem is that I don't know how to pass the user input (text, scalers and radio buttons, button) from the GUI to the algorithm and how to display the result on the GUI.
Do I have to pass an instance of Algorithm to the GUI and call the methods of Algorithm from GUI?
Or is it possible to implement the ActionsListener in MainClass (where I have an instance of Algorithm)? If I choose this way of implementation, how can i pass the result of the Algorithm back to the GUI?
Or should i change the whole implementation? :D

Short answer: Don't (at least not to the Main class).
Long answer: There is a pattern called Model-View-Controller (MVC) which explains how to get data from the user, do something with it and display it again. This link (and the whole site in general) is a good point to start: http://martinfowler.com/eaaDev/uiArchs.html
Applied to your code sample:
public class Algorithm {
//a lot of code
}
public class MainClass {
public static void main(...) {
Algorithm algorithm = new Algorithm();
GUI g = new GUI(algorithm );
}
}
public class GUI extends JFrame implements ActionListener {
private Algorithm algo;
public GUI(Algorithm a) { this.algo = a; }
}
Algorithm plays the role of the model here and GUI is a combination of controller and view.

Since you have the Algorithm nicely encapsulated in its own class then it should be easy to instantiate on object of type Algorithm in response to a button click on your GUI and execute the algorithm there. The main method shoul donly decide if the GUI is necessary and start it up.
So if you have a button called calculate on your GUI then:
calculate.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
//get the user input from the JFrame
Algorithm algorithm = new Algorithm();
algorithm.execute(user input);
algorithm.getResult();
//display results on the JFrame
}
});
Getting input from a JTextField and so on is as simple as
mytextfield.getText();
and to write some value into a JLabel to display is:
mylabel.setText("Some Text");

You can use the Observer Pattern. In this case algorithm is the java.util.Observer and Gui is the java.util.Observable.

Related

Accessing an attribute from container class

I have an A class and a B class
In the A class I have multiple B instances. From A class, after defining B, I write a mouseListener event for the B class, and it works. Now I realiced that I have to write the same mouseListener for every B class that I instantiate, and all they do is the same: Opening a DialogBox asking for a number, so I decided to write that mouseListener in the B class constructor.
The problem comes when that mouseListener has to access to an A's private attribute. In this point, I thought about using a functional interface / callback to send values from B to A when the mouseEvent is fired, but I feel like the code will be a little bit messy, like I'm using the wrong tools to reach the functionality I want, maybe I'm wrong...
Any advice or recomendation ? I'll post a little bit of the code so you can understand it better. This is my A class: This code works but now think that I have to write the same code lines again and again
PowerConfigPanel is the A class.
PTextField is the B class.
connectionListener is the A private attribute I was talking about.
public class PowerConfigPanel extends JPanel {
private ConnectionListener connectionListener;
public PowerConfigPanel(){
PTextField SUSPEND_CHARGER_BF= new PTextField(7);
SUSPEND_CHARGER_BF.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
JPanel insertValuePanel = new JPanel();
insertValuePanel.setLayout(new GridLayout(3,2,1,1));
PTextField field = new PTextField(7);
insertValuePanel.add(UtilsService.createComponentPanel(field,"Insert Value "));
int result = JOptionPane.showConfirmDialog(null, insertValuePanel,
"Please Enter a new Value", JOptionPane.OK_CANCEL_OPTION);
if(result == JOptionPane.OK_OPTION){
JOptionPane.showMessageDialog(null, "Invalid input for seconds", "Error", JOptionPane.ERROR_MESSAGE);
connectionListener.connect("a","b",Integer.valueOf(field.getText()));
}
}
});
}
}
What I mean is: mouseClick returns void... is there any possibility to make it return an integer and collect that integer in the A class when the B class is clicked?

Java - Linking a JTextField variable with another class variable

What I want to achieve is very simple.
I have 2 classes. "SpeedingTicket" & "SpeedingTicket GUI".
Inside my GUI I have 1 textbox name txtSpeedLimit & a button.
Inside my SpeedingTicket class I have a variable "int speedingTicket".
Inside my SpeedingTicket class I also have a get & set method for "speedingTicket".
I know how to get and set text using JTextFields, but I want to be able to:
receive input from the "txtSpeedLimit", and store that value into the "txtSpeedLimit" instance variable in the "SpeedTicket" class. I can then check for validation etc when I come to adding the vehicle speed.
Maybe this isn't the most efficient way of dealing with this program. Maybe I should scrap the instance variables in SpeedingTicket, and deal with it all in the GUI.
Any advice would be hugely appreciated.
Basically what I'm trying to do is this:
class confirmHandler implements ActionListener{
public void actionPerformed(ActionEvent e){
String val = txtSpeedLimit.getText();
int realNum = speed.getSpeedLimit() = txtSpeedLimit; < but obviously that doesn't work, but I want the textbox link to the variable.
EDIT: If we take away the GUI, all I want my program to do is the following:
Speed Limit: 50 < enterd via textfield
Speed: 60 < entered via textfield
if the speed is blah blah (ive already coded this).. then output a result to one of my labels.
I achieved this without making a GUI and making it only console based, but instead of the user typing it via the console, I want it to be typed via textfields.
THe values that are entered into the textfields should be stored in the two variables (speed and speedlimit) that are in the SpeedingTicket class.
You can update a value in:
public class SpeedingTicket {
int speedingTicket;
public SpeedingTicket() {
speedingTicket = 500;
}
public int getSpeedingTicket() {
return speedingTicket;
}
}
by:
public class SpeedingTicketGUI extends JPanel{
SpeedingTicket st;
SpeedingTicketGUI() {
st = new SpeedingTicket();
setLayout(new FlowLayout(FlowLayout.LEFT));
JTextField txtField = new JTextField(10);
txtField.setText(""+st.getSpeedingTicket());
add(txtField);
JButton btn = new JButton("Update");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setSpeedingTicket(txtField.getText());
}
});
add(btn);
}
private void setSpeedingTicket(String text) {
try {
int speedTicket = Integer.parseInt(text);
st.setSpeedingTicket(speedTicket);
System.out.println("Speeding ticket set to " +st.getSpeedingTicket());
} catch (NumberFormatException ex) {
System.out.println("Invalid value " +text);
ex.printStackTrace();
}
}
public static void main(String[] args){
JFrame frame = new JFrame("Speeding Ticket");
frame.setSize(400,100);
frame.add(new SpeedingTicketGUI());
frame.setVisible(true);
}
}
You don't need to store values in JText or any GUI componenets...
Use global static variables. For example:
public static int speed_limit;
You can access this variable from ANY method,class, etc.
There are multiple ways to do it.
You can detect textfield changes by using a DocumentListener or if you want (not recommended) by a KeyListener.
The Listener could be implemented directly by your gui class or by your other class. If you want more abstraction you could implement the DocumentListener by your gui class and create a method
public void addSpeedChangeListener(SpeedChangeListener scl) {
this.speedChangeListeners.add(scl);
}
Your SpeedChangeListener could be very simple:
public interface SpeedChangeListener {
public void speedChanged(int value);
}
Then your second class implements the SpeedChangeListener and calls addSpeedChangeListener(this) on your gui class. Inside the gui class, your document listener calls speedChanged(val) for every listener registered.
EDIT
You can also use the Button and call the speedChanged on every listener inside the actionPerformed method of the ActionListener.
I think it would be easier to use a JOptionDialog which pop ups when the button is clicked. That way you can easily get input and also validate the input straight away.

How to use ActionListener in another class

I am cleaning my code. I read that I putting the ActionListener is another class is better. So that's what I did.
But in my ActionListener, everything works except at some point in the code, I got a setSize(xx,xx). I worked before because it was in the same class. But not anymore. I've tried multiple solutions but I couldn't figure it out.
ActionListener:
public class ActionFrame implements ActionListener{
public void actionPerformed(ActionEvent e){
Object src = e.getSource();
if(src == Frame.Console_Bouton){
System.out.println("Bouton console");
if(getSize().getWidth() >= 750){
/** If True (Retirer) */
for(int i = 1090; i > 689; i--){
setSize(i, 490);
System.out.println("Rétractation du Frame");
}
}else{
/** If False (Etirer) */
for(int i = 689; i < 1090; i++){
setSize(i, 490);
System.out.println("Etirage du Frame");
}
}
}
...
As for errors, there are none, it will just freeze the program.
Guessing: possibly this is a case where extracting the ActionListener is not a great idea, since it uses a private method of your object.
Classes with generic/reusable functionality deserve to be on their own. As long as they are intended for specific usage, it's not bad practice (at all!) to only put them as close as possible to the spot where they're used. I can imagine that your setSize method is not part of your class' public interface, so the ActionListener is merely 'glue' to couple an event to your specific class.
In this case, you would create a 'tiny' line of glue:
abstract class ActionAdapter implements ActionListener {
}
...
frame.Console_Bouton.addActionListener(
new ActionAdapter(){ // anonymous inner class
void actionPerformed(ActionEvent e){
... // (no need to check source!)
}
});
Create a new class as:
ButtonAction implements actionListner
{
//put the code above here
}
A Good way of doing this is use Callback mechanism.
I have posted an answer in the same context here
JFrame in separate class, what about the ActionListener?
-- EDIT--
Get the source from ActionEvent then find its parent (get parent of parent if needed until you get the desired component that needs to be re sized) and call setSize() on it.
Create an instance of the View in the controller
Change the access modifier of setSize(xx,yy)method from private to public.
replace setSize in actionPerformed() with to view.setSize(xx,yy).

Separating classes in java. Eg. virtual keyboard (with activelisteners) and another class to receive input from the keyboard class

I have a virtual keyboard class which implements a QWERTY alphanumeric only on-screen keyboard using JButtons in JAVA.
I have installed actionlisteners to each button so that whenever the button is clicked on the label of the button is logged.
What I want to do is that while keeping the class for keyboard separate, I want to create an instance of the keyboard class so that it receives an input and it passes it back to the main class and then that can happen in a loop. Just like how you can use has.nextLine() to keep on asking for input, I want to be able to do this by creating an instance of the on screen keyboard class.
I have already written the keyboard class and it works nicely and but the problem is that the integers are local to the keyboard class and I cant figure out a way to get it outside of the class.
You can use observer pattern . I am not using swing here but just to show to show it works.
Make Keyboard class Observable
import java.util.Observable;
public class Keybaord extends Observable {
private String keyThatIsPressed;
public void setKeyThatIsPressed(String keyThatIsPressed) {
this.keyThatIsPressed = keyThatIsPressed;
setChanged();
notifyObservers(keyThatIsPressed);
}
public String getKeyThatIsPressed(){
return keyThatIsPressed;
}
}
Make your main class Observer
import java.util.Observable;
import java.util.Observer;
public class MainClass implements Observer {
private String keyThatIsPressed;
#Override
public void update(Observable observable,
Object object) {
if (object instanceof String) {
this.keyThatIsPressed = (String) object;
System.out.println("Key that was unlucky enough to get pressed was: "
+ keyThatIsPressed);
}
}
}

Clearing a JTextArea from another class

I'm very new to Java and I'm setting myself the challenge on writing a Caesar shift cipher decoder. I'm basically trying to clear a JTextArea from another class. I have two classes, a GUI class called CrackerGUI and a shift class. The JtextArea is in the GUI class along with the following method:
public void setPlainTextBox(String text)
{
plainTextBox.setText(text);
}
The GUI class also has a clear button with the following:
private void btnClearActionPerformed(java.awt.event.ActionEvent evt) {
Shift classShift = new Shift();
classShift.btnClear();
}
Lastly i have the method in the shift class to clear the JTextArea.
public class Shift extends CrackerGUI {
public void btnClear()
{
CrackerGUI gui = new CrackerGUI();
gui.setPlainText(" ");
System.out.println("testing");
}
}
The testing text is printing out to console but the JTextArea wont clear. I'm not sure as to why :). I am sure it's a very simple mistake but it has me baffled. Any help would be appreciated.
Thank you in advance.
You're misusing inheritance to solve a problem that doesn't involve inheritance. Don't have Shift extend CrackerGUI and don't create a new CrackerGUI object inside of the btnClear() method since neither CrackerGUi is the one that's displayed. Instead have Shift hold a reference to the displayed CrackerGUI object and have it call a public method of this object.
e.g.,
public class Shift {
private CrackerGUI gui;
// pass in a reference to the displayed CrackerGUI object
public Shift(CrackerGUI gui) {
this.gui = gui;
}
public void btnClear() {
//CrackerGUI gui = new CrackerGUI();
gui.setPlainText(" ");
System.out.println("testing");
}
}
You also should probably not be creating new Shift objects in your GUI's actionPerformed methods, but rather use only one Shift object that is a class field.
The btnClear method clears the text area of a new CrackerGUI instance. It's like if you wanted to clear a drawing on a sheet of paper by taking a new blank sheet and clearing it. The original sheet of paper will keep its drawing.
You need to pass the gui instance to your Shift:
public class Shift {
private CrackerGUI gui;
public Shift(CrackerGUI gui) {
this.gui = gui;
}
public void btnClear() {
this.gui.setPlainText(" ");
}
}
and in the CrackerGUI class :
private void btnClearActionPerformed(java.awt.event.ActionEvent evt) {
Shift classShift = new Shift(this);
classShift.btnClear();
}
Assuming CrackerGUI is your GUI, you should have the following instead:
public class CrackerGUI {
public void setPlainTextBox(String text)
{
plainTextBox.setText(text);
}
public void btnClear()
{
setPlainTextBox("");
System.out.println("testing");
}
}
One last thing, never make your GUI elements public! You should ask the GUI to clear itself and leave that knowledge of clearing elements hidden inside it.
You could try using static methods, as you would end up creating a new gui, then displaying that one, in stead of the current one already displayed.
This would require the parent class to be static too, which may cause errors in some of your methods, just a heads up.
Or else, you could create your own setText method:
void setText(JTextField t, String s){
t.setText(s);
}
that may enable you to directly edit components in the current GUI.

Categories