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?
Related
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.
The following code is within a class that has the buttons and checkboxes defined. The problem that I am having is with the lines "String text = txtField.getText();" and "chkAccount.withdraw(amount);".
I have a separate class file that defines the txtField and am trying to get the text that has been input into that box. The error I see is "cannot find symbol". I have looked into it but cant find information in depth enough to answer my question.
The second line refers to the object chkAccount which is derived from a separate class "Account" and instantiated in the main class of my program. The error for this is the same as the above.
//Button Listeners Class
withdrawalBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//Execute this code when the button is pressed
if(checking.isSelected()) {
String text = txtField.getText();
int amount = Integer.parseInt(text);
try {
chkAccount.withdraw(amount);
} catch (InsufficientFunds ex) {
int messageType = JOptionPane.PLAIN_MESSAGE;
JOptionPane.showMessageDialog(null, "Balance too low" +
"or amount entered not an Interval of 20.",
"Notice", messageType);
}
}
I can't really tell what the code that you've provided is trying to do, but just based on the title of your question, I would recommend you have the class that you want the information to go to extends ActionListener, add an object of that type of class (the one that you had extend ActionListener) as an ActionListener to the JTextField, and then in the actionPerformed method (which you'll have to add, as the class now extends ActionListener) use ActionEvent.getSource (and cast) to get the JTextField! From there, you can extract the information that you need.
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).
The title is a bit ambiguous and I will explain in codes. Suppose I have
Class A extends JFrame implements ActionListener{
B b;
Class B extends JPanel{
public JButton button;
public B(A a){
button = new JButton();
button.addActionListener(a);// I want to process all actionEvents in A
this.add(button);
}
}
public A(){
b = new B(this);
//irrelevant codes omitted for brevity
}
public void actionPerformed(ActionEvent e){
//Here's the question:
//Suppose I have a lot of Bs in A,
//how can I determine which B the button
//that triggers this callback belongs to?
}
}
So is there any way to to that? Or my idea is wrong? Any thought is welcomed.
EDIT:
What I finally do is to add a function has(JComponent component) to B to compare against every clickable B has. The getParent() becomes awkward when you have multiple layers of JPanel as it's hard to figure out which layer of panel it's referring to and it's against the idea of encapsulation.
Use e.getSource() to get a reference to the exact component that triggered the event. In your case, it will be a JButton. To get the panel it sits on, use e.getSource().getParent().
Say you have B[] bs = new B[n];
Then you could set action command for each button, such as:
for (B b : bs) {
b.setActionCommand("some identifiable command"); // use different command for different buttons
}
Then in the actionPerformed method, switch on the commands:
public void actionPerformed (ActionEvent e) {
switch (e.getActionCommand()) {
case "cmd1":
// do something
break;
case "cmd2":
// do something
break;
default:
}
}
You can also use Action objects, which is more flexible but a little more complicated.
For more information, please read Java tutorial:
How to Use Buttons, Check Boxes, and Radio Buttons
How to Use Actions
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.